[英]How to create a UserControl in the MVVM pattern?
当前,在一个实际的应用程序开发中,我正在努力使用MVVM模式中的自定义UserControl
。
在我的应用程序中,有一个DataGrid
,用户可以在其中选择一个条目。 DataGrid
的SelectedItem
TwoWay
DataGrid
到ViewModel的设置为DataContext
的字段。 当用户选择一个条目时,该字段将正确更新(测试)。 在保存DataGrid
的Page
中,该字段通过XAML绑定到以MVVM模式设计的自定义UserControl
的DependencyProperty
:它裸露了自己的ViewModel,并将其设置为DataContext
。 问题在于,即使正确实现了INotifyPropertyChanged
接口,当字段更改时UserControl
的DependencyProperty
也不会更新(请参见下一个最小的工作示例中与传统控件的比较)。
本实施例中由一的Label
和剥开ViewModelUserControl
作为DataContext
, UserControl1
由消耗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 = "";
}
正如您在执行此代码时看到的那样, MainWindow
的Label
被更新,而UserControl1
的Label
不被更新。
我究竟做错了什么? 有没有办法使它可行?
非常感谢您提供任何线索。
首先,您不需要在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
命名为UserControl1
的Grid
并设置其DataContext
:
root.DataContext = view_model_usercontrol;
代替:
DataContext = view_model_usercontrol;
一切正常。
美好的结局 :)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.