For some reason, my ImageBrush background as an odd blurry drop shadow to it.
<Button Style="{StaticResource SeamlessBtn}" Width="30" Height="30" Click="ToggleTheme"
BorderBrush="Transparent" Margin="10,10,105,408" Foreground="Transparent">
<Button.Background>
<ImageBrush x:Name="BrightSwitch" ImageSource="/Images/BootstrapIcons-MoonFill.png"/>
</Button.Background>
</Button>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style BasedOn="{StaticResource {x:Type Button}}" TargetType="Button"
x:Key="SeamlessBtn">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Transparent"></Setter>
<Setter Property="BorderBrush" Value="Transparent"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
Edit: I am using materialDesignTheme
Since the geometry is readily available.
https://icons.getbootstrap.com/icons/moon-fill/
I would suggest trying that.
I put such geometries in a resource dictionary I merge in app.xaml but that could be anywhere in scope of your button instead:
<Window.Resources>
<Geometry x:Key="MoonGeometry">
M6 .278a.768.768 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277.527 0 1.04-.055 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278z
</Geometry>
</Window.Resources>
Since that's seems to be the only thing you have in your button you can just make it content. In just a plain button:
<Button>
<Path Data="{StaticResource MoonGeometry}"
Fill="Black"
Stretch="Uniform"/>
</Button>
Or if you particularly wanted a background and brush:
<Button>
<Button.Background>
<DrawingBrush Stretch="Uniform">
<DrawingBrush.Drawing>
<GeometryDrawing Brush="Black"
Geometry="{StaticResource MoonGeometry}"/>
</DrawingBrush.Drawing>
</DrawingBrush>
</Button.Background>
</Button>
Either approach gives you a sharp picture because it's using vectors.
I have got button Lock and button Unlock placed together in my app. The problem is that they have vector SVG images as content, both are black, so it seems that both buttons are enabled, so I need to change the color on gray, if it's unabled.
Assigning image as button content is realized like this:
<Button x:Name="LockButton" Content="{StaticResource LockButton}"/>
So lock image is some style:
<Rectangle x:Key="LockButton" Style="{StaticResource ButtonRectangle}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill">
<VisualBrush.Visual>
<Canvas Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
<Path Width="34.8333" Height="41.1667" Canvas.Left="20.5833" Canvas.Top="17.4167" Stretch="Fill" Fill="#FF000000" Data="M 12 0 C 8.699219 0 6 2.699219 6 6 L 6 11 L 3 11 L 3 24 L 21 24 L 21 11 L 18 11 L 18 6 C 18 2.699219 15.300781 0 12 0 Z M 12 2 C 14.21875 2 16 3.78125 16 6 L 16 11 L 8 11 L 8 6 C 8 3.78125 9.78125 2 12 2 Z"/>
</Canvas>
</VisualBrush.Visual>
</VisualBrush>
</Rectangle.OpacityMask>
</Rectangle>
And for this Rectangle there is another style:
<Style x:Key="ButtonRectangle" TargetType="Rectangle">
<Setter Property="Width" Value="16" />
<Setter Property="Height" Value="16" />
<Setter Property="Fill" Value="Black" />
</Style>
So I think, that I need to make DataTrigger for some of these blocks. But I don't know how to bind IsEnabled property of button in inner styles. Another idea is to make the same rectangle style with gray fill and make DataTrigger, which will apply different styles to button, depending on value of IsEnabled property.
So, what do you think, how would you solve this?
Better use the Path as Content of a Button and bind its Fill property to the Button's Foreground.
<Geometry x:Key="LockGeometry">M 12 0 C 8.699219 0 6 2.699219 6 6 L 6 11 L 3 11 L 3 24 L 21 24 L 21 11 L 18 11 L 18 6 C 18 2.699219 15.300781 0 12 0 Z M 12 2 C 14.21875 2 16 3.78125 16 6 L 16 11 L 8 11 L 8 6 C 8 3.78125 9.78125 2 12 2 Z</Geometry>
...
<Button Style="{StaticResource IconButtonStyle}">
<Path Data="{StaticResource LockGeometry}"
Fill="{Binding Foreground, RelativeSource={RelativeSource AncestorType=Button}}"
Width="16" Height="16" Margin="4" Stretch="Fill"/>
</Button>
The Foreground would be set by a Style like:
<Style x:Key="IconButtonStyle" TargetType="Button">
<Setter Property="Foreground" Value="Black"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Gray"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Foreground" Value="Green"/>
</Trigger>
</Style.Triggers>
</Style>
don't put visual elements (Rectangle) in Resources - it makes difficult to modify and use them. instead define VisualBrush as resource, apply OpacityMask in Rectangle Style, add DataTrigger in RectangleStyle, and then use rectangle with that Style as Button.Content:
<VisualBrush Stretch="Fill" x:Key="LockButtonIco">
<VisualBrush.Visual>
<Canvas Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
<Path Width="34.8333" Height="41.1667" Canvas.Left="20.5833" Canvas.Top="17.4167" Stretch="Fill" Fill="#FF000000" Data="M 12 0 C 8.699219 0 6 2.699219 6 6 L 6 11 L 3 11 L 3 24 L 21 24 L 21 11 L 18 11 L 18 6 C 18 2.699219 15.300781 0 12 0 Z M 12 2 C 14.21875 2 16 3.78125 16 6 L 16 11 L 8 11 L 8 6 C 8 3.78125 9.78125 2 12 2 Z"/>
</Canvas>
</VisualBrush.Visual>
</VisualBrush>
<Style x:Key="ButtonRectangle" TargetType="Rectangle">
<Setter Property="Width" Value="16" />
<Setter Property="Height" Value="16" />
<Setter Property="OpacityMask" Value="{StaticResource LockButtonIco}" />
<Setter Property="Fill" Value="Black" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource AncestorType=Button}}" Value="False">
<Setter Property="Fill" Value="Blue" />
</DataTrigger>
<Style.Triggers>
</Style>
<Button x:Name="LockButton">
<Rectangle Style="{StaticResource ButtonRectangle}"/>
</Button>
or maybe apply OpacityMask to each Rectangle, not in style:
<Button x:Name="LockButton">
<Rectangle Style="{StaticResource ButtonRectangle}"
OpacityMask="{StaticResource LockButtonIco}"/>
</Button>
The problem: how can I design button, which inherits Foreground from its parent, but allows changing it via style?
More precisely, given following button:
<StackPanel TextBlock.Foreground="Red">
<ToggleButton Width="16" Height="16" FontSize="10" Style="{StaticResource ...}">
<Grid>
<Path Width="8" Height="8" Fill="...">
<Path.Data>
<PathGeometry Figures="M 1 0 L 1 4 L 0 4 L 0 5 L 3 5 L 3 8 L 4 8 L 4 5 L 7 5 L 7 4 L 6 4 L 6 0 L 1 0 z M 2 1 L 4 1 L 4 4 L 2 4 L 2 1 z " FillRule="NonZero"/>
</Path.Data>
</Path>
</Grid>
</ToggleButton>
</StackPanel>
I need, that:
Path's fill color matches StackPanel's current Foreground color, and
When user hovers mouse over the button, path's fill color becomes some specific, constant color.
I tried designing style for button, including the ControlTemplate, but there's a problem with Foreground. Button has its Foreground property set to some DynamicResource via theme, so it doesn't match StackPanel's Foreground.
Obviously I can bind it, but then style and control template triggers stops working, because I've set an immediate value to a dependency property, what overrules all other means of providing value to it.
To give a context to the problem, this is what I want to achieve:
You could bind to the attached TextBlock.Foreground of the ToggleButton's parent Panel like this:
<Path Width="8" Height="8"
Fill="{Binding (TextBlock.Foreground),
RelativeSource={RelativeSource AncestorType=Panel, AncestorLevel=2}}">
...
If you want the Fill to change on mouse over, you could define a Style with a DataTrigger:
<StackPanel TextBlock.Foreground="Red">
<ToggleButton Width="16" Height="16" FontSize="10">
<Grid>
<Path Width="8" Height="8">
<Path.Data>
<PathGeometry Figures="M 1 0 L 1 4 L 0 4 L 0 5 L 3 5 L 3 8 L 4 8 L 4 5 L 7 5 L 7 4 L 6 4 L 6 0 L 1 0 z M 2 1 L 4 1 L 4 4 L 2 4 L 2 1 z "
FillRule="NonZero"/>
</Path.Data>
<Path.Style>
<Style TargetType="Path">
<Setter Property="Fill" Value="{Binding (TextBlock.Foreground),
RelativeSource={RelativeSource AncestorType=Panel, AncestorLevel=2}}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver,
RelativeSource={RelativeSource AncestorType=ToggleButton}}" Value="True">
<Setter Property="Fill" Value="Blue" />
</DataTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
</Grid>
</ToggleButton>
</StackPanel>
I figured it out by myself - I forgot, that style setters may set bindings as well. The solution is following.
Style:
<Style TargetType="ButtonBase" x:Key="DocumentTabButtonStyle">
<Style.Setters>
<Setter Property="TextBlock.Foreground" Value="{Binding Path=(TextBlock.Foreground), RelativeSource={RelativeSource AncestorType=StackPanel}}" />
<Setter Property="Template">
...
</Setter>
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="TextBlock.Foreground" Value="{StaticResource DocumentButtonHoverForegroundBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
Button:
<Button Style="{StaticResource DocumentTabButtonStyle}">
<Path Fill="{Binding Path=(TextBlock.Foreground), RelativeSource={RelativeSource AncestorType={x:Type Button}}}">
<Path.Data>
<PathGeometry Figures="M 0 1 L 3 4 L 0 7 L 2 7 L 4 5 L 6 7 L 8 7 L 5 4 L 8 1 L 6 1 L 4 3 L 2 1 Z" />
</Path.Data>
</Path>
</Button>
I am a beginner with Visual Studio.
I want to have separately defineable icons in my buttons. I want to achieve this using only XAML in order to keep my GUI stuff as separate as possible.
I'd like to be able to use it like this:
<Button x:Name="CallButton" Height="128px" Width="128px"
Style="{DynamicResource RoundButton}" Content="{StaticResource PhoneIcon}">
I have defined RoundButton and PhoneIcon in their respective Resource Dictionaries.
RoundButton:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="RoundButton" TargetType="{x:Type Button}">
<Setter Property="Content" Value="{Binding Grid}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border CornerRadius="100" BorderThickness="2" x:Name="border"
BorderBrush="{TemplateBinding BorderBrush}">
<Grid>
<ContentPresenter VerticalAlignment="Center"
HorizontalAlignment="Center"
x:Name="contentPresenter" Opacity="1" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
PhoneIcon:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas x:Key="PhoneIcon">
<Path Stroke="Gray" Data="m 492.438 397.75 -2.375 -7.156 c -5.625 -16.719 -24.063 -34.156 -41 -38.75 l -62.688 -17.125 c -17 -4.625 -41.25 1.594 -53.688 14.031 L 310 371.438 C 227.547 349.157 162.891 284.5 140.641 202.063 l 22.688 -22.688 c 12.438 -12.438 18.656 -36.656 14.031 -53.656 L 160.266 63 C 155.641 46.031 138.172 27.594 121.485 22.031 l -7.156 -2.406 c -16.719 -5.563 -40.563 0.063 -53 12.5 L 27.391 66.094 c -6.063 6.031 -9.938 23.281 -9.938 23.344 -1.187 107.75 41.063 211.562 117.281 287.781 76.031 76.031 179.453 118.219 286.891 117.313 0.563 0 18.313 -3.813 24.375 -9.844 l 33.938 -33.938 c 12.437 -12.437 18.062 -36.281 12.5 -53 z" />
</Canvas>
</ResourceDictionary>
I have merged my Resource Dictionaries in the App.xaml:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="RoundButton.xaml" />
<ResourceDictionary Source="Icons.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
My problem is that while I get the image displayed, it's disproportionately big. I have tried pretty many solutions so I'm starting to lose track of the tried with my trial-and-error approach.
How to get the image show right in the center of the button with correct size?
NB I have trimmed some of the code I'm posting here - but I have also tested the code I'm posting here and the problem persists.
Thanks in advance!
You may use a Grid instead of a Canvas in your PhoneIcon resource, and set the Path's Stretch property. This would scale the Path to a Size that fits the Button's bounds:
<Grid x:Key="PhoneIcon">
<Path Stretch="Uniform" ... />
</Grid>
You may even set the Grid size explicitly:
<Grid x:Key="PhoneIcon" Width="80">
<Path Stretch="Uniform" ... />
</Grid>
An even simpler solution would be to use the Path without any container:
<Path x:Key="PhoneIcon" Width="80" Stretch="Uniform" ... />
I want to use vector icon as content inside Button style to use in multiple buttons (more than 20). So, I did like this:
my icon:
<Rectangle x:Key="DefaultsIcon" Height="20" Width="20" x:Shared="False" HorizontalAlignment="Center" VerticalAlignment="Center" Fill="{DynamicResource BlackBrush}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill">
<VisualBrush.Visual>
<Canvas Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
<Path Width="29.26" Height="32.5111" Canvas.Left="24.9269" Canvas.Top="21.3222" Stretch="Fill" Fill="{DynamicResource BlackBrush}" Data="F1 M 24.9269,53.8333L 24.9269,21.3222L 36.6106,21.3222C 48.3282,21.3222 54.1869,26.6053 54.1869,37.1714C 54.1869,42.2319 52.588,46.274 49.3901,49.2977C 46.1922,52.3215 41.9324,53.8333 36.6106,53.8333L 24.9269,53.8333 Z M 32.3581,27.36L 32.3581,47.7956L 36.0156,47.7956C 39.2231,47.7956 41.7377,46.8509 43.5591,44.9617C 45.3806,43.0725 46.2914,40.5023 46.2914,37.2512C 46.2914,34.1791 45.3879,31.7625 43.5809,30.0015C 41.7739,28.2405 39.2376,27.36 35.972,27.36L 32.3581,27.36 Z "/>
</Canvas>
</VisualBrush.Visual>
</VisualBrush>
</Rectangle.OpacityMask>
</Rectangle>
my style:
<Style TargetType="Button" BasedOn="{StaticResource CameraButtonBaseStyle}" x:Key="CameraDefaultsButtonStyle">
<Setter Property="Margin" Value="{Binding Source={StaticResource CameraUISettings}, Path=OptionLBMargin, Mode=OneWay, Converter={uiConverters:DoubleToLeftMarginConverter}}"></Setter>
<Setter Property="ToolTip" Value="{Binding Source={StaticResource CameraLocalization}, Path=ToolTips.Default, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"></Setter>
<Setter Property="Content" Value="{DynamicResource DefaultsIcon}"></Setter>
</Style>
and apply style:
<Button Style="{StaticResource CameraDefaultsButtonStyle}"
Click="LoadDefaultX_OnClick">
</Button>
But the problem here is that in design time only 1 icon of all displaying and in runtime all icons displaying good. I want that in design time icons also were visible.
How to reach this?
The problem is DefaultsIcon style contains a visual. The style is created only once per lifetime of your app and reused as often as needed. But a visual can only be used once in the visual tree. A quick fix is to add x:Shared="Falsed" to DefaultsIcon. From the architectural perspective that's not the best solution because now for every usage of DefaultsIcon a new instance is created.
Because I want to share some code I add a new answer. My question is do you need the DefaultsIcon style somewhere else? If not you could do the following to get the same result:
<Style TargetType="Button" x:Key="CameraDefaultsButtonStyle" x:Shared="False" >
<Setter Property="Margin" Value="10"></Setter>
<Setter Property="ToolTip" Value="hello"></Setter>
<Setter Property="Content">
<Setter.Value>
<Path Width="29.26" Height="32.5111" Canvas.Left="24.9269" Canvas.Top="21.3222" Stretch="Fill" Fill="Black" Data="F1 M 24.9269,53.8333L 24.9269,21.3222L 36.6106,21.3222C 48.3282,21.3222 54.1869,26.6053 54.1869,37.1714C 54.1869,42.2319 52.588,46.274 49.3901,49.2977C 46.1922,52.3215 41.9324,53.8333 36.6106,53.8333L 24.9269,53.8333 Z M 32.3581,27.36L 32.3581,47.7956L 36.0156,47.7956C 39.2231,47.7956 41.7377,46.8509 43.5591,44.9617C 45.3806,43.0725 46.2914,40.5023 46.2914,37.2512C 46.2914,34.1791 45.3879,31.7625 43.5809,30.0015C 41.7739,28.2405 39.2376,27.36 35.972,27.36L 32.3581,27.36 Z "/>
</Setter.Value>
</Setter>
</Style>
The need to set x:Shared="False" is for me a sign to think of a small user control instead of a style.
No, I mean a mini user control as a replacement for your CameraDefaultsButtonStyle style, not only the Content within that style. The control could look like this:
<Button x:Class="TabControl1.CameraDefaultsButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
ToolTip="Hello">
<Grid>
<Path Width="29.26" Height="32.5111" Stretch="Fill" Fill="Black" Data="F1 M 24.9269,53.8333L 24.9269,21.3222L 36.6106,21.3222C 48.3282,21.3222 54.1869,26.6053 54.1869,37.1714C 54.1869,42.2319 52.588,46.274 49.3901,49.2977C 46.1922,52.3215 41.9324,53.8333 36.6106,53.8333L 24.9269,53.8333 Z M 32.3581,27.36L 32.3581,47.7956L 36.0156,47.7956C 39.2231,47.7956 41.7377,46.8509 43.5591,44.9617C 45.3806,43.0725 46.2914,40.5023 46.2914,37.2512C 46.2914,34.1791 45.3879,31.7625 43.5809,30.0015C 41.7739,28.2405 39.2376,27.36 35.972,27.36L 32.3581,27.36 Z "/>
</Grid>
</Button>
using System.Windows.Controls;
namespace TabControl1
{
/// <summary>
/// Interaction logic for CameraDefaultsButton.xaml
/// </summary>
public partial class CameraDefaultsButton : Button
{
public CameraDefaultsButton ()
{
InitializeComponent ();
}
}
}
You use it this way like the standard button:
<Window x:Class="TabControl1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:TabControl1"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:CameraDefaultsButton Margin="301,164,0,0"
HorizontalAlignment="Left"
Width="139"
Height="55"
VerticalAlignment="Top"/>
<local:CameraDefaultsButton Margin="301,236,0,0"
HorizontalAlignment="Left"
Width="139"
Height="55"
VerticalAlignment="Top"/>
</Grid>
</Window>
but don't forget to add the namespace where you use it:
xmlns:local="clr-namespace:TabControl1"