Border style based on standard control causing runtime error - wpf

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>

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>

How do you set a DataContext to a Static property in XAML?

This isn't working for me
<UserControl x:Class="BenchmarkPlus.PMT.UI.Views.Circle"
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" x:Name="root"
DataContext="{Binding Source={x:Static Brushes.Blue}}">
<UserControl.Resources>
<Style TargetType="Ellipse">
<Setter Property="Fill" Value="{Binding DataContext}" />
</Style>
</UserControl.Resources>
<Grid>
<Ellipse Stroke="Black"></Ellipse>
</Grid>
</UserControl>
Make it simply DataContext="{x:Static Brushes.Blue}" and change Value="{Binding DataContext}" to Value="{Binding}".
When you specify a path in your binding expression, it's always relative to your DataContext, so when you use {Binding DataContext}, you're actually binding to DataContext.DataContext, which isn't what you want.
I think you want
<UserControl x:Class="BenchmarkPlus.PMT.UI.Views.Circle"
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" x:Name="root"
DataContext="{x:Static Brushes.Blue}">
<UserControl.Resources>
<Style TargetType="Ellipse">
<Setter Property="Fill" Value="{Binding}" />
</Style>
</UserControl.Resources>
<Grid>
<Ellipse Stroke="Black"></Ellipse>
</Grid>
</UserControl>

Understanding how styling and templating work in 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

How do I let my UserControls use the same styles as App.xaml?

I have a UserControl with a Border element within it that I want to style with a particular Border style. It compiles but won't start, giving a XamlParseException, saying, "Cannot find resource ..."
Is there a way to do this?
Thanks.
App.xaml:
<cal:CaliburnApplication x:Class="WahnamProgressTracker.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org"
xmlns:Converters="clr-namespace:WahnamProgressTracker.Converters;assembly=WahnamProgressTracker"
xmlns:Model="clr-namespace:WahnamProgressTracker.Model">
<Application.Resources>
<Style x:Key="FancyBorder"
TargetType="{x:Type Border}">
<Setter Property="Margin" Value="0,0,0,8"/>
<Setter Property="Padding" Value="8"/>
...
</Style>
</Application.Resources>
MainView.xaml:
<Window x:Class="WahnamProgressTracker.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org"
xmlns:uc="clr-namespace:WahnamProgressTracker.UserControls"
MinHeight="500" MinWidth="800">
<DockPanel>
<uc:MainViewMenu x:Name="menu"
DockPanel.Dock="Top" />
<StatusBar x:Name="quoteBar"
DockPanel.Dock="Bottom">
<TextBlock Text="{Binding Path=Quote.Text, Mode=OneWay}" />
</StatusBar>
<uc:MainViewNavigation x:Name="navigationBar"
DockPanel.Dock="Left" />
<uc:ProgressGraph x:Name="graph" />
</DockPanel>
MainViewNavigation.xaml (user control):
<UserControl x:Class="WahnamProgressTracker.UserControls.MainViewNavigation"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Border Style="{StaticResource FancyBorder}">
...
</Border>
</UserControl>
Can you post a sample of what you mean? The only case in which your issue can occur is if the User Control is created and then rendered outside your application's visual tree.
The XAML below works for me:
App.xaml:
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml">
<Application.Resources>
<Style TargetType="{x:Type TextBlock}" x:Key="myStyle">
<Setter Property="Foreground" Value="Green" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
</Application.Resources>
</Application>
Window1.xaml:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:local="clr-namespace:WpfApplication1"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<local:UserControl1 />
</Grid>
</Window>
UserControl1.xaml:
<UserControl x:Class="WpfApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Grid>
<TextBlock Style="{StaticResource myStyle}">HEY!</TextBlock>
</Grid>
</UserControl>

Resources