WPF cannot locate internal UserControl style - c#

I've got a custom UserControl that I try to add to another UserControl:
<UserControl x:Class="MyProject.Screens.Test"
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:local="clr-namespace:MyProject.Screens"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Button Style="{StaticResource TestStyle}"/>
</Grid>
<UserControl.Resources>
<Style x:Key="TestStyle" TargetType="{x:Type Button}">
<Setter Property="Padding" Value="1"/>
</Style>
</UserControl.Resources>
It looks ok in design window, and the projects compiles fine. But if I try to add this UserControl to another UserControl:
<UserControl x:Class="MyProject.Screens.MainScreen"
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:local="clr-namespace:MyProject.Screens"
mc:Ignorable="d"
d:DesignHeight="1080" d:DesignWidth="1920">
<Grid>
<local:Test/>
</Grid>
</UserControl>
I recieve an error:
Cannot locate resource "TestStyle"
in MainScreen.
What am I doing wrong?

Put the Resources declaration before the Content:
<UserControl ...>
<UserControl.Resources>
<Style x:Key="TestStyle" TargetType="{x:Type Button}">
<Setter Property="Padding" Value="1"/>
</Style>
</UserControl.Resources>
<Grid>
<Button Style="{StaticResource TestStyle}"/>
</Grid>
</UserControl>

Related

Cannot add content to a Custom Control

I'm trying to create a custom version of UserControl to implement some standard animations for views when loading.
But when I add a ContentPresenter I'm not able to add content to my control. Why though?
Here is the Template I use for my custom control.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:EzNintendo.Desktop.Controls">
<Style TargetType="{x:Type local:AnimatedView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:AnimatedView}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
and the default code for a custom control
public class AnimatedView : Control
{
static AnimatedView()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AnimatedView),
new FrameworkPropertyMetadata(typeof(AnimatedView)));
}
}
and
and that is how I try to use it.
<controls:AnimatedView x:Class="MyView"
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:controls="clr-namespace:MControls;assembly=MControls">
<Grid>
<TextBlock Text="Hello World!" />
</Grid>
</controls:AnimatedView>
When I remove the Grid it works just fine.

Where can I put the EventSetter so that its handler is searched in the Control's code-behind, not in the resource dictionary's?

I have a template with a Style that uses an EventSetter to set a common event handler to some Hyperlinks. But I want to handle this event not in the resource dictionary's .cs file but in the custom control's .cs file. How can I do this? I am in the process of moving resources into theme .xaml files. I thought about separating the functionality part of the Hyperlink style, but where should I put the event setter? I thought I can use commands, but is there a more concise tehnique that does not require changing each Hyperlink element and works for elements that do not support commands?
I use .NET Framework 4.7.2. I have made a few searches over the web and a simple test example:
App.xaml
<Application x:Class="wpf_test_2.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:wpf_test_2"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Dictionary.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:wpf_test_2">
<ControlTemplate x:Key="MyControlTemplate">
<ControlTemplate.Resources>
<Style TargetType="Button">
<!-- obviously, this does not compile: -->
<EventSetter Event="Click" Handler="MyHandler"/>
</Style>
</ControlTemplate.Resources>
<UniformGrid Rows="5" Columns="5">
<Button>A</Button>
<Button>B</Button>
<Button>C</Button>
<Button>D</Button>
<Button>E</Button>
<Button>F</Button>
<Button>G</Button>
<Button>H</Button>
<Button>I</Button>
</UniformGrid>
</ControlTemplate>
</ResourceDictionary>
MainWindow.xaml
<Window x:Class="wpf_test_2.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:wpf_test_2"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:MyControl/>
</Grid>
</Window>
MyControl.xaml
<Control x:Class="wpf_test_2.MyControl"
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:local="clr-namespace:wpf_test_2"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Template="{DynamicResource MyControlTemplate}">
</Control>
MyControl.xaml.cs
/// <summary>
/// Interaction logic for MyControl.xaml
/// </summary>
public partial class MyControl : Control
{
public MyControl()
{
InitializeComponent();
}
private void MyHandler(object sender, RoutedEventArgs e)
{
var b = sender as Button;
MessageBox.Show($"Button {b.Content.ToString()} was clicked!");
}
}
Screenshot
Expected: the project compiles, and when I click one of the buttons, a MessageBox appears with the content of the button as string.
Actual: the project does not compile.
Thank you.
Inspired by Clemens' comment, I created a RoutedUICommand, a corresponding command binding, and setters which set Command and CommandParameter:
AboutWindow.xaml
<Window
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:local="clr-namespace:cs_timed_silver"
x:Class="cs_timed_silver.AboutWindow"
mc:Ignorable="d"
Width="448" Height="200" ResizeMode="NoResize"
WindowStartupLocation="CenterOwner"
Loaded="Window_Loaded"
Closed="Window_Closed"
Style="{DynamicResource AboutWindowStyle}">
<Window.CommandBindings>
<CommandBinding Command="{x:Static local:AboutWindow.NavigateCommand}"
CanExecute="CommandBinding_CanExecute"
Executed="CommandBinding_Executed"/>
</Window.CommandBindings>
</Window>
AboutWindow.xaml.cs
public partial class AboutWindow : Window
{
public static RoutedUICommand NavigateCommand { get; set; } =
new RoutedUICommand("", "NavigateCommand", typeof(AboutWindow));
[...]
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
System.Diagnostics.Process.Start(
new System.Diagnostics.ProcessStartInfo((e.Parameter as Uri).AbsoluteUri));
}
Light.xaml
<Style x:Key="AboutWindowStyle" TargetType="local:AboutWindow">
[...]
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<ControlTemplate.Resources>
[...]
<Style TargetType="{x:Type Hyperlink}">
<Setter Property="Command" Value="{Binding NavigateCommand}"/>
<Setter Property="CommandParameter"
Value="{Binding RelativeSource={RelativeSource Mode=Self}, Path=NavigateUri}"/>
</Style>
</ControlTemplate.Resources>
[...]

setter property background doesn't change the background color in WPF

I have a PerformanceMeterStyle.xaml with one property that set's the background to yellow:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:TemplateLearn.Controls">
<Style TargetType="controls:PerformanceMeter" x:Key="PerformanceMeterStyle">
<Setter Property="Background" Value="Yellow"/>
</Style>
</ResourceDictionary>
Then I have PerformanceMeter.cs where my dependency property's will come in. For know it just derives from Control:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace TemplateLearn.Controls
{
public class PerformanceMeter : Control
{
}
}
In my MainWindow.xaml i use my created control:
<Window x:Class="TemplateLearn.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:TemplateLearn"
xmlns:controls="clr-namespace:TemplateLearn.Controls"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<ResourceDictionary Source="Theme/Styles/PerformanceMeterStyle.xaml" />
</Window.Resources>
<controls:PerformanceMeter Style="{StaticResource PerformanceMeterStyle}"/>
</Window>
Why is the background color of my control not changing to the property I set in PerformanceMeterStyle.xaml?
you should create control template for that as follows:
<Style TargetType="controls:PerformanceMeter" x:Key="PerformanceMeterStyle">
<Setter Property="Background" Value="Yellow" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:PerformanceMeter}">
<Border x:Name="border"
Background="{TemplateBinding Background}">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This might actually work, if not let me know.

Default value for property of UserControl

UserControl contains BorderBrush property derived from Control. How can I setup it's default value, for example, to Brushes.Black and make it available to be set by developer who will use my control?
I tried to assign initial value in <UserControl> tag in control's xaml file and in constructor of it, but when I do any of this, value assigned for the control
externally is ignored.
You would usually do this by overriding metadata for the BorderBrush property in your UserControl derived class:
public partial class MyUserControl : UserControl
{
static MyUserControl()
{
BorderBrushProperty.OverrideMetadata(
typeof(MyUserControl),
new FrameworkPropertyMetadata(Brushes.Black));
}
public MyUserControl()
{
InitializeComponent();
}
}
Perhaps styles would be best. You could create a new UserControl, let's call it BorderedControl. I've created a new folder called Controls to hold it.
<UserControl x:Class="BorderTest.Controls.BorderedControl"
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">
<Grid>
</Grid>
</UserControl>
Next, create a Resource Dictionary, UserControlResources. Be sure to include the namespace of the control:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrls="clr-namespace:BorderTest.Controls">
<Style TargetType="{x:Type ctrls:BorderedControl}">
<Setter Property="BorderBrush" Value="Lime"/>
<Setter Property="BorderThickness" Value="3"/>
</Style>
</ResourceDictionary>
Here you can set what ever properties you'd like to have default.
Then, include the resource dictionary in the user control resources:
<UserControl x:Class="BorderTest.Controls.BorderedControl"
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">
<UserControl.Resources>
<ResourceDictionary Source="/BorderTest;component/Resources/UserControlResources.xaml"/>
</UserControl.Resources>
<Grid>
</Grid>
</UserControl>
Finally, add the control to your main window:
<Window x:Class="BorderTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrls="clr-namespace:BorderTest.Controls"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ctrls:BorderedControl Width="100"
Height="100"/>
</Grid>
</Window>
Here is my solution:
Here is the application when you run it:
You can simply change the border of your user control with this:
<ctrls:BorderedControl Width="100"
Height="100"
BorderBrush="Orange"/>

What could be preventing styles from applying to a Silverlight control at runtime?

I wrote a simple Silverlight application. My styles are shown correctly at design time, but when I try to run the application, any styles in resource dictionary file which are merged in app.xaml file are not applied to any control at runtime.
Actually, only UserControl styles don't seem to apply. But the rest are working (like the Button on the page). What could be causing this problem and how can I fix it?
My code is something like this:
Styles.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="UserControl">
<Setter Property="FlowDirection" Value="RightToLeft" />
<Setter Property="FontFamily" Value="Tahoma" />
<Setter Property="Background" Value="Aqua" />
</Style>
<Style TargetType="Button" >
<Setter Property="Background" Value="Aqua" />
</Style>
</ResourceDictionary>
App.xaml:
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Silverlight.Test._01.App"
>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
MainPage.xaml:
<UserControl x:Class="Silverlight.Test._01.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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
<Grid x:Name="LayoutRoot" Background="White">
<Button Content="This is a test" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="button1" VerticalAlignment="Top" Width="220" />
<sdk:Label Height="28" HorizontalAlignment="Left" Margin="12,6,0,0" Name="label1" VerticalAlignment="Top" Width="351" Content="Test label" />
</Grid>
</UserControl>
At least one reason this doesn't work is because you never actually create an instance of UserControl. You actually create an instance of Silverlight.Test._01.MainPage.
In addition unlike Button the UserControl does not set the DefaultStyleKey property on the control to UserControl in fact attempting to set a value into DefaultStyleKey in code behind will result in an exception.
There is no general workaround for this. The closest you can get is to change the default style to a standard keyed resource:-
<Style x:Key="UserControlDefaultStyle" TargetType="UserControl">
<Setter Property="FlowDirection" Value="RightToLeft" />
<Setter Property="FontFamily" Value="Tahoma" />
<Setter Property="Background" Value="Aqua" />
</Style>
Now change your usercontrol xaml to look like:-
<UserControl x:Class="Silverlight.Test._01.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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
Style="{StaticResource UserControlDefaultStyle}"
>
<Grid x:Name="LayoutRoot" Background="{Binding Parent.Background, ElementName=LayoutRoot}">
<Button Content="This is a test" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="button1" VerticalAlignment="Top" Width="220" />
<sdk:Label Height="28" HorizontalAlignment="Left" Margin="12,6,0,0" Name="label1" VerticalAlignment="Top" Width="351" Content="Test label" />
</Grid>
</UserControl>
Note that this isn't a general solution since you need to add the additional Style attribute to each UserControl you create.
Also note the binding on LayoutRoot Background property. The UserControl.Background property actually does nothing, you pass this value on to the child control for it have any effect.

Categories

Resources