Wpf Multibinding in a template or style - wpf

I have a class with many properties (not in a list) which must be switchable in view. The converter itself works fine using multibinding.
<TextBox Grid.Row="1" Grid.Column="5">
<TextBox.Text>
<MultiBinding Converter="{StaticResource IntValueConvertor}">
<Binding Path="property1" />
<Binding Path="IntegerDisplay" />
</MultiBinding>
</TextBox.Text>
</TextBox>
In the code, "IntegerDisplay" is a property which is defined in my VM.
Property1 is one of the many properties which must be viewed differently (depending on IntegerDisplay).
What I want to avoid is the need of adding the whole multibinding convertor to each textbox.
Something in this style:
<TextBox
Grid.Row="1"
Grid.Column="4"
Text="{Binding Path=Property1, Converter={StaticResource IntValueConvertor}}" />
I know this code does not work!
I tried using a style, but I could not get to the value of property1.
Is it the best way to use a style or is a datatemplate better?
Kind regards

I recommend sticking with a style and here's a basic start to doing so.
<!--This will go in your resources-->
<Style x:Name="TextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="Text" Value="{Binding Path=Property1, Converter={StaticResource IntValueConverter}, ConverterParameter=IntegerDisplay}"/>
</Style>
<!--This will go in your Display-->
<TextBox Style="{StaticResource TextBoxStyle}"/>

Related

How to set foreground on part of multi binding when concatenating two properties in WPF XAML?

I am displaying two property values using multi-binding in WPF XAML.
I would want to set first/second value by different color.
<DataGridTemplateColumn Header="ConcatCol"
Width="60">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock TextAlignment="Right">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text">
<Setter.Value>
<MultiBinding StringFormat="{} {0:C1} / {1:C1}">
<Binding Path="FirstProp" />
<Binding Path="SecondProp" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
So basically you can see that I am displaying two property values in a single cell but separating them by "/". I am also specifying the string format for each of the property.
Now my question is How can I display the value before "/" in Green color and the latter in Red color?
You could actually use Textblock with multiple runs:
<TextBlock TextAlignment="Right">
<Run Text="{Binding FirstProp}" Foreground="Green"/> / <Run Text="{Binding SecondProp}" Foreground="Red"/>
</TextBlock>

How to make this ItemsControl into StaticResource

I have an ItemsControl which renders some Point into apropriately positioned ellipses similar to small dots in a 2D map.
Since my screen contains drawings where the same ItemsControl must be displayed many times, I tried to make it into StaticResource, but two things were wrong:
When I try to instantiate the same resource multiple times, the second times give an error. I have read in other answer that this is because StaticResources are, well, static, and you cannot have two instances of a static Control in the Visual Tree at the same time;
Whe I instantiate only one, the Element Binding to PainelMarc.ActualHeight (for example) does not work;
So my goal is to DRY up my XAML by converting this ItemsControl, or parts of it, into reusable resources.
<ItemsControl x:Name="PainelMarc"
ItemsSource="{Binding ExameAtivo.ListaMarcadores, Mode=TwoWay}" Grid.Row="1" Grid.RowSpan="3">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="{x:Type FrameworkElement}">
<Setter Property="RenderTransform">
<Setter.Value>
<MultiBinding Converter="{StaticResource MarcadoresConverter}">
<Binding />
<Binding ElementName="PainelMarc" Path="ActualHeight"/>
<Binding ElementName="PainelMarc" Path="ActualWidth"/>
<Binding Source="{StaticResource LimitesFrontal}" Path="Geometry.Bounds"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="Double">
<Canvas>
<Ellipse x:Name="elipsemouseover"
Width="10"
Height="{Binding Width, RelativeSource={RelativeSource Self}}"
Fill="White" Stroke="Black" StrokeThickness="1" RenderTransformOrigin="0.5,0.5">
<Ellipse.RenderTransform>
<TranslateTransform X="-5" Y="-5"/>
</Ellipse.RenderTransform>
</Ellipse>
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Set x:Shared="False" on your resource so that everytime resource lookup is done via StaticResource, it returns new instance of resource.
Default value is true for all resources. Hence, you are getting the error regarding addition of same control in different Visual Trees.
From MSDN link of x:Shared:
When set to false, modifies WPF resource-retrieval behavior so that
requests for the attributed resource create a new instance for each
request instead of sharing the same instance for all requests.
And for second question that ElementName binding not working. That should work fine, I see no issue in that code. Your converter should fire successfully.
Just in case it doesn't, you can try with RelativeSource in place of ElementName to get ItemsControl:
<Binding RelativeSource="{RelativeSource Mode=FindAncestor,
AncestorType=ItemsControl}" Path="ActualHeight"/>
<Binding RelativeSource="{RelativeSource Mode=FindAncestor,
AncestorType=ItemsControl}" Path="ActualWidth"/>

TextBox Text Formatting From Style

I have a MainWindow.XAML
TextBox is added to it
TextBox text binding is done
When I add StringFormat inside binding (in MainWindow.XAML) it works
When I add StringFormat inside Style, it's not working
below is the code from style and MainWindow.xaml
<TextBox Grid.Row="1" Grid.Column="4" Style="{StaticResource TextBoxStyle}" Text="{Binding CustomerAmount,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" HorizontalAlignment="Stretch" Margin="10,0,0,0"/>
<Style x:Key="TextBoxStyle" TargetType="{x:Type TextBox}" >
<Setter Property="Text" Value="{Binding Text, RelativeSource={RelativeSource Self},StringFormat='#,###,###,##0.00;(#,###,###,##0.00)'}"></Setter>
</Style>
Well you've basically applied two Text binding's now, one in MainWindow and one in Style.
The Text property set in MainWindow.xaml on the control has precedence over the one you're setting in Style, so the StringFormat you set via Style is actually never applied cos that entire Style.Setter is ignored.
A very rough way to make this work and prove the above statement is try switching your xaml to the following,
<TextBox Grid.Row="1" Grid.Column="4" Style="{StaticResource TextBoxStyle}" Tag="{Binding CustomerAmount,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" HorizontalAlignment="Stretch" Margin="10,0,0,0"/>
and Style:
<Style x:Key="TextBoxStyle"
TargetType="{x:Type TextBox}">
<Setter Property="Text"
Value="{Binding Tag,
RelativeSource={RelativeSource Self},
StringFormat='#,###,###,##0.00;(#,###,###,##0.00)',
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
</Style>
This will work cos you now have Tag binding in MainWindow and Text in Style. You can switch to a custom Attached property or DP to get the same behavior

Bind a property to an existing Binding

I have an interface with multiple buttons. I'd like to enable or disable these buttons according to a 'complex' condition. I declared this MultiBinding as an application resource in order to avoid code repetition:
<MultiBinding x:Key="MyMultiBinding" Converter="{StaticResource ResourceKey=MyConverter}">
<Binding Path="IsConnected" />
<Binding Path="IsOpened" />
</MultiBinding>
Here is how I declare my button:
<Button Name="MyButton" Content="Click me!" IsEnabled="{StaticResource ResourceKey=MyMultiBinding}" />
At runtime, I get the following error: "Set property IsEnabled threw an exception... MultiBinding is not a valid value for property IsEnabled".
I can't figure why this is not working. Could you please point me to the right way to do this? Thank you.
You can't set the boolean IsEnabled property to a value of type MultiBinding. That is what is happening.
As #Viv pointed out, you could declare a Style to do the heavy lifting:
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Setter Property="IsEnabled">
<Setter.Value>
<MultiBinding Converter="{StaticResource ResourceKey=MyConverter}">
<Binding Path="IsConnected" />
<Binding Path="IsOpened" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
<Button Name="MyButton" Content="Click me!" Style="{StaticResource ButtonStyle}" />
This works well if the Button DataContext has those properties. It works especially well if they each have a different DataContext they are bound to, enabling them for different reasons.
If they are all bound to the same DataContext, or the properties are on a different object, you could use the Freezable Trick to provide a value that your buttons would bind to:
<BindingProxy x:Key="isEnabled">
<BindingProxy.Data>
<MultiBinding Converter="{StaticResource ResourceKey=MyConverter}">
<Binding Path="IsConnected" />
<Binding Path="IsOpened" />
</MultiBinding>
</BindingProxy.Data>
</BindingProxy>
<Button Name="MyButton" Content="Click me!" IsEnabled="{Binding Data, Source={StaticResource isEnabled}}" />
I don't know if this is the best solution, but wrapping the MultiBinding into a style, as Viv said, did the trick. Here is the code of the Style :
<Style x:Key="MyStyle" TargetType="Button">
<Style.Setters>
<Setter Property="IsEnabled">
<Setter.Value>
<MultiBinding Converter="{StaticResource ResourceKey=MyConverter}">
<Binding Path="IsConnected" />
<Binding Path="IsDataAccessOpened" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
And the code of the button :
<Button Name="MyButton" Content="Click me!" Style={StaticResource ResourceKey=MyStyle} />

WPF XamComboBox DisplayMemberPath with concatenated values

I have the following code -
<igEditors:XamComboEditor ItemsSource="{Binding Instances}"
Margin="5,2,5,2" Width="175" HorizontalAlignment="Left"
SelectedItem="{Binding SelectedInstance,Mode=TwoWay,NotifyOnValidationError=True,ValidatesOnDataErrors=True,ValidatesOnExceptions=True}"
>
<igEditors:XamComboEditor.ComboBoxStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} ({1})">
<Binding Path="Name" />
<Binding Path="Id" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</igEditors:XamComboEditor.ComboBoxStyle>
</igEditors:XamComboEditor>
When I set the SelectedInstance from my viewmodel, the combobox is displaying the type of the object. If I then make a selection, it displays correctly, but I click out of the combobox, losing focus, it reverts back to the object type. If I set the DisplayMemberPath manually to just Name, it works correctly, but I really need it to be a concatenated value for the displaymemberpath.
Can anyone help?
Thanks
The answer to this question was to use the ValueToDisplayTextConverter along with a custom converter. More details can be found here -
http://www.infragistics.com/community/forums/p/77378/390782.aspx

Resources