编程语言
首页 > 编程语言> > c# – WPF:TwoWay绑定始终更新 – OneWay绑定仅在ONCE上更新

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

作者:互联网

我知道你的想法: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