Edit: i have simplified this problem a lot since i first wrote it up. See the code examples at the bottom. I will clean the post up tomorrow.
I want to set the DataContext
AFTER the user as filled out a form because that is when I know the type of object I need to create (based on what the user selected). The problem with doing it this way is that the BindingGroup.IsDirty
flag is false because all edits are done by this point and I suppose that is why my call to BindingGroup.UpdateSources
is having no effect.
Essentially this is what I'm doing:
- Have user fill out form. The DataContext has not been set yet, but bindings are in place.
- In the
buttonSave_Click
handler, create and set the correctDataContext
object (based on provided user input) then callBindingGroup.UpdateSources
and close the dialog.
I realize there are other ways to go about this. Probably even better ones, but I am really just experimenting with DataBinding
and trying to learn it better. That is why I am trying out many possible designs with this.
Ultimately I will probably settle on a design where I ask the questions that I need answered in order to know what object to create for the data context then set it and let them fill out the remainder of the form from there. But for now I want to get it working the other way (if it is even possible) just for learning purposes.
EDIT 1:
I have determined that the IsDirty
flag must not be my problem because immediately before the DataContext
is set, IsDirty
is true
. Then immediately after DataContext
is set it becomes false
so I suppose it automatically updated sources then, however, I do not see the changes reflected in my data object so it obviously failed for some reason.
I know my Bindings are correct because if I set the DataContext
in the Windows ctor it updates the data. Move those two lines of code to the buttonSave_Click
handler and it no longer updates data.
I feel like there is something that I am missing that is going to me make me feel reaaallly stupid when I figure it out :\
UPDATE 1:
I have determined that the BindingExpression.Worker.CanUpdate is false. By looking at the source code of BindingExpression I can see that that would cause it to fail. Now to figure out why that is false....
UPDATE 2:
With all the reading i have been doing i am starting to suspect a timing issue. read this I will be able to try it when i get home
UPDATE 3:
Still working on this. Here is a bit of code. I have simplified to get minimal code.
Here is the data objects.
public abstract class Dog
{
public Dog(SexType sex)
{
NickName = string.Empty;
}
public string NickName { get; set; }
}
public class Stud : Dog
{
public Stud()
: base(SexType.Male)
{
}
}
This code works:
//code behind
public partial class AddDogWindow : Window
{
public Dog NewDog { get; set; }
public AddDogWindow()
{
InitializeComponent();
//set the DataContext here and the data object will be updated as expected...
NewDog = new Stud();
DataContext = NewDog;
}
private void buttonSave_Click(object sender, RoutedEventArgs e)
{
DialogResult = true;
}
}
And the XAML
<Window x:Class="PuppyMan.AddDogWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PuppyMan"
mc:Ignorable="d"
Title="AddStudDogWindow" Height="300" Width="300">
<StackPanel>
<TextBox HorizontalAlignment="Stretch" Text="{Binding NickName, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"></TextBox>
<Button x:Name="buttonSave" Click="buttonSave_Click">Save</Button>
</StackPanel>
</Window>
THIS is the code that BREAKS.
public partial class AddDogWindow : Window
{
public Dog NewDog { get; set; }
public AddDogWindow()
{
InitializeComponent();
}
private void buttonSave_Click(object sender, RoutedEventArgs e)
{
//Notice all I have changed is moving the set DataContext out of the ctor and into this handler.
//Now the data object no longer gets updated.
NewDog = new Stud();
DataContext = NewDog;
DialogResult = true;
}
}
The idea is that I let them fully fill out the dog info and then I only create the Stud or Dame dog object based on the final decision of whether the dog is male or female. A kind of lazy data binding I suppose. I know this isn't the best design for this situation but I want to learn how to do it this way for learning purposes. Or learn why this method won't work, either is fine, I just want to learn this data binding stuff and well!
FINAL UPDATE
This post seems to be essentially the same as my problem. I am using OneWayToSource and it always sets my NickName property to the default value (in this case ""). The problem is NOT that the NickName getter is called after the setter, but that it gets set to "". The UI keeps the original value until I type in the TextBox again and INotifyPropertyChange fires then everything syncs up again.
Seems an awful lot like a bug to me that OneWayToSource would push a "" instead of the current value of the target. But I very well may be miss understanding.