从另一个UserControl创建UserControl并在运行时添加到父容器

时间:2018-06-28 06:18:25

标签: c# wpf mvvm user-controls

我有一个简单的UserControl,其中包含一个TextBox和一个Button。 我希望单击该按钮将创建一个新的用户控件,该控件将位于单击该按钮的那个控件之后(下方)。

例如:

enter image description here

这是UserControl的代码:

<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>

我确实按照建议here进行了添加,将新的“ myUserControls”添加到主窗口中的StackPanel中。此实现的两个主要问题是:

  1. 我无法确定我从哪个“ myUserControl”获得了事件。
  2. 即使我确实知道单击了哪个按钮以及通过哪个位置创建新的UserControl,我也不知道如何插入StackPanel的中间(也许是 需要不同的面板吗?)

此外,此解决方案在后面使用了代码。有没有办法在MVVM中完成所有这些工作?

1 个答案:

答案 0 :(得分:1)

如果要管理视图模型中的项目列表,则需要使用ItemsControl.ItemTemplate而不是从代码隐藏中将元素插入到StackPanel中。可以通过<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> 更改项目外观。添加新项的操作应由绑定到按钮的Command触发:

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);
    }
}

视图模型应该具有用于​​存储项目的集合和用于添加/插入项目的命令:

public partial class MyWindow : Window
{
    public MyWindow()
    {
        InitializeComponent();
        DataContext = new MyViewModel
        {
            MyItems = { new StringItem { MyText = "hello world" } }
        };
    }
}

RelayCommand是this lightweight MVVM package

中ICommand的实现

ViewModel和View在View构造函数中连接在一起:

$sql_check = "SELECT * FROM tblroom_equipment WHERE room_id = $_POST['room_id']";
$query_check = $connect->query($sql_check);

while ($row = mysqli_fetch_array($query_check)) {
      $equipment = $row['equipment'];

      //check if equipment exist
      if ($_POST['cr_equipment'] == $equipment) {
         echo "The equipment already exist.";
      }elseif($b !== $equipment){
         $sql = "INSERT INTO tblroom_equipment (room_num,equipment,qty,price) VALUES ('$a','$b','$c','$d')";
$query = $connect->query($sql);
      }
}