【发布时间】:2015-07-22 07:50:35
【问题描述】:
目前,在实际应用程序开发中,我正在努力解决在 MVVM 模式中使用自定义 UserControl 的问题。
在我的应用程序中,有一个DataGrid,用户可以在其中选择一个条目。 DataGrid 的 SelectedItem 是 TwoWay-绑定到 ViewModel 设置为 DataContext 的字段。当用户选择一个条目时,该字段会正确更新(测试)。在包含DataGrid 的Page 中,该字段通过XAML 绑定到在MVVM 模式中设计的自定义UserControl 的DependencyProperty:它拥有自己的ViewModel,设置为DataContext。问题是UserControl 的DependencyProperty 不会在字段更改时更新,即使INotifyPropertyChanged 接口已正确实现(请参阅下一个最小工作示例中与传统控件的比较)。
此示例由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 不会。
我做错了什么?有没有办法让它工作?
非常感谢您提供任何线索。
【问题讨论】:
-
运行时是否遇到任何绑定错误?
-
尽管我的问题解决了,但您提出了一个观点:没有任何更新的事实本身就是一个错误,但对调试并不友好。