2010-04-01 10 views
5

Come posso avere una finestra di dialogo per modificare le proprietà di una classe con associazione e avere OK-Annulla nella finestra di dialogo?Finestra di dialogo Modifica, con collegamenti e OK/Annulla in WPF

La mia prima idea era questa:

public partial class EditServerDialog : Window { 
    private NewsServer _newsServer; 

    public EditServerDialog(NewsServer newsServer) { 
     InitializeComponent(); 

     this.DataContext = (_newsServer = newsServer).Clone(); 
    } 

    private void ButtonClick(object sender, RoutedEventArgs e) 
    { 
     switch (((Button)e.OriginalSource).Content.ToString()) { 
      case "OK": 
       _newsServer = (NewsServer)this.DataContext; 
       this.Close(); 
       break; 
      case "Cancel": 
       this.Close(); 
       break; 
     } 
    } 
} 

Quando nello switch, caso "OK", il DataContext contiene le informazioni corrette, ma l'istanza server delle news originariamente passato non cambia.

+0

Potrebbe essere utile se si visualizza la configurazione del binding. –

+0

Esempio di associazione: {Binding NeedAuthentication, UpdateSourceTrigger = LostFocus, Mode = TwoWay}. L'associazione è corretta perché questo.DataContext contiene i dati corretti. – ErikTJ

risposta

1

L'istanza originale dell'oggetto NewsServer non è stata modificata perché non è stata effettivamente modificata. Dopo che il costruttore viene chiamato si hanno le seguenti tre NewsServer riferimenti:

newsServer = original instance 
_newsServer = original instance 
DataContext = clone of original instance 

Dopo che il pulsante OK si fa clic i riferimenti saranno i seguenti:

newsServer = original instance 
_newsServer = clone of original instance (possibly modified) 
DataContext = clone of original instance (possibly modified) 

Ricordate che gli oggetti sono tipi di riferimento, nel vostro incarico per _newsServer si sta solo aggiornando il suo riferimento, non il valore dell'oggetto stesso.

Al fine di consentire l'aggiornamento all'oggetto NewsServer stesso ci sono due opzioni che vengono in mente, probabilmente esistono altre opzioni, la prima è probabilmente il più semplice.

  • implementare un metodo void Update(NewsServer source) sul NewsServer oggetto allora invece di eseguire la nuova assegnazione al campo _newsServer invece chiamare il metodo di aggiornamento su di esso e passare il valore DataContext riferimento.
  • Esporre il valore _newsServer con una proprietà pubblica/interna. Puoi farne uso attraverso una varietà di meccanismi: rispondere esplicitamente a un evento che viene generato quando il valore della proprietà cambia; associare alla proprietà (ad esempio, renderla una proprietà di dipendenza o implementare INotifyPropertyChanged); oppure aspettarsi che il chiamante recuperi il valore se e quando il metodo ShowDialog() restituisce il valore true.

Si noti che se si spinge un po 'della logica sul chiamante, la classe di dialogo può essere più semplice. In particolare, un approccio è solo mantenere l'oggetto clonato, esposto al chiamante tramite una proprietà (ad esempio, eliminare completamente il campo _newsServer e utilizzare semplicemente DataContext). Questo oggetto sarebbe associato agli elementi della finestra di dialogo come prima. Il chiamante recupera semplicemente il riferimento di questa istanza su un risultato true dal metodo ShowDialog().

Ad esempio:

NewsServer newsServer = ...; 
EditServerDialog editServerDialog = new EditServerDialog(newsServer); 

if (editServerDialog.ShowDialog() == true) 
{ 
    newsServer = editServerDialog.DataContext; 
} 

L'oggetto clonato sarebbe semplicemente ignorato dal chiamante se la finestra viene annullata, e, quindi, il metodo ritorna ShowDialog()false. Si potrebbe semplicemente riutilizzare la proprietà DataContext come mostrato sopra, oppure creare una proprietà diversa (ad esempio denominata NewsServer) che restituisca il valore della proprietà DataContext (ad esempio per rendere il codice un po 'più chiaro per l'interfaccia pubblica della classe di dialogo).

+0

Come devo fare questo ed essere ancora in grado di annullare e/o applicare? – ErikTJ

3

Vecchia domanda ma risponderò per i futuri lettori ...

È necessario impostare UpdateSourceTrigger="Explicit" sui binding in modo che non aggiornino la sorgente effettiva finché l'utente non fa clic su OK. Poi sul vostro gestore di pulsante OK si può scrivere:

BindingExpression be = MyTextBox.GetBindingExpression(TextBox.TextProperty); 
if (be!=null) be.UpdateSource(); 

Inoltre, se si desidera ripristinare attacchi dell'uso iniziale stato

BindingExpression be = MyTextBox.GetBindingExpression(TextBox.TextProperty); 
if (be!=null) be.UpdateTarget(); 

Se il dialogo è complesso si consiglia di percorrere tutti i suoi controlli in modo ricorsivo .

0

Questa è una vecchia domanda, ma recentemente mi sono imbattuto in questo e ho trovato che c'è un modo migliore di gestirlo con .NET 4.5.

In primo luogo, segnare le associazioni UpdateSourceTrigger come esplicito:

<CheckBox IsChecked="{Binding MyProperty, UpdateSourceTrigger=Explicit}"/> 

Poi, nel vostro gestore di eventi scatto del tasto Ok utilizzare questo:

foreach (var be in BindingOperations.GetSourceUpdatingBindings(this)) 
{ 
    be.UpdateSource(); 
} 

GetSourceUpdatingBindings è un nuovo metodo di .NET 4.5.

Il pulsante di annullamento non ha bisogno di fare nulla, poiché i binding sono stati contrassegnati come Explicit e saranno "committed" solo quando viene chiamato UpdateSource.

Problemi correlati