XAML: x:Array of static resources - wpf

I have a number of BitmapImages declared in my ResourceDictionary:
<BitmapImage x:Key="LockImageSource" UriSource="img/lock.png" />
<BitmapImage x:Key="UnlockImageSource" UriSource="img/unlock.png" />
...
My converter takes an array parameter of two ImageSource elements to choose one of images to show depending on passed value:
<Image Source="{Binding Path=IsLocked,
Converter={StaticResource AlteringConverter},
ConverterParameter={StaticResource LockUnlockImageSourcePair}}"
Width="16" Height="16" />
How should LockUnlockImageSourcePair resource look like?
<x:Array x:Key="LockUnlockImageSourcePair" Type="{x:Type BitmapImage}">
<??? />
<??? />
</x:Array>

Instead of a Binding with a Converter and complicated ConverterParameter, you could use this simple Style with a DataTrigger:
<Image Width="16" Height="16">
<Image.Style>
<Style TargetType="Image">
<Setter Property="Source" Value="{StaticResource UnlockImageSource}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsLocked}" Value="True">
<Setter Property="Source" Value="{StaticResource LockImageSource}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
If you want to reuse the Style for multiple Image controls, you may declare it as resource:
<Style x:Key="LockUnlockImageStyle" TargetType="Image">
<Setter Property="Width" Value="16"/>
<Setter Property="Height" Value="16"/>
<Setter Property="Source" Value="{StaticResource UnlockImageSource}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsLocked}" Value="True">
<Setter Property="Source" Value="{StaticResource LockImageSource}"/>
</DataTrigger>
</Style.Triggers>
</Style>
...
<Image Style="{StaticResource LockUnlockImageStyle}"/>

Related

Toggle button - change icon on click

I have an app in WPF. I am using entypo icons and i decalred one as a resource:
<Grid.Resources>
<iconPacks:Entypo x:Key="PlayIcon" Width="50" Height="30" Kind="ControllerPlay"></iconPacks:Entypo>
</Grid.Resources>
Let's say I have two icons like this ( play/pause icon) and I want to change between them when the user clicks on ToggleButton. I came up with something like this, but unfortunately, it's not working:
<ToggleButton>
<Image>
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton}, Path=IsChecked}"
Value="true">
<Setter Property="Source"
Value="{StaticResource PauseIcon}" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton}, Path=IsChecked}"
Value="false">
<Setter Property="Source"
Value="{StaticResource PlayIcon}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</ToggleButton>
Could anyone tell me if I can achieve it like this (with slight modifications) or point me into right direction?
You can't set the Source of an Image to a PackIconEntypo. Set the Content property of the ToggleButton instead:
<ToggleButton>
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Content" Value="{StaticResource PlayIcon}" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter Property="Content" Value="{StaticResource PauseIcon}" />
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>

WPF DataGrid Header contents from style only display once per trigger

An odd problem is occurring with my WPF DataGrid Headers' contents. The XAML for the style looks like this:
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding Type, Converter={StaticResource EnumToStringConverter}}" Value="Default">
<Setter Property="Background" Value="White"/>
</DataTrigger>
<DataTrigger Binding="{Binding Type, Converter={StaticResource EnumToStringConverter}}" Value="Error">
<Setter Property="Background" Value="#F2DEDE"/>
<Setter Property="Header">
<Setter.Value>
<Image Source="{StaticResource IconError}" Width="16" Height="16"></Image>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Type, Converter={StaticResource EnumToStringConverter}}" Value="Warning">
<Setter Property="Background" Value="#FCF8E3"/>
<Setter Property="Header">
<Setter.Value>
<Image Source="{StaticResource IconWarning}" Width="16" Height="16"></Image>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
Error and warning icons should be on every row of those types, with standard rows being blank. However, the output looks like so:
The icons only seem to appear once per trigger, though the trigger is evidently firing as the row colouring is correct.
Snoop shows that the image is simply not inserted into each of the other Headers.
This still happens when replacing the resource image with a path, and when replacing the images entirely with TextBlock elements.
What's going on here? Is there a better way I'm missing?
Edit: For anyone finding this after the fact, the StaticResource icons are BitmapImage instances, not paths.
A UIElement such as an Image can only appear once in the visual tree.
You could define the images and non-shared resources:
<DataGrid>
<DataGrid.Resources>
<Image x:Key="errorImg" x:Shared="False" Source="{StaticResource IconError}" Width="16" Height="16"></Image>
<Image x:Key="warnImg" x:Shared="False" Source="{StaticResource IconWarning}" Width="16" Height="16"></Image>
</DataGrid.Resources>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding Type, Converter={StaticResource EnumToStringConverter}}" Value="Default">
<Setter Property="Background" Value="White"/>
</DataTrigger>
<DataTrigger Binding="{Binding Type, Converter={StaticResource EnumToStringConverter}}" Value="Error">
<Setter Property="Background" Value="#F2DEDE"/>
<Setter Property="Header" Value="{StaticResource errorImg}" />
</DataTrigger>
<DataTrigger Binding="{Binding Type, Converter={StaticResource EnumToStringConverter}}" Value="Warning">
<Setter Property="Background" Value="#FCF8E3"/>
<Setter Property="Header" Value="{StaticResource warnImg}" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
</DataGrid>
In addition to the chosen answer here, I managed to get this working by replacing the direct set of the Header value with a template instead.
<DataTrigger Binding="{Binding Type, Converter={StaticResource EnumToStringConverter}}" Value="Error">
<Setter Property="Background" Value="#F2DEDE"/>
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{StaticResource IconError}" Width="16" Height="16"></Image>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>

DataTriger Style Setter for Image Element

I have an image element that is populated via databinding - if the binding returns a path, the image is drawn. If not (path comes in an an empty string), we get no image.
<Image Source="{Binding Path=.Screenshot, Mode=OneWay}" Stretch="Fill" Margin="5,5,5,5" />
That works well, except that the margin is applied to the layout no matter what (which looks bad for empty images). I figured I'd do a DataTrigger instead that only applies the margin is the path is not empty, but:
Image doesn't seem to have a Style (actually it does, ignore this part)
I don't know how to test for "string is not empty".
What I'd like to do is something like the pseudo-XAML below. Is that possible in XAML?
<Image Source="{Binding Path=.Screenshot, Mode=OneWay}" Stretch="Fill" >
<Image.Style>
<Style TargetType="Image">
<Setter Property="Margin" Value="0,0,0,0" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=.Screenshot}" Value="!NullOrEmpty">
<Setter Property="Margin" Value="5,5,5,5" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
Should I be maybe using an entirely different approach for this?
Do it the other way round, by having a DataTrigger for the values null and "":
<Style TargetType="Image">
<Setter Property="Margin" Value="5,5,5,5" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Screenshot}" Value="{x:Null}">
<Setter Property="Margin" Value="0,0,0,0" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Screenshot}" Value="">
<Setter Property="Margin" Value="0,0,0,0" />
</DataTrigger>
</Style.Triggers>
</Style>
You may probably also just have a Trigger on the Images's Source property:
<Style TargetType="Image">
<Setter Property="Margin" Value="5,5,5,5" />
<Style.Triggers>
<Trigger Property="Source" Value="{x:Null}">
<Setter Property="Margin" Value="0,0,0,0" />
</Trigger>
</Style.Triggers>
</Style>

Style Trigger for different images and border background

I Want to use different Border Background and Different Images (each image must use different background color)
how i change use StyleTrigger to do it ? (Now it just show red border for all images)
<DataTemplate>
<Border BorderThickness="1" Width="18" Height="18" CornerRadius="2" BorderBrush="Red" Background="Red">
<Image Width="16" Height="16">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source" Value="{x:Null}" />
<Style.Triggers>
<DataTrigger Binding="{Binding RowData.DataContext.my}" Value="High">
<Setter Property="Source" Value="/project;component/Images/High.png" />
</DataTrigger>
<DataTrigger Binding="{Binding RowData.DataContext.my}" Value="Medium">
<Setter Property="Source" Value="/project;component/Images/Medium.png" />
</DataTrigger>
<DataTrigger Binding="{Binding RowData.DataContext.my}" Value="Low">
<Setter Property="Source" Value="/project;component/Images/Low.png" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Border>
</DataTemplate>
Thank you.
Assuming that your Binding is correct, you just need to add a similar Style to the Border to update the Background property and remove the Background value from the Border itself:
<DataTemplate>
<Border BorderThickness="1" Width="18" Height="18" CornerRadius="2" BorderBrush="Red">
<Border.Style>
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<DataTrigger Binding="{Binding RowData.DataContext.my}" Value="High">
<Setter Property="Background" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding RowData.DataContext.my}" Value="Medium">
<Setter Property="Background" Value="Blue" />
</DataTrigger>
<DataTrigger Binding="{Binding RowData.DataContext.my}" Value="Low">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<Image Width="16" Height="16">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source" Value="{x:Null}" />
<Style.Triggers>
<DataTrigger Binding="{Binding RowData.DataContext.my}" Value="High">
<Setter Property="Source" Value="/project;component/Images/High.png" />
</DataTrigger>
<DataTrigger Binding="{Binding RowData.DataContext.my}" Value="Medium">
<Setter Property="Source" Value="/project;component/Images/Medium.png" />
</DataTrigger>
<DataTrigger Binding="{Binding RowData.DataContext.my}" Value="Low">
<Setter Property="Source" Value="/project;component/Images/Low.png" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Border>
</DataTemplate>
Try this.

Unable to change background for a Wpf toolkit autocompletebox?

How should i change the background of the wpftoolkit autocompletebox.? I tried by subscribing to enabledchanged event and changed the background of the control which is not changing at all.Can any body help.
<WpfToolkit:AutoCompleteBox x:Name="txtBxSearch" Background="White" IsTextCompletionEnabled="True" MinimumPrefixLength="0" FilterMode="Contains" Height="24" Width="150" KeyDown="txtBxSearch_KeyDown" >
<WpfToolkit:AutoCompleteBox.TextBoxStyle>
<Style TargetType="TextBox">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}"/>
</Style>
</WpfToolkit:AutoCompleteBox.TextBoxStyle>
</WpfToolkit:AutoCompleteBox>
You can do this in XAML:
<toolkit:AutoCompleteBox
ToolTip="Enter the path of an assembly."
x:Name="tbAssembly" Height="27" Width="200"
Populating="tbAssembly_Populating"
>
<toolkit:AutoCompleteBox.Style>
<Style TargetType="toolkit:AutoCompleteBox">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=tbAssembly, Path=IsEnabled}" Value="True">
<Setter Property="Background" Value="Yellow" />
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=tbAssembly, Path=IsEnabled}" Value="False">
<Setter Property="Background" Value="Black" />
<Setter Property="Foreground" Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</toolkit:AutoCompleteBox.Style>
</toolkit:AutoCompleteBox>

Resources