2013-02-13 8 views
8

Ich habe AvalonEdit in meinem Projekt, das auf WPF und MVVM basiert verwendet. Nach this post Lesen habe ich die folgende Klasse:Zwei-Wege-Bindung in AvalonEdit funktioniert nicht

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

und verwendet, um die folgenden XAML dieses Steuerelement zu verwenden:

<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> 

aber die Bindungs ​​Werke OneWay und meine Zeichenfolge nicht aktualisiert Eigenschaft noch laufen Validierung Regel.

Wie kann ich die Bindung reparieren, um wie erwartet zu arbeiten TwoWay?

+0

Können Sie mir bitte genau sagen, wie Sie das funktioniert haben? Ich habe eine andere Frage gestellt [hier] (http://stackoverflow.com/questions/18964176/two-way-binding-to-avalonedit-document-text-using-mvvm?noredirect=1#comment28010773_18964176) ... – MoonKnight

Antwort

6

WPF-Bindungen verwenden nicht Ihre DocumentText-Eigenschaft; Stattdessen greifen sie direkt auf den zugrunde liegenden Wert der Abhängigkeitseigenschaft zu.

Ihre OnTextChanged-Methode ändert den Wert der zugrunde liegenden Abhängigkeitseigenschaft nicht. Sie müssen den Wert von base.Text in die Abhängigkeitseigenschaft bei jeder Änderung kopieren:

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

Dieses Problem wäre einfacher zu sehen, ob Sie das richtige Muster gefolgt DependencyProperty zur Implementierung: Die DocumentText Eigenschaft verwenden, sollte die GetValue/SetValue Methoden und nicht auf einen anderen Hintergrundspeicher zugreifen.

+1

Danke sehr viel für die Antwort - ich habe geholfen. Ich bin jedoch verwirrt darüber, wie man 'GetValue' /' SetValue' im obigen Code für 'MvvmTextEditor' Klasse verwendet? Es scheint, dass es nicht mit der aktuellen Implementierung kompatibel ist. – MoonKnight

4

Sogar mit GetValue und SetValue können Sie die TextProperty nicht dazu bringen, das Binded zu aktualisieren, wenn sich der Text ändert, daher muss die Daniel-Antwort trotzdem beachtet werden.

habe ich ein wenig ändern, um es intuitiver zu dem Endbenutzer zu machen mit dem Text als normal und dependecy-Modus verwenden:

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

ich schon da, wenn der gleiche Text war zu überprüfen, hatte das zu vermeiden, Stack-Engine-Ausnahme rückgängig machen. Auch die Leistung ist ein gutes Geschäft.

1

Ich habe den Code anhand der obigen Antworten mit leichten Modifikationen ausprobiert, da das Binden bei mir nicht in beiden Richtungen funktionierte. Der Inhalt unten sollte erlauben, zwei Arten zu binden.

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