2013-02-13 11 views
8

Ho usato AvalonEdit nel mio progetto basato su WPF e MVVM. Dopo aver letto this post ho creato la seguente classe:L'associazione a due vie in AvalonEdit non funziona

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

e usato il seguente XAML per utilizzare questo controllo:

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

ma le opere di legame OneWay e non aggiorna la mia proprietà stringa né convalida correre regola.

Come posso risolvere il binding per funzionare come previsto TwoWay?

+0

Puoi dirmi esattamente come hai funzionato? Ho fatto un'altra domanda [qui] (http://stackoverflow.com/questions/18964176/two-way-binding-to-avalonedit-document-text-using-mvvm?noredirect=1#comment28010773_18964176) ... – MoonKnight

risposta

6

I binding WPF non utilizzano la proprietà DocumentText; invece accedono direttamente al valore sottostante della proprietà di dipendenza.

Il metodo OnTextChanged non modifica effettivamente il valore della proprietà di dipendenza sottostante. Sarà necessario copiare il valore dal base.Text nella proprietà di dipendenza su ogni cambiamento:

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

Questo problema sarebbe più facile per vedere se avete seguito il modello corretto per l'attuazione DependencyProperty: La proprietà DocumentText dovrebbe utilizzare il GetValue/SetValue metodi e non accedere a un altro backing store.

+1

Grazie molto per la risposta - l'ho aiutato. Sono comunque confuso su come usare 'GetValue' /' SetValue' nel codice sopra per la classe 'MvvmTextEditor'? Sembra che non sia compatibile con l'attuale implementazione. – MoonKnight

4

Anche utilizzando GetValue e SetValue non è possibile ottenere TextProperty per aggiornare il binding quando il testo cambia, quindi la risposta di Daniel deve essere seguita comunque.

ho fatto cambiare un po 'per renderlo più intuitivo per l'utente finale dover utilizzare il testo come normale e dependecy modalità:

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

ho dovuto controllare se lo stesso testo era già lì per evitare il annullare l'eccezione del motore dello stack. Anche le prestazioni sagge sono un buon affare.

1

Ho provato il codice in base alle risposte di cui sopra con lievi modifiche, poiché l'associazione non funzionava per entrambi i modi. Il contenuto di seguito dovrebbe consentire di associare due modi.

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