【问题标题】:Add children to user control with ViewModel?使用 ViewModel 将子级添加到用户控件?
【发布时间】:2017-06-28 13:09:18
【问题描述】:

问题:如何将新子项添加到我的用户控件?我被告知 viewmodel 不应该对视图有任何了解,而是使用绑定。现在我创建了一个项目控件并将我的绑定路径设置为包含标签数组的属性 MyLabels。它不起作用,老实说,我不确定推荐的方法是什么。

我的 XAML 的 itemscontrol(在我的用户控件中的某处):

<UserControl x:Class="Test.Main"
             x:Name="this"
             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="600" d:DesignWidth="1000">

        <ScrollViewer Height="400" Width="900">
            <StackPanel Width="900">
                <Grid x:Name="myGrid">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>

                    <Grid.RowDefinitions>
                        <RowDefinition Height="*" />
                        <RowDefinition Height="*" />
                        <RowDefinition Height="*" />
                        <RowDefinition Height="*" />
                    </Grid.RowDefinitions>

                    <ItemsControl ItemsSource="{Binding Path=MyLabels}"/>
                </Grid>

                <Image PreviewMouseDown="AddLabel""/>
            </StackPanel>
        </ScrollViewer>
    </StackPanel>
</UserControl>

这是我的视图模型:

namespace Test {
    public partial class Main {
        public ObservableCollection<string> MyLabels { get; set; } = new ObservableCollection<string>();

        public Main() {
            InitializeComponent();
            DataContext = this;
        }

        public void AddLabel(object sender, RoutedEventArgs e) {
            for (int i = 0; i < 2; i++) {
                MyLabels.Add("eee");
            }
        }
    }
}

【问题讨论】:

  • 您是否检查了是否在标签中添加了一些文本?
  • 是的,我做到了。它没有工作
  • 还有为什么需要从UserControl继承Main?我认为您可以删除该继承、事件(因为没有人会提出您的事件),而是将 VM 保留为纯 POCO。
  • @SivaGopal 谢谢,改了。
  • @jαsοndιnAlt 我可以设置一个 x:Name 并直接添加孩子,但这不是一个好习惯。这个 vm 的作用是将数据绑定到用户控件,并在用户单击按钮时添加新元素。

标签: c# wpf xaml viewmodel


【解决方案1】:

将视图的DataContext 设置为视图模型的实例:

public Main() {
    InitializeComponent();
    DataContext = this;
}

然而视图模型应该是它自己的一个类:

public MainWindow() {
    InitializeComponent();
    DataContext = new ViewModel();
}

它不应该创建任何Label 元素,而是创建strings

public class ViewModel
{
    public List<string> MyLabels { get; set; } new List<string>();

    public ViewModel()
    {
        AddLabels();
    }

    public void AddLabels()
    {
        for (int i = 0; i < 5; i++)
        {
            MyLabels.Add("Sample");
        }
    }
}

Label 是一个用户界面元素类型,它们只属于视图。

另请注意,您只能绑定到公共属性

它现在可以工作了,唯一的问题是我不确定如何在不违反 MVVM 模式的情况下添加实际标签。

您在ItemsControlItemTemplate 中添加Label 元素。此模板定义源集合中项目的外观,即在本例中为 string

<ItemsControl ItemsSource="{Binding Path=MyLabels}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Label Content="{Binding}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

【讨论】:

  • 有趣,我去看看
  • 奇怪的是它不起作用。 AddLabels 仍然是一个事件处理程序。单击它不会在视图中执行任何操作。我应该看到反映到 xaml 的更改
  • 将集合的类型从 List 更改为 ObservableCollection。并确保它是一个属性。
  • 很奇怪,我在我的网格中找到了 ItemsControl。该网格位于用户控件内。现在以某种方式将数据类型更改为 ObservableCollection 后它仍然不起作用
  • ItemsControl 的 DataContext 是什么?请提供您的问题的完整示例,以便轻松复制:stackoverflow.com/help/mcve
【解决方案2】:

通过以下 MVVM 模仿(轻量级风味!),您应该能够看到在视图中创建的标签。根据您的更新,仍在生成字符串。

视图模型

public class ViewModel
{
        public ObservableCollection<string> MyStrings { get; set; }
        public ICommand AddStringCommand { get; private set; }

        public ViewModel()
        {
            if (MyStrings == null) MyStrings = new ObservableCollection<string>();

            for (int i = 0; i < 5; i++)
            {
                MyStrings.Add("string " + i);
            }

            AddStringCommand = new AddLabelCommand(AddString);

        }

        public void AddString()
        {
            MyStrings.Add("string " + (MyStrings.Count));
        }

 }

public class AddLabelCommand : ICommand
{
        readonly Action _action = null;

        public AddLabelCommand(Action commandToExecute)
        {
            _action = commandToExecute; //Handle null condition
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            _action();
        }
}   

MainWindow.xaml.cs(视图背后的代码)

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

MainWindow.xaml(内部视图)

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="402" Width="540"
        xmlns:local="clr-namespace:WpfApplication1">
    <Window.Resources>
        <local:ViewModel x:Key="ViewModel"/> <!--Initialize ViewModel inside XAML-->
    </Window.Resources>
    <Grid Height="367" Width="526" DataContext="{StaticResource ViewModel}">
        <ItemsControl ItemsSource="{Binding Path=MyStrings}" Width="100" BorderBrush="Red">
            <ItemsControl.ItemTemplate> <!--If you want to display your content in a control you can use ItemTemplate as suggested by @mm8-->
                <DataTemplate>
                    <Label Content="{Binding}"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
        <Button Content="Add Label" Height="23" Width="100" Command="{Binding Path=AddStringCommand}"/>
    </Grid>
</Window>

希望这能为您提供一个起点!!

【讨论】:

  • MyLabels 在视图模型的构造函数中将始终为空......并且视图模型类不应创建标签元素。这违反了 MVVM 模式。
  • 更新了我的问题。
  • 我真的不明白为什么我们需要将 ViewModel 添加到视图内的数据上下文中。
  • 这是您告诉视图在哪里查找其数据的方法之一。您也可以在视图中执行此操作。
  • 好的,但最后我添加的是文本而不是标签?如果违反 MVVM 模式,不确定在哪里执行此操作
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-02
  • 1970-01-01
相关资源
最近更新 更多