I'm trying to use a StaticResource in a ControlTemplate for a custom object, and whenever that object is rendered, the application crashes. As you can see in the code below, I define both the template and the resource in App.XAML. I've been doing a bit of searching to see if/why this isn't allowed, but have had no luck so far.
<Color x:Key="PersonBackground">#FF003B00</Color>
<ControlTemplate x:Key="PersonTemplate" TargetType="this:Person">
<Border Background="{StaticResource PersonBackground}" BorderBrush="White"
BorderThickness="2" CornerRadius="10" MinHeight="70" MinWidth="120">
...
</ControlTemplate>
If anyone could explain why this isn't allowed or what I'm doing wrong (or, best yet, a better way to do custom theming in Silverlight), I would greatly appreciate it.
Edit: I feel like I should specify that I'm mostly just interested in being able to set the color scheme in one place; the rest of the theme won't need to change as much.
Instead of Color, can you try using a SolidColorBrush
<SolidColorBrush x:Key="PersonBackground" Color="#FF003B00"/>
Related
In our app we use 3rd party library components.
I need to change only one value in whole template. How can I archieve this without redefine template?
For example, controlTemplate:
<ControlTemplate TargetType="{x:Type Label}">
<Border x:Name="PART_MainBorder"
BorderBrush="Black"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter/>
</Border>
</ControlTemplate>
I need to change PART_MainBorder.BorderBrush. How can I do this?
I have found this link, but I can't believe there is no other way to do it..
Thanks.
I'm sure there are more elegant ways to do it in XAML but to answer your question template is nothing more but a cookie cuter so you cannot just start changing properties of template objects in code behind. You can modify template controls properties via control to which the template has been applied. In case of ControlTemlate it will be templated control and for DataTemplate it will be ContentPresenter used to generate content. So let's say that you have 2 Labels to which you applied template above:
<Label Content="A" x:Name="Label1"/>
<Label Content="B" x:Name="Label2"/>
an then in the code you can change Border.BorderBrush like this:
(Label1.Template.FindName("PART_MainBorder", Label1) as Border).BorderBrush = new SolidColorBrush(Colors.Red);
(Label2.Template.FindName("PART_MainBorder", Label2) as Border).BorderBrush = new SolidColorBrush(Colors.Orange);
worth noting that 2 Labels will have different BorderBrush color
In my current project I have a quite large WPF based application with lots of Static and DynamicResources.
Because of many refactorings and changes in the past there are lots of DynamicResources that can not be found during runtime and therefore no value is applied.
What I like to do is run the application and get an output, exception or whatever when a DynamicResource could not be found.
I have tried to build a DefaultTraceListener and a Converter that checks for unused DynamicResources, but to no avail.
Does anyone have a solution for me on how to achieve that?
Example:
<Grid.Resources>
<Style x:Key="myStyle1" TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="Blue"></Setter>
</Style>
</Grid.Resources>
<StackPanel>
<TextBlock Style="{DynamicResource myStyle1}">DynamicResource exists</TextBlock>
<TextBlock Style="{DynamicResource myStyle3}">DynamicResource does not exist</TextBlock>
</StackPanel>
How can I be informed during runtime that myStyle3 does not exist?
Thanks in advance !
There are many tools that show you witch binding doesn't work..
WPF Inspector is my favorite tool, take a look. WPF Inspector
Snoop utility is one of those. In short - in the top right corner you'll find DropDown list which allows filter visuals, just select Visuals with binding Error. Source: How to locate the source of a binding error?
In Visual Studio, you can enable all exceptions (with binding errors) in the Debug menu, Exceptions, then check everything.
But I don't know if it's exactly what you want, let other people answer this...
I'm facing a problem that I assumed would be very easy to solve but... Turns out it's not that easy.
Here is the situation: I created a custom UserControl which inherits from WPFToolkit's DataGrid (I'm required to work in .NET 3.5 :/ ).
This control is a matrix displaying financial values, and user should be able to choose the display format (percentage, absolute, percentage with 1 or 2 decimals...).
And... Maybe I'm just stupid here, but I can't solve it.
My control has a custom DependencyProperty which contains a full market data referential, and then dispatches specific parts of the referential to specific properties (for example, the prices difference go to ItemsSource).
Since users can change what is displayed(prices, price difference, yesterday's prices, other random financial stuff...), the display format will regularly change AND user should be allowed to select it itself.
My cells just follow a Style defined in my ResourceDictionary:
<Style x:Key="CellStyle" TargetType="{x:Type tk:DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type tk:DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I won't work with Binding's StringFormat cause I don't bind the ItemsSource (I set it in the code behind when the market referential property changed)
I already saw this answer, proposing a converter
However, seems like I don't know where should I add a converter to the cells...
Any ideas?
Thanks!
I finally solved this problem by adding a logical step in my Binding: now I set my ÌtemsSource to a string[] which is generated from the original double[], using ToString(CurrentFormat) when needed :)
I have a Header style for my datagrid custom header. I am using theme for my application. The problem here is the header background of the datagrid is not changing however when I remove the styles, the header background has no problem, it change.
Here's the themes
Here's my sample application, right click the grid and context menu will appear for the list of themes, select the different themes. I have two columns namely, with header style and without header style. See the difference. Thank you for your help.
<Style x:Key="DataGridHeaderStyle" TargetType="primitive:DataGridColumnHeader">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding}" Grid.Column="0" HorizontalAlignment="Left" />
<filter:DataGridColumnFilter Grid.Column="1" HorizontalAlignment="Right" />
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Thank you
I did a quick test, and it does not seem to work with either the tag approach or the ImplicitStyleManager attribute approach. This is probably because the style setter is outside the scope and therefore gets applied without a theme.
Suggestion 1: Look at the way that the Jet Pack theme handles it with resource dictionaries in App.xaml, and try to do something similar. (You will need the theme.xaml file for this. EDIT: This link might help.) If you want to change the theme dynamically, then consider this (old) post about swapping themes in resource dictionaries (I haven't tried it, but it should work).
Suggestion 2: You need to think about style inheritance. Since "BasedOn" needs an x:Key tag, you could instead copy the theme's implicit DataGridColumnHeader style and only modify the parts you are interested in. (I don't know if there's a more elegant way.)
If this is not what you meant, then please provide more sample code.
EDIT [2010-12-09]:
I looked at the code, and I believe the root of the problem is the absence of style inheritance. Your "DataGridHeaderStyle" is saying "Do not use the normal DataGridColumnHeader style, but instead use this TextBlock inside this Grid." So Silverlight does just that: it gives you a styled TextBlock in an unstyled default DataGridColumnHeader.
Proof: Update your "Home.xaml" and add a TextBox in the second column of your "DataGridHeaderStyle" style, next to the current TextBlock. Notice how the theme for the TextBox in the header is changing every time you change the theme (look at the TextBox backgroud), but the background of the column header is stuck on the default colour. Like I said, your custom style is telling Silverlight to ignore the implicit style.
FIX: I do not know how to inherit from implicit styles without an "x:Key" attribute. I googled quite a bit but could not find anything helpful. You will either have to a) create a custom column definition style for all your datagrid headers, or you will have to b) bother the Silverlight team for a new feature in the next version of Silverlight. Or c) pick one theme to stick with and edit a copy of the theme's implicit column header style as your new "DataGridHeaderStyle" style.
My holiday is about to start, so I hope this helped. At least now you know where the problem lies.
What is the difference between these 2 bindings:
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderBrush="{TemplateBinding Property=Background}">
<ContentPresenter />
</Border>
</ControlTemplate>
and
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderBrush="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}">
<ContentPresenter />
</Border>
</ControlTemplate>
?
TemplateBinding is not quite the same thing. MSDN docs are often written by people that have to quiz monosyllabic SDEs about software features, so the nuances are not quite right.
TemplateBindings are evaluated at compile time against the type specified in the control template. This allows for much faster instantiation of compiled templates. Just fumble the name in a templatebinding and you'll see that the compiler will flag it.
The binding markup is resolved at runtime. While slower to execute, the binding will resolve property names that are not visible on the type declared by the template. By slower, I'll point out that its kind of relative since the binding operation takes very little of the application's cpu. If you were blasting control templates around at high speed you might notice it.
As a matter of practice use the TemplateBinding when you can but don't fear the Binding.
TemplateBinding - More limiting than using regular Binding
More efficient than a Binding but it has less functionality
Only works inside a ControlTemplate's visual tree
Doesn't work with properties on Freezables
Doesn't work within a ControlTemplate's Trigger
Provides a shortcut in setting properties(not as verbose),e.g. {TemplateBinding targetProperty}
Regular Binding - Does not have above limitations of TemplateBinding
Respects Parent Properties
Resets Target Values to clear out any explicitly set values
Example: <Ellipse Fill="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Background}"/>
One more thing - TemplateBindings don't allow value converting. They don't allow you to pass a Converter and don't automatically convert int to string for example (which is normal for a Binding).
TemplateBinding is a shorthand for Binding with TemplatedParent but it does not expose all the capabilities of the Binding class, for example you can't control Binding.Mode from TemplateBinding.
I thought TemplateBinding does not support Freezable types (which includes brush objects). To get around the problem. One can make use of TemplatedParent
They are used in a similar way but they have a few differences.
Here is a link to the TemplateBinding documentation:
http://msdn.microsoft.com/en-us/library/ms742882.aspx