text box with multiple bindings? - wpf

Is there a way have a single textbox bind to two things. I want to have one binding set to "OneWay" and the Other set to "OneWayToSource". Basically I want to combine these two textboxes into one (and preferably with little to no code behind).
<TextBox Text="{Binding Path=ActionParameter.Value, Mode=OneWayToSource}" />
<TextBox Text="{Binding Path=StatusSignal.Value, Mode=OneWay}" />

You can use MultiBinding to set 2 or more bindings to your TextBox
Example:
<TextBox>
<TextBox.Text>
<MultiBinding StringFormat="{}{0}{1}">
<Binding Path="ActionParameter.Value" Mode="OneWayToSource" />
<Binding Path="StatusSignal.Value" Mode="OneWay" />
</MultiBinding>
</TextBox.Text>
</TextBox>
But depending on what you need to do with the 2 properties you may need to use a IMultiValueConverter to process the properties.
Example:
<TextBox>
<TextBox.Resources>
<local:TextConverter x:Key="MyConverter"/>
</TextBox.Resources>
<TextBox.Text>
<MultiBinding Converter="{StaticResource MyConverter}">
<Binding Path="ActionParameter.Value" Mode="OneWayToSource" />
<Binding Path="StatusSignal.Value" Mode="OneWay" />
</MultiBinding>
</TextBox.Text>
</TextBox>

Related

Shorthand and longhand WPF binding equivalence

I'm trying to make some XAML fragments more readable (not production code, just for me to get a better understanding of XAML inner workings).
The original code is
<CheckBox IsChecked="{Binding Path=IsSelected, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridRow}}}">
I've changed it to
<CheckBox>
<CheckBox.IsChecked>
<Binding Path="IsSelected" UpdateSourceTrigger="PropertyChanged" Mode="TwoWay">
<Binding.Source>
<RelativeSource Mode="FindAncestor" AncestorType="{x:Type DataGridRow}"/>
</Binding.Source>
</Binding>
</CheckBox.IsChecked>
</CheckBox>
The first form works ok (it properly binds the IsChecked property of the CheckBox to the IsSelected property of the container (a DataGridRow).
The second one does not work.
How should it look to work properly?
This is because you have set <Binding.Source> instead of <Binding.RelativeSource> in second case. If you set <Binding.RelativeSource> it will work too.
<CheckBox>
<CheckBox.IsChecked>
<Binding Path="IsSelected" UpdateSourceTrigger="PropertyChanged" Mode="TwoWay">
<Binding.RelativeSource>
<RelativeSource Mode="FindAncestor" AncestorType="{x:Type DataGridRow}"/>
</Binding.RelativeSource>
</Binding>
</CheckBox.IsChecked>
</CheckBox>

Programmatically retrieving MultiBindingExpression from control

How to retrieve (using code-behind) binding expression from control bounded with using MultiBinding?
Using BindingOperations.GetMultiBindingExpression method.
Example:
<TextBlock x:Name="MyTextBlock">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource myConverter}">
<Binding ElementName="lst" Path="Items.Count" />
<Binding ElementName="txtName" Path="Text" />
<Binding ElementName="txtAge" Path="Text" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
Accesing it from code:
TextBlock textblock = FindName("MyTextBlock") as TextBlock;
var bindingExpression = BindingOperations.GetMultiBindingExpression(textblock, TextBlock.TextProperty);
Hope this helps

How do I set the default text of a textbox with a Binding of RelativeSource Self

On the initial page load, I am setting it up so that the form is ready to enter a new record. For some custom data validators, I set the binding to itself. My question is how can I set the default text to something?
<TextBox>
<TextBox.Text>
<Binding RelativeSource="{RelativeSource Self}"
Path="Text"
UpdateSourceTrigger="LostFocus" >
<Binding.ValidationRules>
<validators:MyCustomValidators />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Add an event handler on the Loaded or Initialized event, and set the Text there.
<TextBox Loaded="TextBox_Loaded_1">
<TextBox.Text>
<Binding RelativeSource="{RelativeSource Self}"
Path="Text"
UpdateSourceTrigger="LostFocus" >
<Binding.ValidationRules>
<validators:MyCustomValidators />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
And in the code behind :
private void TextBox_Loaded_1(object sender, RoutedEventArgs e)
{
((TextBox)sender).Text = "Default text";
}
EDIT:
XAML only solution :
<TextBox>
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Text" Value="Default text" />
</Style>
</TextBox.Style>
<TextBox.Text>
<Binding RelativeSource="{RelativeSource Self}"
Path="Text"
UpdateSourceTrigger="LostFocus" >
<Binding.ValidationRules>
<validators:MyCustomValidators />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>

WPF MultiBinding same converter with different binding path

I have ten UI Controls of the same type in a UI and all will be using same multi binding converter.
The problem is I can not create a common style for multibinding which I can apply to all UI controls to avoid duplicate code, as each control will use a different binding property to pass as a Binding to converter.
Is there any way in WPF we can avoid duplicate code for this scenario?
You can extend MarkupExtension, which allows you to define a custom Converter wrapper and then just call it with the 2 Paths.
Edit: in your case it's probably best to inherit directly from MultiBinding and set sensible defaults in the constructor.
I assume you have something like this:
<Button>
<Button.Content>
<MultiBinding Converter="{StaticResource conv}">
<Binding Path="COMMON" />
<Binding Path="SPECIFIC1" />
</MultiBinding>
</Button.Content>
</Button>
<Button>
<Button.Content>
<MultiBinding Converter="{StaticResource conv}">
<Binding Path="COMMON" />
<Binding Path="SPECIFIC2" />
</MultiBinding>
</Button.Content>
</Button>
<Button>
<Button.Content>
<MultiBinding Converter="{StaticResource conv}">
<Binding Path="COMMON" />
<Binding Path="SPECIFIC3" />
</MultiBinding>
</Button.Content>
</Button>
and so on...
this looks ugly, I agree.
I am not aware of any alternatives, however by thinking a little, you could create(imo) a little better solution:
just create new CommonMultiBindings.xaml;
which includes:
<MultiBinding Converter="{StaticResource conv}">
</MultiBinding>
and voila, done. Now just reference it as CommonMultiBindings object and use it as:
<Button.Content>
<CommonMultiBindings>
<!--Actual bindings here-->
</CommonMultiBindings>
</Button.Content>
you can take it further by factoring "" into the CommonMultiBindings and adding new property(UserBindings) which will be used to synchronize between Bindings property.
Ideally, you would want to create a custom MultiBinding class which has style property. Then you could do something like this + combined with "custom" default bindings which are automatically added to "Bindings" collection
<Grid.Resources>
<Style TargetType="MultiBinding">
<Setter Property="Converter" Value="{StaticResource conv}" />
</Style>
</Grid.Resources>

How can I pass a constant value for 1 binding in multi-binding?

I have a multi-binding like
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource myConverter}">
<Binding Path="myFirst.Value" />
<Binding Path="mySecond.Value" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
And I want to pass a fixed value e.g. "123" to one of the two bindings above. How can I do that using XAML?
If your value is simply a string, you can specify it as a constant in the Source property of a binding. If it is any other primitive data type, you need to define a static resource and reference this.
Define the sys namespace in the root of the XAML to point to System in mscorlib, and the following should work:
<TextBlock>
<TextBlock.Resources>
<sys:Int32 x:Key="fixedValue">123</sys:Int32>
</TextBlock.Resources>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource myConverter}">
<Binding Path="myFirst.Value" />
<Binding Source="{StaticResource fixedValue}" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
Or, combining the two answers above:
Define the namespace sys at the document head:
xmlns:sys="clr-namespace:System;assembly=mscorlib"
and then:
<MultiBinding Converter="{StaticResource ScalingConverter}">
<Binding>
<Binding.Source>
<sys:Double>0.5</sys:Double>
</Binding.Source>
</Binding>
<Binding ElementName="TC" Path="ActualWidth" />
</MultiBinding>
Which provides the right type without the Resources kludge.
I don't quite follow the question but there are two options:
Put the line <Binding Source="123" /> in your multibinding will pass 123 as a bound value to your converter.
Put ConverterParameter="123" in your MultiBinding:
<MultiBinding Converter="{StaticResource conv}" ConverterParameter="123">
I'm not saying this an especially good answer but here is another approach:
<Binding Path="DoesNotExist" FallbackValue="123" />

Resources