c# - 从另一个 UserControl 创建 UserControl 并在运行时添加到父容器
问题描述
我有一个简单的 UserControl,其中包含一个 TextBox 和一个 Button。我希望单击该按钮将创建一个新的用户控件,该控件将位于单击其按钮的那个之后(下方)。
例如:
这是用户控件的代码:
<UserControl x:Class="LearnWPF.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height=".9*"/>
<RowDefinition Height=".1*"/>
</Grid.RowDefinitions>
<TextBox ></TextBox>
<Button Grid.Row="1" Content="Create New UserControl" FontSize="20"/>
</Grid>
这是主窗口:
<Window x:Class="LearnWPF.MyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:myUserControl="clr-namespace:LearnWPF"
Title="MainWindow" Height="450" Width="800">
<StackPanel>
<myUserControl:MyUserControl />
</StackPanel>
</Window>
通过按照此处的建议,我确实成功地将新的“myUserControls”添加到主窗口中的 StackPanel 。这个实现的两个主要问题是:
- 我不知道我是从哪个“myUserControl”得到事件的。
- 即使我知道单击了哪个按钮以及在哪里创建新的 UserControl,我也不知道如何在 StackPanel 中间插入(可能需要不同的面板?)
此外,此解决方案使用了后面的代码。有没有办法在 MVVM 中完成所有这些工作?
解决方案
如果要管理视图模型中的项目列表,则需要使用 anItemsControl
而不是从代码隐藏向 StackPanel 插入元素。可以通过 更改项目外观ItemsControl.ItemTemplate
。添加新项目的操作应由绑定到按钮的命令触发:
<Window x:Class="XamlApp.MyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MyWindow" WindowStartupLocation="CenterScreen"
Height="300" Width="300">
<Grid>
<ScrollViewer>
<ItemsControl ItemsSource="{Binding Path=MyItems}"
Margin="5"
Background="Wheat">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height=".9*" />
<RowDefinition Height=".1*" />
</Grid.RowDefinitions>
<TextBox Text="{Binding Path=MyText}" />
<Button Grid.Row="1"
Content="Create New UserControl"
FontSize="20"
Command="{Binding Path=DataContext.AddCmd,
RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Window>
视图模型应该有一个集合来存储项目和一个添加/插入项目的命令:
public class StringItem
{
public string MyText { get; set; }
}
public class MyViewModel
{
public MyViewModel()
{
MyItems = new ObservableCollection<StringItem>();
AddCmd = new RelayCommand<StringItem>(Add);
}
public ObservableCollection<StringItem> MyItems { get; private set; }
public ICommand AddCmd { get; private set; }
private void Add(StringItem current)
{
var item = new StringItem { MyText = "new item " + (MyItems.Count + 1) };
int idx = MyItems.IndexOf(current);
if (idx < 0)
MyItems.Add(item);
else
MyItems.Insert(idx + 1, item);
}
}
RelayCommand 是来自这个轻量级 MVVM 包的 ICommand 的实现
ViewModel 和 View 在 View 构造函数中连接在一起:
public partial class MyWindow : Window
{
public MyWindow()
{
InitializeComponent();
DataContext = new MyViewModel
{
MyItems = { new StringItem { MyText = "hello world" } }
};
}
}
推荐阅读
- php - 如何设置下拉codeigniter中选择的值
- mysql - 通过多个类别对表进行排名
- typescript - 如何从外部函数渲染组件
- javascript - 从包含 c# 变量的文件中执行 JS 脚本
- android - 从系统级别禁用所有无线电;AOSP
- c - 使用 EC_KEY 时 EVP_PKEY_verify 不起作用
- reactjs - 自动填充的输入字段会触发哪个事件?
- javascript - 为什么需要使用 promise 作为异步回调的包装器
- docker - 在 Windows10 hyper-V 上运行的 Docker Desktop for Windows 无法在 Oracle Virtualbox 6 中运行
- php - 如何在图像中添加产品永久链接标签 woocommerce 购物车项目?