解决 WPF 绑定集合后数据变动界面却不更新的问题

独立观察员 2020 年 9 月 9 日

在 .NET Core 3.1 的 WPF 程序中打算用 ListBox 绑定显示一个集合(满足需求即可,无所谓什么类型的集合),以下是 Xaml 代码(瞟一眼就行,不是本文讨论重点):

<ListBox ItemsSource="{Binding SipRegistrations, Mode=OneWay}" SelectedValue="{Binding SelectedAccountBinding, Mode=OneWayToSource}"><ListBox.ItemTemplate><DataTemplate><TextBlock Text="{Binding SIPAccount.SIPUsername}"></TextBlock></DataTemplate></ListBox.ItemTemplate>
</ListBox>

ViewModel 中有一个目标集合,当前是一个 List。

属性变动通知有两种实现方式,一是使用 PropertyChanged.Fody,二是使用自定义绑定基类 BindableBase,如下图。

下面主要谈论数据变动(集合增加内容)后,前台的界面却没有更新的问题。具体来说就是,List.Add 之后,第一次有效果,但后面就没效果了,界面始终只显示一条数据。

原始(无效果):

SipRegistrations.RemoveAll(x => x.SIPAccount.SIPUsername == sipAccount.SIPUsername); // 移除重复项(如果有的话)
SipRegistrations.Add(binding); // 添加新项

猜想是因为 List 的引用并没有变化,所以被认为该属性没有改变,进而也就没有变动通知。

其实这种需要变动通知的情况,推荐使用的是 ObservableCollection:

但是本人之前使用 ObservableCollection 没有成功过,反而是使用 List 是可以的,所以还是先看看用 List 怎么解决吧。

变体一(调试时有几率有效果):

// 添加联系人到集合并处理界面绑定;
SipRegistrations.RemoveAll(x => x.SIPAccount.SIPUsername == sipAccount.SIPUsername);
List<SIPAccountBinding> tempList = SipRegistrations;    // 临时集合;
SipRegistrations = new List<SIPAccountBinding>();       // 目标集合先置为空;
tempList.Add(binding);                                  // 临时集合添加新项;
SipRegistrations = tempList;                            // 临时集合赋值给目标集合;

变体一通过临时变量做中转,强制让目标集合(的引用)发生改变,但结果是只在调试时以很小的概率成功过。

由于这部分代码是在异步逻辑里,所以有可能是在多线程环境,而 List 不是线程安全的,所以有了以下加锁版本的变体二。

变体二(无效果,应该是和变体一类似):

#region 成员/// <summary>
/// 加锁对象
/// </summary>
private object _lockObj = new object();#endregion// 加锁;
lock (_lockObj)
{// 添加联系人到集合并处理界面绑定;SipRegistrations.RemoveAll(x => x.SIPAccount.SIPUsername == sipAccount.SIPUsername);List<SIPAccountBinding> tempList = SipRegistrations;SipRegistrations = new List<SIPAccountBinding>();tempList.Add(binding);SipRegistrations = tempList;
}

加了锁还是不行(不过锁还是需要的),又想到,既然调试的时候有几率成功,那么是不是和代码运行速度有关呢?于是在目标集合置空和重新赋值之间加了个线程休眠,竟然真的可以,也就是以下的变体三。

变体三(有效果):

lock (_lockObj)
{// 添加联系人到集合并处理界面绑定;SipRegistrations.RemoveAll(x => x.SIPAccount.SIPUsername == sipAccount.SIPUsername);List tempList = SipRegistrations;SipRegistrations = new List();Thread.Sleep(500); // 关键代码;tempList.Add(binding);SipRegistrations = tempList;
}

好了,以上就是解决方法了。

接下来再尝试一下 ObservableCollection 吧:

#region 成员/// <summary>
/// 加锁对象
/// </summary>
private object _lockObj = new object();public ObservableCollection<SIPAccountBinding> SipRegistrations { get; set; } = new ObservableCollection<SIPAccountBinding>();#endregionlock (_lockObj)
{SipRegistrations.Remove(SipRegistrations.FirstOrDefault(x => x.SIPAccount.SIPUsername == sipAccount.SIPUsername));SipRegistrations.Add(binding);          // 情况一//SipRegistrations.Append (binding);     // 情况二
}Console.WriteLine($" 注册联系人 [{binding.RegisteredContact}] 为 [{sipAccount.SIPUsername}].");

这个有两种情况(都不能成功):

情况一,使用 Add 方法,结果是执行完 Add 方法后就返回了,后面的方法不再执行(不知道为什么),界面上是有几率能添加一条。

情况二,使用 Append 方法,执行完 Append 后倒是可以继续执行后面的代码,但是界面上一条也出现不了。

后记:本文主要是抛砖引玉,大家有什么更好的方法,或者能解释文中所描述现象的原理,请不吝赐教。

项目地址:https://gitee.com/DLGCY_GB28181/SimpleSIPServer

解决 WPF 绑定集合后数据变动界面却不更新的问题相关推荐

  1. 解决 WPF 绑定集合后数据变动界面却不更新的问题(使用 ObservableCollection)

    解决 WPF 绑定集合后数据变动界面却不更新的问题 独立观察员 2020 年 9 月 9 日 在 .NET Core 3.1 的 WPF 程序中打算用 ListBox 绑定显示一个集合(满足需求即可, ...

  2. 解决DataGridView绑定List后不能排序的问题

      阅读全文并下载例子 :http://www.sufeinet.com/forum.php?mod=viewthread&tid=190 以前不都是用table直接绑定DataGridVie ...

  3. 解决重启Linux服务器后数据消失问题

    目录 一.挂载 1.重新挂载 2.数据消失的原因 二.重启服务器 1.shutdown 2.其它关机重启指令 参考自 一.挂载 1.重新挂载 使用 reboot 命令重启服务器后,服务器内挂载的文件全 ...

  4. ComponentOne For WPF学习心得-实时数据

    ComponentOne For WPF学习心得-实时数据 写在前面 不断更新的数据 数据源绑定 写在前面 这是ComponentOne For WPF学习的第三篇文章,我对比着读了前两篇文章,感觉还 ...

  5. hp服务器通过ilo5安装系统,HPE ProLiant Gen10 通过iLO 5(v1.15) web界面多种方式更新服务器固件,包含升级系统恢复集方法...

    一.iLO web界面固件&操作系统软件界面简单介绍 1.固件 这个界面可以查看服务器安装的固件版本,可以查看以下类型的固件: u电源管理控制器Power Management Control ...

  6. [WPF 基础知识系列] —— 绑定中的数据校验Vaildation

    [WPF 基础知识系列] -- 绑定中的数据校验Vaildation 原文:[WPF 基础知识系列] -- 绑定中的数据校验Vaildation 前言: 只要是有表单存在,那么就有可能有对数据的校验需 ...

  7. 解决 IntelliJ IDEA 安装后界面消失,再次打开后界面不动

    解决 IntelliJ IDEA 安装后界面消失,再次打开后界面不动   为了能解析 JDK 17,笔者不得不下载当前最新版的 IntelliJ IDEA,结果在安装完 IntelliJ IDEA 之 ...

  8. JAVAWEB开发之SpringMVC详解(二)——高级开发、数据回显、参数绑定集合、图片上传、json交互、validation校验、异常处理、RESTful支持、拦截器

    知识回顾 springmvc框架 用户请求url到DispatcherServlet前端控制器,相当于中央调度器,降低系统各组件之间的耦合度. DispatcherServlet前端控制器通过Hand ...

  9. 使用python解决验证码登录并爬取登录后的个人界面:本篇以古诗文网站为例

    爬取总结记录:由于经验不足,个人尝试了很多方法,都失败了,查看了网站的上面别人的爬取经验,按照别人做的,但都没有成功. 几经波折最后终于解决了. 好了上代码: 其中有涉及到个人信息的,这里进行了模糊处 ...

最新文章

  1. mysql find_in_set
  2. 转:Oracle 应用服务器 MapViewer 10.1.2截图
  3. get与post请求问题
  4. boost::filesystem目录相关的测试程序
  5. spring无法用三级缓存解决循环依赖的问题分析
  6. 图形图像技术在手游中的潜在应用
  7. android10获取imei,Android 10 root用户获取imei
  8. SAP HANA Backup and Recovery
  9. 美团设计模式在外卖营销业务中的实践-学习笔记(一)
  10. Rxjava + retrofit + dagger2 + mvp搭建Android框架
  11. c语言相反数补码,求一个数的相反数的补码
  12. DataTables如何重新加载数据
  13. 创蓝253云通讯 paas 短信发送接口和定义说明
  14. 爬虫之京东5g手机爬虫+谷歌浏览器打开窗口使用
  15. 通信原理第6章节-数字基带传输系统
  16. 首度基因lims(实验室)管理系统
  17. 2014-2018年中国巨型计算机行业发展分析及投资研究报告
  18. Firefox 使用、设置和常见问题的解决方法
  19. PHP中RabbitMQ之amqp扩展实现(四)
  20. tensorflow2 auto mpg汽车油耗预测实践(3.5节)

热门文章

  1. 纳税服务系统【角色与用户】
  2. 【转】js老生常谈之this,constructor ,prototype
  3. arcgis server 无法手动删除切片
  4. gmail收件箱标签设置_通过多个收件箱实验室有效管理您的Gmail
  5. angular ng-zorro 用组件自身方的法来重置表单校验
  6. 【前端基础进阶】JS-Object 功能详解
  7. AWD-LSTM为什么这么棒?
  8. 理解云计算备份与灾难恢复
  9. Lucene5.5.4入门以及基于Lucene实现博客搜索功能
  10. Net与Flex入门