10

WPF と MVVM に基づくプロジェクトで AvalonEdit を使用しました。この投稿を読んだ後、次のクラスを作成しました。

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ですか?

4

3 に答える 3

8

DocumentTextWPF バインディングはプロパティを使用しません。代わりに、依存関係プロパティの基になる値に直接アクセスします。

OnTextChangedメソッドは、基になる依存関係プロパティの値を実際には変更しません。base.Text変更のたびに値を依存関係プロパティにコピーする必要があります。

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

この問題は、実装の正しいパターンに従った場合に簡単に確認できますDependencyPropertyDocumentTextプロパティはGetValue/SetValueメソッドを使用し、別のバッキング ストアにアクセスしないようにする必要があります。

于 2013-02-13T21:27:09.577 に答える
4

GetValue と SetValue を使用しても、テキストが変更されたときに TextProperty を取得してバインドされたものを更新することはできないため、とにかく Daniel の回答に従う必要があります。

テキストを通常モードと依存モードとして使用する必要があるエンドユーザーにとってより直感的になるように、少し変更を加えました。

    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);
    }

元に戻すスタック エンジンの例外を回避するために、同じテキストが既に存在するかどうかを確認する必要がありました。また、パフォーマンスに関してもお得です。

于 2014-04-09T15:41:11.510 に答える
2

バインディングが両方の方法で機能しなかったため、上記の回答に基づいてコードを少し変更してみました。以下のコンテンツは、2 つの方法でバインドできるようにする必要があります。

    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);
    }
于 2015-01-16T09:58:25.397 に答える