So we are trying to retemplate some stock wpf controls by changing their default styles in the generic.xaml
When we normally do this we subclass a control and then override the default style key of the subclassed control in its static initializer. However, we are trying to just override the basic control now without subclassing it. That way anyone in the company using the stock wpf control will get our new styling by default.
I can't seem to get this to work though.
In my sandbox application which is a watered down version of our actual problem, I have the following.
MainWindow.xaml
<StackPanel>
<TextBlock>It doesn't work</TextBlock>
<local:CustomTextBlock>It works</local:CustomTextBlock>
</StackPanel>
Themes/Generic.xaml
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="100" />
</Style>
<Style TargetType="{x:Type test:CustomTextBlock}">
<Setter Property="FontSize" Value="100" />
</Style>
CustomTextBlock.cs
public class CustomTextBlock : TextBlock
{
static CustomTextBlock()
{
Type _CustomTextBlock = typeof(CustomTextBlock);
DefaultStyleKeyProperty.OverrideMetadata(
_CustomTextBlock,
new FrameworkPropertyMetadata(_CustomTextBlock));
}
}
Which results in this being displayed.
My theory is that the WPF engine is ignoring our style because the default style key is either A: not overridden or B: is finding their style in their generic.xaml first.
My question is, is there a work around for this? Are my assumptions correct?
UPDATE:
According to reference source, the default style key is overridden in the stock wpf control for TextBlock.cs in this case
Reference Source TextBlock.cs (Line 346)
To accomplish this, you can put your styles either directly into App.xaml or into a separate ResourceDictionary (named DefaultStyles.xaml).
Putting directly into App.xaml is easy enough, just put the style within the Resources element.
If you want to put the styles into a file (this is useful if you want the styles for multiple applications or within multiple assemblies) you add it to the MergedDictionaries of your App.xaml as such
<Application x:Class="MyAwesomeApp"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/DefaultStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
This assumes that you put the file DefaultStyles into the Themes folder. If it is in another assembly you would do the following:
<ResourceDictionary Source="/Company.Controls.UI;component/DefaultStyles.xaml"/>
Have a look at this post (What is so special about Generic.xaml).
The main issue seems to be:
WPF looks for the default style in a special resource dictionary in the Themes folder in the same assembly as the control.
'Your' control is defined in 'your' assembly, TextBlock is defined in PresentationFramework. So you better create another ResourceDictionary for re-styling standard controls and include/merge it in each of your xaml documents (I suppose, this hurts).
Hope it helps.
I am using GraphX in Winform project. I am trying to display labels besides the edges. I want to know what property do I have to set in order to display some text in the label.
I have tried setting the 'Text' property of DataEdge, and then calling
ShowAllEdgesLabels(true);
but it does not work this way. Going through the forums I have found that WPF has a way to bind this property to the visual control. The XAML code is as follows
<gxl:EdgeLabelControl x:Name="PART_edgeLabel" Content="{Binding Edge.Text, RelativeSource={RelativeSource TemplatedParent}}" />
Now the question is what is the equivalent of Winform to achieve this functionality.
I found a solution with the help of the admin at the host of GraphX (PantheR).
Basically, we need to add the hostControler for WPF in a windows form.
We need to add a custom XAML template in the resources folder.
We need to load the XAML as a new resource in the code, before we initialize the graph.
We need to add a line of code to merge the resources.
Then in the XAML code we do the binding as mentioned in the question. The code has been updated at the repository to reflect these changes.
The downfall of this solution is that, we need to provide a XAML resource file with the program, but thats just another resource (in my opinion).
For anyone that need some reference code from #ResVic's answer:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:graphx="http://schemas.panthernet.ru/graphx/"
xmlns:local="clr-namespace:YOUR_NAME_SPACE">
...
<Style TargetType="{x:Type graphx:AttachableEdgeLabelControl}">
<Setter Property="ShowLabel" Value="False" />
</Style>
...
</ResourceDictionary>
The Show case demo is protentially helpful for figuring out what stuff the lib could do and how to tweak it to work.
Library.xaml
<ResourceDictionary>
<ControlTemplate x:Key="test" TargetType="{x:Type Button}">
<Button Width="200" Height="40" Name="my_custom_btn" Click="r_Click_1" Style="{StaticResource button_style}">Button</Button>
</ControlTemplate>
</ResourceDictionary>
I want to access this Button element defined within my ControlTemplate from my C# file when template is not applied in Main.xaml.
I have tried all methods
Template.FindName, Application.Current.Resource, Control.GetTemplateChild(), using VISUALTREE HELPER search but i am not getting this element in my c# code.
As far as I know these methods are used to find elements when a control template which is defined somewhere in Library.xaml is loaded in Main.xaml file by giving its TargetType.
But what if this template is not applied and Still I want to access its element from my code.
I have looking for a proper solution for a past few days. plz help!!
Please explain it fully as I am new to WPF..
Is there a way to change the style of checkboxes when the ItemsOptionListType="CheckList"
inside a RadTreeView?
There are a couple of ways of doing this that I can think of, but sadly neither of them is particularly easy.
One way is to use Blend or a similar tool to obtain the template for the RadTreeViewItem class. The RadTreeViewItem class and its template are in the Telerik.Windows.Controls.Navigation assembly. Take a copy of this template and modify the CheckBox within this template to customise its appearance as you wish.
To use the template, add a ControlTemplate and a Style to the <UserControl.Resources> element of a XAML page, as follows:
<UserControl.Resources>
<ControlTemplate x:Key="myRadTreeViewItemTemplate" TargetType="telerik:RadTreeViewItem">
<!-- modified template goes here... -->
</ControlTemplate>
<Style TargetType="telerik:RadTreeViewItem">
<Setter Property="Template" Value={StaticResource myRadTreeViewItemTemplate}" />
</Style>
</UserControl.Resources>
This should then apply the modified template to any RadTreeViews in the same XAML file.
Note that we have to use an implicit style (i.e. one without an x:Key), since there seems to be no other way to tell a RadTreeView to apply a given style to its child items.
Alternatively, you can modify a built-in theme. This approach could also change the styles of CheckBoxes used within other Telerik controls in your application, for example in a GridViewCheckBoxColumn within a RadGridView.
EDIT: if you want the template for the CheckBox as used in the RadTreeView by default,
you'll find it in Themes\Office\Black\System.Windows.Controls.xaml within the Telerik.Windows.Controls assembly. This assumes you're using the 'Office Black' theme; adjust the path of this file if you're using a different Telerik theme.
I have the following scenario:
Create a new class library project called Lib1
1.1. Add a new control called control1, Themes/generic.xaml file and specify
the default style of control1.
Create a new class library project called lib2.
2.1.Add a new control called control2, Themes/generic.xaml file and specify
the default style of control2. In the dafaultStyle of control2 I use control1.
My question is: Do I have to copy/paste the defaultStyle xaml of control1 into the
generic.xaml of lib2, to use control1 with its style applied in control2?
The default style lookup for a Control is always done in the assembly that the Control is defined in. So if Control1 is defined in Lib1.dll, the default style will always be looked for in generic.xaml in Lib1.dll. It doesn't matter where the Control is being used from.
Just to make sure I understand your answer correctly, I will restate it in my own words:
You want to have a Silverlight class
library (Lib1) that houses a control
(Control1).
You want to have a
Silverlight class library (Lib2)
that houses a control (Control2).
You want to have the control use their respective generic.xaml files for respective control styles.
Control2 is to include Control1 in its style definition, without redefining its style in the generic.xaml file from Lib2.
If this is correct, I will describe my answer below:
Yes, this is possible as Keith Mahoney said here. I will go into detail on his answer and an example.
Each Silverlight class library generates a Dynamic-link library (dll) when compiled. All the classes (controls) and resources (styles) are contained in these dll's. Thus, when you create a lib1 class library with a style resource for a control contained within, it will all be stored in the lib1 dll.
Below is my example of the solution:
Setting up the solution:
First, I created new solution (StackOverflow Example.sln). Then I added a new project to the solution of type Silverlight Class Library (Lib1 1.1). Please note that Silverlight does not always play nicely with spaces in the namespace, so you may want to (as I did) rename the namespace to Lib1. See "How-To's" section for details on how to do this. Next I added the second project to the solution of type Silverlight Class Library (Lib2 2.1). I again, changed the root namespace of this project to one without spaces. Finally, I added a Silverlight Application project to my solution (SLApplication). Please note that in adding the Silverlight application project, you will be prompted to add a web project or web page to your project for creating the Silverlight control. Either option will work, please use the best for your situation. I used the separate website option (default). Now, when we setup the two class libraries, we were given a default starter class1.vb file. Let's rename these file to Control1.vb (for Lib1 1.1) and Control2.vb (for Lib2 2.1) in the solution explorer. When we do this, Visual Studio 2008 asks us if we'd like it to rename the class to match this new name, Click 'Yes'. Next up, let's figure out how to setup the themes for each of our controls.
Setting up themes:
I will start with the first control library (Lib1 1.1). First, create a new folder under the root of the project; name it "Themes" (case doesn't matter). Under this folder, add a new item of type xml and name it generic.xaml. For help on how to do this, see the "How-To's" section. Open the generic.xaml file, if it isn't already open. Delete the xml declaration text that was automatically inserted for you, and use the following for your initial definition:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Styles go here. -->
</ResourceDictionary>
Now, since our Control1 control lives in this class library, we will need to add an xml namespace declaration (xmlns) (http://en.wikipedia.org/wiki/XML_namespace -sorry about the non link, my rep needs to be higher.) to our generic.xaml file. To do this, add the following line: xmlns:lib1="clr-namespace:Lib1" before the grater than symbol (>) in the top declaration. Once this is done, we can layout a simple style. Please note that we're setting the default background color to "Red" in order to differentiate the two controls. Please see below for the simple style for Control1:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lib1="clr-namespace:Lib1">
<!-- Style for Control1 -->
<Style TargetType="lib1:Control1">
<Setter Property="Background" Value="Red" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="lib1:Control1">
<Grid x:Name="LayoutGrid" Background="{TemplateBinding Background}">
<TextBlock Text="Control 1" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
With this let's start with the Control2. This will be very similar to the previous declaration for Lib1 1.1. If you haven't already done so, please add the Themes folder and the generic.xaml file as you did for the first library (Lib1 1.1). Now, for this project, you will need a reference to the Lib1 1.1 project. If you need help doing this, please see the "How To's" section. Once this is referenced, open the generic.xaml file, if it isn't already open. The definition of this file is almost identical; however, we will also be referencing the other projects namespace as well. See below:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lib2="clr-namespace:Lib2"
xmlns:lib1="clr-namespace:Lib1;assembly=Lib1">
<!-- Styles go here. -->
</ResourceDictionary>
Notice that now we are not only referencing our own namespace (lib2) but also referencing the other control's namespace (lib1) in the xml namespace declaration. Also notice that in the non-local control library, we also must reference the assembly name. Since we want to use the control (and its style) from lib one, we will need a place to use it in this project. For this, I have setup a grid with separate rows for each control. Please note that we're setting the default background color to "Blue" in order to differentiate the two controls. Please see below for Control2's definition:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lib2="clr-namespace:Lib2"
xmlns:lib1="clr-namespace:Lib1;assembly=Lib1">
<!-- Style for Control2 -->
<Style TargetType="lib2:Control2">
<Setter Property="Background" Value="Blue" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="lib2:Control2">
<Grid x:Name="LayoutGrid">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<lib1:Control1 Grid.Row="0" />
<Grid x:Name="Control2" Grid.Row="1" Background="{TemplateBinding Background}">
<TextBlock Text="{TemplateBinding Text}" />
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
This just sets up the fact that we want to have styles. We now need to tell Silverlight that we want these styles to be applied to our controls.
Using themes:
In our classes, we have to tell Silverlight that these are going to be custom user controls, to do this, we need to inherit from Control (or any other UIElement control - for this example, we will stay simple, and use Control). In order to tell the control to use a style defined in the generic.xaml, we need to do this in our constructor of each control.
For Control1:
Public Sub New()
MyBase.DefaultStyleKey = GetType(Control1)
End Sub
For Control2:
Public Sub New()
MyBase.DefaultStyleKey = GetType(Control2)
End Sub
Now all we have to do now, is tell our web site to use our new control(Control2).
Setting up the WebApplication:
You will need to reference both class libraries from your web project. See "How-To's" section for details on how to do this. Open up the Page.xaml file in your web application project (SLApplication). Your default should look something like this:
<UserControl x:Class="SLApplication.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
</Grid>
</UserControl>
We will add to this the xml namespace declaration for our Silverlight class library (Lib2 2.1) so that we may reference Control2. Now that we have referenced our class library, we can use any controls that are declared within. If you try to use the namespace without building after you add it to your xmlns declaration, you may not see any declared classes (controls) within. To fix this, build once. Please also note, that Visual Studio 2008 is sometimes weird about custom libraries, and may generate an error that says the custom library is not defined. This is fixed with a re-launch of the solution (Close Visual Studio and reopen). The final code to show the Control2 (which contains Control1) is as follows:
<UserControl x:Class="SLApplication.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lib2="clr-namespace:Lib2;assembly=Lib2"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<lib2:Control2 />
</Grid>
</UserControl>
Now build, and run. If everything went well, you should see the following:
Screen Shot http://www.imagefrog.net/out.php/i40631_StackOverflowExample.jpg
The full project can be downloaded from Google Code:
http://code.google.com/p/stackoverflow-answers-by-scott/wiki/1366075
Zipped source:
http://stackoverflow-answers-by-scott.googlecode.com/files/1366075.zip
Enjoy!
How-To's:
Change project namespace
In the solution explorer expand the project on which you want to change the namespace, and double click on the "My Project". For Silverlight class library projects, you will have four tabs on the left, one of which is "Silverlight". Select this tab, if it is not already selected. Under the "Root namespace" textbox, change the namespace to your desired namespace.
Add 'generic.xaml' to project
In the solution explorer, right click on the project name. Click "Add", and then click "New Folder". This will create a folder under the root of the project. Name this folder "themes". Please note that case does not matter here. Right click on the "themes" folder, click "Add", then click "New Item...". A dialog box appears for you to select what item type you want to add. Click "XML File" under the Templates section. Change the name to generic.xaml under the name field (at the bottom of the dialog). Click Add.
Create a project reference
To create a project reference, right click on the project that needs the reference. Select "Add Reference..." from the menu. A dialog box will be displayed for you to choose the reference to add. Select the "Projects" tab at the top of this dialog. Select the desired project reference. If you do not see the project that you want to reference in this list, check that you have added the project to the solution.