ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

c# – WPF:TwoWay绑定始终更新 – OneWay绑定仅在ONCE上更新

2019-06-07 18:01:58  阅读:308  来源: 互联网

标签:c wpf xaml binding oneway


我知道你的想法:2017年,请不要再提出这个,但我真的找不到任何有价值的解释.

请查看此XAML代码中的ActiveNotes属性.

我在我的XAML中有这个TwoWay绑定,它完美地运行.如果触发了ScaleNotes的PropertyChanged事件并且绑定设置为TwoWay,则它始终更新.

<c:Keyboard 
            Grid.Row="2" 
            Grid.Column="0" 
            PlayCommand="{Binding PlayCommand}" 
            StopCommand="{Binding StopCommand}" 
            ActiveNotes="{Binding ScaleNotes, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

ViewModel中的ScaleNotes属性如下所示.每当它发生变化时,都会保证触发PropertyChanged事件.我检查并仔细检查了一下. ViewModel中的业务逻辑有效.

private ReadOnlyCollection<eNote> _ScaleNotes;
public ReadOnlyCollection<eNote> ScaleNotes
{
    get { return _ScaleNotes; }
    set { SetField(ref _ScaleNotes, value); }
}

[DebuggerStepThrough]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

[DebuggerStepThrough]
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
    if (EqualityComparer<T>.Default.Equals(field, value)) return false;
    field = value;
    OnPropertyChanged(propertyName);
    return true;
}

到这里一切都很好.每当更改VM中的ScaleNotes属性时,都会更新目标属性ActiveNotes.

现在的问题是:

如果我只将XAML中的绑定更改为OneWay并且VM中的业务逻辑保持100%相同,则即使触发了PropertyChanged事件,目标对象中的ActivesNotes属性也只更新一次.我检查并仔细检查了一下.始终触发ScaleNotes属性的PropertyChanged事件.

<c:Keyboard 
            Grid.Row="2" 
            Grid.Column="0" 
            PlayCommand="{Binding PlayCommand}" 
            StopCommand="{Binding StopCommand}" 
            ActiveNotes="{Binding ScaleNotes, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>

只是为了完成这个,这里是目标对象中的DP.

public static DependencyProperty ActiveNotesProperty = DependencyProperty.Register(
        "ActiveNotes", 
        typeof(ReadOnlyCollection<eNote>), 
        typeof(Keyboard), 
        new PropertyMetadata(OnActiveNotesChanged));


public ReadOnlyCollection<eNote> ActiveNotes
{
    get
    {
        return (ReadOnlyCollection<eNote>)GetValue(ActiveNotesProperty);
    }
    set
    {
        SetValue(ActiveNotesProperty, value);
    }
}

private static void OnActiveNotesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    Keyboard keyboard    = (Keyboard)d;
    keyboard.ActiveNotes = (ReadOnlyCollection<eNote>)e.NewValue;

    if ((keyboard.ActiveNotes != null) && (keyboard.ActiveNotes.Count > 0))
    {
        keyboard.AllKeys.ForEach(k => { if ( k.Note != eNote.Undefined) k.IsActiveKey = true; });
        keyboard.AllKeys.ForEach(k => { if ((k.Note != eNote.Undefined) && (!keyboard.ActiveNotes.Contains(k.Note))) k.IsActiveKey = false; });
    }
    else
    {
        keyboard.AllKeys.ForEach(k => { if (k.Note != eNote.Undefined) k.IsActiveKey = true; });
    }
}

我不明白这一点.据我所知,OneWay和TwoWay只定义值更新的方向,而不是更新它们的频率.

我无法理解,一切都运行良好的TwoWay,业务逻辑保持100%相同,OneWay是一个交易破坏者.

如果你问自己,为什么我想知道这个:这个绑定计划为OneWay绑定.以任何方式更新源都没有意义.我只将它改为TwoWay,因为OneWay没有按预期工作.

在@MikeStrobel的帮助下解决方案:(见评论)

代码需要以这种方式更改:

private static void OnActiveNotesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    Keyboard keyboard    = (Keyboard)d;

    //THIS LINE BREAKED THE CODE, WHEN USING OneWay binding BUT NOT WITH TwoWay binding
    //keyboard.ActiveNotes = (ReadOnlyCollection<eNote>)e.NewValue;

    if ((keyboard.ActiveNotes != null) && (keyboard.ActiveNotes.Count > 0))
    {
        keyboard.AllKeys.ForEach(k => { if ( k.Note != eNote.Undefined) k.IsActiveKey = true; });
        keyboard.AllKeys.ForEach(k => { if ((k.Note != eNote.Undefined) && (!keyboard.ActiveNotes.Contains(k.Note))) k.IsActiveKey = false; });
    }
    else
    {
        keyboard.AllKeys.ForEach(k => { if (k.Note != eNote.Undefined) k.IsActiveKey = true; });
    }
}

使用OneWay绑定,OnActiveNotesChanged事件处理程序方法中的赋值将删除或清除绑定.迈克是正确的说,这种分配是完全没必要的,因为在这个时间点,价值已经在物业中设定.因此,无论我使用OneWay还是TwoWay绑定,它都毫无意义.

解决方法:

依赖项属性具有precedence的复杂系统.任何给定时间的依赖项属性的值可能来自各种来源:绑定,样式设置器,触发器设置器等.本地值具有最高优先级,并且当您设置本地值时,你压制来自其他来源的价值.

在绑定的情况下,设置本地值将导致*删除源到目标绑定(OneWay或OneTime)*.但是,当您使用目标到源绑定(TwoWay或OneWayToSource)在属性上设置本地值时,将保持绑定,并且您指定的本地值将传播回源.

在您的情况下,问题出在这里:

keyboard.ActiveNotes = (ReadOnlyCollection<eNote>)e.NewValue;

在OnActiveNotesChanged处理程序中,您将为ActiveNotes分配一个新的本地值,这会导致您的OneWay绑定被删除.幸运的是,解决方案很简单:您可以完全删除此行,因为它是多余的.在大多数情况下,不必在自己的更改处理程序中分配依赖项属性 – 已经应用了新值. (如果您希望有机会在应用之前替换建议值,那么执行此操作的位置将是CoerceValueCallback,您也可以在PropertyMetadata中指定.)

标签:c,wpf,xaml,binding,oneway
来源: https://codeday.me/bug/20190607/1195609.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有