How to create custom controls using generic.xaml in Silverlight 5 without using WPF? - silverlight

I want to create a custom controls datagrid using the generic.xaml.I have created the custom controls using the User control template in Silverlight 5. I am not using WPF.
How is it possible to create using generic.xaml?

What you describe is called a Templated Control in Silverlight.
You have to provide three things:
a class containing your control's logic
a default Style with a ControlTemplate
an entry in generic.xaml that includes the default Style
Example: MyFeeblefezer.cs
public class MyFeeblefezer : Control
{
public MyFeeblefezer() { DefaultStyleKey = typeof(MyFeeblefezer); }
}
and MyFeeblefezer.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="MyFeeblefezer">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="MyFeeblefezer">
<Grid>
<!-- here goes your visible control UI parts -->
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
and themes/generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyFeebleProject;Component/MyFeeblefezer.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

Related

Using BasedOn Style with static ResourceDictionary in different Assembly

Background
I have multiple projects in my solution and in one project I've made a static class containing a merged ResourceDictionary, which I use in all my other projects:
namespace GUI.Shared.Resources
{
public static class ResourceFactory
{
public static ResourceDictionary _resources = null;
public static ResourceDictionary Resources
{
get
{
if (_resources == null)
{
_resources = new ResourceDictionary();
_resources.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("pack://application:,,,/GUI.Shared;component/Resources/VectorIcons.xaml") });
_resources.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("pack://application:,,,/GUI.Shared;component/Resources/ButtonStyles.xaml") });
}
return _resources;
}
}
}
}
With my styles defined in the xaml files ButtonStyles.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="SpecialButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Red"/>
</Style>
</ResourceDictionary>
Normally I use the style like this:
<UserControl x:Class="GUI.Modules.TextControl.Views.TextControlView"
x:Name="TextControl"
xmlns:resources="clr-namespace:GUI.Shared.Resources;assembly=GUI.Shared">
<Grid>
<Button Style="{Binding Path=[SpecialButtonStyle], Source={x:Static resources:ResourceFactory.Resources}}">
</Grid>
</UserControl>
Problem
Now I want to extend my style locally in a View. I found out that you do this by using the BasedOn property.
<Button>
<Button.Style>
<Style TargetType="Button" BasedOn="{Binding Path=[SpecialButtonStyle], Source={x:Static resources:ResourceFactory.Resources}}">
</Style>
</Button.Style>
</Button>
Only my binding method is not allowed, giving the error:
A Binding cannot be set on the BasedOn property of type Style. A Binding can only be set on a DependencyProperty of a DependencyObject.
How can I use this style from my ResourceFactory.Resources as a BasedOn style?
The BasedOn property is a regular CLR property, not a dependency property, which means you cannot bind it. Furthermore the indexer syntax among other binding path constructs are only available in the Binding markup extension, not in x:Static, StaticResource or DynamicResource.
You can create your own markup extension based on the x:Static implementation, but that is very complex and the wrong thing to do. Instead, you should think about following a different built-in approach to your issue.
If you want to share resources, why create a static ResourceFactory at all? WPF already supports resource provision with the App.xaml resource dictionary and scoped resources within each FrameworkElement through the Resources property. Create a resource dictionary for your shared resources e.g. like this:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/GUI.Shared;component/Resources/VectorIcons.xaml"/>
<ResourceDictionary Source="pack://application:,,,/GUI.Shared;component/Resources/ButtonStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
As you can see, this is the same as your ResourceFactory, but easier to use. Include this dictionary into the application resources or any other resources section of any project using a pack URI e.g.:
<UserControl x:Class="GUI.Modules.TextControl.Views.TextControlView"
x:Name="TextControl"
xmlns:resources="clr-namespace:GUI.Shared.Resources;assembly=GUI.Shared">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/GUI.Shared;component/Resources/SharedResourceDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Button>
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource SpecialButtonStyle}">
<!-- ...your style definition. -->
</Style>
</Button.Style>
</Button>
</Grid>
</UserControl>
There is no need for Binding here and it is much easier to access resources this way. You can access the resources in child controls, too, because access to resources is scoped to where they are defined.

How to Apply Theme to Custome Control Inherited from Textbox

I have created a WPF Control That Inherits from a Textbox
I have added Theme BureauBlue to my project and added the following XAML to my Application.xaml
<Application.Resources>
<ResourceDictionary Source="Themes/BureauBlue.xaml"/>
</Application.Resources>
I want the same theme to be applied to my Custom Control that Inherited from
the TextBox
How can I achieve this
Amit Saraf
Edit Changes Made as per suggestion
<Application.Resources>
<ResourceDictionary Source="Themes/BureauBlue.xaml"/>
<Style TargetType="WPFControls:MyTextBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<TextBox Text="{TemplateBinding Text}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
Error
The property "Resources" can only be set once.
The specified value cannot be assigned. The following type was expected: "ResourceDictionary".
If a Style Targeted to Textbox will not apply for its custom control( control which inherits from Textbox. If you know the BureauBlue's style, place it in your App Resource as a new style which is targeted to your derived class name and if you dont know that style, I can suggest a workaround for this.
Create a new style targeted to your custom control and define a Template in it as follows
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/BureauBlue.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="WPFControls:MyTextBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<TextBox Text="{TemplateBinding Text}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Application.Resources>
Note: Template bind the properties which you tend to use in your custom control class.
Here the Style which is targeted to Textbox will apply to the your custom control

Generic.xaml not used in custom WPF control

I am using Visual Studio express, so do not have the WPF Custom Control Library project type. Using snoop I can see that the style is not used at all, however if I put the style in Window.Resources it works.
My structure is as follows:
MyApp.Controls
- Themes (Folder)
- generic.xaml (build action "Content", no custom tool)
MyApp
*References MyApp.Controls*
At the end of MyApp.Controls.Properties.Assemblyinfo.cs I have:
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
generic.xaml content:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:MyApp.Controls">
<Style TargetType="{x:Type controls:LogView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:LogView}">
<TextBlock>Hello!</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
The log view class itself has the following:
public class LogView : Control
{
static LogView()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(LogView),
new FrameworkPropertyMetadata(typeof(LogView)));
}
Any ideas what may still be missing, or is something I've done wrong?

Apply themes to wpf and use styles

I am trying to apply a theme to a bunch of wpf projects. There is one assembly containing the generic.xaml and different applications. As far as i understand i can't use the ThemeInfo attribute with ResourceDictionaryLocation.ExternalLocation because the name have to be the same as my program but I have more than one program...
So I search and found that I only have to include the dictionary as MergedDictionary in the app.xaml
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ClassLibrary1;component/Themes/generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
This basically works. But if I use a style for the controls it will not apply the generic.xaml style anymore:
generic.xaml in ClassLibrary1.dll
<ResourceDictionary x:Class="ClassLibrary1.Themes.generic"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="{x:Type Button}">
<Setter Property="Background"
Value="Black" />
</Style>
Window in program
<Window x:Class="Theming.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>
<Style TargetType="Button"
x:Key="ButtonGreenTextStyle">
<Setter Property="Foreground"
Value="Green" />
</Style>
</Window.Resources>
<Grid>
<Button Style="{DynamicResource ButtonGreenTextStyle}" Content="Test" />
</Grid>
</Window>
What I have to do, that WPF will understand the style in my generic.xaml as basestyle for all buttons (I know I will also have to write a ControlTemplate; the above code is just for simplicity)
Two things I would try
Create a generic ButtonBase style/template to set the look of all
buttons
Try using a BasedOn attribute on the ButtonGreeTextStyle,
basing it on an existing style.
I found another solution. You have to write styles based on a custom markup:
This will apply the current theme style. The code for this MarkupExtension can be found here:
How do I alter the default style of a button without WPF reverting from Aero to Classic?

Loading WPF Style from Resource File

I am trying to load WPF Style from other file actually from WPF Custom Control Library
but i am failing to load here is my solution.
The solution contains two projects
WpfTestControls of Type WPF Custom Control Library
WpfTestApp of type WPF Application Library which has reference to WpfTestControls
MainWindow.xaml from WPF Application Library
<Window.Resources>
<Style x:Key="TempStyle" TargetType="{x:Type TextBox}">
<Setter Property="BorderBrush" Value="Green"/>
</Style>
</Window.Resources>
<Grid>
<TextBox Height="50px" Width="100px" Style="{DynamicResource TempStyle}"/>
</Grid>
Generic.xaml from WPF Custom Control Library
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/WpfTestControls;component/TextBoxStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
TextBoxStyle.xaml from WPF Custom Control Library
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="TempStyle" TargetType="{x:Type TextBox}">
<Setter Property="BorderBrush" Value="Green"/>
</Style>
My AssemblyInfo.cs file contains the following
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries))]
But still i am failing to load the Style.
If i am using the not using the Generic.xaml everything work fine for example the following code works as expected
<Window x:Class="WpfTestApp.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>
<Style x:Key="TempStyle" TargetType="{x:Type TextBox}">
<Setter Property="BorderBrush" Value="Green"/>
</Style>
</Window.Resources>
<Grid>
<TextBox Height="50px" Width="100px" Style="{StaticResource TempStyle}"/>
</Grid>
What am i doing wrong ?
Thanks in advance
Please answer few things for me...
Is "WPF Custom Control Library" assembly same as "WpfTestControls" assembly?
If not, then does "WPF Custom Control Library" have a reference to the "WpfTestControls" assembly?
Does your WpfTestApp have a reference to both "WPF Custom Control Library" and "WpfTestControls" assemblies?
If you add that reference(s), the resources should load correctly.
My Steps...
Add a "WPF Custom Control Library" say "ThemesLibray"
In this add two resource dictionaries under "Themes" folder
TextBoxStyle.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="GreenTextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="Green"/>
</Style>
</ResourceDictionary>
Generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="TextBoxStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
I have main starup project "MyWPFTestApp" that has assembly reference to ThemesLibray. In that the window has ThemesLibrary resources merged this way....
<Window x:Class="MyWPFTestApp.Window7"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window7" Height="300" Width="300">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="/ThemseLibrary;component/Themes/Generic.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<TextBox Style="{StaticResource GreenTextBoxStyle}"/>
</Grid>
</Window>
When I launch MyWPFTestApp, I see the Window with green TextBox.
Main thing is : Make sure you have Build Action of your Resource Dictionary set to Resource.

Resources