Can't set style for path in resource dictionary - silverlight

I create a style for Path in resource dictionary as below:
<Style x:Key="HeaderPathStyle" TargetType="Path">
<Setter Property="Opacity" Value="0.8"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="Stretch" Value="Fill"/>
<Setter Property="StrokeThickness" Value="0.5"/>
<Setter Property="Data" Value="M12.5,7 C47.333332,7 115.85664,7 117,7 C118.14336,7 122.1255,6.7291665 122.25,12 C122.3745,17.270834 122.25,18.333334 122.25,21.5 L12.5,21.5 z"/>
<Setter Property="Fill">
<Setter.Value>
<RadialGradientBrush GradientOrigin="0.699000000953674,0.792999982833862">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5" CenterY="0.5" ScaleX="1.4" ScaleY="2.188"/>
<SkewTransform CenterX="0.5" CenterY="0.5"/>
<RotateTransform CenterX="0.5" CenterY="0.5"/>
<TranslateTransform X="0.017" Y="0.009"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Color="#FF6C6C8E" Offset="1"/>
<GradientStop Color="#FFADD8E6" Offset="0"/>
</RadialGradientBrush>
</Setter.Value>
</Setter>
</Style>
Then use it usercontrol as below:
<Path Style="{StaticResource HeaderPathStyle}"/>
But I get error. If I set Path in user control xaml directly with same setting, no error.
How to fix it?

You can't just create a Resource Dictionary and expect all resources placed there to accessible immediately. If you want to create a resource that is available from any UserControl then place that resource in the App.xaml in the <Application.Resources> element.
If you'd rather not cluter the App.Xaml with all sorts of resources but still want them to be globally available then using a resource dictionary is the correct approach but then you need to create a reference to that dictionary in the App.xaml:-
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="YourDictionaryFile.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>

Related

Problems with APP.XAML moved to .NET Core 5

I have a WPF application that is working just fine as written for .NET Framework targeting 4.7.2
There are several styles in the App.xaml file.
<BitmapImage x:Key="BitImageAdd" UriSource="Images/iconAdd.png" ></BitmapImage>
<BitmapImage x:Key="BitImageDelete" UriSource="Images/iconDelete.png" ></BitmapImage>
<BitmapImage x:Key="BitImageArrowUp" UriSource="Images/iconArrowUp.png" ></BitmapImage>
<BitmapImage x:Key="BitImageArrowDown" UriSource="Images/iconArrowDown.png" ></BitmapImage>
<Style TargetType="Button" x:Key="btnAdd" x:Shared="False">
<Setter Property="Content">
<Setter.Value>
<Image Source="{StaticResource BitImageAdd}"></Image>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="Button" x:Key="btnDelete" x:Shared="False">
<Setter Property="Content">
<Setter.Value>
<Image Source="{StaticResource BitImageDelete}"></Image>
</Setter.Value>
</Setter>
</Style>
When I use this in the new application written in a new project for .NET CORE 5.0 I get an underline below 'BitmapImage' that says the System.Windows.Media.Imaging.BitmapImage must have IsFrozen set to false to modify. I can't set that property. If I use that for Content on a button it shows "System.Windows.Style"
Another part of the App.xaml file creates a text style that's used later in data grid.
<Style TargetType="{x:Type DataGridRow}" x:Key="BatchStateRowStyle">
<Style.Resources>
<LinearGradientBrush x:Key="Hold" StartPoint="0,0" EndPoint="0,1" >
<GradientStop Offset="0.35" Color="#FF4F4F4F" />
<GradientStop Offset="0.5" Color="Purple" />
<GradientStop Offset="0.65" Color="#FF4F4F4F" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="Sent" StartPoint="0,0" EndPoint="0,1" >
<GradientStop Offset="0.35" Color="#FF4F4F4F" />
<GradientStop Offset="0.5" Color="Purple" />
<GradientStop Offset="0.65" Color="#FF4F4F4F" />
</LinearGradientBrush>
... more styles
</Style.Resources>
<Style.Triggers>
<DataTrigger Binding="{Binding State}" Value="3">
<Setter Property="Background" Value="{StaticResource Hold}" />
</DataTrigger>
<DataTrigger Binding="{Binding State}" Value="4">
<Setter Property="Background" Value="{StaticResource Sent}" />
</DataTrigger>
... more triggers
<Style.Triggers>
In this case the underlined word is the Style at the top which says that StaticResourceExtension is not valid for Setter.Value. So it appears that it's the Setter.Value on Background that's complaining about the StaticResource of the styles defined just above.
I tried moving the BitmapImage items into their own ResourceDictionary and merging it into App.XAML but that didn't help.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Bitmap Images-->
<BitmapImage x:Key="BitImageAdd" UriSource="Images/iconAdd.png" ></BitmapImage>
<BitmapImage x:Key="BitImageDelete" UriSource="Images/iconDelete.png" ></BitmapImage>
<BitmapImage x:Key="BitImageArrowUp" UriSource="Images/iconArrowUp.png" ></BitmapImage>
<BitmapImage x:Key="BitImageArrowDown" UriSource="Images/iconArrowDown.png" ></BitmapImage>
</ResourceDictionary>
App.XAML
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ImageDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
and with that the app crashed telling me the Resources property was already set on App.
I've been looking at different options for how to use these but nothing that really explains how to make these work for .Net Core 5

WPF Style for rectangle - fill not working

I have a WPF application. I have a rectangle that I want to fill with a radial brush that I have created. However when I go to set the value of the fill property with the name of my radial brush it tell me token is not valid?
<RadialGradientBrush x:Key="brushRadSecurity" RadiusY="0.825" RadiusX="0.669">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterY="0.5" CenterX="0.5" ScaleY="1.248" ScaleX="1.276"/>
<SkewTransform CenterY="0.5" CenterX="0.5"/>
<RotateTransform CenterY="0.5" CenterX="0.5"/>
<TranslateTransform Y="0.317" X="-0.007"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Color="#940FDCDC" Offset="0"/>
<GradientStop Offset="1"/>
<GradientStop Color="#94022FF3" Offset="0.974"/>
<GradientStop Color="#940092C9" Offset="0.526"/>
<GradientStop Color="#940FDCDC" Offset="0.25"/>
<GradientStop Color="#940052C9" Offset="0.703"/>
</RadialGradientBrush>
<Style x:Key="recSecurity" TargetType="Rectangle">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="Opacity" Value="0"/>
<Setter Property="RadiusX" Value="10"/>
<Setter Property="RadiusY" Value="10"/>
<Setter Property="StrokeThickness" Value="0"/>
<Setter Property="Fill" Value="brushRadSecurity"/>
</Style>
It should read
<Setter Property="Fill" Value="{StaticResource brushRadSecurity}"/>
try this
<Setter Property="Fill" Value="{StaticResource brushRadSecurity}"/>

How do you style a WPF GridView Header?

I went from this: WPF GridViewHeader styling questions
to this:
Now I just need to get rid of the white space to the right of the "Size" header. I basically have a template for the GridViewColumnHeader that makes it a TextBlock. Is there any way I can set the background for that header area so that it spans the entire width of the GridView?
ADDED CODE:
This is my right-most column. The grid does not span 100% of available window area. In the header I need everything to the right of this column to have the same background as the column headers themselves.
<Style x:Key="GridHeaderRight" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GridViewColumnHeader}">
<TextBlock Text="{TemplateBinding Content}" Padding="5" Width="{TemplateBinding Width}" TextAlignment="Right">
<TextBlock.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0.0" Color="#373638" />
<GradientStop Offset="1.0" Color="#77797B" />
</LinearGradientBrush>
</TextBlock.Background>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Background" Value="Green" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="12" />
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0.0" Color="#373638" />
<GradientStop Offset="1.0" Color="#77797B" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
<GridViewColumn Width="200" HeaderContainerStyle="{ StaticResource GridHeaderRight}" Header="Size">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=EmployeeNumber}" HorizontalAlignment="Right"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
UPDATE
I am one step closer (I think) to solving this.
I added the following code inside the GridView tag:
<GridView.ColumnHeaderContainerStyle>
<Style TargetType="GridViewColumnHeader">
<Setter Property="BorderThickness" Value="1"></Setter>
<Setter Property="BorderBrush" Value="Green"></Setter>
<Setter Property="Height" Value="Auto"></Setter>
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0.0" Color="#373638" />
<GradientStop Offset="1.0" Color="#77797B" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</GridView.ColumnHeaderContainerStyle>
The border is there just so you can see the boundary of what this style covers. This is an enlarged image of what this does. It seems to be what I want if I can get rid of the little white border on the bottom.
So I guess removing that tiny white bottom border would also be an accepted answer for this one.
This is a simple style that will accomplish what you are looking for. Just change the Transparent background on the Border to be your desired gradient.
<Style TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GridViewColumnHeader}">
<Border BorderThickness="0,0,0,1" BorderBrush="Black" Background="Transparent">
<TextBlock x:Name="ContentHeader" Text="{TemplateBinding Content}" Padding="5,5,5,0" Width="{TemplateBinding Width}" TextAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="FontFamily" Value="Segoe UI" />
<Setter Property="FontSize" Value="12" />
</Style>
sometimes the simplest way is the best. All you need to do it to change the TextBlock attached properties of GridViewColumnHeader
Define something like this in Resources:
<Style TargetType="{x:Type GridViewColumnHeader}" BasedOn="{StaticResource {x:Type GridViewColumnHeader}}">
<Setter Property="TextBlock.TextWrapping" Value="Wrap"/>
<Setter Property="TextBlock.Foreground" Value="Black"/>
</Style>
Have a look at the GridViewColumnHeader.Role property. The sample in the documentation for the GridViewColumnHeaderRole enumeration might give you some ideas...
EDIT: Have you considered using the GridView.HeaderStyle property ?
I solved this issue but I think there should be a better way of doing it. The problem was that I had TextBlocks on the header of each column. The unused area didn't have anything on the header row. I just added a TextBlock with the same background in the GridView.ColumnHeaderContainerStyle and it happened to span the rest of the unused width of the grid.
<GridView.ColumnHeaderContainerStyle>
<Style TargetType="GridViewColumnHeader">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GridViewColumnHeader}">
<TextBlock Text="" Padding="5">
<TextBlock.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0.0" Color="#373638" />
<GradientStop Offset="1.0" Color="#77797B" />
</LinearGradientBrush>
</TextBlock.Background>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GridView.ColumnHeaderContainerStyle>

WPF ControlTemplate Style GradientStop in Trigger

Here is my XAML for a TabItem. I want to be able to set the Color of a single gradient stop in a trigger. I know that I can re-define the gradient completely in the trigger's setter, but I want to access a specific property on the background so I can animate it in the future.
I have tried every variation of everything in the trigger's setter and googled for a long time - but I still can't get it to compile. I have also tried class.property syntax, but still nothing. The current error this code raises is:
"Type 'Background.GradientStops[0]' was not found."
I am pretty sure I know what is going on here - and perhaps what I want is impossible. But there has to be a way to animate a control's gradient in a control template...
Can anyone help me?
thanks
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<TextBlock Padding="6 2 6 2" Name="TheHeader">
<TextBlock.Background>
<LinearGradientBrush StartPoint="0, 0" EndPoint="0, 1">
<GradientStop Offset="0" Color="#f4fafd" />
<GradientStop Offset="1" Color="#ceedfa" />
</LinearGradientBrush>
</TextBlock.Background>
<ContentPresenter ContentSource="Header" Margin="0" />
</TextBlock>
<ControlTemplate.Triggers >
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="TheHeader" Property="Background.GradientStops[0].Color" Value="White" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You can animate it, like in the example here.
You also could use a slight hack to set it, though I always prefer creating multiple brushes as resources and swapping them or re-creating a brush in the as you mentioned.
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<TextBlock Padding="6 2 6 2"
Name="TheHeader" Tag="#f4fafd">
<TextBlock.Background>
<LinearGradientBrush StartPoint="0, 0"
EndPoint="0, 1">
<GradientStop Offset="0"
Color="{Binding ElementName=TheHeader, Path=Tag}"/>
<GradientStop Offset="1"
Color="#ceedfa" />
</LinearGradientBrush>
</TextBlock.Background>
<ContentPresenter ContentSource="Header"
Margin="0" />
</TextBlock>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected"
Value="True">
<Setter TargetName="TheHeader"
Property="Tag"
Value="Red" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Is it possible to extend a ControlTemplate the same way you extend a Style in WPF?

So the thing is that I have a main ControlTemplate which defines the most basic stuff for the new button look we're designing. But I want to do 3 other control templates for this button so we can set different colors in those; but I don't want to copy paste the main ControlTemplate and change the color there, instead I want to "inherit" from that (like with the BasedOn property in Style) and change the color in the inherited ControlTemplate.
Is this possible?
Thanks!
Found the solution. You don't extend ControlTemplates, instead you define all the basic behavior you want, and then you let either a style or the control itself modify it. Take the example below for instance. The ControlTemplate sets the OpacityMask and the round corners for my rectangle, the Styles sets the color of the background for each button (with help of a TemplateBinding), and there's my solution:
<Window.Resources>
<ControlTemplate x:Key="BaseMainButtonTemplate" TargetType="{x:Type Button}">
<Grid TextBlock.Foreground="White" TextBlock.FontFamily="Calibri">
<Rectangle Stroke="#FFE8E6E6" x:Name="rectangle" RadiusX="14.5" RadiusY="14.5" Fill="{TemplateBinding Property=Background}"> <!-- This TemplateBinding takes the color set by the style and applies it to the rectangle. Doing it this way, allows the style to modify the background color -->
<Rectangle.OpacityMask>
<LinearGradientBrush EndPoint="0,1" SpreadMethod="Reflect">
<GradientStop Offset="0" Color="Transparent"></GradientStop>
<GradientStop Offset="1" Color="Gray"></GradientStop>
</LinearGradientBrush>
</Rectangle.OpacityMask>
</Rectangle>
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/>
</Grid>
<ControlTemplate.Triggers>
<!-- OpacityMask when it's Focused, Defaulted and Mouse is over -->
<Trigger Property="IsFocused" Value="True"/>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="OpacityMask" TargetName="rectangle">
<Setter.Value>
<LinearGradientBrush EndPoint="0,1" SpreadMethod="Repeat">
<GradientStop Offset="1" Color="Transparent"></GradientStop>
<GradientStop Offset="0" Color="Gray"></GradientStop>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<!-- OpacityMask when it's pressed -->
<Trigger Property="IsPressed" Value="True">
<Setter Property="Stroke" TargetName="rectangle">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF223472" Offset="0"/>
<GradientStop Color="#FFF2F0F0" Offset="0.911"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="StrokeThickness" TargetName="rectangle" Value="3"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="BlueButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Blue" />
<Setter Property="Template" Value="{StaticResource BaseMainButtonTemplate}">
</Setter>
</Style>
<Style x:Key="RedButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Red" />
<Setter Property="Template" Value="{StaticResource BaseMainButtonTemplate}">
</Setter>
</Style>
<Style x:Key="GreenButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Green" />
<Setter Property="Template" Value="{StaticResource BaseMainButtonTemplate}">
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel>
<Button Style="{StaticResource BlueButtonStyle}" Height="30" Content="Test">
</Button>
<Button Style="{StaticResource RedButtonStyle}" Height="30" Content="Test">
</Button>
<Button Style="{StaticResource GreenButtonStyle}" Height="30" Content="Test">
</Button>
</StackPanel>
</Grid>
Alternately you can define a "DynamicResource" reference to any dependency property in your Control Template and have it go resolve it's value given the presence of available resources.
For example, you can set Background="{DynamicResource SomeBrushColorVariable}"
Then SomeBrushColorVariable can change given different ResourceDictionaries that are merged into your App.xaml file or even set by the user given some user preferences display setting or color scheme.

Resources