Understanding how styling and templating work in Silverlight - silverlight

I'm trying to understand how styles works in silverlight, this is what I've done :
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:SilverlightApplication1" mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.DataContext>
<vm:ViewModel />
</UserControl.DataContext>
<UserControl.Resources>
<Style x:Key="TestStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Image Source="test.png" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<StackPanel x:Name="LayoutRoot" Background="White">
<TextBlock Text="{Binding SayHello}" />
<Button Style="{StaticResource TestStyle}" Width="100" Height="100 />
</StackPanel>
The text and the image are displayed correctly, note that test.png is a resource file at the root of my projet.
First thing I don't understand : why is my image correctly displayed at runtime, but not at design in visual studio ?
Then, I would like to use a databinded value in my style, so I use :
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:SilverlightApplication1" mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.DataContext>
<vm:ViewModel />
</UserControl.DataContext>
<UserControl.Resources>
<Style x:Key="TestStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Image Source="{Binding MyUrl}" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<StackPanel x:Name="LayoutRoot" Background="White">
<TextBlock Text="{Binding SayHello}" />
<Button Style="{StaticResource TestStyle}" Width="100" Height="100" />
</StackPanel>
Ok, it's working, my viewmodel exposes an Uri with the test.png as relative.
What I would like to do now is to use the button with many images, so it could have been great to be able to do something like this :
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:SilverlightApplication1" mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.DataContext>
<vm:ViewModel />
</UserControl.DataContext>
<UserControl.Resources>
<Style x:Key="TestStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Image Source="{TemplateBinding TheUrl}" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<StackPanel x:Name="LayoutRoot" Background="White">
<TextBlock Text="{Binding SayHello}" />
<Button Style="{StaticResource TestStyle}" Width="100" Height="100" TheUrl="{Binding MyUrl}" />
</StackPanel>
but the property TheUrl of course doesn't exists in the button.
I don't want to create my own control, the purpose is to understand styles.
How can I do this ?
Thanks in advance for any help.
Best regards

you are correct in your observation that button does not have a TheUrl property. You have to options here. One is to use the Tag property of Button:
<UserControl.Resources>
<Style x:Key="TestStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Image Source="{TemplateBinding Tag}" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<StackPanel x:Name="LayoutRoot" Background="White">
<TextBlock Text="{Binding SayHello}" />
<Button Style="{StaticResource TestStyle}" Width="100" Height="100" Tag="{Binding MyUrl}" />
</StackPanel>
As an aside, I would not bind to the Width / Height properties, these may not be set explicitly. Instead, bind to ActualHeight and ActualWidth which you can guarantee will always be set.
Tag is a property of type object which can be used for general extensibility. The other, more elegant option is to define an attached property. See the tutorial in the following blog post:
http://www.hardcodet.net/2009/01/create-wpf-image-button-through-attached-properties

Related

WPF - Set ContentTemplate with static resource child?

I am relatively new in MVVM. May i know is that a way i can get the element in my user control and bind it separately in a ContentTemplate? I draft a sample code like below.
I have a user control consists of RedStack, GreenStack, BlueStack. My goal is if condition A then show the RedStack and BlueStack in the ContentTemplate, else show all color stacks in the ContentTemplate
Color user control :
<UserControl x:Class="MapDisplay.ColorView"
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">
<StackPanel>
<StackPanel x:Name="RedStack">
<Rectangle Fill="Red" Width="100" Height="100"/>
</StackPanel>
<StackPanel x:Name="GreenStack" >
<Rectangle Fill="Green" Width="100" Height="100"/>
</StackPanel>
<StackPanel x:Name="BlueStack" >
<Rectangle Fill="Blue" Width="100" Height="100"/>
</StackPanel>
</StackPanel>
Main user control:
<UserControl x:Class="WpfApplication.UserControl"
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"
xmlns:custom="clr-namespace:MapDisplay;assembly=MapDisplay"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
mc:Ignorable="d" >
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<DataTemplate DataType="{x:Type custom:ColorController}">
<custom:ColorView/>
</DataTemplate>
<DataTemplate x:Key="ColorDisplay">
<Controls:MetroAnimatedSingleRowTabControl ItemsSource="{Binding Colors}" />
</DataTemplate>
<ControlTemplate x:Key="SplitColorDisplay">
<StackPanel>
<ContentControl Content="{Binding}"
ContentTemplate="{StaticResource ColorDisplay.Colors.RedStack?}" />
<ContentControl Content="{Binding}"
ContentTemplate="{StaticResource ColorDisplay.Colors.BlueStack?}" />
</StackPanel>
</ControlTemplate>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Border>
<ContentControl DockPanel.Dock="Top" Content="{Binding}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{StaticResource ColorDisplay}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSplitColor}" Value="True">
<Setter Property="Template" Value="{StaticResource SplitColorDisplay}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</Border>
</UserControl>

wpf Control Template not working at runtime

After creating ControlTemplate for Wpf window it's working fine in design view. But when I run, it does not show the outer red border.
here is my code
<Window x:Class="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"
WindowStyle="None"
AllowsTransparency="True"
WindowStartupLocation="CenterScreen"
>
<Window.Resources>
<Style TargetType="Window">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Window">
<Border Padding="20" Background="red">
<ContentPresenter Content="{TemplateBinding Content}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<WindowChrome.WindowChrome>
<WindowChrome
ResizeBorderThickness="10"
CaptionHeight="40"
CornerRadius="0"
GlassFrameThickness="0"
/>
</WindowChrome.WindowChrome>
<Grid>
<Border Background="Black" Padding="20">
<Button Content="ok"/>
</Border>
</Grid>
</Window>
The outer red border not showing when I run it. Can anyone tell me if I made any mistake?
At runtime, your window's type is MainWindow, not Window, hence the Style does not apply.
You may change the Style's TargetType to MainWindow:
<Window xmlns:local="clr-namespace:YourNamespace" ...>
<Window.Resources>
<Style TargetType="local:MainWindow">
...
</Style>
</Window.Resources>
...
</Window>
Or set the Window's Style property directly:
<Window ...>
<Window.Style>
<Style TargetType="Window">
...
</Style>
</Window.Style>
...
</Window>
Or set only the Template property directly:
<Window ...>
<Window.Template>
<ControlTemplate TargetType="Window">
<Border Padding="20" Background="red">
<ContentPresenter Content="{TemplateBinding Content}" />
</Border>
</ControlTemplate>
</Window.Template>
...
</Window>
Just making small change it worked fine for me
<Window.Resources>
<Style TargetType="local:MainWindow">
<Setter Property="Template">
...
</Style>
</Window.Resources>

Border style based on standard control causing runtime error

I created a new WPF project by Blend 2017 (.net 4.7) with one window and this Xaml (added no code behind):
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow"
Height="350"
Width="525">
<Window.Resources>
<Style x:Key="_borderStyleWithChildBinding"
TargetType="{x:Type Border}"
BasedOn="{StaticResource {x:Type Border}}">
<Setter Property="BorderBrush"
Value="{Binding RelativeSource={RelativeSource Self}, Path=Child.Fill}" />
</Style>
</Window.Resources>
<Grid Width="50"
Height="30"
Margin="10">
<Border BorderThickness="5"
Style="{StaticResource _borderStyleWithChildBinding}">
<Border.Child>
<Rectangle Width="20"
Height="10"
Fill="Green" />
</Border.Child>
</Border>
</Grid>
</Window>
It compiles but reports a runtime error concerning line
BasedOn="{StaticResource {x:Type Border}}"
Exception: System.Windows.Markup.XamlParseException: A value for System.Windows.Markup.StaticResourceHolder caused an exception.
InnerException: Resource System.Windows.Controls.Border cannot be found.
The designer is smart enough to show the right thing:
We can solve the problem by omitting the x:Key and the BasedOn property of the border style:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow"
Height="350"
Width="525">
<Window.Resources>
<Style TargetType="{x:Type Border}" >
<Setter Property="BorderBrush"
Value="{Binding RelativeSource={RelativeSource Self}, Path=Child.Fill}" />
</Style>
</Window.Resources>
<Grid Width="50"
Height="30"
Margin="10">
<Border BorderThickness="5">
<Border.Child>
<Rectangle Width="20"
Height="10"
Fill="Green" />
</Border.Child>
</Border>
</Grid>
</Window>

How to disable (globally) the FocusVisualStyleKey

I want to disable (globally) the FocusVisualStyleKey.
I'm looking for a possibility, that I have not put on any element the following code:
<Style TargetType="ToggleButton">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
</Style>
So I read this article, and found this solution:
App.xaml
<Application x:Class="WpfApplication7.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style x:Key="{x:Static SystemParameters.FocusVisualStyleKey}">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle StrokeThickness="0" SnapsToDevicePixels="true" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
</Application>
MainWindow.xaml
<Window x:Class="WpfApplication7.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>
</Window.Resources>
<Grid>
<Button Content="Button" HorizontalAlignment="Left" Margin="98,230,0,0" VerticalAlignment="Top" Width="75"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="217,230,0,0" VerticalAlignment="Top" Width="75"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="368,230,0,0" VerticalAlignment="Top" Width="75"/>
<ComboBox HorizontalAlignment="Left" Margin="40,40,0,0" VerticalAlignment="Top" Width="150" Height="40"/>
<ComboBox HorizontalAlignment="Left" Margin="317,40,0,0" VerticalAlignment="Top" Width="150" Height="40"/>
</Grid>
</Window>
But it doesn't work...
Does anyone have another idea?
Yes, there is a way to do this but you are not going to like it. First make another xaml dictionary. In it define a style for each control in Aero or w/e theme you're using, then set BasedOn property to implicit key.
example
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
then create a setter for FocusVisualStyle
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
</Style>
Note: you'll have to do this for EVERY control.
Next merge your new themes dictionary into Window.Resources
<Window.Resources>
<ResourceDictionary Source="[your dictionary]"/>
</Window.Resources>

How to style WPF tooltip like a speech bubble?

I want to shape my WPF tooltip like the image below:
How do I achieve this?
Use this Code:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
x:Name="Window"
Title="MainWindow"
Width="640"
Height="480">
<Window.Resources>
<Style x:Key="{x:Type ToolTip}" TargetType="ToolTip">
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="HasDropShadow" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<ed:Callout Name="Border"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
MinWidth="100"
MinHeight="30"
Margin="0,0,0,50"
AnchorPoint="0,1.5"
Background="{StaticResource LightBrush}"
BorderBrush="{StaticResource SolidBorderBrush}"
BorderThickness="1"
CalloutStyle="RoundedRectangle"
Fill="#FFF4F4F5"
FontSize="14.667"
Stroke="Black">
<ContentPresenter Margin="4"
HorizontalAlignment="Left"
VerticalAlignment="Top" />
</ed:Callout>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Button ToolTip="Hello" />
</Grid>
this is the begining, now you have to play with it... enjoy!

Resources