Toggle navigation
首页
关于TCPGAME
快乐分享
联系我们
C# WPF MVVM下显示ObservableCollection集合Count Add或者Remove界面不更新的解决方法
Lonner
时间:2021-07-17 08:49:13
阅读:3368
现在有个需求,就是要在TextBlock控件上显示ObservableCollection的count,但是发现绑定后出现ObservableCollection数量变化时,TextBlock的内容却不刷新的问题。 ObservableCollection表示一个动态数据集合,它可在添加、删除项目或刷新整个列表时提供通知。 [microsoft官方文档](https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.objectmodel.observablecollection-1?view=netframework-4.5&f1url=%3FappId%3DDev16IDEF1%26l%3DZH-CN%26k%3Dk%28System.Collections.ObjectModel.ObservableCollection%601%29;k%28TargetFrameworkMoniker-.NETFramework,Version%253Dv4.5%29;k%28DevLang-csharp%29%26rd%3Dtrue "microsoft官方文档") 常规的绑定方式是,首先在ViewModel中定义集合 ``` public class VMMain: BaseNotify { private ObservableCollection<int> numbers; public ObservableCollection<int> Numbers { get => numbers; set => SetProperty(ref numbers, value); } public VMMain() { Numbers = new ObservableCollection<int>(new List<int> {1,2,3,4,5,6,7,8,9 }); } } ``` 其中**BaseNotify基类**请到文章后面查看**BaseNotify.cs** 在界面中这样绑定显示 ``` <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="32" Text="{Binding Numbers,Converter={StaticResource ObservableCollectionCountConverter}}"/> ``` 其中ObservableCollectionCountConverter转换器的代码请到文章后面查看**ObservableCollectionCountConverter.cs** 程序界面运行起来后,首次显示的数量为9,是正确的,但是之后对ObservableCollection集合进行元素的add或者remove操作,实际上界面并不会刷新,还保留着之前的显示的9,这并不是我们想实现的效果。实际上是ObservableCollection实现接口的数据集合的内置实现 INotifyCollectionChanged ,所以他元素变化是通知了INotifyCollectionChanged事件。普通非列表控件的绑定,实际上只监听INotifyPropertyChanged的变化,所以add或者remove以及clear不会影响普通绑定。 ###解决方案 在ObservableCollection的CollectionChanged中通知界面更新,仅需修改ViewModel即可,修改后的VMMain如下: ``` public class VMMain : BaseNotify { private ObservableCollection<int> numbers; public ObservableCollection<int> Numbers { get => numbers; set => SetProperty(ref numbers, value); } public VMMain() { Numbers = new ObservableCollection<int>(new List<int> {1,2,3,4,5,6,7,8,9 }); Numbers.CollectionChanged += Numbers_CollectionChanged; } private void Numbers_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { RaisePropertyChanged("Numbers"); } } ``` 问题解决! ###完整代码 ####VMMain.cs ``` using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Threading; namespace TcpGameDemo { public class VMMain : BaseNotify { private ObservableCollection<int> numbers; public ObservableCollection<int> Numbers { get => numbers; set => SetProperty(ref numbers, value); } public VMMain() { Numbers = new ObservableCollection<int>(new List<int> {1,2,3,4,5,6,7,8,9 }); Numbers.CollectionChanged += Numbers_CollectionChanged; DispatcherTimer dispatcher = new DispatcherTimer(); dispatcher.Tick += Dispatcher_Tick; dispatcher.Interval = TimeSpan.FromMilliseconds(1000); dispatcher.Start(); } private void Dispatcher_Tick(object sender, EventArgs e) { Numbers.Add(999); } private void Numbers_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { RaisePropertyChanged("Numbers"); } } } ``` ####BaseNotify.cs ``` using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; namespace BatteryPackInfo { public class TcpGameDemo : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; /// <summary> /// 属性发生改变时调用该方法发出通知 /// </summary> /// <param name="propertyName">属性名称</param> public void RaisePropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } protected bool SetProperty<T>(ref T target, T value, [CallerMemberName] string propertyName = null) { if (EqualityComparer<T>.Default.Equals(target, value)) { return false; } target = value; RaisePropertyChanged(propertyName); return true; } } } ``` ####MainWindow.xaml ``` <Window x:Class="TcpGameDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:TcpGameDemo" xmlns:converters="clr-namespace:TcpGameDemo.Converters" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Window.DataContext> <local:VMMain></local:VMMain> </Window.DataContext> <Window.Resources> <converters:ObservableCollectionCountConverter x:Key="ObservableCollectionCountConverter"></converters:ObservableCollectionCountConverter> </Window.Resources> <Grid> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="32" Text="{Binding Numbers,Converter={StaticResource ObservableCollectionCountConverter}}"/> </Grid> </Window> ``` ####ObservableCollectionCountConverter.cs ``` using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Data; namespace TcpGameDemo.Converters { public class ObservableCollectionCountConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var collection = value as ObservableCollection<int>; if (collection == null) return 0; else return collection.Count(); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } } ```
上一章:C# HttpClient 发送Json数据的Post请求出现服务器无响应异常
下一章:C# 使用System.Data.SQLite.dll出现找不到SQLite.Interop.dll问题的解决方案