[英]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.