How to set style for ItemsPanel from outside? - c#

I define a style to make all StackPanel green:
<Window.Resources>
<Style TargetType="StackPanel">
<Setter Property="Background" Value="Green" />
</Style>
</Window.Resources>
But if I use StackPanel as panel template then it's NOT green:
<UniformGrid>
<StackPanel /><!-- this one is green -->
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel /><!-- this one is not -->
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</UniformGrid>
Why? How to make it also green?

Either move the implicit Style to App.xaml or add resource that is based on the implicit Style to the ItemsPanelTemplate:
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<ItemsPanelTemplate.Resources>
<Style TargetType="StackPanel" BasedOn="{StaticResource {x:Type StackPanel}}" />
</ItemsPanelTemplate.Resources>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Types that don't inherit from Control won't pick up implicit styles if you don't do any of this.

Related

Bind Style-Resource to StackPanel items

I am trying to bind a a Style-Resource which is defined in the local ResourceDictionary of a UserControl to all items in a StackPanel.
The ItemSource of the StackPanel is bound to an ObservableCollection<Button> in the ViewModel.
Thus, the aim is to bind the Style-Resource to the Style-Property of these Buttons.
The following simplified approach results in this error:
ArgumentException: Style object is not allowed to affect the Style property of the object to which it applies.
MyViewModel.cs:
public class MyViewModel
{
public ObservableCollection<Button> MyButtons { get; private set; }
}
MyView.xaml
<UserControl x:Class="MyView"
d:DataContext="{d:DesignInstance Type=MyViewModel}">
<UserControl.Resources>
<ResourceDictionary>
<Style x:Key="StyleStackPanelButton" TargetType="{x:Type Button}"
BasedOn="{StaticResource MyDefaultStyle}">
<Setter Property="Margin" Value="15" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</ResourceDictionary>
</UserControl.Resources>
<StackPanel>
<ItemsControl ItemsSource="{Binding MyButtons}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Style" Value="{StaticResource StyleStackPanelButton}" />
</Style>
</StackPanel.Resources>
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<Button Style="{StaticResource StyleStackPanelButton}" />
</StackPanel>
</UserControl>
I've also tried to use a Converter as suggested here
Binding for WPF Styles
as follows:
...
<ItemsControl ItemsSource="{Binding ButtonExtensions}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Style">
<Setter.Value>
<MultiBinding Converter="{StaticResource StyleConverter}">
<MultiBinding.Bindings>
<Binding RelativeSource="{RelativeSource Self}" />
<Binding Source="{StaticResource StyleStackPanelButton}" />
</MultiBinding.Bindings>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</StackPanel.Resources>
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
...
This results in the same error:
ArgumentException: Style object is not allowed to affect the Style property of the object to which it applies.
Is there a any other way to bind a lcoal Style-Resource to a Setter-Property of an Item in a Stackpanel-ItemSource?
Since you are adding Buttons directly to the ItemsSource collection, it is sufficient to assign the Button Style to the ItemContainerStyle property of the ItemsControl:
<ItemsControl ItemsSource="{Binding MyButtons}"
ItemContainerStyle="{StaticResource StyleStackPanelButton}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Alternatively, declare a default Button Style - without x:Key - in the StackPanel Resources:
<ItemsControl ItemsSource="{Binding MyButtons}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<Style TargetType="Button"
BasedOn="{StaticResource StyleStackPanelButton}"/>
</StackPanel.Resources>
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>

WPF: DataTemplate binding for different usercontrol

I'm new on WPF and I'm tryng to figure out how to implement a binding with different type of user control.
After the user clicks a button, a usercontrol (a simple shape like rectangle or ellipse) is added to the window.
I'm tryng to use an MVVM approach so the xaml appears as follow:
...
Title="{Binding Path=Titolo}"
Height="450" Width="800"
d:DataContext="{d:DesignInstance vm:MainWindowViewModel}">
<Canvas>
<Button Content="Add Shape" Command="{Binding TestCommand}"/>
<ItemsControl ItemsSource="{Binding RectCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<uc:MyCustomRectangle/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Left" Value="{Binding xLT}" />
<Setter Property="Canvas.Top" Value="{Binding yLT}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</Canvas>
All works fine but I want to add different type of UserControl (not only MyCustomRectangle) using the same button (for example, randomly adding rectangle or ellipse).
A possible solution could be duplicate the section of ItemsControl and select a different collection of binding:
<Canvas>
<Button Content="Add Shape" Command="{Binding TestCommand}"/>
<ItemsControl ItemsSource="{Binding RectCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<uc:MyCustomRectangle/> <!-- bind to my usercontrol -->
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Left" Value="{Binding xLT}" />
<Setter Property="Canvas.Top" Value="{Binding yLT}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
<ItemsControl ItemsSource="{Binding EllipseCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<uc:MyCustomEllipse/> <!-- bind to my usercontrol -->
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Left" Value="{Binding xLT}" />
<Setter Property="Canvas.Top" Value="{Binding yLT}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</Canvas>
I don't think this is the correct solution, especially because I would to add many different types of shapes (and also text and images).
So, if exist, what is the correct way to bind a data template to different type of usercontrol?
Is MVVM the correct approach to solve this problem?
What you can do is to bind to a global list with all Shapes.
And then you can define different DataTemplates for different Types.
Like this:
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type MyType1}">
...
</DataTemplate>
<DataTemplate DataType="{x:Type MyType2}">
....
</DataTemplate>
</ItemsControl.Resources>

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>

ItemsControl in HubSection not 100% height

Can anyone explain what's going on here. The two news articles in this WrapGrid aren't taking up the full space available to them as visible in the image below
My xaml looks like this
<HubSection Header="{Binding SportArticles[0].Title}" Background="{Binding SportArticles[0].Image}" MaxWidth="1000" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch">
<DataTemplate>
<ItemsControl
x:Name="xItems" ItemTemplate="{StaticResource ScoreNewsArticleTemplate}" ItemsSource="{Binding SportArticles}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Vertical" ItemWidth="350"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</HubSection>
The outer blue box is the HubSection and the inner blue box is the ItemsControl. I can't understand why its not taking up the full space available
Try setting the VerticalContentAlignment of your ItemContainerStyle to Stretch.
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
</Style>
</ItemsControl.ItemContainerStyle>

ItemsPanelTemplate Selector in wpf?

I need to set the ItemsPanelTemplate property of a listbox based on a dependency property on the control. How do I use the DataTemplateSelector to do that?
I have something like:
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<!-- Here I need to replace with either a StackPanel or a wrap panel-->
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
Thanks
There isn't an ItemsPanelSelector (probably because it isn't a DataTemplate) but you can bind it or use a Trigger
Binding example
<ListBox ItemsPanel="{Binding RelativeSource={RelativeSource Self},
Path=Background,
Converter={StaticResource MyItemsPanelConverter}}">
Trigger in Style example
<ListBox ItemsSource="{Binding Source={x:Static Fonts.SystemFontFamilies}}">
<ListBox.Style>
<Style TargetType="ListBox">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<!-- Your Trigger.. -->
<Trigger Property="Background" Value="Green">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Style>
</ListBox>
I'm thinking the best route here would be to use a Style for your ListBox and set Triggers that change the ItemsPanel based on the DependencyProperty you reference.

Categories