Bind to GeometryDrawing brush - wpf

I have 3 buttons in my user control, all 3 have little icons instead of text.
Image buttons
For example:
<controls:CheckButton Grid.Column="1" Style="{StaticResource ActionButtonStyle}">
<Image Source="{StaticResource Video}" Stretch="None"/>
</controls:CheckButton>
The image has this code to allow me to bind its color later:
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V24 H25 V0 H0 Z">
<GeometryDrawing Brush="{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType=Control}}" Geometry="F0 M25,24z M0,0z M20.75,12C20.75,9.345,19.22,7.065,17,5.955L17,18.03C19.22,16.935,20.75,14.655,20.75,12L20.75,12z M0.5,7.5L0.5,16.5 6.5,16.5 14,24 14,0 6.5,7.5 0.5,7.5 0.5,7.5z" />
</DrawingGroup>
</DrawingImage.Drawing>
In order to set the color I use this style:
<Style x:Key="ActionButtonStyle" TargetType="ButtonBase">
<Setter Property="Foreground" Value="#FFE22880"/>
</Style>
I can see the pinkish color when in design time, but when running the app, this is what I get:
Black icons
*Some of the code is partial, but I've included everything important

Related

Changing DrawingImage brush binded to DynamicResource

I have a DrawingImage object as a resource which uses brush color from DynamicResource like this:
<DrawingImage x:Key="img_building">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V512 H512 V0 H0 Z">
<DrawingGroup Opacity="1">
<GeometryDrawing Geometry="F1 M512,512z M0,0z M256.5,17.2L512,119.4 512,153.8 477.6,153.8C477.6,158.4 475.7,162.2 472,165.9 468.3,169.6 463.6,170.5 459,170.5L53,170.5C48.4,170.5 43.7,168.6 40,165.9 36.3,163.1 34.4,158.5 34.4,153.8L0,153.8 0,119.4 256.5,17.2z M68.8,188.2L136.6,188.2 136.6,392.6 171,392.6 171,188.2 238.8,188.2 238.8,392.6 273.2,392.6 273.2,188.2 341,188.2 341,392.6 375.4,392.6 375.4,188.2 443.2,188.2 443.2,392.6 459,392.6C463.6,392.6 468.3,394.5 472,397.2 475.7,400 477.6,404.6 477.6,409.3L477.6,426 35.3,426 35.3,409.3C35.3,404.7 37.2,400.9 40.9,397.2 44.6,393.5 49.3,392.6 53.9,392.6L69.7,392.6 69.7,188.2 68.8,188.2z M493.4,443.7C498,443.7 502.7,445.6 506.4,448.3 510.1,452 512,455.7 512,460.4L512,494.8 0.9,494.8 0.9,460.4C0.9,455.8 2.8,452 6.5,448.3 10.2,444.6 14.9,443.7 19.5,443.7L493.4,443.7z" >
<GeometryDrawing.Brush>
<SolidColorBrush Color="{DynamicResource Image.FillColor}" />
</GeometryDrawing.Brush>
</GeometryDrawing>
</DrawingGroup>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
And then I'm using this resource in a template like this:
<DataTemplate x:Key="buildingImage">
<WrapPanel>
<WrapPanel.Resources>
<Style TargetType="{x:Type Image}">
<Setter Property="Margin" Value="0,0,4,0"></Setter>
<Setter Property="MaxHeight" Value="20"></Setter>
</Style>
</WrapPanel.Resources>
<Image Source="{DynamicResource img_building}" />
</WrapPanel>
</DataTemplate>
It's running fine but when I change the theme of my app, image remains same although the Image.FillColor changes.
I guess it's rendering the image for once and then uses the same rendered resource over and over again.
How to fix this? Is there a way to force a hard reload on DrawingImage in code behind?

How to set size of Image.Source which is a static resource in XAML?

I have the following Image in my GUI:
<Image Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" Grid.RowSpan="2" Margin="5" Source="{Binding SelectedExternalCameraDevice.LiveStreamSource, FallbackValue={StaticResource LivestreamDefaultImage}, TargetNullValue={StaticResource LivestreamDefaultImage}}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stretch="Uniform"/>
The static resource for the fallback and targetnullvalue look as follows (This is basically taken from Windows's Image library - it is the icon "PlayVideo"):
<DrawingImage x:Key="LivestreamDefaultImage" >
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="{ui:DynamicColor SystemControlPageTextBaseMediumBrush}" Geometry="F1M16,16L0,16 0,0 16,0z" />
<GeometryDrawing Brush="{ui:DynamicColor SystemControlPageBackgroundChromeLowBrush}" Geometry="F1M16,4L16,12C16,13.103,15.103,14,14,14L2,14C0.897,14,0,13.103,0,12L0,4C0,2.897,0.897,2,2,2L14,2C15.103,2,16,2.897,16,4" />
<GeometryDrawing Brush="{ui:DynamicColor SystemControlPageTextBaseMediumBrush}" Geometry="F1M6,11L6,5 10.954,8z M14,3L2,3C1.448,3,1,3.448,1,4L1,12C1,12.552,1.448,13,2,13L14,13C14.552,13,15,12.552,15,12L15,4C15,3.448,14.552,3,14,3" />
<GeometryDrawing Brush="{ui:DynamicColor SystemControlPageBackgroundChromeLowBrush}" Geometry="F1M6,5L10.954,8 6,11z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
As soon as the bound ImageSource in the ViewModel has a proper image, the Image control will stretch uniformly to the available space, keeping it's aspect ration. However, while the source is null the image takes the static resource as source, I have some default aspect ratio (which looks like 1:1). How can I set the width/height/aspect ration of the LivestreamDefaultImage, so that it will also stretch to the available space with my chosen dimensions?
If I understand you correctly, then try this Style:
<Image x:Name="image" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2"
Grid.RowSpan="2" Margin="5"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Image.Style>
<Style TargetType="Image">
<Setter Property="Source" Value="{Binding SelectedExternalCameraDevice.LiveStreamSource}"/>
<Setter Property="Stretch" Value="Uniform"/>
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedExternalCameraDevice.LiveStreamSource}" Value="{x:Null}">
<Setter Property="Source" Value="{DynamicResource LivestreamDefaultImage}"/>
<Setter Property="Stretch" Value="Fill"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>

WPF RelativeSource not updating it's value

I'm trying to implement a button that uses XAML-defined icons to show a different state (like in the second comment here: https://codereview.stackexchange.com/questions/183871/wpf-button-with-xaml-defined-icon-that-changes-with-state). The icons are defined with a "Fill" property that uses a RelativeSource binding, like so:
<Canvas x:Key="icon_stop"
x:Shared="False"
Width="76"
Height="76"
Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
<Rectangle
Width="28.5"
Height="28.5"
Canvas.Left="23.75"
Canvas.Top="23.75"
Stretch="Fill"
Fill="{Binding RelativeSource={
RelativeSource Mode=FindAncestor,
AncestorType=Control
}, Path=Foreground}"
/>
</Canvas>
The button is bound to a property in the window's ViewModel like this:
<Button Name="PlayStopButton"
Padding="20 0 20 0"
Command="{Binding Path=StartStopCommand}">
<ContentControl Style="{StaticResource style_icon}">
<Binding
Path="IsRunning"
UpdateSourceTrigger="PropertyChanged"
FallbackValue="{StaticResource icon_play}">
<Binding.Converter>
<converters:BoolToObjectConverter
TrueObject="{StaticResource icon_stop}"
FalseObject="{StaticResource icon_play}"
NullObject="{StaticResource icon_play}"
/>
</Binding.Converter>
</Binding>
</ContentControl>
</Button>
(I'm omitting the "style" part here and the "BoolToObjectConverter", that should be clear for the purpose)
The problem is that, when I run the program, the button gets correctly updated, but the icon is not visible. This is because the "icon_stop" resource is not updated with the correct "Fill" color. In fact, if I force it (for example to "Black") the icon shows correctly.
It seems to me that the "RelativeSource" bounded property gets not updated.
I think this is related to the fact that the resource is a "StaticResource" and thus gets created only once on the application loading.
I've found that there are also "DynamicResource" references in WPF, but I can't use them here (or at least I can't see how now as them must be bound to a dependency property and I have the value converter here).
How can I solve this?
Your XAML seems overly complicated. You may try something simple like this:
<Style TargetType="Button" x:Key="PlayButtonStyle">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Path Fill="{Binding Foreground,
RelativeSource={RelativeSource AncestorType=Button}}"
Data="{Binding}"/>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Content" Value="M5,0 L25,15 5,30Z"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsRunning}" Value="True">
<Setter Property="Content">
<Setter.Value>
<RectangleGeometry Rect="0,0,30,30"/>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
Try it like this:
<Button Style="{StaticResource PlayButtonStyle}" Foreground="Red" />

Change Background color to a Visual pattern based

I have a list of elements (simple buttons with plain textblock) which are color coded based on the list item content. User can update the Listitem and thus listitem color should change. For certain listitem background colors like "Red", I want to add a pattern as well.
I have added the following VisualPatterns in XAML:
<Window.Resources>
<VisualBrush x:Key="FwdPattern" TileMode="Tile" Viewport="0,0,15,15" ViewportUnits="Absolute" Viewbox="0,0,15,15" ViewboxUnits="Absolute">
<VisualBrush.Visual>
<Grid>
<Path Data="M 0 15 L 15 0" Stroke="Gray" />
</Grid>
</VisualBrush.Visual>
</VisualBrush>
<VisualBrush x:Key="BckPattern" TileMode="Tile" Viewport="0,0,15,15" ViewportUnits="Absolute" Viewbox="0,0,15,15" ViewboxUnits="Absolute">
<VisualBrush.Visual>
<Grid>
<Path Data="M 0 0 L 15 15" Stroke="Gray" />
</Grid>
</VisualBrush.Visual>
</VisualBrush>
</Window.Resources>
Button template used in ListItem is:
<Border Background="{Binding BackgroundClr}">
<Button Name="MyButton" Content="Testing">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="{Binding BackgroundClr}"/>
<Style.Triggers>
<!-- This does not work, see [http://stackoverflow.com/questions/39583263/brush-mvvm-binding-does-not-give-named-color/39583422#39583422][1] -->
<DataTrigger Binding="{Binding BackgroundClr}" Value="Red">
<Setter Property="Background" Value="{StaticResource BckPattern}"/>
</DataTrigger>
<!-- This does not work either, it goes in infinite loop
and StackOverflow exception is thrown-
probably because I am reading the background color in
the datatrigger and again updating it- but i dont know-->
<DataTrigger Binding="{Binding Background.Color, RelativeSource={RelativeSource Self}}" Value="Red">
<Setter Property="Background" Value="{StaticResource BckPattern}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Border>
Currently I have no other knowledge except the Button BackgroundClr from VM to determine if I need to provide a pattern or not.
Tried Solutions
One solution is to have a bound property- PatternName and based on it, determine which pattern to apply:
The above code works, but I have to have an additional property in VM
The other solution is to access VisualBrush in VM and directly apply the pattern in BackgroundClr - i have not figured out how to do this yet.
Which is a better solution or there any other way to achieve the same?
Thanks,
RDV
Change {Binding BackgroundClr} to {Binding BackgroundClr.Color}.

Binding an ImageSource to a DrawingImage

<Style
TargetType="{x:Type local:ObjectWindow}"
BasedOn="{StaticResource {x:Type Window}}">
<Setter
Property="Icon">
<Setter.Value>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<ImageDrawing
Rect="0,0,32,32"
ImageSource="{Binding View.ImageSource, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:ObjectWindow}}}" />
<ImageDrawing
Rect="16,16,16,16"
ImageSource="{DynamicResource View_Image}" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Setter.Value>
</Setter>
</Style>
You can see what I'm trying to do. Trying to overlay two images on top of each other for a Window's Icon. One image is a dynamic resource, which works fine, the other is the result of a Binding expression against a property of the Window.
This however does not work. ImageDrawing doesn't seem to support bindings. Is there something I should be using other than ImageDrawing to accomplish this?

Resources