[英]How to create a UserControl in the MVVM pattern?
Currently, within a real-world application development, I am struggling with the consumption of a custom UserControl
in the MVVM pattern. 当前,在一个实际的应用程序开发中,我正在努力使用MVVM模式中的自定义
UserControl
。
In my application, there is a DataGrid
where the user can select an entry. 在我的应用程序中,有一个
DataGrid
,用户可以在其中选择一个条目。 The DataGrid
's SelectedItem
is TwoWay
-bound to a field of the ViewModel set as DataContext
. DataGrid
的SelectedItem
TwoWay
DataGrid
到ViewModel的设置为DataContext
的字段。 When the user selects an entry, the field is properly updated (tested). 当用户选择一个条目时,该字段将正确更新(测试)。 In the
Page
where holds the DataGrid
, the field is bound through XAML to a DependencyProperty
of a custom UserControl
devised in the MVVM pattern : it bares its own ViewModel which is set as DataContext
. 在保存
DataGrid
的Page
中,该字段通过XAML绑定到以MVVM模式设计的自定义UserControl
的DependencyProperty
:它裸露了自己的ViewModel,并将其设置为DataContext
。 The trouble is that the UserControl
's DependencyProperty
is not updated when the field changes even though the INotifyPropertyChanged
interface is correctly implemented (see the comparison with a traditional control in the next minimal working example). 问题在于,即使正确实现了
INotifyPropertyChanged
接口,当字段更改时UserControl
的DependencyProperty
也不会更新(请参见下一个最小的工作示例中与传统控件的比较)。
This example is constituted of a Label
and bares ViewModelUserControl
as a DataContext
, UserControl1
is consumed by the MainWindow
and the binding is compared to that of a Label
. 本实施例中由一的
Label
和剥开ViewModelUserControl
作为DataContext
, UserControl1
由消耗MainWindow
和结合相比较,一个的Label
。
The file MainWindow.xaml: 文件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>
The code-behind MainWindow.xaml.cs: 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;
}
}
The ViewModel of the MainWindow
, the file ViewModelWindow.cs : 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";
}
The file UserControl1.xaml: 文件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>
The code-behind file UserControl1.xaml.cs: 代码隐藏文件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;
}
}
The ViewModel of UserControl1
, the file ViewModelUserControl.cs: 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 = "";
}
As you can see when executing this code, the MainWindow
's Label
gets updated while the UserControl1
's Label
doesn't. 正如您在执行此代码时看到的那样,
MainWindow
的Label
被更新,而UserControl1
的Label
不被更新。
What am I doing wrong? 我究竟做错了什么? Is there a way to makes this works?
有没有办法使它可行?
Many thanks in advance for any clue. 非常感谢您提供任何线索。
first you do not need to add anything in the UserControl just the XAML. 首先,您不需要在UserControl中添加任何内容,只需添加XAML。 Remove all the code of the UserControl and try.
删除所有的UserControl代码,然后尝试。
Let's explain why: 让我们解释一下原因:
Content="{Binding Text}" you set this in the usercontrol xaml, it's binded to the ViewModelWindow. 您在用户控件xaml中设置的Content =“ {Binding Text}”,它已绑定到ViewModelWindow。 and that works.
那行得通。 and remove in
并删除
<Local:UserControl1 => Text="{Binding Text, Mode=OneWay}"
Ok, but it is correct to define a property in the user control in case of other situation?, that's right, in order to do that: 好的,但是在其他情况下在用户控件中定义属性是正确的吗?是的,这样做是正确的:
<UserControl x:Name="UserControlInstance"...>
<Label Content="{Binding Text, ElementName=UserControlInstance}" ...>
Where in this case Text is the dependency property and not the datacontext property. 在这种情况下,Text是依赖项属性,而不是datacontext属性。
Try the first option, and then the second defining just a Dependency Property and in this case bind the dependency property as you did. 尝试第一个选项,然后第二个仅定义依赖项属性,在这种情况下,像您一样绑定依赖项属性。 And a tip, if a dependency property is in the visual element tree like in your case you do not need to call the callback.
还有一个提示,如果依赖项属性位于可视元素树中(如您的情况),则无需调用回调。
Thank you Juan for your answer, here is the solution for conceiving the UserControl
in the MVVM pattern: 感谢Juan的回答,这是在MVVM模式中构思
UserControl
的解决方案:
I gave the name root
to the Grid
of UserControl1
and set its DataContext
: 我将
root
命名为UserControl1
的Grid
并设置其DataContext
:
root.DataContext = view_model_usercontrol;
instead of: 代替:
DataContext = view_model_usercontrol;
Everything works fine. 一切正常。
Happy ending :) 美好的结局 :)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.