How could i get control from ControlTemplate of ListBoxItem? - c#

Good day.
For ItemContainerStyle of ListBox I set my own style:
StyleClass.xaml
<Style x:Key="ItemContainerGalleryStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid x:Name="itemGrid">
...
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ListBoxGalleryStyle2" TargetType="{x:Type ListBox}">
<Setter Property="ItemContainerStyle" Value="{DynamicResource ItemContainerGalleryStyle}" />
</Style>
MainWindow.xaml
<Window ...>
<Window.Resources>
<XmlDataProvider x:Key="GalleryXmlDataProvider" Source="Gallery.xml"></XmlDataProvider>
</Window.Resources>
<Grid>
<ListBox x:Name="listBoxGallery"
Style="{StaticResource ListBoxGalleryStyle2}"
ItemsSource="{Binding Mode=Default,
Source={StaticResource GalleryXmlDataProvider},
XPath=/Gallery/Image}" />
</Grid>
</Window>
In code I want to retrieve Grid Control of my selected item. I attempt to do it by means of a listBoxGallery.Template.FindName. But I can't get at how to use this method.
How can I extract Grid from ControlTemplate?

You are trying to get an element from ListBoxItem's template and not from ListBox. So you need to get the exact ListBoxItem, before you using accessing its template. In below code snippet, I shown you how to get item from 0th element and taking the Grid from its template.
var container = listBoxGallery.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem;
var iremgrid = container.Template.FindName("itemGrid") as Grid;

Related

How do I remove the borders separating the headers in a Listview in XAML (WPF)?

I am making a ListView which loads users in from an Active Directory. To accomplish the brand/styling of the company I am developing the application for I would like to tweak some of the styling of the ListView element.
I have made it so the border of the headers in the Listview are transparent. In the editor in Visual Studio it looks how I want it to be, but when I look at the headers in the ListView in runtime I still get to see borders separating the headers (See image below).
https://i.gyazo.com/99dc8d60d6c5b2e1761456df685d850f.png
I have already tried Googling and I even went to the second page of the Google search result. Can you imagine?
Down here is the style I have used for the headers in my XAML file
<Style x:Key="ListViewHeaderStyle" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Background" Value="Transparent"></Setter>
<Setter Property="BorderBrush" Value="Transparent"></Setter>
<Setter Property="IsHitTestVisible" Value="False"></Setter>
</Style>
What I want is to remove those borders separating the headers in my ListView element.
You can override the template of the GridViewColumnHeader
<Window.Resources>
<Style x:Key="GridHeader" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GridViewColumnHeader}">
<TextBlock Text="{TemplateBinding Content}" Padding="5"
Width="{TemplateBinding Width}" TextAlignment="Right" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<ListView>
<ListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource GridHeader}">
</ListView.View>
</ListView>
Solution taken form here: Remove Separators in ListView Columns - WPF

MahApps MetroProgressBar does not work inside ControlTemplate

I would like to use MetroProgressBar in my UserControl.
<UserControl x:Class="WpfApplication7.UserControl1">
<StackPanel Background="#ccc">
<controls:MetroProgressBar IsIndeterminate="True"/>
</StackPanel>
</UserControl>
It works fine. But now I need to support external content in the user control.
So I created a new one "UserControl2" to demo:
<UserControl x:Class="WpfApplication7.UserControl2">
<UserControl.Resources>
<Style TargetType="{x:Type local:UserControl2}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:UserControl2}">
<StackPanel Background="#ccc">
<controls:MetroProgressBar IsIndeterminate="True"/>
<!--<ContentPresenter/>-->
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
</UserControl>
Then I put the both controls to the form:
<StackPanel>
<local:UserControl1 Background="#ccc"/>
<local:UserControl2 Background="#ccc" Margin="0,6,0,0"/>
</StackPanel>
As result I see that UserControl2 does not show Progress Bar.
How can I fix it?
Note: In the designer UserControl2 is rendered as expected with progress bar.
In your style for UserControl2, set properties EllipseDiameter and EllipseOffset to some value (default is 4), as shown below:
<Style TargetType="{x:Type local:UserControl2}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:UserControl2}">
<StackPanel Background="#ccc">
<controls:MetroProgressBar EllipseDiameter="12"
EllipseOffset="12"
IsIndeterminate="True"/>
<!--<ContentPresenter/>-->
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

WPF XAML display content in a ContentControl

I need to display a number in a square, centered horizontally and vertically.
When I tried to use a label for that purpose, it seemed like it ignored the centering completely. So I decided to use a grid and display a label on the grid as that centers perfectly.
I need to use a template as there's several themes available. From what I've found on the internet, I thought this ( ignoring the centering for now )
<ControlTemplate x:Key="ClockTemplate">
<Grid>
<Grid.Style>
<Style TargetType="Grid">
<Setter Property="Background" Value="White"/>
</Style>
</Grid.Style>
<Label>
<Label.Style>
<Style TargetType="Label">
<Setter Property="Foreground" Value="#376092"/>
</Style>
</Label.Style>
<ContentPresenter/>
</Label>
</Grid>
</ControlTemplate>
would be correct. Using it as follows:
<ContentControl Content="20" Height="64" Width="64" Template="{DynamicResource ClockTemplate}"/>
the content is not displayed tho, what am I doing wrong? Also, is there a better way to achieve my goal?
As per my understanding this is not the correct approach. Instead of creating ControlTemplate you have to write a Style for your control like below, also use StaticResource binding if possible. It is faster than Dynamic binding. Please not that, I have not mentioned the Label size inside the ControlTemplate. Please do it based on your needs
<Style x:Key="ContentControlStyle"
TargetType="ContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Grid Background="White">
<Label Foreground="#376092"
Width="200"
Height="100" Content="{TemplateBinding Content}">
</Label>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
bind your ContentControl with the newly created Style like below
<ContentControl Style="{StaticResource ContentControlStyle} ">
If your requirement is only to set some value in ContentControl, use Label instead and change the Style of the Label. Because ContentControl is heavy

Inversion of inheritance in WPF styles

I've got a UserControl that contains a button:
<Button Content="Button"/>
And a style:
<Style TargetType="Button">
<Setter Property="Background" Value="Blue"/>
</Style>
The parent window (or another UserControl) may set another more general style:
<Style TargetType="Button">
<Setter Property="Background" Value="Red"/>
</Style>
The result is (what is obvious) that parent buttons will have more general style (Red) and my user control will have buttons with more specific style (Blue).
I'm wondering how to invert such behaviour in order to achieve something like setting the default style in my custom user control which could be then overriden in parent control or window if necessary?
The key is, that default style is defined first in custom user control and it is overriden automaticly by its parent. That is way I called it an inversion.
The imaginary example of the solution maight look like the following:
<Style TargetType="Button" StylePriority="Default">
<Setter Property="Background" Value="Blue"/>
</Style>
The StylePriority could indicate that if there is no other style defined for that button, then the default style should be applied to it.
You could use dynamic resources.
A UserControl:
<UserControl x:Class="Example.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Example">
<UserControl.Resources>
<Style TargetType="local:UserControl1">
<Style.Resources>
<Style TargetType="Button" x:Key="UserControl1.DefaultButtonStyle">
<Setter Property="Background" Value="Red"/>
</Style>
</Style.Resources>
</Style>
</UserControl.Resources>
<Button Content="UserControlButton" Style="{DynamicResource UserControl1.DefaultButtonStyle}"/>
</UserControl>
And a Window:
<Window x:Class="Example.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Example">
<Window.Resources>
<Style TargetType="Button">
<Setter Property="Background" Value="Blue" />
</Style>
</Window.Resources>
<StackPanel>
<local:UserControl1 >
<local:UserControl1.Resources>
<Style x:Key="UserControl1.DefaultButtonStyle" TargetType="Button"
BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="FontSize" Value="40" />
</Style>
</local:UserControl1.Resources>
</local:UserControl1>
<Button Content="WindowButton" />
</StackPanel>
</Window>
If you remove the style for the control in the window, the default user control button style will be applied.
Create a dependency property in your UserControl for the buttons colour, and then bind to it. You can specify a default value of blue for that property.
public static readonly DependencyProperty ButtonColorProperty =
DependencyProperty.Register("ButtonColor", typeof(Color), typeof(MyUserControl),
new PropertyMetadata(Colors.Blue));
public Color State
{
get { return (Color)this.GetValue(ButtonColorProperty); }
set { this.SetValue(ButtonColorProperty, value); }
}
<UserControl ...
x:Name="root">
<Button Content="Button" Background="{Binding ElementName=root, Path=ButtonColor}" />
</UserControl>
Then set that property to red where you want to use the UserControl.
<local:MyUserControl ButtonColor="Red" />

Different tab style depending on tab item template?

I have a tab control with two different potential item templates:
<TabControl ItemTemplateSelector="{StaticResource tabTemplateSelector}"/>
Now, I also have styles for it:
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
...
The thing is, I want the tab item style template to be different depending on the value of ItemTemplateSelector. How can I do this? Basically, I don't want that entire style rule to be applied to every tab item, just the ones with a specific tab item template.
Update: to make it clearer, the style has TargetType set to TabItem. I want to apply that style only to those tab items that have a specific item template.
The ContentPresenter in the ControlTemplate will display what's in the ItemTemplate. So you won't be able to switch the Template from inside the ControlTemplate.
Instead, you could use a DataTrigger to set the Template. The DataTrigger will check if the ItemTemplate that will be generated should have the other Template or not.
You will probably need a converter for this but here is an easy example. Say that your ItemTemplateSelector returns the other DataTemplate if Name is equal to "Tab 2". Then your Style with the DataTrigger would look like this
<Style TargetType="TabItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<!-- Your first Template -->
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Name}" Value="Tab 2">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<!-- Your other Template -->
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>

Categories

Resources