代码之家  ›  专栏  ›  技术社区  ›  Ilia

WPF双向绑定和属性更改

  •  0
  • Ilia  · 技术社区  · 7 年前

    假设有一个枚举

        enum SampleEnum 
        {
            Item1,
            Item2
        }
    

    然后是一个组合框

        <ComboBox ItemsSource="{Binding SomeItemSource}"    
            SelectedItem="{Binding 
                Path=ItemX,
                Mode=TwoWay,
                UpdateSourceTrigger=PropertyChanged,
                Converter={StaticResource ResourceKey=SomeConverter}}">
    

    组合框中有一个ViewModel作为其 DataContext

        ViewModel : INotifyPropertyChanged, ...
        {
            ...
    
            public SampleEnum ItemX
            {
                get => model.GetItemX();
                set
                {
                    model.SetItemX(value);
                    RaisePropertyChanged();
                }
            }
    
            ...
        }
    

    RaisePropertyChanged([CallerMemberName] string caller = "") 调用 PropertyChanged 使用属性的名称。

    但是 .

    当我运行代码时,打开 CheckBox ,选择一项,我得到以下行为:我的代码进入setter,设置模型的值,引发PropertyChanged,然后调用我的getter,检索值, 但它从未达到 ComboBox . 组合框 显示我手动选择的值,而不是访问者返回的值。

    E、 g.如果你重写 get => SampleEnum.Item2 要始终返回相同的值, 组合框 即使我百分之百确定调用了getter,但仍然会在UI中显示我亲手挑选的值,而不是访问器返回的值,然后值会传递到转换器,Converter也会返回正确的值。

    如果 RaisePropertyChanged(nameof(ItemX)) 从任何其他地方调用, 组合框 立即从访问器中检索值并显示它。

    简言之 组合框 忽略 房地产变更 如果从setter调用,但在任何其他情况下,它都可以正常工作。直接指定属性的名称(而不是依赖于编译器服务)或在setter中调用行中更改的多个RasiePropertyChanged不起作用。

    一般来说,在组合框中选择的值和getter返回的值应该是相同的,但有时模型可以拒绝提供的值,而返回默认值。这不是最好的行为,但这是可能的。在这种情况下,用户将被错误地告知 组合框 实际上已选中。

    我只是想知道这个访问器有什么特别之处,以至于ComboBox忽略了它。

    1 回复  |  直到 7 年前
        1
  •  4
  •   15ee8f99-57ff-4f92-890c-b56153    7 年前

    tl;dr:你要做的是数据验证。这是一个已解决的问题:您可以使用 IDataErrorInfo ,或在您看来 ValidationRules . 其中任何一个都管用 具有 WPF,而不是反对它。反对WPF几乎总是失去主张。

    您还可以为组合框编写一个ItemContainerStyle来禁用无效项,或者您的viewmodel可以更新组合框项集合以排除当前无法选择的任何项。我更喜欢这种方法:而不是“在这里,你可以选择这些选项中的任何一个——BZZZT,LOL,错误的选择!”,只向他们提供他们所需要的选项似乎更为友好 可以 选择

    如果你在他们做出选择后知道哪些选项是有效的,你几乎可以肯定提前知道。


    如果从setter调用,ComboBox会忽略PropertyChanged,但在任何其他情况下,它都可以很好地工作。

    这是正确的。组合框仍在处理从用户那里得到的更改,直到setter完成一段时间后才能完成。组合框将忽略其当前正在更新的属性上的任何PropertyChanged事件。这是故意的。

    标准的解决方法是使用 ApplicationIdle 优先级,并提升委托中更改的属性。这将产生在组合框完全完成当前选择更改事件后再次引发PropertyChanged的效果。但这不是viewmodel应该关心的事情。

    正如你所说, “不是最好的行为” . 最好编写以下验证: 拒绝 首先是错误的值,而不是像上面那样编写奇怪的解决方法。