DataTemplate Doesn't Apply - c#

I am new to WPF and some help would be appreciated.
I got a resource Dictionary where I am trying to style a ListViewItem or ItemTemplate ListView's Property, But both ways have failed.
First way:
Dictionary
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<StackPanel Orientation="Horizontal">
<Ellipse Height="45" Width="45" Fill="Gray"/>
<ContentPresenter/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
MainWindow
<ListView Grid.Row="1" Background="LightSkyBlue">
<ListViewItem>Text cannot be seen</ListViewItem>
</ListView>
"This one doesn't show any text"
Second Way:
Dictionary
<DataTemplate x:Key="LeftMenuButtons">
<StackPanel Orientation="Horizontal">
<Ellipse Height="45" Width="45" Fill="Gray"/>
<ContentPresenter/>
</StackPanel>
</DataTemplate>
MainWindow
<ListView ItemTemplate="{StaticResource LeftMenuButtons}" Grid.Row="1" >
<ListViewItem>No Effect for DataTemplate Only Text Appears</ListViewItem>
</ListView>
This Doesn't apply anything in DataTemplate.
If possible I would like to know what is going wrong in both two ways ... Thanks in advance.

First Way - Control Template
Please specify the TargetType of the control template explicity.
<ControlTemplate TargetType="{x:Type ListViewItem}">
You could also give the list view item style a name, so it is not applied on all items in your scope, but only to the target list view.
<Style x:Key="ListViewItemStyle"
TargetType="ListViewItem">
Make sure, that you assign the style to your target list view.
<ListView Grid.Row="1"
Background="LightSkyBlue"
ItemContainerStyle="{StaticResource ListViewItemStyle}">
Second Way - Data Template
First, data templates only work if your items are assigned via the ItemsSource property. If you directly assign ListViewItems to your list view, they will not be affected. You have to bind the ItemsSource to a collection. Second, you do not use a ContentPresenter in the data template, you bind to properties of the objects in the ItemsSource collection. In this example you would have a collection of strings that are assigned to the Text property of the TextBlock. Maybe this is beyond the scope of your question.
<ListView Grid.Row="1"
ItemsSource="{Binding StringCollection}"
ItemTemplate="{StaticResource LeftMenuButtons}"/>
<DataTemplate x:Key="LeftMenuButtons"
<StackPanel Orientation="Horizontal">
<Ellipse Height="45"
Width="45"
Fill="Gray"/>
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>

The code below works. You just forgot to write ControlTemplate TargetType.
<Style x:Key="ListViewItemStyle" TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<StackPanel Orientation="Horizontal">
<Ellipse Height="45" Width="45" Fill="Gray"/>
<ContentPresenter/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Related

ContentPresenter steals resources?

In a simple view I want to display two buttons, that have as contents images, that are provided via resources in an extra style.xaml that is loaded in the App.xaml.
<BitmapImage x:Key="AddIcon" UriSource="pack://application:,,,/WpfTestBench;component/Images/plus.png"></BitmapImage>
<BitmapImage x:Key="RemoveIcon" UriSource="pack://application:,,,/WpfTestBench;component/Images/minus.png"></BitmapImage>
<Style x:Key="AddButtonWithIconStyle" TargetType="{x:Type Button}">
<Setter Property="Content">
<Setter.Value>
<Image Source="{DynamicResource AddIcon}" Stretch="None"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="RemoveButtonWithIconStyle" TargetType="{x:Type Button}">
<Setter Property="Content">
<Setter.Value>
<Image Source="{DynamicResource RemoveIcon}" Stretch="None"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Setter.Value>
</Setter>
</Style>
In my view I use the styles like this:
<DockPanel Margin="0,0,5,0" DockPanel.Dock="Bottom" LastChildFill="False" >
<Button Command="{Binding DeleteCommand}" DockPanel.Dock="Right"
Style="{StaticResource RemoveButtonWithIconStyle}"/>
<Button Command="{Binding AddCommand}" DockPanel.Dock="Right" Margin="5,0"
Style="{StaticResource AddButtonWithIconStyle}"/>
</DockPanel>
So far this looks good.
But when I add another view into this view via a ContentPresenter, that has basically the same content (again with the above described button styles) the display of the first two buttons (of the parent view) does not work anymore. All I get ist two small circles with the button functionality.
<ContentPresenter Content="{Binding SomeEmbeddedViewModel, UpdateSourceTrigger=PropertyChanged}"/>
Why does this happen? Does the ContentPresenter somehow prevent to share the resources?
As explained in the other answer, you should have the Image control in the ContentTemplate of the Button.
Declare a simple Image Button Style with an Image that has its Source property bound to the actual Content:
<Style x:Key="ImageButtonStyle" TargetType="Button">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
...
<Button Style="{StaticResource ImageButtonStyle}"
Content="{DynamicResource RemoveIcon}" .../>
You may also declare the Style as default Button Style, probably inside the DockPanel:
<DockPanel>
<DockPanel.Resources>
<Style TargetType="Button">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{Binding}" Stretch="None"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DockPanel.Resources>
<Button Command="{Binding DeleteCommand}" DockPanel.Dock="Right"
Content="{DynamicResource RemoveIcon}"/>
<Button Command="{Binding AddCommand}" DockPanel.Dock="Right" Margin="5,0"
Content="{DynamicResource AddIcon}"/>
</DockPanel>
Diagnosis
The core reason of this behavior is that an element can only appear once in the visual tree.
First of all, resources in a ResourceDictionary are by default shared, i.e. every time you fetch a resource with a particular key, you always get the same instance. In your case, you always get the same instance of Style, which also means that there's always only one instance of Image (for each style).
So if you apply the same style to two buttons, the framework tries to put the same Image instance in two different places, which is not allowed. To avoid that, upon attempt to load the image into the visual tree, if it already is in the visual tree, it is unloaded from the previous location first.
That's why the image is only visible in the last button (in order in which they were loaded).
Solution
There are basically two solutions to this problem.
1. Disable resource sharing
You can disable the resource sharing so that each time you fetch a resource from a ResourceDictionary you get a new instance of the resource. In order to do that, you set x:Shared="False" on your resource:
<Style x:Key="AddButtonWithIconStyle" x:Shared="False" TargetType="{x:Type Button}">
(...)
</Style>
2. Use ContentTemplate in your style
Instead of putting the image as the content of the button, you could define a ContentTemplate, which is realized separately for each button it is applied to (so each button gets its own instance of the image):
<Style x:Key="RemoveButtonWithIconStyle" TargetType="{x:Type Button}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{DynamicResource RemoveIcon}" Stretch="None"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Personally I'd advise you to use the second solution, since that's exactly the purpose of templates in WPF.

WPF Combobox style will not change when DisplayMemberPath is set

So i've looked around but have been unable to find an answer to this issue. I am trying to style a combobox that has DisplayMemberPath. As long as that field is set the fontsize that I set has no effect on the combobox. I've also tried applying template styles, but the results are the same for the font. The question/answer listed in question "ComboBox Style problems with DisplayMemberPath" doesn't address fontsize but appears to be more geared to resulting colors.
Here is the combobox:
<ComboBox
Grid.Row="0"
Height="36"
VerticalAlignment="Center"
ItemsSource="{Binding VideoDeviceFilters}"
SelectedValue="{Binding VideoDeviceFilter}"
DisplayMemberPath="Name"
Margin="0,11.857,1.333,11.856"
Grid.Column="1"
TextBlock.FontSize="18.333"/>
And here is the combobox without the displaymemberpath:
<ComboBox Grid.Row="1"
Height="35"
VerticalAlignment="Center"
Margin="0,12.857,1.333,11.856"
ItemsSource="{Binding InstalledPrinters}"
SelectedValue="{Binding Printer}"
Grid.Column="1"
TextBlock.FontSize="18.333"/>
Here is also the style declared in the view:
<UserControl.Resources>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border x:Name="ItemBorder" Padding="2,0" BorderThickness="1" CornerRadius="3" TextBlock.FontSize="18.333" >
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
Please let me know if you need any more information.
And here is the result:
The Result

Wpf Prism give style to each items of a ItemControl (Views in a Region)

I have a WPF Prism project and it has a Region base on ItemControl:
<ItemsControl prism:RegionManager.RegionName="WorkspaceRegion" >
In this ItemControl i see some of my Views verticaly well but i want give a style to each Item of ItemControl (each View).
All of items (views) must have same style (for example: background
color, padding, margin, border and...)
I want something like this (for example):
I used a simple style and code like this:
<ItemsControl prism:RegionManager.RegionName="WorkspaceRegion" Background="#765e4d" Margin="10">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Border BorderBrush="Red" Padding="10" BorderThickness="1" CornerRadius="5">
<ContentPresenter Content="{Binding}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
Its Error:
A style intended for type 'ItemsControl' cannot be applied to type
'View1'
Also i tested this codes:
<ItemsControl prism:RegionManager.RegionName="WorkspaceRegion" Background="#765e4d" Margin="10">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid >
<TextBlock Text="Test"/>
<Border BorderBrush="Red" Padding="10" Margin="10" BorderThickness="1" CornerRadius="5">
<ContentPresenter Content="{Binding}"/>
</Border>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
But the result is like when i write:
<ItemsControl prism:RegionManager.RegionName="WorkspaceRegion" >
Why? What is my mistake?
How can i do this?
Edit1:
I used <ItemsPresenter/> instead of <ContentPresenter Content="{Binding}"/>
Result: without any change
Edit2:
I write this style for ItemContainerStyle property of the ItemsControl and it works if i remove ControlTemplate part from it.
Now the question is which kind of Presenter or Xaml Tag i should use inside the following ControlTemplate to my Views (UserControls) be shown.
<Style TargetType="{x:Type UserControl}" x:Key="MyItemContainerStyle">
<Setter Property="Background" Value="Brown"/>
<Setter Property="BorderBrush" Value="Blue"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="Margin" Value="10"/>
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate>
??????????????????????????
<!-- The following ContentPresenter not working and the Items dose not show -->
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Set the ContentTemplate property of the style, not Control.Template or Template
An ItemsControl gets rendered like this :
<ItemsControl>
<ItemsPanel>
<ContentPresenter>
<ItemTemplate>
</ContentPresenter>
<ContentPresenter>
<ItemTemplate>
</ContentPresenter>
<ContentPresenter>
<ItemTemplate>
</ContentPresenter>
</ItemsPanel>
</ItemsControl>
The ItemContainerStyle applies to the ContentPresenter object that wraps each item in this XAML tree, and I don't believe a ContentPresenter has either a Control.Template or a Template property.
When changing how a ContentPresenter is displayed you should overwrite the ContentTemplate property instead.
This works for me in my test application:
<ItemsControl Background="#FF85664F" prism:RegionManager.RegionName="WorkspaceRegion">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="DarkGray" Padding="10"
Margin="5, 5, 5, 0" BorderThickness="1"
CornerRadius="5" Background="#FFC3BF8F">
<ContentPresenter Content="{Binding}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<system:String>ItemsControl Item #1</system:String>
<system:String>ItemsControl Item #2</system:String>
<system:String>ItemsControl Item #3</system:String>
<system:String>ItemsControl Item #4</system:String>
<system:String>ItemsControl Item #5</system:String>
</ItemsControl>

WPF: Styling ContentControl

I would like to create a style that could be applied to any ContentControl which would take the ToolTip and add an image to the ContentControl and apply the tool tip text from the object to the image. I have about a hundred of these that need to be done (in various projects) so being able to create a style would save a lot of typing.
What I am trying to recreate is this (ToolTip text is on the blue 'i' and not the 'Reload Employee Data':
which is accomplished via the following:
<StackPanel Orientation="Horizontal">
<CheckBox Content="Reload Employee Data"
IsChecked="{Binding AdjustmentSettings.ReloadEmployeeData}"
Grid.Row="0"
Grid.Column="0">
</CheckBox>
<Image Source="/DelphiaLibrary;Component/Resources/info.ico"
ToolTip="Check if you want to re-upload ..."/>
</StackPanel>
What I am trying to avoid is creating a new stack panel each time I want to add the blue 'i' with the tool tip text on the 'i' and not on the text of the object.
I was able to create the following that works for a Label:
<!-- Works for just Label -->
<Style x:Key="LabelToolTipStyle"
TargetType="{x:Type Label}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{TemplateBinding Content}" />
<Image Source="info.ico" ToolTip="{TemplateBinding ToolTip}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And I can call this simply by adding the style to the label like so:
<Label Content="First Text" Style="{StaticResource LabelToolTipStyle}" ToolTip="Label with LabelToolTipStyle" />
I then tried to make this more generalized by creating a style targeting ContentControl but obviously doesn't work because this overrides the entire template (in the case of CheckBox control, the checkbox is missing):
<!-- Works on Label but not CheckBox -->
<Style x:Key="ContentToolTipStyle"
TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{TemplateBinding Content}" />
<Image Source="info.ico" ToolTip="{TemplateBinding ToolTip}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Is there a way that I could create a style for ContentControls that would allow me to ADD to the template without redefining the entire template? If it cannot be done to ContentControl I wouldn't be opposed to creating a separate style for each control type but would like to avoid redefining the entire template to do so.
You are almost there. You need to create a custom control template for a ContentControl:
<Style x:Key="ToolTipWrapper" TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<StackPanel Orientation="Horizontal">
<StackPanel.ToolTip>
<ToolTip Visibility="Hidden" />
</StackPanel.ToolTip>
<ContentPresenter />
<Image Source="info.ico" ToolTip="{TemplateBinding ToolTip}" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then wrap your elements in a ContentControl and apply the style:
<ContentControl Style="{StaticResource ToolTipWrapper}" ToolTip="Hello world">
<CheckBox Content="I am a check box" />
</ContentControl>
What you can't do is to automatically apply the custom style to all "content" controls: you will always need the extra ContentControl wrapped around each element you want to style in this way.

How to use an ItemTemplate on a templated control?

I am trying to create custom templated control based on a ListBox to display only the single selected item in the control's collection.
To this aim, I have defined a Template with an ContentPresenter, databound to the SelectedItem property of the control.
As illustrated in scenario 1, it works well when providing the control with a collection of UIElement.
But when needing to use a DataTemplate to display an entity object, the ItemTemplate is ignored because the control has a Template which will prevent the `ItemTemplate from being used. From what I've read this is by design and it sorts of makes sense.
But how can I use DataTemplates for my control's ItemTemplate and retain my control default template?
I have tried overriding PrepareContainerForItemOverride, and many different template configurations to no avail.
Here is some of what I tried:
<UserControl.Resources>
<local:StringCollection x:Key="MyColors">
<sys:String>Yellow</sys:String>
<sys:String>Purple</sys:String>
</local:StringCollection>
</UserControl.Resources>
<StackPanel Background="White">
<TextBlock Margin="0,25,0,0">Scenario 1: Providing UIElements to the
ControlTemplate's ContentPresenter: Works</TextBlock>
<control:RotatingFlipView x:Name="Works" SelectedIndex="1">
<control:RotatingFlipView.Template>
<ControlTemplate>
<ContentPresenter
Content="{Binding ElementName=Works, Path=SelectedItem}"/>
</ControlTemplate>
</control:RotatingFlipView.Template>
<Rectangle Height="100" Width="100" Fill="Red"/>
<Rectangle Height="100" Width="100" Fill="Blue"/>
<Rectangle Height="100" Width="100" Fill="Green"/>
</control:RotatingFlipView>
<TextBlock Margin="0,25,0,0">Scenario 2: The ItemTemplate provided is ignored in
favor of the RotatingFlipView's Template which displays the source as raw
Strings</TextBlock>
<control:RotatingFlipView x:Name="Broken"
ItemsSource="{StaticResource MyColors}">
<control:RotatingFlipView.Template>
<ControlTemplate>
<ContentPresenter
Content="{Binding ElementName=Broken, Path=SelectedItem}"/>
</ControlTemplate>
</control:RotatingFlipView.Template>
<control:RotatingFlipView.ItemTemplate>
<DataTemplate>
<Rectangle Height="100" Width="100" Fill="{Binding}"/>
</DataTemplate>
</control:RotatingFlipView.ItemTemplate>
</control:RotatingFlipView>
<TextBlock Margin="0,25,0,0">Scenario 3: Removing the RotatingFlipView's
Template, causes the display to fall back on the ListBox's Template,
though now my ItemTemplate is used:</TextBlock>
<control:RotatingFlipView x:Name="Broken2"
ItemsSource="{StaticResource MyColors}">
<control:RotatingFlipView.ItemTemplate>
<DataTemplate>
<Rectangle Height="100" Width="100" Fill="{Binding}"/>
</DataTemplate>
</control:RotatingFlipView.ItemTemplate>
</control:RotatingFlipView>
</StackPanel>
RotatingFlipView.cs
public class RotatingFlipView : ListBox
{
public RotatingFlipView()
{
DefaultStyleKey = typeof(RotatingFlipView);
}
}
generic.xaml
<Style TargetType="local:RotatingFlipView">
<Setter Property="SelectionMode" Value="Single"/>
<Setter Property="SelectedIndex" Value="0"/>
</Style>
Output:
I have now figured it out. Here is how I've done it:
Mainpage.xaml
<UserControl.Resources>
<local:StringCollection x:Key="MyColors">
<sys:String>Yellow</sys:String>
<sys:String>Purple</sys:String>
</local:StringCollection>
</UserControl.Resources>
<StackPanel Background="White">
<control:RotatingFlipView>
<Rectangle Height="100" Width="100" Fill="Red"/>
<Rectangle Height="100" Width="100" Fill="Green"/>
<Rectangle Height="100" Width="100" Fill="Blue"/>
</control:RotatingFlipView>
<control:RotatingFlipView ItemsSource="{StaticResource MyColors}">
<control:RotatingFlipView.ItemTemplate>
<DataTemplate>
<Rectangle Height="100" Width="100" Fill="{Binding}"/>
</DataTemplate>
</control:RotatingFlipView.ItemTemplate>
</control:RotatingFlipView>
<StackPanel/>
RotatingFlipView.cs
public class RotatingFlipView : ListBox
{
public RotatingFlipView()
{
DefaultStyleKey = typeof(RotatingFlipView);
}
}
generic.xaml
<Style TargetType="local:RotatingFlipView">
<Setter Property="SelectionMode" Value="Single"/>
<Setter Property="SelectedIndex" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:RotatingFlipView">
<ContentPresenter
Content="{TemplateBinding SelectedItem}"
ContentTemplate="{TemplateBinding ItemTemplate}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Categories