我正在尝试将可观察集合绑定到用户控件,但它没有获得有关用户更改的更新,但是当通过代码更改用户控件时它会更新。以下是我试过的一个例子。它可能有点长,但它正在工作,因此您可以按原样复制和粘贴代码。
请在帖子末尾看到我的问题。
- Customer.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel; namespace TestMVVM { class Customer : INotifyPropertyChanged { private string firstName; private string lastName; public string FirstName { get { return firstName; } set { if (firstName != value) { firstName = value; RaisePropertyChanged("FirstName"); } } } public string LastName { get { return lastName; } set { if (lastName != value) { lastName = value; RaisePropertyChanged("LastName"); } } } #region PropertChanged Block public event PropertyChangedEventHandler PropertyChanged; private void RaisePropertyChanged(string property) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(property)); } } #endregion } }
- UCTextBox.xaml
<UserControl x:Class="TestMVVM.UCTextBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="40" Width="200">
<Grid>
<TextBox Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="txtTextControl"
VerticalAlignment="Top" Width="120" />
</Grid>
- UCTextBox.xaml.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Collections.ObjectModel; using System.ComponentModel; namespace TestMVVM { /// /// Interaction logic for UCTextBox.xaml /// public partial class UCTextBox : UserControl, INotifyPropertyChanged { public UCTextBox() { InitializeComponent(); } public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(UCTextBox), new UIPropertyMetadata(string.Empty, new PropertyChangedCallback(textChangedCallBack))); static void textChangedCallBack(DependencyObject property, DependencyPropertyChangedEventArgs args) { UCTextBox pasTextBox = (UCTextBox)property; pasTextBox.txtTextControl.Text = (string)args.NewValue; } public string Text { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); NotifyPropertyChanged("Text"); } } private void NotifyPropertyChanged(String info) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(info)); } } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; #endregion } }
- Window1.xaml
<Window x:Class="TestMVVM.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestMVVM"
Title="Window1" Height="300" Width="300">
<Grid>
<local:UCTextBox x:Name="txtUC" />
<Button Height="23" HorizontalAlignment="Left" Margin="39,0,0,82"
Name="btnUpdate" VerticalAlignment="Bottom" Width="75" Click="btnUpdate_Click">Update</Button>
<Button Height="23" Margin="120,0,83,82" Name="btnChange" VerticalAlignment="Bottom" Click="btnChange_Click">Change</Button>
</Grid>
- Window1.xaml.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Collections.ObjectModel; namespace TestMVVM { /// /// Interaction logic for Window1.xaml /// public partial class Window1 : Window { CustomerHeaderViewModel customerHeaderViewModel = null; public Window1() { InitializeComponent(); customerHeaderViewModel = new CustomerHeaderViewModel(); customerHeaderViewModel.LoadCustomers(); txtUC.DataContext = customerHeaderViewModel.Customers[0]; Binding binding = new Binding(); binding.Source = customerHeaderViewModel.Customers[0]; binding.Path = new System.Windows.PropertyPath("FirstName"); binding.Mode = BindingMode.TwoWay; binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; txtUC.SetBinding(UCTextBox.TextProperty, binding); } private void btnUpdate_Click(object sender, RoutedEventArgs e) { MessageBox.Show(customerHeaderViewModel.Customers[0].FirstName); } private void btnChange_Click(object sender, RoutedEventArgs e) { txtUC.Text = "Tom"; } } class CustomerHeaderViewModel { public ObservableCollection Customers { get; set; } public void LoadCustomers() { ObservableCollection customers = new ObservableCollection(); customers.Add(new Customer { FirstName = "Jim", LastName = "Smith", NumberOfContracts = 23 }); Customers = customers; } } }
当我运行Window1.xaml时,我的用户控件将数据显示为“Jim”。现在,当我将文本更改为“John”并单击“更新”时,消息框仍显示“Jim”,表示可观察的集合未获得更新。当我单击“更改”按钮时,用户控件将数据更改为“Tom”。现在,当我点击“更新”按钮时,消息框显示“Tom”。谁能告诉我如何通过更改用户控件中的数据而不是通过代码来实现可观察集合的更新?
答案 0 :(得分:2)
那是因为您没有处理txtTextControl.TextChanged
事件,所以您的Text
依赖项属性永远不会更新。
无论如何,您不需要使用DependencyPropertyChangedCallback
和事件处理程序手动处理它,您只需将txtTextControl.Text
绑定到Text
依赖项属性:
<TextBox Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="txtTextControl"
VerticalAlignment="Top" Width="120"
Text="{Binding Path=Text, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:UCTextBox}}}"/>
答案 1 :(得分:0)
可观察的集合,仅观察集合。添加或删除项目时,如果单个项目的字段发生更改,则会收到通知。这是完全不同的东西。就像Thomas Levesque所说的那样,你只需要绑定正确的财产。