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
Related
Unable to remove whitespace from StringFormat.
If no 'Type' data the following whitespace doesn't fallback.
ReleaseDate, space, space, dot, space, space, Type, space (some reason it doesn't remove this space), Color
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0:yyyy} · {1} {2}" >
<Binding Path="ReleaseDate" FallbackValue="{x:Null}"/>
<Binding Path="Type" FallbackValue="{x:Null}"/>
<Binding Path="Color" FallbackValue="{x:Null}"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
You may probably replace the MultiBinding and its StringFormat by a DataTrigger:
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text">
<Setter.Value>
<MultiBinding StringFormat="{}{0:yyyy} · {1} {2}" >
<Binding Path="ReleaseDate" FallbackValue="{x:Null}"/>
<Binding Path="Type"/>
<Binding Path="Color" FallbackValue="{x:Null}"/>
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Type}" Value="{x:Null}">
<Setter Property="Text">
<Setter.Value>
<MultiBinding StringFormat="{}{0:yyyy} · {1}" >
<Binding Path="ReleaseDate" FallbackValue="{x:Null}"/>
<Binding Path="Color" FallbackValue="{x:Null}"/>
</MultiBinding>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
While the approach with DataTrigger works, it is very verbose. I would make it a two-step process: bind Type separately with a StringFormat which has a space, then bind everything together
<TextBlock Name="Title"
local:Attached.SomeString="{Binding Type,
StringFormat='\{0} ',
TargetNullValue=''}">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0:yyyy} · {1}{2}">
<Binding Path="Login" />
<Binding Path="(local:Attached.SomeString)"
RelativeSource="{RelativeSource Self}" />
<Binding Path="Name" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
If Type is not null then SomeString binding uses string format, and returns Type + space at the end. If Type is null, then binding return empty string.
SomeString is a reusable attached dependency property without special meaning. It declared as
public class Attached
{
public static readonly DependencyProperty SomeStringProperty =
DependencyProperty.RegisterAttached("SomeString", typeof (string), typeof (Attached));
public static void SetSomeString(UIElement element, string value)
{
element.SetValue(SomeStringProperty, value);
}
public static string GetSomeString(UIElement element)
{
return (string)element.GetValue(SomeStringProperty);
}
}
TextBlock has Tag property which can be used to store (or bind) some data, but Tag is of type object, and doesn't use StringFormat from binding. So I couldn't use Tag for my purpose here, and had to create another property, which has string type. (note also special syntax to bind attached property)
I am using MultiBinding and a MultiValueConverter on a Grid in order to set the MaxHeight of each Grid.Row according to the ActualHeight of all Grid.Rows.
<RowDefinition x:Name="grdRow1" Height="Auto" >
<RowDefinition.MaxHeight>
<MultiBinding Converter="{StaticResource CalculateMaxHeightConverter}" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
<Binding Path="ActualHeight" ElementName="grdRow1" />
<Binding Path="ActualHeight" ElementName="grdRow2" />
<Binding Path="ActualHeight" ElementName="grdRow3" />
<Binding Path="ActualHeight" ElementName="grdRow4" />
<Binding Path="ActualHeight" ElementName="grdRow5" />
</MultiBinding>
</RowDefinition.MaxHeight>
</RowDefinition>
MultiConverter:
public class AvailableHeightConverter : IMultiValueConverter
{
public double PanelHeight { get; set; }
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null)
return Binding.DoNothing;
double currentHeight = 0d;
double availableHeight = 0d;
foreach (object value in values)
{
currentHeight += (double)value;
}
availableHeight = PanelHeight - currentHeight;
if (availableHeight < 0)
return Binding.DoNothing;
return availableHeight;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
UserControl.Resources:
<cvc:AvailableHeightConverter x:Key="CalculateMaxHeightConverter" PanelHeight="1080" />
My problem (a dummy one) is that i cannot figure out how to UpdateSourceTrigger whenever the ActualHeight of a Grid.Row is being changed.
There are two problems with your xaml (as far as I can see without trying it myself)
ActualHeight has no setter, so you need to use Mode="OneWay"
Binding the MaxHeight of grdRow1 to all rows ActualHeight including grdRow1 itself could produce an endless loop of resizing
Try the following:
<RowDefinition x:Name="grdRow1" Height="Auto" >
<RowDefinition.MaxHeight>
<MultiBinding Converter="{StaticResource CalculateMaxHeightConverter}" Mode="OneWay" UpdateSourceTrigger="PropertyChanged">
<Binding Path="ActualHeight" ElementName="grdRow2" Mode="OneWay" />
<Binding Path="ActualHeight" ElementName="grdRow3" Mode="OneWay" />
<Binding Path="ActualHeight" ElementName="grdRow4" Mode="OneWay" />
<Binding Path="ActualHeight" ElementName="grdRow5" Mode="OneWay" />
</MultiBinding>
</RowDefinition.MaxHeight>
</RowDefinition>
OK. After experimenting with various senarios i ended up that Binding row's ActualHeight doesn't notify MultiBinding for changes. Also what #christoph noticed (2.) was very helpful. So i ended up binding TextBox's ActualWidth as shown below:
for Row 1
<RowDefinition x:Name="grdRow1" Height="Auto" >
<RowDefinition.MaxHeight>
<MultiBinding Converter="{StaticResource CalculateMaxHeightConverter}">
<Binding Path="ActualHeight" ElementName="txtBox2" Mode="OneWay" />
<Binding Path="ActualHeight" ElementName="txtBox3" Mode="OneWay" />
<Binding Path="ActualHeight" ElementName="txtBox4" Mode="OneWay" />
<Binding Path="ActualHeight" ElementName="txtBox5" Mode="OneWay" />
</MultiBinding>
</RowDefinition.MaxHeight>
</RowDefinition>
for Row 2
<RowDefinition x:Name="grdRow2" Height="Auto" >
<RowDefinition.MaxHeight>
<MultiBinding Converter="{StaticResource CalculateMaxHeightConverter}">
<Binding Path="ActualHeight" ElementName="txtBox1" Mode="OneWay" />
<Binding Path="ActualHeight" ElementName="txtBox3" Mode="OneWay" />
<Binding Path="ActualHeight" ElementName="txtBox4" Mode="OneWay" />
<Binding Path="ActualHeight" ElementName="txtBox5" Mode="OneWay" />
</MultiBinding>
</RowDefinition.MaxHeight>
</RowDefinition>
and subtract the Height of one row from the PanelHeight (of AvailableHeightConverter).
<cvc:AvailableHeightConverter x:Key="CalculateMaxHeightConverter" PanelHeight="1028" />
(Used to be 1080 (-52 MinHeight of a Row)
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>
I am trying to create a style for comboxitem. I want to pass the current comboboxitem to converter. Style is like
<Style x:Key="MyVisibilityStyle" TargetType="{x:Type ComboBoxItem}">
<Setter Property="Visibility">
<Setter.Value>
<MultiBinding Converter="{StaticResource VisibiltyMultiValueConverter}">
<Binding Path="."/>
<Binding Path="SelectedItem"
ElementName="ABCComboBox"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
Problem is the "." is passing the object of MainWindow not the comboboxitem.
Through <Binding Path="."> youre passing the object which the ComboBoxItem holds, but with <Binding RelativeSource="{RelativeSource Self}"/> you can pass the control itself.
What you also could do is passing the whole ComboBox and its selected index/item:
and in your converter you could get your ComboBoxItem like so:
ComboBoxItem cbi = (ComboBoxItem)(cb.ItemContainerGenerator.ContainerFromIndex(selectedindex));
or
ComboBoxItem cbi = (ComboBoxItem)(cb.ItemContainerGenerator.ContainerFromItem(selecteditem));
You can get the selected item of the combobox by using FindAncestor:
<Binding Path="SelectedItem" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ComboBox}"/>
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" />