Use image as WPF Button icon mask? - wpf

I'd like to know if it's possible to do the following:
create a black and white image, say of a dog
add the image to a button as a mask
change the style using (data) triggers, e.g. disabled - the dog is grey, "loading" - the dog is red, "ready" the dog is yellow, etc.
Basically I want to create button icons using pixels but be able to set the color at runtime depending on triggers. Something like this:

After 2 hours of googling here's the answer
<Window x:Class="IconTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<!-- button style -->
<Style x:Key="ToolButton" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Width="16" Height="16" Background="#ffbbbbbb">
<Rectangle Name="rect" Fill="Black" OpacityMask="{TemplateBinding Content}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="rect" Property="Fill" Value="Green" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="rect" Property="Fill" Value="Yellow" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Button Width="16" Height="16" Style="{StaticResource ToolButton}">
<ImageBrush ImageSource="/test.png"/>
</Button>
</Grid>
</Window>

You can define an OpacityMask for the Button. I believe you will be able to add triggers (if you need them) to change the Background of Button.
Sample:
<Button Height="100" Width="100" Background="Green">
<Button.OpacityMask>
<DrawingBrush AlignmentX="Left" AlignmentY="Top">
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="#33000000">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,40,40" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="#FF000000">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="10,10,20,20">
<RectangleGeometry.Transform>
<RotateTransform Angle="45" CenterX="20" CenterY="20" />
</RectangleGeometry.Transform>
</RectangleGeometry>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Button.OpacityMask>
</Button>

In my opinion, you don't need create image mask in WPF to achieve your requirement. You could simply edit the control template of the button class.
Please refer to the Ellipse button example in this page. Control Template
Then you could simply change the Fill Color of that shape using trigger. Trigger
Cheers,

Related

How to scale an svg image inserted using DrawingBrush

Is there a way to scale an svg image inserted using DrawingBrush as in the following code?
<Style x:Key="HamburgerMenuItemStyle" TargetType="{x:Type MenuItem}">
<Setter Property="Template" Value="{StaticResource MenuItemControlTemplate1}"/>
<Setter Property="Icon">
<Setter.Value>
<DrawingImage>
<DrawingImage.Drawing>
<GeometryDrawing Geometry="M6 36v-3h36v3Zm0-10.5v-3h36v3ZM6 15v-3h36v3Z"
Brush="Red"/>
</DrawingImage.Drawing>
</DrawingImage>
</Setter.Value>
</Setter>
</Style>
According to your description, I think you should code as below:
<Style x:Key="HamburgerMenuItemStyle" TargetType="{x:Type MenuItem}">
<Setter Property="Template" Value="{StaticResource MenuItemControlTemplate1}"/>
<Setter Property="Icon">
<Setter.Value>
<Image Stretch="UniformToFill" Width="auto" Height="auto" HorizontalAlignment="Left">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<GeometryDrawing Geometry="M6 36v-3h36v3Zm0-10.5v-3h36v3ZM6 15v-3h36v3Z" Brush="Red"/>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</Setter.Value>
</Setter>
</Style>
Note:
Since I didn't have the Template property, I removed it. If you have problems displaying the icon despite this property, you should check it.
Also, if you are not sensitive to the use of Drawing Image, you can use the Path tag
<Path Stretch="Fill" Height="30" Width="30" Data="M6 36v-3h36v3Zm0-10.5v-3h36v3ZM6 15v-3h36v3Z" Fill="Red"></Path>

Have DrawingImage inherit color from containing Button

I have a few buttons that have a common style. This style has a ContentPresenter, which is filled with a DrawingImage in the button declaration.
This works just fine when the DrawingImage uses a predefined brush. However I would very much like my DrawingImage to use the Foreground color that is used in the style, or on the button if it is overridden there.
How can I accomplish this?
My current style:
<UserControl.Resources>
<DrawingImage x:Key="SomeIcon">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup>
<GeometryDrawing Brush="White" Geometry="PATH" />
<GeometryDrawing Brush="White" Geometry="OTHER_PATH" />
</DrawingGroup>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<Style x:Key="MyButton" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="Blue" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<Button Style="{StaticResource MyButton">
<!-- I want this icon to be Blue as inherited from the style. -->
<Image Source="{StaticResource SomeIcon}"/>
</Button>
<Button Style="{StaticResource MyButton" Foreground="Red">
<!-- I want this icon be Red as overriden by the button -->
<Image Source="{StaticResource SomeIcon}"/>
</Button>
</Grid>
I only want pure XAML answers. Other XAML routes towards the same goal are also appreciated, for instance using Path instead of DrawingImage.
You could declare the icon resource as a Geometry, and have a Button Style with a Path like this:
<Window.Resources>
<Geometry x:Key="SomeIcon">M0,20 L20,0 40,20 20,40Z</Geometry>
<Style x:Key="PathButtonStyle" TargetType="Button">
<Setter Property="Foreground" Value="Blue"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ControlTemplate TargetType="Button">
<Path Fill="{TemplateBinding Background}"
Stroke="{TemplateBinding Foreground}"
Data="{TemplateBinding Content}"
Stretch="None"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Button Style="{StaticResource PathButtonStyle}"
Content="{StaticResource SomeIcon}"/>
</Grid>

Display Error using Datatemplate

today you helped me with Need multiple styles dependent on Listboxitem
But now i get a gray rectangle while drawing or moving the objects.
Picture with how it should look like, and how it looks like when iam drawing a line:
https://drive.google.com/file/d/0B_F04v1afwM5c0kteExsamlMcHM/edit?usp=sharing
here is the code i used:
<ListBox.Resources>
<DataTemplate DataType="{x:Type model:PathLine}">
<Path Stroke="{Binding ObjectColor}" StrokeThickness="{Binding StrokeThickness}" Data="{Binding PathGeometryData}" x:Name="PathLine" Opacity="{Binding Opacity}" >
</Path>
</DataTemplate>
<DataTemplate DataType="{x:Type model:ImageObject}">
<Image Source="H:\Dropbox\WPF Projekte\Arena WPF\ArenaProgram\ArenaProgram\Pictures\tree1.png" Name="imgPic1" Width="100" Height="75" Stretch="Fill" VerticalAlignment="Top" />
</DataTemplate>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect Color="Crimson" ShadowDepth="3" BlurRadius="10" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
hope someone can help me :)
Aha! Finally, I know what you're talking about. :)
It seems to me that that (in my opinion, white) rectangle with a light crimson border is the ListBoxItem object. You added a Style that tells the ListBoxItem to display a crimson glow around its edge when it is selected, so that is what you are seeing. Try adding a Setter which sets the Background property to Transparent:
<Style TargetType="ListBoxItem">
<Setter Property="Background" Value="Transparent" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect Color="Crimson" ShadowDepth="3" BlurRadius="10"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
If that doesn't work, you might think about removing the Trigger altogether.

How to Clear Triggered Control Template

I am trying to achieve the "hint text" functionality for a TextBox in WPF. I can set the default text fine, but the problem comes when I want the control to return its appearance to a normal TextBox. Here is the trigger I have so far:
Trigger A
<Trigger Property="Text" Value="{x:Static sys:String.Empty}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<TextBox>
<TextBox.Background>
<VisualBrush AlignmentX="Left" AlignmentY="Center" Stretch="UniformToFill">
<VisualBrush.Visual>
<Label Content="{TemplateBinding TextBox.Tag}" Background="White"/>
</VisualBrush.Visual>
</VisualBrush>
</TextBox.Background>
</TextBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
This sets the Background to a VisualBrush when the Text property is empty. What I need to do is clear this ControlTemplate when the user selects the TextBox to input text.
Here is what I tried:
Trigger B
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<TextBox/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
These two don't work together. I tested each by changing the Background colors. If I comment out either one, they will each work. If both are uncommented, Trigger A works and B is never seen. How can I remove/overwrite Trigger A?
I know that the functionality of these templates is supposed to clear when the trigger condition is no longer met, but for example, Trigger A's setting will not go away when I enter text into the TextBox like it should. Like the Text property is still String.Empty or something.
So what am I missing?
EDIT:
Here is the whole style (there's not much more to it):
<UserControl.Resources>
<Style TargetType="TextBox" x:Key="FormsTextBox">
<Setter Property="Width" Value="45"/>
<Setter Property="Margin" Value="3 2 3 2"/>
<Style.Triggers>
<Trigger Property="Text" Value="{x:Static sys:String.Empty}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<TextBox>
<TextBox.Background>
<VisualBrush AlignmentX="Left" AlignmentY="Center" Stretch="UniformToFill">
<VisualBrush.Visual>
<Label Content="{TemplateBinding TextBox.Tag}" Background="White" Width="45"/>
</VisualBrush.Visual>
</VisualBrush>
</TextBox.Background>
</TextBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
I cannot see whole template but this looks a bit overcomplicated. I assume you're trying to achieve watermark text. For hint use box standard ToolTip property, which by default will display your text in a popup when hover your TextBox but this behaviour can be disabled and ToolTip property reused. You can either create reusable Style - which I prefer - for TextBox, something like this:
<Window ...>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<Style TargetType="{x:Type TextBox}" x:Key="WatermarkTextBoxStyle">
<Setter Property="ToolTipService.IsEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
BorderThickness="1"
BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}">
<Grid>
<TextBlock Margin="5,0,0,0"
Text="{TemplateBinding ToolTip}"
Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Text.IsEmpty, Converter={StaticResource BooleanToVisibilityConverter}}"
Opacity="0.5"/>
<ScrollViewer Name="PART_ContentHost"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<TextBox ToolTip="watermark text" Style="{StaticResource WatermarkTextBoxStyle}"/>
</Window>
or, if it's a one-off thing, then do you can do something like this without any Style or Template:
<Grid Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
<TextBlock Margin="5,0,0,0"
Text="watermark text"
Opacity="0.5"
Visibility="{Binding ElementName=myTextBox, Path=Text.IsEmpty, Converter={StaticResource BooleanToVisibilityConverter}}" />
<TextBox Name="myTextBox" Background="Transparent" />
</Grid>

Looking for a Office 2007 Style zoom slider template

Has anyone seen a good template for a Office 2007 style zoom slider?
As shown in this picture
alt text http://www.theexceladdict.com/images/zoom_controls_excel_2007_2003.jpg
Something like this would be very easy to create.
First create a button style:
<Style x:Key="ZoomIncreaseDecreaseStyle" TargetType="{x:Type RepeatButton}">
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="IsTabStop" Value="false" />
<Setter Property="Focusable" Value="false" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Grid>
<Ellipse Stroke="Gray" x:Name="Ellipse">
<Ellipse.Fill>
<RadialGradientBrush ... />
</Ellipse.Fill>
</Ellipse>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
<ControlTemplate.Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="Ellipse" Property="Fill">
<RadialGradientBrush ... />
</Setter>
</Trigger>
</ControlTemplate.Trigger>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style>
Then modify the ControlTemplate in Blend (create copy), and add something like this around the <Grid>:
<DockPanel>
<RepeatButton
DockPanel.Dock="Left"
Command="{x:Stastic Slider.DecreaseLarge}"
ControlTemplate="{StaticResource ZoomIncreaseDecreaseStyle}">
<Path Data="{StaticResource MinusGeometry}" />
</RepeatButton>
<RepeatButton
DockPanel.Dock="Right"
Command="{x:Stastic Slider.IncreaseLarge}"
ControlTemplate="{StaticResource ZoomIncreaseDecreaseStyle}">
<Path Data="{StaticResource PlusGeometry}" />
</RepeatButton>
<Grid>
...
You can play with the button stroke color, gradient fill, and the + and - paths to get it the way you want it. I assume the actual Office 2007 buttons are copyrighted so you probably won't be able to copy them too closely without infringing. But this will give you something visually very similar.

Resources