Создать UserControl из другого UserControl и добавить в родительский контейнер во время выполнения - PullRequest
0 голосов
/ 28 июня 2018

У меня есть простой UserControl, который содержит TextBox и кнопку. Мне бы хотелось, чтобы нажатие на кнопку создало новый пользовательский элемент управления, который будет расположен сразу после (ниже) того, на котором была нажата его кнопка.

Например:

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>

Мне удалось добавить новые "myUserControls" в StackPanel в главном окне, выполнив все рекомендации здесь . 2 основные проблемы с этой реализацией:

  1. Я не могу понять, из какого "myUserControl" я получил событие.
  2. Даже если бы я знал, какая кнопка была нажата и по тому, где создать новый UserControl, я не знал, как вставить его в середину StackPanel (может быть, нужна другая панель?)

Кроме того, это решение использовало код позади. Есть ли способ сделать все это в MVVM?

1 Ответ

0 голосов
/ 28 июня 2018

Если вы хотите управлять списком элементов из модели представления, тогда вам нужно использовать ItemsControl вместо вставки элементов в 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 является реализацией ICommand из этого легкого пакета MVVM

ViewModel и View соединены вместе в конструкторе View:

public partial class MyWindow : Window
{
    public MyWindow()
    {
        InitializeComponent();
        DataContext = new MyViewModel
        {
            MyItems = { new StringItem { MyText = "hello world" } }
        };
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...