Two-way databinding: Updating textbox not updating bound property - c#

I am databinding a textbox of a UserControl to a property as follows.
<TextBox Name="txtData" Text="{Binding MyData, Mode=TwoWay}"/>
But when I click the Submit button on the page that hosts the usercontrol after entering some text in the txtData textbox of the usercontrol, userControl.MyData returns null. What can I do to have the txtData.text value be assigned to property other than through TextChangedevent?

From your comments you wish to update userControl.MyData when the TextBox.Text changes.
From the binding perspective TextBox.Text is the target and MyData is the source so strictly speaking this is a OnWayToSource binding (to source => to MyData) - so there should be no need to implement INotifyPropertyChanged. But that is not the issue.
The way the binding is currently written, the MyData property expects to be found on the DataContext of the TextBox - is that the case? You could fix the data context or possibly use some other binding source e.g. ElementName or RelativeSource - difficult to say without seeing more xaml.
You might also consider setting UpdateSourceTrigger=PropertyChanged on the binding.

Related

"Transfer" a binding from a property to an other

I am trying to wrap a TextBox in a custom UserControl and by then my custom UserControl has a Text dependency property. An example use of the custom UserControl would look like this :
<MyTextBoxWrapper Text="{Binding SomeProperty}"/>
and MyTextBoxWrapper looks like this :
<UserControl ...>
<TextBox x:Name="wrappedTextBox"/>
</UserControl>
I'd like my wrapper to work exactly like if it was written like this :
<UserControl ...>
<TextBox x:Name="wrappedTextBox" Text="{Binding SomeProperty}"/>
</UserControl>
My issue is that I can't manage to "transfer" the binding from the MyTextBoxWrapper.Text property to the TextBox.Text property. (kind of like binding the bindings themselves)
I only managed to obtain the binding used by MyTextBoxWrapper.Text with this :
myTextBoxWrapperInstance.GetBindingExpression(MyTextBoxWrapper.TextProperty);
How can I have the same binding being used for both properties? I don't necessarily need the same binding instance but I at least need the binding used by TextBox.Text to be created from the binding used by MyTextBoxWrapper.Text.
Bind the TextBox in the UserControl to the Text property of the UserControl itself:
<TextBox x:Name="wrappedTextBox"
Text="{Binding Text, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
This doesn't fit my needs, I need to have the binding on TextBox.Text to be the same binding as the one on MyTextBoxWrapper.Text, what you gave me creates a different binding
Yes, a single binding always has a single target and single source.
You may try to register a callback for the custom Text property of the UserControl and programmatically bind the Text property of the TextBox to the same property.
Or make Text a property of type Binding.

WPF TwoWay DataBound ComboBox from a DataView

I Currently have a XAML ComboBox inside a custom control.
<ComboBox Name="cboPropertyName"
ItemsSource="{Binding}"
Visibility="Hidden"
GotFocus="TxtPropertyName_GotFocus"
DataContextChanged="CboPropertyName_DataContextChanged"
SelectionChanged="CboPropertyName_SelectionChanged"/>
which is connected via Code Behind
DataView DataPropsView = new DataView(_ControlData.Tables["GME_DataProperties"]);
DataPropsView.RowFilter = "Key < 1000";
DataPropsView.Sort = "Key ASC";
cboPropertyName.DataContext = DataPropsView;
cboPropertyName.DisplayMemberPath = "Name";
cboPropertyName.SelectedValuePath = "Key";
cboPropertyName.SelectedValue = Convert.ToInt32(_PropData["SubPropertyValue"]);
But when this customer control has the drop downlist changed the _PropData DataView never changes / Updates.
How can I make this be a TwoWay DataBinding so the DataView updates?
I recommend that you abandon the codebehind and setup all the info in XAML to allow easier setup.
To use two-way binding on needs to bind the target to SelectedValue such as:
SelectedValue="{Binding CategoryID, Mode=TwoWay}"
You seem to have an issue with where the data resides which is really your greatest issue.
Generally one does not bind to a dictionary. Binding is in essence reflection and reflection into a dictionary is problematic to say the least. To do what you need to do, you should create a Notified property on the control and two-way bind to that. On the set for that property, change the dictionary value at the same time.
Also one does not bind to a view to change, because it is a view. Look into using a MVVM pattern, and create the view from the ViewModel, and bind your combobox to the viewmodel's data. Then the two-way binding will work as generally designed.

Multiple sources bound to same target dependency property

Is it possible to attach multiple (two-way) source bindings to a dependency property? That is, so that if one source changes, the DP gets updated via one binding, and the change would then get propagated to the second source via the second binding.
In my scenario, the dependency property is in a user control, the first binding is to its internal view-model, and the second binding is for the view-model of the consumer of the user control.
Below is for illustration. The consumer of the user control looks like this:
<MyControl SelectedValue="{Binding Selected,Mode=TwoWay}" />
Now "MyControl" has the "SelectedValue" defined as a dependency property. The XAML for the control binds to its dependency property like this:
<UserControl>
<Grid x:Name="LayoutRoot">
<TextBox Text="{Binding SelectedValue,Mode=TwoWay,
RelativeSource={RelativeSource AncestorType=UserControl}}"
/>
</Grid>
</UserControl>
"MyControl" has its internal data context set, in the control's constructor, to its own view model:
LayoutRoot.DataContext = new ViewModelForControl();
So far so good, but if I then attempt to add the second binding, that being the dependency property to a "SelectedInternal" property on the internal view-model --
SetBinding(SelectedValueProperty, new Binding("SelectedInternal") {
Source = LayoutRoot.DataContext,
Mode = BindingMode.TwoWay
});
-- then the first binding is destroyed. Is there a way to add this second binding while preserving the first?
Is this being overthought?
Why not simply do the plumbing in the code behind of the custom control and forgo binding?
This can be done by
SelectedValue dependency property will utilize its changed handler and upon any change set SelectedInternal to the new value.
When SelectedInternal changes write to the property SelectedValue.
You create the VM on the control, so you have access to the VM and its property, which can provide the vectoring of the data for two way transfer.
At the end of the day binding is just getting a reference via reflection. In this case how one gets a reference is immaterial to simply writing back and forth between two properties.
Or am I missing something?

Assigning view model to data context: when does view model override XAML element?

I'm learning WPF and MVVM. I'm curious about what happens in a particular situation.
Assuming that my view model implements INotifyPropertyChanged, the situation is where my code has already constructed my view model and then assigns it to my window's DataContext.
At the point in time that I assign the view model to DataContext, the value in my view model may be different than the value in the XAML element. And so I'm curious about which value wins.
I assumed the XAML element would pull in all the values from my view model but that is not what seems to be happening. Changes made to my view model correctly notify and update the XAML elements. But those changes made before I set DataContext are not reflected in the XAML elements.
Can anyone confirm my interpretation is correct? I've Googled extensively but could not find anything on this specific issue. Yet that seems to be the behavior in my application. Would appreciate someone else perspective or a link to a more detailed discussion.
I'm curious about the situation where my view model implements INotifyPropertyChanged, my code builds my view model and then assign it to my windows DataContext.
The problem is, at that stage where I assign to DataContext, the value in the XAML element may not match my view model. So which one wins.
Based on my testing, it appears that the value already in the XAML element wins. And if I want it set to the value in my view model, I must set it somehow or have my view model send a new property-changed notification.
Sounds like your changing your data template to show a hardcoded value rather than the default value provided by the binding.
For example in a TextBlock you can only assign the Text property once, either via a binding syntax where the value is sourced from the DataContext, or a static value.
<TextBlock Text="{Binding Path=Display}"/> <- only uses the DataContext
<TextBlock Text="123"/> <- only shows the static value
If you try and set the Text property twice, you get an error:
<TextBlock Text="{Binding Path=Display}">
<TextBlock.Text>
123
</TextBlock.Text>
</TextBlock>
You can provide the binding with a fallback value when there is no valid value available via the DataContext such as an exception being thrown, but the DataContext value wins when it provides a value:
<TextBlock Text="{Binding Path=Display, FallbackValue=123}" />
If you want to set a default value, you might be best to set a default in the constructor of the DataContext class and leave the binding in the Xaml to only source from the DataContext

How do I bind to one data source but update trigger from another?

I have a TextBox with a OneWay binding to a string property, and I'd like it to update when some other property on my DataContext changes. My DataContext is an ObservableCollection and the TextBox displays statistics about the collection. So I want the statistics to be updated whenever the collection changes, but I don't want to have to raise a dummy "statistics changed" event.
In other words, does XAML (or databinding generally) allow me to specify one binding for the data of a control and another for its update event?
If I understand you correctly, there is a much easier way to achieve what you want:
<ListBox ItemsSource={Binding Items} />
<TextBox Text="{Binding Items/PropertyName}" />
Assuming that your ObservableCollection has a bindable property named PropertyName in it and that your view model (or DataContext) has a property called Items of the type of your ObservableCollection, then the TextBox control will display the PropertyName value of the currently selected item in the collection.
You can find out more about the '/' path syntax from the PropertyPath XAML Syntax page on MSDN.

Categories

Resources