Replace a text-converter dynamically - wpf

I have a textblock of a user-control which uses a converter to display figures. This converter gets loaded in a ResourceDictionary at the start of the application.
Now I'd like to exchange this converter with another one, to display a different format, depending on a parameter in the app-settings. Unfortunatley using just a trigger doesn't work. Is it possible to load a converter dynamically into the user-control, and put a reference on it from a textblock?
Edit: Here's my trigger attempt:
<TextBlock>
<TextBlock.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type mycontrol}, AncestorLevel=1}, Path=mode}" Value="0">
<Setter Property="TextBlock.Text" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type cg:Fader}, AncestorLevel=1}, Path=Figure, Converter={StaticResource ConverterA}}"/>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type mycontrol}, AncestorLevel=1}, Path=mode}" Value="1">
<Setter Property="TextBlock.Text" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type cg:Fader}, AncestorLevel=1}, Path=Figure, Converter={StaticResource ConverterB}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>

The reason why triggers are not working in your example is in bindings. Overall Style + DataTriggers are perfectly suitable for dynamic template selection.

Related

How to get the WPF column binding field from DataGridColumnHeader style

I am doing custom sorting for WPF datagrid (as I use pagination so I can not use default sorting), how can I get name of the field that column binding to? Below is my current code inside DataGrid.Resources
<Style TargetType="DataGridColumnHeader">
<Setter Property="Command" Value="{Binding Path=DataContext.SortCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
<Setter Property="CommandParameter" Value="{Binding Path=DisplayIndex, RelativeSource={RelativeSource Mode=Self}}"/>
</Style>
I try to get the Column but it return null?
I figured it out, I give the style a key
<DataGrid.Resources>
<Style x:Key="SortableColumnHeader" TargetType="DataGridColumnHeader">
<Setter Property="Command" Value="{Binding Path=DataContext.SortCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
<Setter Property="CommandParameter" Value="{Binding Path=Column.Binding.Path.Path, RelativeSource={RelativeSource Mode=Self}}"/>
</Style>
</DataGrid.Resources>
and apply it in column's HeaderStyle and it worked
<DataGridTextColumn Binding="{Binding Name}" Header="Column Name" MinWidth="150" HeaderStyle="{StaticResource SortableColumnHeader}"/>

How to bind a DataTrigger to a non-bound attribute?

This is not in a template, it is a <Label> in the body of my XAML document. Notice that the Content of the label is set to 'PENDING'. This is monitoring a server connection and at various times the code-behind might change the value of the content to CONNECTED or ERROR. When that happens, I would like for the color of the text to change. I thought this would do it, but it doesn't... all I get is black text.
<Label x:Name="lbl_Connected" Content="PENDING" FontWeight="Bold" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center">
<Label.Style>
<Style TargetType="Label">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource self}, Path=Content.Value}" Value="CONNECTED">
<Setter Property="Label.Foreground" Value="Green"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource self}, Path=Content.Value}" Value="PENDING">
<Setter Property="Label.Foreground" Value="Yellow"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource self}, Path=Content.Value}" Value="ERROR">
<Setter Property="Label.Foreground" Value="Red"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
Can someone tell me how I should be doing this?
Just remove the ".Value" part from the Binding's Path, i.e.:
<DataTrigger Binding="{Binding RelativeSource={RelativeSource self}, Path=Content}" Value="CONNECTED">
<Setter Property="Label.Foreground" Value="Green"></Setter>
</DataTrigger>
Anyway if I were you, I would use a Binding in order to set the Label content and a converter to handle the Foreground color.

ContextMenu not updating parent change

I have following, straightforward example
<ContextMenu x:Shared="false">
<MenuItem Header="UsuĊ„" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Parent}"/>
<MenuItem CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Parent}">
<MenuItem.Style>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="On"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Parent.IsEnabled}" Value="False">
<Setter Property="Header" Value="Off"/>
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
</MenuItem>
</ContextMenu>
For the first time when it is created it sets Header's value to On, but in time property IsEnabled is set to false and no change is reflected. Any help would be appreciated.
In this case it seems like it's because the element's Parent didn't change. Try using a different RelativeSource (example untested):
<DataTrigger Binding="{Binding IsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1}}"
Value="False">

WPF Styling and Templating over many buttons?

I can't seem to get the correct combination to get the desired effect:
Current XAML:
<Button Content="Foo" prism:Click.Command="{Binding FooCommand}"
Visibility="{Binding IsEnabled, RelativeSource={RelativeSource Self}, Converter={ncon:VisibilityBooleanConverter}}" />
<Button Content="Bar" prism:Click.Command="{Binding BarCommand}"
Visibility="{Binding IsEnabled, RelativeSource={RelativeSource Self}, Converter={ncon:VisibilityBooleanConverter}}" />
I want to extract out the Visibility="{Binding IsEnabled, RelativeSource={RelativeSource Self}, Converter={ncon:VisibilityBooleanConverter}}" as a style to apply over all the Buttons (within this UserControl resources). I can't seem to get the correct combination going here to make that happen.
Basically, what it does is instead of just disabling the button based on the ICommand.CanExecute it takes that DependencyProperty and binds it to the Visibility of the Button using a boolean-visiblity converter so the button is not only disabled, but also collapsed.
Style would look like this i suppose:
<Style TargetType="{x:Type Button}">
<Setter Property="Visibility"
Value="{Binding IsEnabled, RelativeSource={RelativeSource Self}, Converter={ncon:VisibilityBooleanConverter}}"/>
</Style>
Doesn't that work?
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}, Converter={ncon:VisibilityBooleanConverter}}" Value="Visible">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>

Automatically focusing parts of a ListBoxItem on selection

I have a ListBox which is populated from a collection of ViewModels, which uses in place editing, which I do by having a couple of styles which I can apply to parts of the DataTemplate which make them visible/collapsed as required. These look something like:
<Style
x:Key="UnselectedVisibleStyle"
TargetType="{x:Type FrameworkElement}">
<Setter
Property="Visibility"
Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}, Converter={StaticResource boolToVis}, ConverterParameter=False}" />
</Style>
<Style
x:Key="SelectedVisibleStyle"
TargetType="{x:Type FrameworkElement}">
<Setter
Property="Visibility"
Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}, Converter={StaticResource boolToVis}, ConverterParameter=True}" />
</Style>
With my ListBox having it's ItemTemplate given by something like:
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock
Text="{Binding Name}"
Style="{StaticResource UnselectedVisibleStyle}" />
<TextBox
x:Name="textBox"
Text="{Binding Name}"
Style="{StaticResource SelectedVisibleStyle}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
This works fine, but what I want ideally is to have the TextBox automatically selected when a user clicks the item, ideally in a nice generic way I can use throughout my project, and without too much messing around in my codebehind.
Thanks,
DM.
The following change to your selected Style seemed to work for me:
<Style x:Key="SelectedVisibleStyle" TargetType="{x:Type FrameworkElement}">
<Setter Property="Visibility" Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}, Converter={StaticResource boolToVis}, ConverterParameter=True}"/>
<Style.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}"/>
</Trigger>
</Style.Triggers>
</Style>

Resources