繁体   English   中英

如何在MVVM模式中创建UserControl?

[英]How to create a UserControl in the MVVM pattern?

当前,在一个实际的应用程序开发中,我正在努力使用MVVM模式中的自定义UserControl

在我的应用程序中,有一个DataGrid ,用户可以在其中选择一个条目。 DataGridSelectedItem TwoWay DataGrid到ViewModel的设置为DataContext的字段。 当用户选择一个条目时,该字段将正确更新(测试)。 在保存DataGridPage中,该字段通过XAML绑定到以MVVM模式设计的自定义UserControlDependencyProperty :它裸露了自己的ViewModel,并将其设置为DataContext 问题在于,即使正确实现了INotifyPropertyChanged接口,当字段更改时UserControlDependencyProperty也不会更新(请参见下一个最小的工作示例中与传统控件的比较)。

本实施例中由一的Label和剥开ViewModelUserControl作为DataContextUserControl1由消耗MainWindow和结合相比较,一个的Label

文件MainWindow.xaml:

<Window x:Class="UserControlWithinUserControlDataContext.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Local="clr-namespace:UserControlWithinUserControlDataContext"
        Title="MainWindow"
        Height="350" Width="525"
        >

    <StackPanel Orientation="Horizontal"
                >

        <ListBox SelectedItem="{Binding Text, Mode=TwoWay}"
                 x:Name="listbox"
                 Height="150"
                 >
        </ListBox>

        <Local:UserControl1 Text="{Binding Text, Mode=OneWay}"
                            Height="50" Width="150"
                            />

        <Label Content="{Binding Text, Mode=OneWay}"
               />

    </StackPanel>

</Window>

MainWindow.xaml.cs背后的代码:

 public partial class MainWindow : Window
    {
        public ViewModelWindow view_model_window
        {
            get { return _view_model; }
        }
        private ViewModelWindow _view_model = new ViewModelWindow();

        public MainWindow()
        {
            InitializeComponent();
            DataContext = view_model_window;

            IList<String> list = new List<String>();
            list.Add("A");
            list.Add("B");
            list.Add("C");
            listbox.ItemsSource = list;
        }
    }

MainWindow的ViewModel,文件ViewModelWindow.cs:

public class ViewModelWindow : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public String Text
    {
        get { return text; }
        set
        {
            if (text != value)
            {
                text = value;
                NotifyPropertyChanged("Text");
            }
        }
    }
    private String text = "Bli";
}

文件UserControl1.xaml:

<UserControl x:Class="UserControlWithinUserControlDataContext.UserControl1"
             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="300" d:DesignWidth="300">
    <Grid>
        <Label Content="{Binding Text}"
               Background="Magenta"
               HorizontalAlignment="Stretch"
               />
    </Grid>
</UserControl>

代码隐藏文件UserControl1.xaml.cs:

 public partial class UserControl1 : UserControl
    {
        public ViewModelUserControl view_model_usercontrol
        {
            get { return _view_model; }
        }
        private ViewModelUserControl _view_model = new ViewModelUserControl();

        public String Text
        {
            get { return (String)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(String), typeof(UserControl1),
                new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.AffectsRender,
                        new PropertyChangedCallback(TextPropertyChangedCallback)));

        private static void TextPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            UserControl1 user_control = d as UserControl1;
            if(user_control != null)
            {
                user_control.view_model_usercontrol.Text = user_control.Text;
            }
        }

        public UserControl1()
        {
            InitializeComponent();
            DataContext = view_model_usercontrol;
        }
    }

UserControl1的ViewModel,文件ViewModelUserControl.cs:

public class ViewModelUserControl : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    public String Text
    {
        get { return text; }
        set
        {
            if (text != value)
            {
                text = value;
                NotifyPropertyChanged("Text");
            }
        }
    }
    private String text = "";
}

正如您在执行此代码时看到的那样, MainWindowLabel被更新,而UserControl1Label不被更新。

我究竟做错了什么? 有没有办法使它可行?

非常感谢您提供任何线索。

首先,您不需要在UserControl中添加任何内容,只需添加XAML。 删除所有的UserControl代码,然后尝试。

让我们解释一下原因:

您在用户控件xaml中设置的Content =“ {Binding Text}”,它已绑定到ViewModelWindow。 那行得通。 并删除

  <Local:UserControl1 => Text="{Binding Text, Mode=OneWay}"

好的,但是在其他情况下在用户控件中定义属性是正确的吗?是的,这样做是正确的:

<UserControl x:Name="UserControlInstance"...>
<Label Content="{Binding Text, ElementName=UserControlInstance}" ...>

在这种情况下,Text是依赖项属性,而不是datacontext属性。

尝试第一个选项,然后第二个仅定义依赖项属性,在这种情况下,像您一样绑定依赖项属性。 还有一个提示,如果依赖项属性位于可视元素树中(如您的情况),则无需调用回调。

感谢Juan的回答,这是在MVVM模式中构思UserControl的解决方案:

我将root命名为UserControl1Grid并设置其DataContext

root.DataContext = view_model_usercontrol;

代替:

DataContext = view_model_usercontrol;

一切正常。

美好的结局 :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM