可观察的集合没有在 UI 更改时更新

Posted

技术标签:

【中文标题】可观察的集合没有在 UI 更改时更新【英文标题】:observable collection not getting updated on UI change 【发布时间】:2011-04-01 02:37:40 【问题描述】:

我正在尝试将可观察集合绑定到用户控件,但它没有在用户更改时更新,但是当用户控件通过代码更改时它正在更新。以下是我尝试的示例。它可能有点长,但它可以正常工作,因此您可以按原样复制和粘贴代码。

请在帖子末尾查看我的问题。

--Customer.cs

使用系统; 使用 System.Collections.Generic; 使用 System.Linq; 使用 System.Text; 使用 System.ComponentModel; 命名空间 TestMVVM 客户类:INotifyPropertyChanged 私有字符串名字; 私人字符串姓氏; 公共字符串名字 得到返回名字; 放 如果(名字!=值) 名字=值; RaisePropertyChanged("名字"); 公共字符串姓氏 得到返回姓氏; 放 如果(姓氏!=值) 姓氏 = 值; RaisePropertyChanged("姓氏"); #region PropertChanged 块 公共事件 PropertyChangedEventHandler PropertyChanged; 私人无效 RaisePropertyChanged(字符串属性) if (PropertyChanged != null) 属性改变(这个, 新的 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

使用系统; 使用 System.Collections.Generic; 使用 System.Linq; 使用 System.Text; 使用 System.Windows; 使用 System.Windows.Controls; 使用 System.Windows.Data; 使用 System.Windows.Documents; 使用 System.Windows.Input; 使用 System.Windows.Media; 使用 System.Windows.Media.Imaging; 使用 System.Windows.Navigation; 使用 System.Windows.Shapes; 使用 System.Collections.ObjectModel; 使用 System.ComponentModel; 命名空间 TestMVVM /// /// UCTextBox.xaml 的交互逻辑 /// 公共部分类 UCTextBox : UserControl, INotifyPropertyChanged 公共 UCTextBox() 初始化组件(); 公共静态只读 DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(UCTextBox), 新的 UIPropertyMetadata(string.Empty, new PropertyChangedCallback(textChangedCallBack))); 静态无效 textChangedCallBack(DependencyObject 属性,DependencyPropertyChangedEventArgs 参数) UCTextBox pasTextBox = (UCTextBox) 属性; pasTextBox.txtTextControl.Text = (string)args.NewValue; 公共字符串文本 得到 返回(字符串)GetValue(文本属性); 放 设置值(文本属性,值); NotifyPropertyChanged("文本"); 私人无效NotifyPropertyChanged(字符串信息) if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(info)); #region INotifyPropertyChanged 成员 公共事件 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

使用系统; 使用 System.Collections.Generic; 使用 System.Linq; 使用 System.Text; 使用 System.Windows; 使用 System.Windows.Controls; 使用 System.Windows.Data; 使用 System.Windows.Documents; 使用 System.Windows.Input; 使用 System.Windows.Media; 使用 System.Windows.Media.Imaging; 使用 System.Windows.Navigation; 使用 System.Windows.Shapes; 使用 System.Collections.ObjectModel; 命名空间 TestMVVM /// /// Window1.xaml 的交互逻辑 /// 公共部分类 Window1:窗口 CustomerHeaderViewModel customerHeaderViewModel = null; 公共窗口1() 初始化组件(); customerHeaderViewModel = new CustomerHeaderViewModel(); customerHeaderViewModel.LoadCustomers(); txtUC.DataContext = customerHeaderViewModel.Customers[0]; 绑定绑定 = 新绑定(); binding.Source = customerHeaderViewModel.Customers[0]; binding.Path = new System.Windows.PropertyPath("FirstName"); binding.Mode = BindingMode.TwoWay; binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; txtUC.SetBinding(UCTextBox.TextProperty,绑定); 私人无效btnUpdate_Click(对象发送者,RoutedEventArgs e) MessageBox.Show(customerHeaderViewModel.Customers[0].FirstName); 私人无效btnChange_Click(对象发送者,RoutedEventArgs e) txtUC.Text = "汤姆"; 类 CustomerHeaderViewModel 公共 ObservableCollection 客户 获取;放; 公共无效负载客户() ObservableCollection 客户 = 新的 ObservableCollection(); 客户.Add(新客户 FirstName = "Jim", LastName = "Smith", NumberOfContracts = 23 ); 客户=客户;

当我运行 Window1.xaml 时,我的用户控件将数据显示为“Jim”。现在,当我将文本更改为“John”并单击“更新”时,消息框仍然显示“Jim”,这意味着可观察的集合没有得到更新。当我单击更改按钮时,用户控件将数据更改为“汤姆”。现在,当我单击更新按钮时,消息框显示“汤姆”。谁能告诉我如何通过更改用户控件中的数据而不是通过代码来实现可观察集合的更新?

【问题讨论】:

【参考方案1】:

那是因为你没有处理 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 个更改,您可以更改您的答案,以便其他人可以使用它,也就是说,缺少 Mode=TwoWay,这给了我一个构建错误,即 Text="Binding Path =Text, Mode=TwoWay, RelativeSource=RelativeSource Mode=FindAncestor, AncestorType=x:Type local:UCTextBox" TextBox.Text 默认情况下是双向绑定的,因此您不必明确说明。无论如何,它不应该给你一个构建错误......这很奇怪【参考方案2】:

一个可观察的集合,只观察集合。您将在添加或删除项目时收到通知,而不是在单个项目的字段发生更改时收到通知。那是完全不同的东西。正如 Thomas Levesque 所说,您只需要绑定正确的属性即可。

【讨论】:

以上是关于可观察的集合没有在 UI 更改时更新的主要内容,如果未能解决你的问题,请参考以下文章

当 ObservableCollection 更改时 ItemsControl 不更新

可观察的集合未更新

将更改发布到可观察对象的集合

WPF ListView在运行时不更新

刷新 WPF Datagrid 未绑定到可观察集合?

当 MVVM 中的属性更改时通知可观察集合