Expression Blend, an ItemTemplate and an Implicit Style - wpf

I'm having an issue with Blend not rendering items in a DataTemplate styled implicity.
I've setup a basic project to replicate the issue. Below is the Xaml + ResourceDictionary for those with Eagle eyes to see what I'm doing wrong (if anything) and if you're really keen theres a link to the Zipped project below.
This is what renders when the application is run:
and this is what Blend presents:
<Color x:Key="TextColor1">#FF3631C4</Color>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="TextWrapping" Value="NoWrap"/>
<Setter Property="TextTrimming" Value="None"/>
<Setter Property="Foreground">
<Setter.Value>
<SolidColorBrush Color="{DynamicResource TextColor1}"/>
</Setter.Value>
</Setter>
</Style>
<Canvas x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource SampleDataSource}}">
<TextBlock Text="Textblock" Canvas.Left="44.954" Canvas.Top="49.305" />
<TextBlock Text="Textblock 2" Canvas.Left="44.954" Canvas.Top="86.284" />
<ListBox ItemsSource="{Binding Collection}" Canvas.Left="134.016" Canvas.Top="29.026" Height="154.275" Width="384.575">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Property1}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Canvas>
Complete Example Project (65kb) - WpfApplication2.zip
The problem can of course be solved by explictly setting the style, but in my main project this will cause a bit of a headache.
I've seen some comments on other posts around that Blend may have issues but nothing concrete.
Any thoughts / suggestions?
Thanks!
Edit:
I discovered that if I give my style an Explicit Key, I can then create an Implicit Style based on the Explicit like so:
<Style x:Key="TextBlockStyle1" TargetType="{x:Type TextBlock}">
<Setter Property="TextWrapping" Value="NoWrap"/>
<Setter Property="TextTrimming" Value="None"/>
<Setter Property="Foreground">
<Setter.Value>
<SolidColorBrush Color="{DynamicResource TextColor1}"/>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource TextBlockStyle1}" />
This then gives me the ability to add another Implicit Style as a Resource in my DataTemplate:
<DataTemplate>
<DataTemplate.Resources>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource TextBlockStyle1}"></Style>
</DataTemplate.Resources>
<TextBlock Text="{Binding Property1}" />
</DataTemplate>
This will then give me the blendability I'll need in my main Project but still doesn't quite answer my original question.

Firstly Blend is written in WPF and XAML.
So Blend has its own application style and as your application also defines global styles, in order not to merge them it will be applying them differently and there is probably a bug in the method they used to apply those styles.
This is my guess why this is happening.
It doesn't solve the problem though, but might help you to find out other workarounds.

Related

WPF/Designer: ItemContainerStyle RadioButton as ToggleButton. Works when in runtime but fails in designer

I have a ItemsControl with an ItemContainerStyle based on ToggleButton.
This works just fine at runetime, but it casts an error in the designer. (So I have to comment it out if i want to use the designer)
I populate this with code behind. Using RadioButtons.
InvalidOperationException: A style intended for type 'RadioButton' cannot be applied to type 'ContentPresenter'.
Iv lived with this for along time now, but its time to see if there is a solution!
Any ideas how to work around this?
<ItemsControl x:Name="BrushButtons"
Grid.Row="1"
Grid.Column="3"
VerticalAlignment="Bottom">
<ItemsPanelTemplate>
<StackPanel VerticalAlignment="Bottom" Orientation="Vertical" />
</ItemsPanelTemplate>
<ItemsControl.ItemContainerStyle>
<Style BasedOn="{StaticResource {x:Type ToggleButton}}" TargetType="{x:Type RadioButton}">
<Setter Property="LayoutTransform">
<Setter.Value>
<RotateTransform Angle="-90" />
</Setter.Value>
</Setter>
<Setter Property="Width" Value="70" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
Kind Regards.

DataGrid Style template not applying to All DataGrids

I have a Style that I am trying to apply to a DataGrid, but it only works if i give it a key and explicitly say to use it.
<Application ...>
<Application.Resources>
<Style TargetType="{x:Type Control}" x:Key="ErrorStyle">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Right"
Foreground="Orange"
FontSize="12pt">
!!!!
</TextBlock>
<Border BorderBrush="Green" BorderThickness="1">
<AdornedElementPlaceholder />
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="TextBox" BasedOn="{StaticResource ErrorStyle}" />
<Style TargetType="Label" BasedOn="{StaticResource ErrorStyle}" />
<Style TargetType="Button" BasedOn="{StaticResource ErrorStyle}" />
<Style TargetType="DataGrid" BasedOn="{StaticResource ErrorStyle}" />
</Application.Resources>
</Application>
The above works for all Textboxs, Labels, Buttons within my Application. But it isn't working for DataGrids.
So then I changed the DataGrids style to be:
<Style TargetType="DataGrid" BasedOn="{StaticResource ErrorStyle}" x:Key="DataGridErrorStyle" />
And then explicitly add it to my DataGrids like so
<DataGrid Name="myGrid" Style="{StaticResource ResourceKey=DataGridErrorStyle}" />
Then it all works fine.
I'm just wondering if anyone knows why a DataGrid wouldn't use the implicit Style defined? Why does it require explicit Styling?
When I tried it, I got a green box with exclamation marks as required, whether I explicitly set an x:Key for the style or just rely on it coming implicitly. Is it possible that your DataGrid is inheriting a style from somewhere else in your code that is overriding the app default one? 

Binding the background colour of a control using a trigger in WPF/XAML

Okay, first off I have no experience of WPF whatsoever so please bear with me and apologies if my terminology is a little wayward... ;)
The following code snippet is part of a WPF application that I have inherited. The trigger governs whether mandatory fields on a particular form are highlighted or not. The code works but the highlighting seems to apply to the control and the border (??) which contains it.
<ItemsControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="clr-namespace:Caliburn.PresentationFramework.ApplicationModel;assembly=Caliburn.PresentationFramework"
x:Class="company.product.Jobs.JobParametersEditor"
IsTabStop="False">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DockPanel MinHeight="30">
<TextBlock Text="{Binding DisplayName, Mode=OneWay}"
DockPanel.Dock="Left"
VerticalAlignment="Center"
MinWidth="120"
Margin="6,0" />
<Border>
<Border.Style>
<Style TargetType="{x:Type Border}">
<Setter Property="Background"
Value="{x:Null}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsValid}"
Value="False">
<Setter Property="Background"
Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<ContentControl cal:View.Model="{Binding ValueEditor}"
ToolTip="{Binding ToolTip}"
IsTabStop="False"
MinHeight="19"
VerticalAlignment="Center"
HorizontalAlignment="Stretch" />
</Border>
</DockPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The result is a bit clunky so I would like to restrict the highlighting to the control only but I can't figure out how to do it. I've tried moving the trigger so that it applies to the ContentControl instead of the Border but that didn't work and fiddling about with border margins, padding and thickness hasn't had any effect either.
Could anybody enlighten me as to how to accomplish this?

How to propagate styles to Hyperlinks inside a DataTemplate?

I'm try to set the Foreground colour on a Hyperlink using a Style object in an ancestor's Resources, but it's not having any effect. I even used the BasedOn tip from Changing Hyperlink foreground without losing hover color, but it's not made any difference - I still get a blue hyperlink that is red on hover.
Here's the XAML for my controls, including an ItemsControl whose items are shown using a hyperlink:
<StackPanel Background="Red" TextElement.Foreground="White">
<StackPanel.Resources>
<Style TargetType="Hyperlink" BasedOn="{StaticResource {x:Type Hyperlink}}">
<Setter Property="Foreground" Value="Yellow"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<TextBlock>Data import errors</TextBlock>
<ItemsControl ItemsSource="{Binding Errors}"/>
</StackPanel>
And the items in the ItemsControl are picking up the following DataTemplate:
<DataTemplate DataType="{x:Type Importer:ConversionDetailsMessage}">
<TextBlock>
<Run Text="{Binding Message, Mode=OneTime}"/>
<Hyperlink Command="Common:ImportDataCommands.ExplainConversionMessage" CommandParameter="{Binding}">
<Run Text="{Binding HelpLink.Item2, Mode=OneTime}"/>
</Hyperlink>
</TextBlock>
</DataTemplate>
It's worth noting, too, that I don't want to just set the different colours directly on the Hyperlink in the DataTemplate. This is because the template will be used by a number of different ItemsControl objects, most of which will be on a white background and so can use the standard hyperlink colours. (Note that the one in the XAML above, however, has a red background.)
In short, I don't want the DataTemplate to have to know anything about the control in which it's being used. The styles for the template's controls should just filter down to it.
So... can anyone tell me why the style's not filtering down and what I can do to fix it?
Thanks.
Update:
Since I couldn't get Pavlo's answer to work in my production app, I've since tried it in a separate test app. The app is a WinForms app, with the main form containing nothing but an ElementHost, which itself contains a simple WPF usercontrol. Here's its XAML:
<UserControl x:Class="DataTemplateStyling.StylingView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:DataTemplateStyling="clr-namespace:DataTemplateStyling"
x:Name="root" Loaded="StylingViewLoaded">
<UserControl.Resources>
<Style x:Key="MyDefaultHyperlinkStyle" BasedOn="{StaticResource {x:Type Hyperlink}}"/>
<DataTemplate DataType="{x:Type DataTemplateStyling:ImportMessage}">
<DataTemplate.Resources>
<Style TargetType="{x:Type Hyperlink}"
BasedOn="{StaticResource MyDefaultHyperlinkStyle}"/>
</DataTemplate.Resources>
<TextBlock>
<Run Text="{Binding Message, Mode=OneTime}"/>
<Hyperlink NavigateUri="{Binding HelpLink.Item1}">
<Run Text="{Binding HelpLink.Item2, Mode=OneTime}"/>
</Hyperlink>
</TextBlock>
</DataTemplate>
</UserControl.Resources>
<Grid DataContext="{Binding ElementName=root}">
<StackPanel Background="Red" TextElement.Foreground="White">
<StackPanel.Resources>
<Style x:Key="MyDefaultHyperlinkStyle" TargetType="Hyperlink" BasedOn="{StaticResource {x:Type Hyperlink}}">
<Setter Property="Foreground" Value="Yellow"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<TextBlock>Data import errors</TextBlock>
<ItemsControl ItemsSource="{Binding Messages}"/>
</StackPanel>
</Grid>
</UserControl>
As it stands above, this generates an InvalidOperationException, stating "Can only base on a Style with target type that is base type 'IFrameworkInputElement'."
That can be fixed by putting TargetType="Hyperlink" on the Style definition immediately inside the UserControl.Resources element. However, while the messages are being shown, the link part of them still has the default blue hyperlink styling:
In short, it's not working, so I'd welcome any other suggestions/corrections. :(
Update 2:
Thanks to an alternative solution from Pavlo, it now is working. :)
After some googling I ran into this post: http://www.11011.net/archives/000692.html.
As it described there, it turns out that elements that are not derived from Control (like TextBlock and Hyperlink) do not look for implicit styles outside the DataTemplate boundary.
Again, as the article says, the possible workaround is to specify the style key explicitly. In your case it might be something like this:
<StackPanel Background="Red" TextElement.Foreground="White">
<StackPanel.Resources>
<Style x:Key="MyDefaultHyperlinkStyle" TargetType="Hyperlink" BasedOn="{StaticResource {x:Type Hyperlink}}">
<Setter Property="Foreground" Value="Yellow"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<TextBlock>Data import errors</TextBlock>
<ItemsControl ItemsSource="{Binding Errors}"/>
</StackPanel>
Then, you can add an implicit style for Hyperlink that just references our named style in the DataTemplate resources:
<DataTemplate DataType="{x:Type Importer:ConversionDetailsMessage}">
<DataTemplate.Resources>
<Style TargetType="{x:Type Hyperlink}"
BasedOn="{StaticResource MyDefaultHyperlinkStyle}"/>
</DataTemplate.Resources>
<TextBlock>
<Run Text="{Binding Message, Mode=OneTime}"/>
<Hyperlink Command="Common:ImportDataCommands.ExplainConversionMessage" CommandParameter="{Binding}">
<Run Text="{Binding HelpLink.Item2, Mode=OneTime}"/>
</Hyperlink>
</TextBlock>
</DataTemplate>
And because the data template can be used in different places, there is a possibility that parent container doesn't define a style with key "MyDefaultHyperlinkStyle". In this case an exception will be thrown saying that resource "MyDefaultHyperlinkStyle" cannot be found. To address this, you can define a style with such key that will only inherit default style somewhere in App.xaml:
<Style x:Key="MyDefaultHyperlinkStyle"
BasedOn="{StaticResource {x:Type Hyperlink}}/>
Update:
The code you included in your update will not work because of the nature of static resources, which means that the following resource reference in date template...
BasedOn="{StaticResource MyDefaultHyperlinkStyle}"
... will always point to the following resource (which is the default style):
<Style x:Key="MyDefaultHyperlinkStyle" BasedOn="{StaticResource {x:Type Hyperlink}}"/>
Static resource references are resolved at compile time, therefore the closest resource in the tree is used.
You might be tempted to use DynamicResource, but unfortunately it is not supported with the BasedOn property.
BUT, Foreground property supports dynamic resources, so we can use the same trick with brushes we use inside our style. Here is your test user control modified to use dynamic brushes:
<UserControl x:Class="DataTemplateStyling.StylingView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:DataTemplateStyling="clr-namespace:DataTemplateStyling"
x:Name="root"
Loaded="StylingViewLoaded">
<UserControl.Resources>
<SolidColorBrush x:Key="HyperlinkForeground"
Color="Blue" />
<SolidColorBrush x:Key="HyperlinkHoverForeground"
Color="Gray" />
<Style x:Key="MyDefaultHyperlinkStyle"
TargetType="Hyperlink"
BasedOn="{StaticResource {x:Type Hyperlink}}">
<Setter Property="Foreground"
Value="{DynamicResource HyperlinkForeground}" />
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Foreground"
Value="{DynamicResource HyperlinkHoverForeground}" />
</Trigger>
</Style.Triggers>
</Style>
<DataTemplate DataType="{x:Type DataTemplateStyling:ImportMessage}">
<DataTemplate.Resources>
<Style TargetType="{x:Type Hyperlink}"
BasedOn="{StaticResource MyDefaultHyperlinkStyle}" />
</DataTemplate.Resources>
<TextBlock>
<Run Text="{Binding Message, Mode=OneTime}" />
<Hyperlink NavigateUri="{Binding HelpLink.Item1}">
<Run Text="{Binding HelpLink.Item2, Mode=OneTime}" />
</Hyperlink>
</TextBlock>
</DataTemplate>
</UserControl.Resources>
<Grid DataContext="{Binding ElementName=root}">
<StackPanel Background="Red"
TextElement.Foreground="White">
<StackPanel.Resources>
<SolidColorBrush x:Key="HyperlinkForeground"
Color="Yellow" />
<SolidColorBrush x:Key="HyperlinkHoverForeground"
Color="White" />
</StackPanel.Resources>
<TextBlock>Data import errors</TextBlock>
<ItemsControl ItemsSource="{Binding Messages}" />
</StackPanel>
</Grid>
</UserControl>
It works as expected, i.e. all links inside StackPanel will be Yellow/White, while outside they will be blue.
Hope this helps.

How do I change the CellErrorStyle for an Xceed Datagrid?

So in the Xceed documentation there is a code example that does not work for me. It may be because my grid is bound to a DataGridCollectionView. The objects in the collection used by the datagridcollection are what implement IDataErrorInfo.
The errors are showing up just fine. The problem is that they are using the default orange background for errors...I need a red border. Below is the XAML instantiation of my grid. I set the DataCell background property to red just so I could be sure I had access to the grid's properties... I do. I just can't find the way to identify the cell's w/ errors so I can style them. Thanks!
<XceedDG:DataGridControl Grid.Row="1" Grid.ColumnSpan="5" ItemsSource="{Binding Path = ABGDataGridCollectionView, UpdateSourceTrigger=PropertyChanged}"
Background="{x:Static Views:DataGridControlBackgroundBrushes.ElementalBlue}" IsDeleteCommandEnabled="True"
FontSize="16" AutoCreateColumns="False" x:Name="EncounterDataGrid" AllowDrop="True">
<XceedDG:DataGridControl.View>
<Views:TableView ColumnStretchMode="All" ShowRowSelectorPane="True"
ColumnStretchMinWidth="100">
<Views:TableView.FixedHeaders>
<DataTemplate>
<XceedDG:InsertionRow Height="40"/>
</DataTemplate>
</Views:TableView.FixedHeaders>
</Views:TableView>
</XceedDG:DataGridControl.View>
<!--Group Header formatting-->
<XceedDG:DataGridControl.Resources>
<Style TargetType="{x:Type XceedDG:GroupByControl}">
<Setter Property="Visibility" Value="Collapsed"/>
</Style>
<Style TargetType="{x:Type XceedDG:DataCell}">
<Setter Property="Background" Value="Red"/>
</Style>
</XceedDG:DataGridControl.Resources>
...
The knowledge base entry:
http://xceed.com/KB/questions.php?questionid=256
Does seem to be potentially missing a critical piece.
Did you try the CellErrorStyle Property on DataGridView?
<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid">
<Grid.Resources>
<Style x:Key="errorStyle" TargetType="{x:Type xcdg:DataCell}">
<Setter Property="Foreground" Value="Red"/>
</Style>
</Grid.Resources>
<xcdg:DataGridControl CellErrorStyle="{StaticResource errorStyle}" >
<!--STUFF OMITTED-->
</xcdg:DataGridControl>
</xcdg:DataGridControl>

Resources