How can i have a dialog for editing the properties of a class with binding, and have OK-Cancel in the dialog?
My first idea was this:
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;
}
}
}
When in the switch, case "OK", the DataContext contains the correct information, but the originally passed NewsServer instance does not change.
This is an old question, but I recently ran into this and found there is a better way to handle it with .NET 4.5.
First, mark your bindings UpdateSourceTrigger as Explicit:
<CheckBox IsChecked="{Binding MyProperty, UpdateSourceTrigger=Explicit}"/>
Then, in your Ok button click event handler use this:
foreach (var be in BindingOperations.GetSourceUpdatingBindings(this))
{
be.UpdateSource();
}
GetSourceUpdatingBindings is a new method in .NET 4.5.
The cancel button doesn't need to do anything, since the bindings have been marked as Explicit and will only be "committed" when UpdateSource is called.
Old question but I'll answer it for future readers...
You have to set UpdateSourceTrigger="Explicit"
on your bindings so they will not update actual source until user clicks OK. Then on your OK button handler you can write:
BindingExpression be = MyTextBox.GetBindingExpression(TextBox.TextProperty);
if (be!=null) be.UpdateSource();
Also if you want to reset bindings to initial state use
BindingExpression be = MyTextBox.GetBindingExpression(TextBox.TextProperty);
if (be!=null) be.UpdateTarget();
If your dialog is complex you may want to walk all of its controls recursively.
The original instance of your NewsServer
object is not changed because you haven't actually modified it. After your constructor is called you have the following three NewsServer
references:
newsServer = original instance
_newsServer = original instance
DataContext = clone of original instance
After the OK button is clicked the references will be as follows:
newsServer = original instance
_newsServer = clone of original instance (possibly modified)
DataContext = clone of original instance (possibly modified)
Remember that objects are reference types, in your assignment to _newsServer
you are only updating its reference, not the value of the object itself.
In order to allow updating the NewsServer
object itself there are two options that come to mind, other options likely exist, the first is probably the simplest.
void Update(NewsServer source)
method on your NewsServer
object then instead of performing the new assignment to the _newsServer
field instead call the update method on it and pass in the DataContext
reference value._newsServer
value with a public/internal property. You can make use of this through a variety of mechanisms: explicitly respond to an event that is raised when the property value changes; bind to the property (e.g. make it a dependency property or implement INotifyPropertyChanged
); or just expect the caller to retrieve the value if and when the ShowDialog()
method returns with a value of true
.Note that if you push a bit of the logic back on the caller, your dialog class can be simpler. In particular, one approach is to only maintain the cloned object, exposed to the caller via a property (e.g. get rid of the _newsServer
field altogether and just use DataContext
). This object would be bound to the dialog's elements as before. The caller would simply retrieve this instance's reference on a true
result from the ShowDialog()
method.
For example:
NewsServer newsServer = ...;
EditServerDialog editServerDialog = new EditServerDialog(newsServer);
if (editServerDialog.ShowDialog() == true)
{
newsServer = editServerDialog.DataContext;
}
The cloned object would simply be ignored by the caller if the dialog is cancelled, and thus the ShowDialog()
method returns false
. You could just reuse the DataContext
property as shown above, or you could create a different property (e.g. named NewsServer
) that just returns the DataContext
property value (i.e. to make the code a bit clearer as to the public interface of the dialog class).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With