Why does data binding break in OneWay mode? - wpf

Here's a little XAML fragment. You will see
<StackPanel>
<TextBox x:Name="txtValue">250</TextBox>
<Slider x:Name="slide"
Value="{Binding ElementName=txtValue, Path=Text,
Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Minimum="0" Maximum="500"></Slider>
</StackPanel>
when you change the textbox value, the slider updates
If you change the slider value explicitly, the previous behavior breaks a.k.a. stops working.
If I remove the Mode=OneWay set directive, (defaults to two-way) everything works perfectly.
Why is this happening?

Use mode=TwoWay and set the UpdateSourceTrigger=Explicit.

Your data binding is not broken but deactivated (http://en.wikipedia.org/wiki/Euphemism):
System.Windows.Data Warning: 75 : BindingExpression (hash=52697953): Deactivate
System.Windows.Data Warning: 99 : BindingExpression (hash=52697953): Replace item at level 0 with {NullDataItem}
System.Windows.Data Warning: 59 : BindingExpression (hash=52697953): Detach
Setting the trace level to high will produce this message in the VS output window in case you move the slider:
<Slider xmlns:trace="clr-namespace:System.Diagnostics;assembly=WindowsBase"
Value="{Binding trace:PresentationTraceSources.TraceLevel=High,
ElementName=txtValue, Path=Text, Mode=OneWay,
UpdateSourceTrigger=PropertyChanged}"
Minimum="0" Maximum="500"></Slider>

If you create a control which inherits from Slider, then override the Value property and use DependencyObject.SetCurrentValue when changing the value rather than DependencyOpbject.SetValue, then your databindings will be preserved when changing the values programmatically.
Sorry this isn't particularly exhaustive, will update this answer to include a basic implementation of this at a later date.
Alternatively, a UserControl which contains both the textbox and the slider would make for a very reusable implementation, in which you could bind them both to the same custom dependencyproperty, make the binding oneway, hijack the valuechanged event of the slider, set e.Handled = true, and call the SetCurrentValue function from that.

Related

Binding Error Reported with Converter in WPF Textbox

a textbox is either hidden or not depending on whether its text is null or not.
The actual hiding works ok but i keep getting a Data.Error as follows.
System.Windows.Data Error: 40 : BindingExpression path error: 'new_file_path' property not found on 'object' ''main_window_vm' (HashCode=44962972)'. BindingExpression:Path=new_file_path; DataItem='main_window_vm' (HashCode=44962972); target element is 'Run' (HashCode=28141317); target property is 'Text' (type 'String')
xaml is
<Padding="10" Visibility="{Binding Path=Text, RelativeSource={RelativeSource Self},
Converter={StaticResource null_to_viz}}">
<Run Text="Updated file path : " />
<Run Text="{Binding new_file_path}" />
any ideas to fix this error?
The issue is complaining about not finding new_file_path yet the example is binding to the property Text.
Most likely this converter is not failing and it is a different control. Investigate by either finding the right control which is not binding properly or verifying that textbox is actually binding to the proper VM.
seems like this error occurs when one foolishly set a property to private, not public. Which is why it was not able to be found.

How to get and set TemplateBinding of a property in code in WPF?

I have a textblock with a TemplateBinding:
<TextBlock Text="{TemplateBinding Text}" />
It might seem weird but to spare you the details, I need to retrieve this TemplateBinding of Text property in the C# code, save it to a variable temporarily, and then assign it back to the same Text property.
How can I do that?
So far I've tried these to get TemplateBinding:
//First approach
BindingExpression bindingExpression = textBox1.GetBindingExpression(TextBox.TextProperty);
Binding parentBinding = bindingExpression.ParentBinding;
//Second approach
BindingOperations.GetBinding(textBox1, TextBox.TextProperty);
They don't work, probably because they retrieve only regular binding not TemplateBinding

WPF - How to use DataTrigger without interfering with DataContext of child UIElements

I am trying to allow a user to choose one of two format types for inputting double values, and then I want to use a DataTrigger in xaml to choose one of two separate control types for the user to input these values, based on the format they have chosen.
I have a view and a viewmodel. The view model has properties like this:
public class MyViewModel
{
public string DoubleFormat {get;set;}
public double X {get;set;}
public double Y {get;set;}
public double Z {get;set;}
}
The application will set the DoubleFormat property to something like "FormatA" or "FormatB" for the DataTrigger to trigger off of.
The xaml for my view looks like this:
<DataTemplate x:Key="FormatAEditTemplate" DataType="common:MyViewModel">
<util:FormatAEditorControl Value="{Binding X}"/>
</DataTemplate>
<DataTemplate x:Key="FormatBEditTemplate" DataType="common:MyViewModel">
<wpftk:DecimalUpDown Value="{Binding X}" />
</DataTemplate>
<DataTemplate x:Key="MyEditTemplate" DataType="common:MyViewModel">
<ContentControl x:Name="MyDoubleInputControl" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding DoubleFormat}" Value="FormatA">
<Setter TargetName="MyDoubleInputControl" Property="ContentTemplate" Value="
{StaticResource FormatAEditTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding DoubleFormat}" Value="FormatB">
<Setter TargetName="MyDoubleInputControl" Property="ContentTemplate" Value="
{StaticResource FormatBEditTemplate}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
So in the trigger I'm essentially trying to set the ContentControl's ContentTemplate property to equal either of the two template values at the top, rendering either a util:FormatAEditorControl or a wpftk:DecimalUpDown for the user to edit the double value for the property X on the viewmodel.
The trigger does work and the correct control type is rendered, however the databinding of the input controls themselves does not work. The controls are rendered but with no "0.0" default value for the double property, nor does updating the property in the U/I affect the viewmodel property value. I also get the following output in the Output window when I turn on tons of WPF output logging:
System.Windows.Data Information: 41 : BindingExpression path error: 'X' property not found for 'object' because data item is null. This could happen because the data provider has not produced any data yet. BindingExpression:Path=X; DataItem=null; target element is 'DecimalUpDown' (Name='FooBar'); target property is 'Value' (type 'Nullable1')
System.Windows.Data Information: 20 : BindingExpression cannot retrieve value due to missing information. BindingExpression:Path=X; DataItem=null; target element is 'DecimalUpDown' (Name='FooBar'); target property is 'Value' (type 'Nullable1')
System.Windows.Data Information: 21 : BindingExpression cannot retrieve value from null data item. This could happen when binding is detached or when binding to a Nullable type that has no value. BindingExpression:Path=X; DataItem=null; target element is 'DecimalUpDown' (Name='FooBar'); target property is 'Value' (type 'Nullable1')
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=X; DataItem=null; target element is 'DecimalUpDown' (Name='FooBar'); target property is 'Value' (type 'Nullable1')
... along with several other lines which seem to state essentially the same thing.
I can simply choose one of the two Control types to "hard code" into the xaml in place of the data trigger, and the databinding works properly, which leads me to suspect that setting the Binding property of the DataTrigger is interfering with the DataContext of the "child" Elements which are chosen by the trigger.
So then my question is, since I basically want every last thing in this entire view to have MyViewModel as its DataContext, is there any good way to have my DataTrigger choose either of the double input control types without interfering with their DataContexts? Or if I am fundamentally misunderstanding this scenario, then perhaps someone could just throw me a bone.
A gracious coworker managed to work around this situation by binding like this:
{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ContentControl}}, Path=DataContext.X}
but this seems like a fairly circuitous workaround.
Thank you!
You are using a ContentControl, so the templated content is inherently referring to its Content property. From what you written above, that property is not set, hence the binding fault.
Try to set the ContentControl as:
<DataTemplate x:Key="MyEditTemplate" DataType="common:MyViewModel">
<ContentControl x:Name="MyDoubleInputControl" Content="{Binding}" />
...
</DataTemplate>

wpf debug error output System.WIndows.Data Error 25

I have a custom styled Combobox which works fine. It is placed inside a usercontrol and bound to a data structure. I use DisplayMemberPath to show only one element in the Combobox TextBox. The ComboBox Style is taken from MSDN and used many times. So it's not displayed here.
<UserControl x:Class="wpf.projext1.MyComboBox"
x:Name="MyControl"
...
<ComboBox Style="{StaticResource ComboBoxStyle}"
Text="{Binding ElementName=MyControl, Path=Text}"
IsEditable="True"
IsTextSearchEnabled="False"
StaysOpenOnEdit="True"
ItemsSource="{Binding ElementName=MyControl, Path=MyItemsSource}"
DisplayMemberPath="Name"
</ComboBox
I get the following annoying error message populating the output window:
System.Windows.Data Error: 25 : Both 'ContentTemplate' and 'ContentTemplateSelector' are set; 'ContentTemplateSelector' will be ignored. ComboBoxItem:'ComboBoxItem' (Name='')
if i leave out the
DisplayMemberPath="Name"
... no debug output about error 25 is shown. But I definitely need DiplayMemberPath="Name"!
Do You have an idea to fix this ?
You canĀ“t set both DisplayMemberPath and ItemTemplate at the same time.
DisplayMemberPath is used to tell the ItemsControl which property to display when showing your objects. It makes no sense to set this field if you're already passing a custom ItemTemplate, since you can choose how to show the object within that ItemTemplate.
Since the default Combobox style from MSDN also sets an ItemTemplate, this is likely the cause of the error.
resolved: use the TextSearch attached property, no matter if TextSearch is enabled!
TextSearch.TextPath="Name"
Should note TextSearch.TextPath="Name" instead of DisplayMemberPath="Name".

WPF Element Binding

I have two controls within my UserControl where I bind to the exact same object using Element Binding:
AllowNext="{Binding ElementName=MainGrid, Path=DataContext.CanContinue}"
On the first control it works fine but on the second I get a binding exception:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=MainGrid'. BindingExpression:Path=DataContext.CanContinue; DataItem=null; target element is 'WizardPage' (Name='DeductionPage'); target property is 'AllowNext' (type 'Boolean')
I have also tried using RelativeSource binding on the second control:
AllowNext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid}}, Path=DataContext.CanContinue}"
But this also gives me an error.
Does anyone know what this might be?
--
Here is the simplified control:
<Grid Name="MainGrid">
<w:Wizard Name="MyWizard" w:Designer.PageIndex="1" DataContext="{Binding ElementName=MainGrid, Path=DataContext.Policy}" >
<w:WizardPage Header="Main Member" MaxHeight="600" AllowNext="{Binding ElementName=MainGrid, Path=DataContext.CanContinue}" Name="MainPage">
</w:WizardPage>
<w:WizardPage Name="DeductionPage" Header="Policy Details" AllowBack="False" AllowNext="{Binding ElementName=MainGrid, Path=DataContext.CanContinue}">
</w:WizardPage>
</w:Wizard>
</Grid>
Now as I mentioned, MainPage binds fine, whereas the DeductionPage does not bind at all and gets the supplied error. The DataContext of MainGrid is set from code behind:
public void SetDataContext(object o)
{
MainGrid.DataContext = o;
}
I bet it's the MainGrid which is the binding source is not in the logical tree of your binding target.
This is the problem absolutely with the binding element. However, you didn't give the source so You want to debug it and solve the issue.
Refer the below url and "Cannot find source for binding with reference" section where explained obviously how to debug and solve it.
http://www.codeproject.com/Articles/244107/Debugging-WPF-data-bindings

Resources