首页 > 其他分享 >【WPF】WPF 双向绑定中的 SelectedItem 与 ViewModel 属性更新机制详解

【WPF】WPF 双向绑定中的 SelectedItem 与 ViewModel 属性更新机制详解

时间:2024-12-27 21:41:53浏览次数:10  
标签:OnPropertyChanged 绑定 SelectedSequence SelectedItem ViewModel selectedSequence 更新

 

在 WPF 开发中,ListBox 等控件常用于显示绑定的数据集合,

其中ItemsSource绑定的数据源,在没有显式设置 Mode 属性时,默认为单向绑定,它将 数据源 集合的内容传递给 ListBox,但不会反向更新 数据源。

SelectedItem ,默认情况下它的绑定是双向的。这意味着当用户在 ListBox 中选择一个项时,数据源 会自动更新为该项的引用。此外,如果你在代码中更改 数据源 的值,ListBox 的选中项也会更新为相应的项。虽然没有显式设置 Mode=TwoWay,但 SelectedItem 的默认行为是双向的。

 

在处理这种场景时,我们需要考虑如何避免重复更新和潜在的循环问题。本文将详细探讨这一机制,并回答以下问题:

  1. 为什么在 ViewModel 中的属性更新需要检查值是否相同?
  2. 如果省略检查,会不会引发循环更新?
  3. WPF 框架是否有类似的防重复更新机制?
  4. 最佳实践是什么?

一、WPF 双向绑定的基础机制

在 XAML 中,通常会通过以下代码为 ListBox 设置数据绑定:

<ListBox 
    ItemsSource="{Binding Sequences}" 
    SelectedItem="{Binding SelectedSequence}" 
    DisplayMemberPath="SequenceNumber" 
    Height="Auto" />

 

对应的 ViewModel 属性如下:

public class ViewModel : INotifyPropertyChanged
{
    private DPIItem _selectedSequence;
    public DPIItem SelectedSequence
    {
        get => _selectedSequence;
        set
        {
            if (_selectedSequence != value) // 值检查
            {
                _selectedSequence = value;
                OnPropertyChanged(nameof(SelectedSequence));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

 

在这里,SelectedSequenceset 方法中,通过 if (_selectedSequence != value) 检查新值是否与旧值相同。如果值不同,则触发 OnPropertyChanged 通知 UI 更新。


二、为什么需要检查值是否相同?

1. 提高性能

如果没有 if (_selectedSequence != value) 的判断,每次 SelectedSequence 被赋值时,即使新值与旧值相同,也会触发以下逻辑:

  • _selectedSequence 的重新赋值。
  • OnPropertyChanged(nameof(SelectedSequence)) 的调用。

这会通知 WPF 的绑定系统更新 UI。对于复杂界面或频繁操作,这种冗余更新会造成性能问题。

2. 避免冗余更新逻辑

OnPropertyChanged 的触发可能会导致 UI 或其他绑定组件响应不必要的更新。如果还有其他依赖于 SelectedSequence 的逻辑,这些逻辑也会被意外触发,导致非预期行为。

3. 逻辑清晰

通过检查值是否相同,明确表达了属性更新的意图:仅在值真正发生变化时,触发相关逻辑。这让代码更加易读和可维护。


三、省略检查会引发循环更新吗?

当我们省略 if (_selectedSequence != value),代码如下:

public DPIItem SelectedSequence
{
    get => _selectedSequence;
    set
    {
        _selectedSequence = value;
        OnPropertyChanged(nameof(SelectedSequence));
    }
}

 

很多开发者担心这种写法会因为 SelectedItem 的双向绑定机制而引发循环更新。然而在实际测试中,通常不会出现循环。这是因为 WPF 框架自带了防止重复更新的机制。


四、WPF 框架的防重复更新机制

WPF 的绑定系统在更新目标或源时,会自动检查新值和当前值是否相同。如果值没有变化,WPF 会跳过后续更新逻辑。例如:

  1. 用户在界面中修改 ListBox 的选中项。
  2. SelectedItem 将新值传递给绑定的 SelectedSequence
  3. WPF 在更新之前,发现新值与当前值相同,则不会触发 SelectedSequenceset 逻辑。

这种内置机制大大减少了冗余更新的风险,但仍有以下局限性:

  • 如果绑定涉及自定义类型或使用了 IValueConverter,可能绕过 WPF 的值比较机制。
  • 不同框架可能没有类似的优化机制。

五、最佳实践:结合框架机制与代码检查

尽管 WPF 自带防重复更新机制,但从代码可维护性和健壮性考虑,仍然推荐在 ViewModel 中进行值检查。

1. 保持代码一致性

显式地检查值是否相同,可以确保逻辑始终明确,而不依赖于框架的隐式优化行为。即使未来迁移到其他框架(如 WinForms 或 MAUI),代码仍然保持一致。

2. 避免触发额外逻辑

set 中的逻辑可能不仅仅是触发 OnPropertyChanged,还可能包括其他业务逻辑(例如日志记录、事件触发)。显式检查可以避免不必要的重复逻辑。


六、完整代码示例

以下是一个完整的代码实现,结合了上述最佳实践:

XAML 代码

<ListBox 
    ItemsSource="{Binding Sequences}" 
    SelectedItem="{Binding SelectedSequence}" 
    DisplayMemberPath="SequenceNumber" 
    Height="Auto" />

 

ViewModel 代码

public class ViewModel : INotifyPropertyChanged
{
    private DPIItem _selectedSequence;
    public DPIItem SelectedSequence
    {
        get => _selectedSequence;
        set
        {
            if (_selectedSequence != value)
            {
                _selectedSequence = value;
                OnPropertyChanged(nameof(SelectedSequence));
            }
        }
    }

    public ObservableCollection<DPIItem> Sequences { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

 


七、总结

WPF 框架确实内置了防止重复更新的机制,但在实际开发中,我们仍然推荐显式检查值是否相同。这样做的原因包括提高代码的可维护性、兼容性以及避免潜在的额外逻辑触发。结合 WPF 的绑定优化和 ViewModel 中的检查,可以实现更高效、更稳定的双向绑定。

标签:OnPropertyChanged,绑定,SelectedSequence,SelectedItem,ViewModel,selectedSequence,更新
From: https://www.cnblogs.com/ban-boi-making-dinner/p/18636782

相关文章

  • WPF Combobox屏蔽按上下键切换选项
    最近在项目中有一个需求是Combobox可以进行编辑,类似于多行文本框一样进行编辑,在编辑的过程中可能需要上下键切换当前的行,但是combobox的上下键对应了切换选项,所以需要屏蔽combobox的上下键切换功能,并且加上文本框换行的功能combobox自身的previewkeydown事件是无法捕获到上下键的......
  • 解决WPF弹出子窗体如何设置停靠在主窗体的边缘
    窗体代码思路获取主窗体的位置坐标,根据主窗体的位置坐标和长宽尺寸计算子窗体的实际位置,并赋值给子窗体的Top和Left属性。publicpartialclassPromptDialogBox:Window{///<summary>///关闭计时器///</summary>privateDispatcherTimer_timerCl......
  • C# WPF PrintDialog 打印(3)
    前面https://www.cnblogs.com/yinyu5/p/18634080使用PrintDocument方法打印了Canvas,这里打印下面的DataGrid列表内容:这里DataGrid的数据源是DataTable,后台代码:1privatevoidPrintDocument_DataTable_Method(stringTitle,DataTabledataTable)2{3......
  • C# WPF PrintDialog 打印(2)
    前面https://www.cnblogs.com/yinyu5/p/18633910使用PrintVisual方法只打印了可见部分的元素,所以这里改为使用PrintDocument方法来进行打印。需要引用System.Printing.dll界面代码:1<Windowx:Class="WpfApp123.MainWindow"2xmlns="http://schemas.microsoft.com......
  • C# WPF PrintDialog 打印(1)
    参考“WPF打印实例”的文章:https://www.cnblogs.com/gnielee/archive/2010/07/02/wpf-print-sample.html测试程序: 首先打印Canvas效果: 看起来似乎没问题,但是调整窗体尺寸遮挡部分元素:再打印Canvas效果: 可以发现PrintVisual方法只打印了可见部分的元素,测试打印DataG......
  • WPF TabControl 去掉鼠标悬浮效果
     1.资源<Window.Resources><Stylex:Key="TabStyle"TargetType="TabItem"><SetterProperty="TextBlock.FontSize"Value="12"/><SetterProperty="Template">......
  • WPF 构建属性结构
    在WPF中构建树形结构首先构建一个属性结构的类,在这个类中,其中NodeId、NodeName、ParentId是最重要的3个属性,是构建树形结构的关键.另外一个比较重要的属性就是ChildNodes,它是一个树形集合类对象,该属性存储子树,是构建树形结构的必要条件。其他都是附加属性,如Icon用于存储图标......
  • WPF TileMode ViewPort ImageBrush VisualBrush
    <Windowx:Class="WpfApp98.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.......
  • WPF应用启动时,检测触摸失效的几种方式
    在开发OPS项目,发现插拔式的OPS在切换系统、开关机、重启,会时不时出现部分WPF开机自启的应用触摸失效的问题。而且出现问题的应用都是全屏窗口应用。用snoop附加上去,没有Touch和Styulus的的相关事件,但是鼠标事件是能触发的,而且系统的其他的应用软件都可以触摸。这就是我们常见......
  • WPF LogicalTree VisualTree
    <Windowx:Class="WpfApp94.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.......