簡體   English   中英

AvalonEdit中的雙向綁定不起作用

[英]Two-way binding in AvalonEdit doesn't work

我在我的項目中使用了AvalonEdit,它基於WPF和MVVM。 閱讀這篇文章后,我創建了以下課程:

public class MvvmTextEditor : TextEditor, INotifyPropertyChanged
{
    public static DependencyProperty DocumentTextProperty =
        DependencyProperty.Register("DocumentText", 
                                    typeof(string), typeof(MvvmTextEditor),
        new PropertyMetadata((obj, args) =>
        {
            MvvmTextEditor target = (MvvmTextEditor)obj;
            target.DocumentText = (string)args.NewValue;
        })
    );

    public string DocumentText
    {
        get { return base.Text; }
        set { base.Text = value; }
    }

    protected override void OnTextChanged(EventArgs e)
    {
        RaisePropertyChanged("DocumentText");
        base.OnTextChanged(e);
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged(string info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}

並使用以下XAML來使用此控件:

<avalonedit:MvvmTextEditor x:Name="xmlMessage">
   <avalonedit:MvvmTextEditor.DocumentText>
      <Binding Path ="MessageXml" Mode="TwoWay" 
               UpdateSourceTrigger="PropertyChanged">
         <Binding.ValidationRules>
            <local:XMLMessageValidationRule />
          </Binding.ValidationRules>
      </Binding>
   </avalonedit:MvvmTextEditor.DocumentText>
</avalonedit:MvvmTextEditor>

但綁定工作OneWay並不更新我的字符串屬性也不運行驗證規則。

如何修復綁定以按預期方式工作? TwoWay

WPF綁定不使用您的DocumentText屬性; 相反,他們直接訪問依賴屬性的基礎值。

您的OnTextChanged方法實際上不會更改基礎依賴項屬性的值。 您需要在每次更改時將base.Text的值復制到依賴項屬性中:

protected override void OnTextChanged(EventArgs e)
{
    SetCurrentValue(DocumentTextProperty, base.Text);
    base.OnTextChanged(e);
}

如果您遵循正確的模式來實現DependencyProperty則會更容易看到此問題: DocumentText屬性應使用GetValue / SetValue方法,而不是訪問其他后備存儲。

即使使用GetValue和SetValue,也無法讓TextProperty在文本更改時更新綁定,因此無論如何都必須遵循Daniel的回答。

我確實改變了一點,使最終用戶不得不使用Text作為正常和依賴模式更直觀:

    public new string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    internal string baseText { get { return base.Text; } set { base.Text = value; } }

    public static DependencyProperty TextProperty =
    DependencyProperty.Register("Text", typeof(string), typeof(MvvmTextEditor),
        // binding changed callback: set value of underlying property
        new PropertyMetadata((obj, args) =>
        {
            MvvmTextEditor target = (MvvmTextEditor)obj;
            if(target.baseText != (string)args.NewValue)    //avoid undo stack overflow
                target.baseText = (string)args.NewValue;
        })
    );

    protected override void OnTextChanged(EventArgs e)
    {            
        SetCurrentValue(TextProperty, baseText);
        RaisePropertyChanged("Text");
        base.OnTextChanged(e);
    }

我必須檢查是否已存在相同的文本以避免撤消堆棧引擎異常。 表現明智也很划算。

我嘗試了基於上面的答案的代碼稍作修改,因為綁定對我來說兩種方式都不起作用。 下面的內容應該允許綁定兩種方式。

    public static readonly DependencyProperty MyContentProperty = DependencyProperty.Register(
        "MyContent", typeof(string), typeof(MyTextEditor), new PropertyMetadata("", OnMyContentChanged));

    private static void OnMyContentChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        var control = (MyTextEditor)sender;
        if (string.Compare(control.MyContent, e.NewValue.ToString()) != 0)
        {
            //avoid undo stack overflow
            control.MyContent = e.NewValue.ToString();
        }
    }

    public string MyContent
    {
        get { return Text; }
        set { Text = value; }
    }

    protected override void OnTextChanged(EventArgs e)
    {
        SetCurrentValue(MyContentProperty, Text);
        base.OnTextChanged(e);
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM