I'm trying to customize the TreeView control. When a user selects an item in the TreeView, I need the ActualWidth of the SelectedItem to be stored in the item's Tag:
<Style x:Key="{x:Type TreeViewItem}" TargetType="{x:Type TreeViewItem}">
<!-- ... -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Rectangle x:Name="rect" />
<ContentPresenter x:Name="PART_Header" ContentSource="Header" Margin="5" />
<ItemsPresenter x:Name="ItemsHost" Grid.Row="1" Grid.Column="1" />
<!-- ... -->
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Tag" Value="{Binding ElementName=rect, Path=ActualWidth}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Later, I listen to the SelectedItemChanged event of the TreeView:
private void views_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
TreeViewItem item = (TreeViewItem)e.NewValue;
double i = (double)item.Tag;
}
Now the problem is that item.Tag is always null. Is this a problem with my binding? Or should things be done in a different way?
Try that :
<Setter Property="Tag" Value="{Binding Path=ActualWidth, RelativeSource={x:Static RelativeSource.Self}}" />
Related
How would you design a Google images -like component?
I'm not sure how to handle the detail panel which shows under each image when selected.
The detail panel:
- shows between two rows of images.
- keep left and right items in place.
SOLUTION:
Thanks to LittleBit for providing a very nice solution to the problem. Based on his hints, i created the following general-purpose component taking care of a few details you will eventually face when making LittleBit solution production-ready.
file: DetailedList.cs
public class DetailedList : ListBox
{
#region DetailsTemplate
public DataTemplate DetailsTemplate
{
get { return (DataTemplate)GetValue( DetailsTemplateProperty ); }
set { SetValue( DetailsTemplateProperty, value ); }
}
public static readonly DependencyProperty DetailsTemplateProperty =
DependencyProperty.Register( nameof( DetailsTemplate ), typeof( DataTemplate ), typeof( DetailedList ) );
#endregion
static DetailedList()
{
Type ownerType = typeof( DetailedList );
DefaultStyleKeyProperty.OverrideMetadata( ownerType,
new FrameworkPropertyMetadata( ownerType ) );
StyleProperty.OverrideMetadata( ownerType,
new FrameworkPropertyMetadata( null, ( depObj, baseValue ) =>
{
var element = depObj as FrameworkElement;
if( element != null && baseValue == null )
baseValue = element.TryFindResource( ownerType );
return baseValue;
} ) );
}
}
file: StretchGrid.cs
internal class StretchGrid : Grid
{
private Expander _expander;
#region ParentPanel
public Panel ParentPanel
{
get { return (Panel)this.GetValue( ParentPanelProperty ); }
set { this.SetValue( ParentPanelProperty, value ); }
}
public static readonly DependencyProperty ParentPanelProperty = DependencyProperty.Register(
nameof( ParentPanel ), typeof( Panel ), typeof( StretchGrid ), new PropertyMetadata( null, ParentPanelChanged ) );
private static void ParentPanelChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
var stretchGrid = d as StretchGrid;
if( stretchGrid == null ) return;
if( e.NewValue is Panel panel )
panel.SizeChanged += stretchGrid.UpdateMargins;
}
#endregion
public StretchGrid()
{
this.Loaded += StretchGrid_Loaded;
}
private void StretchGrid_Loaded( object sender, RoutedEventArgs e )
{
_expander = this.FindLogicalParent<Expander>();
_expander.Expanded += UpdateMargins;
_expander.SizeChanged += UpdateMargins;
this.UpdateMargins( null, null );
}
private void UpdateMargins( object sender, RoutedEventArgs e )
{
if( ParentPanel == null ) return;
if( _expander == null ) return;
Point delta = _expander.TranslatePoint( new Point( 0d, 0d ), ParentPanel );
//Create negative Margin to allow the Grid to be rendered outside of the Boundaries (full row under the item)
this.Margin = new Thickness( -delta.X, 0, delta.X + _expander.ActualWidth - ParentPanel.ActualWidth, 0 );
}
}
file: DetailedList.xaml
<Style x:Key="{x:Type cc:DetailedList}" TargetType="{x:Type cc:DetailedList}"
BasedOn="{StaticResource {x:Type ListBox}}">
<Style.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="NoButtonExpander.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Style.Resources>
<Setter Property="Grid.IsSharedSizeScope" Value="True"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
<Setter Property="SelectionMode" Value="Single"/>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type cc:DetailedList}}}"
Tag="{Binding RelativeSource={RelativeSource Self}}" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border Name="Border" SnapsToDevicePixels="True">
<Expander Style="{StaticResource NoButtonExpander}" VerticalAlignment="Top"
IsExpanded="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}"
Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}">
<Expander.Header>
<Grid>
<Grid.RowDefinitions>
<RowDefinition SharedSizeGroup="A"/>
</Grid.RowDefinitions>
<ContentPresenter Grid.Row="0"/>
</Grid>
</Expander.Header>
<cc:StretchGrid ParentWrapPanel="{Binding Path=Tag,
RelativeSource={RelativeSource AncestorType={x:Type WrapPanel}}}">
<ContentPresenter ContentTemplate="{Binding DetailsTemplate,
RelativeSource={RelativeSource AncestorType={x:Type cc:DetailedList}}}"/>
</cc:StretchGrid>
</Expander>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background"
Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
file: NoButtonExpander.xaml
<Style x:Key="ExpanderRightHeaderStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Padding="{TemplateBinding Padding}">
<Grid Background="Transparent" SnapsToDevicePixels="False">
<ContentPresenter HorizontalAlignment="Center" Margin="0,4,0,0" Grid.Row="1" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Top"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ExpanderUpHeaderStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Padding="{TemplateBinding Padding}">
<Grid Background="Transparent" SnapsToDevicePixels="False">
<ContentPresenter Grid.Column="1" HorizontalAlignment="Left" Margin="4,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Center"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ExpanderLeftHeaderStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Padding="{TemplateBinding Padding}">
<Grid Background="Transparent" SnapsToDevicePixels="False">
<ContentPresenter HorizontalAlignment="Center" Margin="0,4,0,0" Grid.Row="1" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Top"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ExpanderHeaderFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Border>
<Rectangle Margin="0" SnapsToDevicePixels="true" Stroke="Black" StrokeThickness="1" StrokeDashArray="1 2"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ExpanderDownHeaderStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Padding="{TemplateBinding Padding}">
<Grid Background="Transparent" SnapsToDevicePixels="False">
<ContentPresenter Grid.Column="1" HorizontalAlignment="Left" Margin="4,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Center"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="NoButtonExpander" TargetType="{x:Type Expander}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Expander}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="3" SnapsToDevicePixels="true">
<DockPanel>
<ToggleButton x:Name="HeaderSite" ContentTemplate="{TemplateBinding HeaderTemplate}" ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}" Content="{TemplateBinding Header}" DockPanel.Dock="Top" Foreground="{TemplateBinding Foreground}" FontWeight="{TemplateBinding FontWeight}" FocusVisualStyle="{StaticResource ExpanderHeaderFocusVisual}" FontStyle="{TemplateBinding FontStyle}" FontStretch="{TemplateBinding FontStretch}" FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" MinWidth="0" MinHeight="0" Padding="{TemplateBinding Padding}" Style="{StaticResource ExpanderDownHeaderStyle}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
<ContentPresenter x:Name="ExpandSite" DockPanel.Dock="Bottom" Focusable="false" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" Visibility="Collapsed" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</DockPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="true">
<Setter Property="Visibility" TargetName="ExpandSite" Value="Visible"/>
</Trigger>
<Trigger Property="ExpandDirection" Value="Right">
<Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Right"/>
<Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Left"/>
<Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderRightHeaderStyle}"/>
</Trigger>
<Trigger Property="ExpandDirection" Value="Up">
<Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Top"/>
<Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Bottom"/>
<Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderUpHeaderStyle}"/>
</Trigger>
<Trigger Property="ExpandDirection" Value="Left">
<Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Left"/>
<Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Right"/>
<Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderLeftHeaderStyle}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My approach is to use a ListView with some modifications
The ItemsPanel of the ListView must have a 'wrap' function, so i used a Wrappanel to display the Image-Previews in a field.
The ItemContainter of the ListViewItem must have two states. An Image-Preview state and a Detail-View therfore an Expander should do the trick.
The Details of an Image must be displayed across the whole Column under the Image. We need something which renders outside the Boundaries of a ListViewItem (more later)
It now looks like this
The Image Details are now messed up due to the Boundaries. The Height is no problem because it just moves the next Column down until it fits in. The Problem is the Width and its Position (its not left aligned).
I created a small CustomControl, the StretchGrid which renders its Content across the whole Column and left aligned. This StretchGrid get the relative distance to the left Boundary and sets it as negative Margin.Left to render it properly. Now it looks like this (and i hope that is exactly what you are looking for).
Now the Style of the ListView
<!-- Image List with Detail -->
<Style x:Key="PicList" TargetType="{x:Type ListView}">
<!-- Only one Picture can be selected -->
<Setter Property="SelectionMode" Value="Single"/>
<!-- Enable Multi-Line with a WrapPanel Around the Items -->
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel Width="{Binding (ListView.ActualWidth),RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}" Tag="{Binding RelativeSource={RelativeSource Self}}" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<!-- Override Display area of the Item -->
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListViewItem}">
<!-- Define Image Item -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<!-- Use Expander Header as Preview/Thumbnail and display Details below when expanded -->
<Expander x:Name="PicThumbnail" Style="{StaticResource NoButtonExpander}" IsExpanded="{Binding (ListViewItem.IsSelected), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}}" Width="{Binding (ListViewItem.ActualWidth), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}}">
<Expander.Header>
<!-- Thumbnail/Preview Section -->
<StackPanel>
<Image Source="/XAML;component/Assets/Images/Thumb.png" Height="16" Width="16" />
<Label Content="{Binding Name}"/>
</StackPanel>
</Expander.Header>
<!-- Self stretching Grid (Custom Control) -->
<cc:StretchGrid x:Name="PicDetails" Background="LightGray" ParentWrappanel="{Binding Path=Tag, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type WrapPanel}}}">
<!-- Picture Detail Section (quick & dirty designed, replace later) -->
<Image ClipToBounds="False" Source="/XAML;component/Assets/Images/Highres.png" Width="128" Height="128" HorizontalAlignment="Left" Margin="10,0" />
<Rectangle Fill="Black" Height="128" Width="5" HorizontalAlignment="Left"/>
<Rectangle Fill="Black" Height="128" Width="5" HorizontalAlignment="Right"/>
<StackPanel Margin="150,0">
<Label Content="{Binding Name}"/>
<Label Content="Description: Lorem"/>
<Label Content="Category: Ipsum"/>
<Label Content="Owner: Dolor"/>
<Label Content="Size: 5kB"/>
</StackPanel>
</cc:StretchGrid>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
<!-- Brings selected element to front, details see edit -->
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Panel.ZIndex" Value="1" />
</Trigger>
</Style.Triggers>
</Style>
</Setter.Value>
</Setter>
</Style>
Note: Its necessary to add a Reference to the StretchGrid.
And the StretchGrid Custom Control
class StretchGrid : Grid
{
//Reference for parent expander (used to calculate Grid Margin)
private Expander m_expander;
//Property for relativesource Binding to Wrappanel in Style
public WrapPanel ParentWrappanel
{
get { return (WrapPanel)this.GetValue(Wrappanel); }
set { this.SetValue(Wrappanel, value); }
}
//DependencyProperty for RelativeSource Binding to Wrappanel in Style (Note: the Binding is set inside the Style, not here programmatically in PropertyMetaData)
public static readonly DependencyProperty Wrappanel = DependencyProperty.Register("ParentWrappanel", typeof(WrapPanel), typeof(StretchGrid), new PropertyMetadata(null));
//Constructor
public StretchGrid() : base()
{
Application.Current.MainWindow.Loaded += Init;
Application.Current.MainWindow.SizeChanged += UpdateMargins;
}
private void Init(object sender, RoutedEventArgs e)
{
m_expander = (Expander)this.Parent; //Change when xaml markup hirarchy changes
if(m_expander != null) //(or make it similar to the Wrappanel with
{ //RelativeSource Binding)
m_expander.Expanded += UpdateMargins; //Update when expander is expanded
m_expander.SizeChanged += UpdateMargins; //Update when the expander changes the Size
//Update all StretchGrids on Initialization
UpdateMargins(null, null);
}
}
//Calculate Grid Margin when an according Event is triggered
private void UpdateMargins(object sender, RoutedEventArgs e)
{
if(ParentWrappanel != null)
{
Point delta = m_expander.TranslatePoint(new Point(0d, 0d), ParentWrappanel);
//Create negative Margin to allow the Grid to be rendered outside of the Boundaries (full column under the Image)
this.Margin = new Thickness(-delta.X, 0, delta.X + m_expander.ActualWidth - ParentWrappanel.ActualWidth, 0);
//Theese Values arent calculated exavtly, just broad for example purpose
}
}
}
This is a little bit tricky to incorporate in existing Code. A working Example may help and is found HERE.
SideNote: If i got more time i would pack this stuff into a bigger Custom Control to use it like a normal UIElement (eg. Border). This would improve the re-usability and usability quite a lot.
EDIT
The 'newest' element in the ListView is also atop of the Z-Index, therefore it is 'above' the expanded StretchGrid and some Controls can not be clicked because they are 'behind' the next ListviewItem.
To fix this, add
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Panel.ZIndex" Value="1" />
</Trigger>
</Style.Triggers>
to the ListViewItem Style. Now when its visible it will place itself atop the other Controls.
This is what I have done so far:-
Images listed:
An Image Clicked - will show the Details view below it:
At the moment I am not closing other Detail Views - so below can happen for me.
However, all this needs is to propagate an event that some other item has been clicked. and close all other Detail Views (its mvvm and driven by a bool property)
======================================================
I have a Base UserControl which will load Items in a Top Down manner:
<Grid>
<Grid>
<ScrollViewer>
<ItemsControl ItemsSource="{Binding GridData, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
</Grid>
</Grid>
Each Row (Item) of this UserControl itself uses another ItemsControl. So that Images are lined up horizontally. Also, Each Item has a Details View Section (Border with Visibility controlled by Image clicks)
<UserControl.Resources>
<ResourceDictionary>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ItemsControl Grid.Row="0" ItemsSource="{Binding ImagesList, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Margin="5" Command="{Binding DataContext.ItemClickedCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"
CommandParameter="{Binding}">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Image Grid.Row="0" Source="{Binding Image, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Name="DisplayText" Grid.Row="1" HorizontalAlignment="Center" Text="{Binding DisplayText, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Border Margin="2" Grid.Row="1" Background="Black" Padding="10"
Visibility="{Binding ShowDetailsPanel, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BooleanToVisibilityConverter}}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Background="White" CornerRadius="10">
<Image Margin="5" Source="{Binding SelectedImage.Image, UpdateSourceTrigger=PropertyChanged}"/>
</Border>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Margin="20 20 0 0" FontSize="15"
Text="{Binding SelectedImage.ImageName, StringFormat={}Filename: {0}}" Foreground="White"/>
<TextBlock Grid.Row="1" Margin="20 20 0 0" FontSize="15"
Text="{Binding SelectedImage.Size, StringFormat={}Size: {0} bytes}" Foreground="White"/>
<TextBlock Grid.Row="2" Margin="20 20 0 0" FontSize="15"
Text="{Binding SelectedImage.Location, StringFormat={}Path: {0}}" Foreground="White"/>
<TextBlock Grid.Row="3" Margin="20 20 0 0" FontSize="15"
Text="{Binding SelectedImage.CreatedTime, StringFormat={}Last Modified: {0}}" Foreground="White"/>
</Grid>
</Grid>
</Border>
</Grid>
</Grid>
I have a Stackpanel with a Image in it. The Image is partly transperent.
So i want the Background to be Red, when the mouse is not over (which works). But wen the mouse is over it should turn into green. But it doesn't work. Can you please help me out.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:shell="clr-namespace:System.Windows.Shell;assembly=PresentationFramework">
<Style x:Key="PhoenixWindowStyle" TargetType="{x:Type Window}">
<Setter Property="shell:WindowChrome.WindowChrome">
<Setter.Value>
<shell:WindowChrome GlassFrameThickness="0"
ResizeBorderThickness="1"
CaptionHeight="32"
CornerRadius="0"/>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="{DynamicResource DefaultBackgroundBrush}"/>
<Setter Property="MinWidth" Value="100"/>
<Setter Property="MinHeight" Value="100"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Grid Background="{DynamicResource BorderBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="1"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition Height="*"/>
<RowDefinition Height="1"/>
</Grid.RowDefinitions>
<DockPanel Grid.Column="1" Grid.Row="0">
<TextBlock DockPanel.Dock="Left" Margin="0, 2, 0, 2" Padding="0">
<Image Width="24"
Height="24"
Margin="2"
Source="{TemplateBinding Icon}"
SnapsToDevicePixels="True"
RenderOptions.EdgeMode="Aliased" />
<Run BaselineAlignment="Center"
Text="{TemplateBinding Title}"
Foreground="{DynamicResource DefaultBackgroundBrush}"/>
</TextBlock>
<TextBlock DockPanel.Dock="Right" HorizontalAlignment="Right">
<!--This it the part I showed before -->
<StackPanel Width="38" Height="32">
<StackPanel.Style>
<Style TargetType="StackPanel">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Green"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Background" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<Image
Width="38"
Height="32"
Margin="0"
Source="../Images/FrameControlIcons/38x32/close.png"/>
</StackPanel>
<!--/////////////////////-->
</TextBlock>
</DockPanel>
<DockPanel Grid.Column="1" Grid.Row="1" >
<ContentPresenter />
</DockPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
My co-worker recognized the problem. The Problem was, that my Image was covered by the CaptionHeight of the WindowChrome. When i set the CaptionHeigt to zero it works.
So i found a solution to make both work. The CaptionHeight (To drag the window around) and the mouse event on Element that are coverd by the CaptionHeight.
I had to set this property on the affected element:
shell:WindowChrome.IsHitTestVisibleInChrome="True"
I found this Solution here:
How can I add a button to the WPF caption bar while using custom window chrome?
I'm relatively new to WPF, so bear with me.
I'm trying to set the background colour of a combo box when it receives focus. I'm setting a trigger in the control template for it's togglebutton to change colour on mouse over, and when it receives focus. Mouse over works fine, but when I tab into the combobox nothing happens until I tab a second time(It changes colour then).
So what I want is for the background colour to change when the user first tabs in.
Any help would be greatly appreciated.
<SolidColorBrush x:Key="ComboBoxNormalBorderBrush" Color="Black" />
<SolidColorBrush x:Key="ComboBoxNormalBackgroundBrush" Color="#fff" />
<SolidColorBrush x:Key="ComboBoxDisabledForegroundBrush" Color="#888" />
<SolidColorBrush x:Key="ComboBoxDisabledBackgroundBrush" Color="#eee" />
<SolidColorBrush x:Key="ComboBoxDisabledBorderBrush" Color="#888" />
<ControlTemplate TargetType="ToggleButton" x:Key="ComboBoxToggleButtonTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Border
Grid.ColumnSpan="2"
Name="Border"
BorderBrush="{StaticResource ComboBoxNormalBorderBrush}"
CornerRadius="0" BorderThickness="0.6"
Background="{StaticResource YellowBrush}">
</Border>
<Border
Grid.Column="1"
Margin="1"
BorderBrush="#444"
Name="ButtonBorder"
CornerRadius="0, 0, 0, 0"
BorderThickness="2"
Background="Gray" />
<Path Name="Arrow" Grid.Column="1"
Data="M0,0 L0,2 L4,6 L8,2 L8,0 L4,4 z"
HorizontalAlignment="Center" Fill="White"
VerticalAlignment="Center" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsMouseOver" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource YellowBrush1}" />
</Trigger>
<Trigger Property="ToggleButton.IsFocused" Value="True">
<Setter TargetName="Border" Property="Background" Value="{StaticResource YellowBrush1}" />
</Trigger>
<Trigger Property="UIElement.IsMouseOver" Value="True">
<Setter Property="Panel.Background" TargetName="ButtonBorder" Value="DarkGray"/>
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="True">
<Setter Property="Panel.Background" TargetName="ButtonBorder" Value="LightGray"/>
<Setter Property="Shape.Fill" TargetName="Arrow" Value="Black"/>
</Trigger>
<Trigger Property="UIElement.IsEnabled" Value="False">
<Setter Property="Panel.Background" TargetName="Border" Value="{StaticResource ComboBoxDisabledBackgroundBrush}"/>
<Setter Property="Panel.Background" TargetName="ButtonBorder" Value="{StaticResource ComboBoxDisabledBackgroundBrush}"/>
<Setter Property="Border.BorderBrush" TargetName="ButtonBorder" Value="{StaticResource ComboBoxDisabledBorderBrush}"/>
<Setter Property="TextElement.Foreground" Value="{StaticResource ComboBoxDisabledForegroundBrush}"/>
<Setter Property="Shape.Fill" TargetName="Arrow" Value="#999"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="UIElement.SnapsToDevicePixels" Value="True"/>
<Setter Property="FrameworkElement.OverridesDefaultStyle" Value="True"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="True"/>
<Setter Property="TextElement.Foreground" Value="Black"/>
<Setter Property="Height" Value="25"/>
<Setter Property="Margin" Value="0,0,0,4"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="IsEditable" Value="False"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="FrameworkElement.FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Background" Value="{StaticResource NouvemYellowBrush}"/>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton Name="ToggleButton"
ClickMode="Press"
Focusable="True"
IsChecked="{Binding Path=IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
Template="{StaticResource ComboBoxToggleButtonTemplate}"/>
<ContentPresenter Name="ContentSite" Margin="5, 3, 23, 3" IsHitTestVisible="False"
HorizontalAlignment="Left" VerticalAlignment="Center"
Focusable="False"
Content="{TemplateBinding ComboBox.SelectionBoxItem}"
ContentTemplate="{TemplateBinding ComboBox.SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"/>
<TextBox Name="PART_EditableTextBox" Margin="3, 3, 23, 3"
IsReadOnly="{TemplateBinding IsReadOnly}"
Visibility="Hidden" Background="Transparent"
HorizontalAlignment="Left" VerticalAlignment="Center"
Focusable="False">
<TextBox.Template>
<ControlTemplate TargetType="TextBox">
<Border Name="PART_ContentHost" Focusable="False"/>
</ControlTemplate>
</TextBox.Template>
</TextBox>
<!-- Popup showing items -->
<Popup Name="Popup"
Placement="Bottom"
Focusable="False"
AllowsTransparency="True"
IsOpen="{TemplateBinding ComboBox.IsDropDownOpen}"
PopupAnimation="Slide">
<Grid Name="DropDown" SnapsToDevicePixels="True"
MinWidth="{TemplateBinding FrameworkElement.ActualWidth}"
Focusable="False"
MaxHeight="{TemplateBinding ComboBox.MaxDropDownHeight}">
<Border Name="DropDownBorder"
Background="White"
Focusable="False"
Margin="0, 1, 0, 0"
CornerRadius="0"
BorderThickness="1"
BorderBrush="Black"/>
<ScrollViewer Margin="4" SnapsToDevicePixels="True" Focusable="False">
<ItemsPresenter KeyboardNavigation.DirectionalNavigation="Contained" Focusable="False"/>
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ItemsControl.HasItems" Value="False">
<Setter Property="FrameworkElement.MinHeight" TargetName="DropDownBorder" Value="95"/>
</Trigger>
<Trigger Property="UIElement.IsEnabled" Value="False">
<Setter Property="TextElement.Foreground" Value="{StaticResource ComboBoxDisabledForegroundBrush}"/>
</Trigger>
<Trigger Property="ItemsControl.IsGrouping" Value="True">
<Setter Property="ScrollViewer.CanContentScroll" Value="False"/>
</Trigger>
<Trigger Property="ComboBox.IsEditable" Value="True">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False"/>
<Setter Property="UIElement.Visibility" TargetName="PART_EditableTextBox" Value="Visible"/>
<Setter Property="UIElement.Visibility" TargetName="ContentSite" Value="Hidden"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Edit: showing the relevant view
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<command:EventToCommand Command="{Binding OnLoadingCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
<i:EventTrigger EventName="Unloaded">
<command:EventToCommand Command="{Binding OnClosingCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="11*"/>
<ColumnDefinition Width="14*"/>
<ColumnDefinition Width="14*"/>
<ColumnDefinition Width="14*"/>
<ColumnDefinition Width="14*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height=".2*"/>
<RowDefinition Height="3.5*"/>
<RowDefinition Height="8*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid x:Name="GridGlobalData" Grid.Row="1" Grid.ColumnSpan="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--left side-->
<Label Content="Code _________________________________________________________________________________________________________________"/>
<Label Content="Name _________________________________________________________________________________________________________________" Grid.Row="1"/>
<Label Content="Business Partner Type ________________________________________________________________________" Grid.Row="2"/>
<Label Content="Group _________________________________________________________________________________________________________________" Grid.Row="3"/>
<Label Content="Currency ___________________________________________________________________________________________________________" Grid.Row="4"/>
<TextBox x:Name="TextBoxCode" Text="{Binding PartnerCode, UpdateSourceTrigger=PropertyChanged}" Grid.Column="1">
<TextBox.InputBindings>
<KeyBinding Command="{Binding ControlButtonCommand}" CommandParameter="Add" Key="A" Modifiers="Control" />
<KeyBinding Command="{Binding FindBusinessPartnerCommand}" CommandParameter="Code" Key="Enter"/>
</TextBox.InputBindings>
</TextBox>
<TextBox Text="{Binding PartnerName, UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Grid.Row="1">
<TextBox.InputBindings>
<KeyBinding Command="{Binding FindBusinessPartnerCommand}" CommandParameter="Name" Key="Enter"/>
</TextBox.InputBindings>
</TextBox>
<ComboBox ItemsSource="{Binding BusinessPartnerTypes}" DisplayMemberPath="Type" SelectedItem="{Binding PartnerType}" SelectedIndex="0" Grid.Column="1" Grid.Row="2"/>
<ComboBox ItemsSource="{Binding BusinessPartnerGroups}" DisplayMemberPath="BPGroupName" SelectedItem="{Binding PartnerGroup}" SelectedIndex="0" Grid.Column="1" Grid.Row="3"/>
<ComboBox ItemsSource="{Binding BusinessPartnerCurrencies}" DisplayMemberPath="Name" SelectedItem="{Binding PartnerCurrency}" SelectedIndex="0" Grid.Column="1" Grid.Row="4"/>
<!--right side-->
<Label Content="Display Currency _________________________________________________________________________________________________________________" Grid.Column="3" />
<Label Content="Invoices _________________________________________________________________________________________________________________" Grid.Column="3" Grid.Row="1"/>
<Label Content="Deliveries _________________________________________________________________________________________________________________" Grid.Column="3" Grid.Row="2"/>
<Label Content="Orders _________________________________________________________________________________________________________________" Grid.Column="3" Grid.Row="3"/>
<ComboBox ItemsSource="{Binding BusinessPartnerCurrencies}" DisplayMemberPath="Name" SelectedItem="{Binding DisplayCurrency}" Style="{StaticResource StyleComboBoxReadonly}" SelectedIndex="0" Grid.Column="4"/>
<TextBox Style="{StaticResource StyleTextBoxNonEditable}" Grid.Column="4" Grid.Row="1"/>
<TextBox Style="{StaticResource StyleTextBoxNonEditable}" Grid.Column="4" Grid.Row="2"/>
<TextBox Style="{StaticResource StyleTextBoxNonEditable}" Grid.Column="4" Grid.Row="3"/>
</Grid>
<TabControl SelectedIndex="{Binding SelectedPartnerView}" Grid.Row="2" Grid.ColumnSpan="6" >
<TabItem Header="General">
<BusinessPartner:BPGeneralView />
</TabItem>
<TabItem Header="Contacts">
<BusinessPartner:BPContactView />
</TabItem>
<TabItem Header="Addresses">
<BusinessPartner:BPAddressesView />
</TabItem>
<TabItem Header="Payment Terms">
<BusinessPartner:BPPaymentTerms />
</TabItem>
<TabItem Header="Properties">
<BusinessPartner:BPPropertiesView />
</TabItem>
<TabItem Header="Remarks">
<BusinessPartner:BPRemarksView />
</TabItem>
<TabItem Header="Attachments">
<BusinessPartner:BPAttachmentsView />
</TabItem>
</TabControl>
<Grid x:Name="GridCrontrolButtons" Grid.Row="3" Grid.ColumnSpan="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="7*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<data:CrudView Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"/>
</Grid>
</Grid>
You should be able to achieve this by adding an additional IsKeyboardFocused trigger alongside your MouseOver and IsFocused triggers in the ToggleButton control template:
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter TargetName="Border" Property="Background" Value="{StaticResource YellowBrush1}" />
</Trigger>
MSDN: https://msdn.microsoft.com/en-us/library/bb613567%28v=vs.110%29.aspx (Scroll down to IsKeyboardFocused section)
UPDATE:
The problem in this case is to do with where you're setting your triggers. You're relying on the ToggleButton to have focus so that you can change it's background colour - but in actual fact you want to the content of the combobox to have focus.
The reason you have to TAB twice to apparently achieve focus is because for each ComboBox you're tabbing between the control's ToggleButton, and then the ComboBox selected item (through the ContentPresenter).
One possible fix: First you need to prevent your ToggleButton in your ComboBox template from getting focus:
<ToggleButton Name="ToggleButton"
ClickMode="Press"
Focusable="False"
IsTabStop="False" ... >
I've actually removed ALL of the Focusable="False" setters from your ToggleButton template as they're not needed.
Then make your ToggleButton template transparent (Border.Background), and remove the existing triggers that affect the Border.Background colour.
Now move to your ComboBox template and give the root <Grid> a name. I've called it templateRoot in my example.
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid Name="templateRoot">
<ToggleButton Name="ToggleButton" ... >
And now set the background colour for your combobox using that templateRoot. You can add the Triggers you removed from the ToggleButton template to the ComboBox template:
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="Background" TargetName="templateRoot" Value="{StaticResource YellowBrush1}" />
</Trigger>
... and the other triggers.
With this approach, you're relying on the ComboBox control to trigger your changes when it has focus.
If this solution doesn't work for your needs, then I hope at least you can see where the problem you're having originates.
You shouldn't need to go to the level of editing the template for this, just the style:
<ComboBox>
<ComboBoxItem>Apple</ComboBoxItem>
<ComboBoxItem>Banana</ComboBoxItem>
<ComboBoxItem>Pear</ComboBoxItem>
<ComboBox.Style>
<Style TargetType="{x:Type ComboBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Background" Value="Violet" />
</Trigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
My Groupbox template is defined as so
<Style x:Key="{x:Type GroupBox}" TargetType="{x:Type GroupBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupBox}">
<Border BorderThickness="1" BorderBrush="SomeColour"
Background="SomeColour"
CornerRadius="4">
<Grid SnapsToDevicePixels="true">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<ContentPresenter Grid.Row="0" ContentSource="Header"
Margin="2"/>
<ContentPresenter Grid.Row="1"
Margin="{TemplateBinding Padding}"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
How do I make it so that if the Header is set to a simple simple string, e.g
<GroupBox Header="The header!" />
The text is bold and with some default colour?
I tried the following, but it only works for the weight, not the colour.
<ContentPresenter ContentSource="Header" TextBlock.Foreground="Red"
TextBlock.FontWeight="Bold"/>
Edit : here is the textblock style
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="{StaticResource LabelForegroundBrush}" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Margin" Value="1" />
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{StaticResource DisabledLabelForegroundBrush}" />
</Trigger>
</Style.Triggers>
</Style>
Edit 2 : If I place the following in <Window.Resources> it seems to work, yet if I place them in <Application.Resources>, .. it fails???
<XXX.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Green" />
</Style>
<Style x:Key="{x:Type GroupBox}" TargetType="{x:Type GroupBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupBox}">
<Grid SnapsToDevicePixels="true">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<ContentPresenter Grid.Row="0" ContentSource="Header" TextElement.Foreground="Red" />
<ContentPresenter Grid.Row="1" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</XXX.Resources>
Usage :
<GroupBox Header="Header">
<Button Content="Content" />
</GroupBox>
Try this
<Style x:Key="{x:Type GroupBox}" TargetType="{x:Type GroupBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupBox}">
<Border BorderThickness="1" BorderBrush="SomeColour"
Background="SomeColour"
CornerRadius="4">
<Grid SnapsToDevicePixels="true">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Foreground="Red" FontWeight="Bold" Margin="2">
<ContentPresenter ContentSource="Header"/>
</TextBlock>
<ContentPresenter Grid.Row="1" Margin="{TemplateBinding Padding}"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You need attached properties TextElement.FontWeight and TextElement.Foreground instead.
<ContentPresenter ContentSource="Header"
Margin="2"
TextElement.FontWeight="Bold"
TextElement.Foreground="Red"/>
In case style is under Application resources, it
ignores the foreground set on ContentPresenter. If i have it under Window resources, it works
fine.
However, you can override Style for TextBlock and set only Foreground property. Also you can inherit all other properties from Style declared under App resources using BasedOn. Place that style under resource of ContentPresenter so that it gets overridden only for your ContentPresenter.
This will work:
<ContentPresenter Grid.Row="0" ContentSource="Header"
Margin="2" TextBlock.FontWeight="Bold">
<ContentPresenter.Resources>
<Style TargetType="TextBlock"
BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="Foreground" Value="Red"/>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
I have a Usercontrol: SnazzyForm, which in addition to a couple of borders and and a header area and whatnot, also has a Content Presenter which under .NET Framework 3.5 presented content passed to it in other forms that used the control just fine.
However after moving the project to 4.0 I am greeted with "Cannot add content to object of type" blah blah blah.
The codebehind for the control is thus:
Imports System
Imports System.IO
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Data
Imports System.Windows.Media
Imports System.Windows.Media.Animation
Imports System.ComponentModel
Public Class SnazzyForm
Inherits ContentControl
Public Shared TitleProperty As DependencyProperty = DependencyProperty.Register("Title", GetType(String), GetType(SnazzyForm))
<Description("Title to display"), _
Category("Custom")> _
Public Property Title() As String
Get
Return CType(GetValue(TitleProperty), String)
End Get
Set(ByVal value As String)
SetValue(TitleProperty, value)
End Set
End Property
Shared Sub New()
' Insert code required on object creation below this point.
DefaultStyleKeyProperty.OverrideMetadata(GetType(SnazzyForm), New FrameworkPropertyMetadata(GetType(SnazzyForm)))
End Sub
End Class
The template in the resourcedictionary that governs this control is thus:
<Style TargetType="{x:Type local:SnazzyForm}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:SnazzyForm}">
<ControlTemplate.Resources>
<Style TargetType="{x:Type Border}" x:Key="formOuterBorderStyle">
<Setter Property="Margin" Value="22,22,22,3" />
<Setter Property="Padding" Value="0" />
<Setter Property="BorderBrush" Value="{StaticResource BrushBorder}" />
<Setter Property="BorderThickness" Value="3" />
<Setter Property="Background" Value="{StaticResource BrushBackgroundDark}" />
<Setter Property="CornerRadius" Value="20,20,0,0" />
</Style>
<Style TargetType="{x:Type TextBlock}" x:Key="formTitleStyle">
<Setter Property="Foreground" Value="{StaticResource BrushWhiteSmoke}" />
<Setter Property="FontFamily" Value="Verdana" />
<Setter Property="FontSize" Value="16" />
<Setter Property="Padding" Value="11,7,7,7" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
<Style TargetType="{x:Type TextBlock}" x:Key="formBreadcrumbStyle">
<Setter Property="Foreground" Value="{StaticResource BrushWhiteSmoke}" />
<Setter Property="FontFamily" Value="Verdana" />
<Setter Property="FontSize" Value="11" />
<Setter Property="Padding" Value="7" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
<Style TargetType="{x:Type Rectangle}" x:Key="formBackgroundRectangleStyle">
<Setter Property="Fill" Value="{StaticResource BrushABCLight}" />
</Style>
<Style TargetType="{x:Type Border}" x:Key="formTitleBorderStyle">
<Setter Property="BorderBrush" Value="{StaticResource BrushBlack}" />
<Setter Property="BorderThickness" Value="0,0,0,2" />
</Style>
</ControlTemplate.Resources>
<AdornerDecorator d:DesignWidth="640" d:DesignHeight="480">
<Grid Width="Auto" Height="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<TextBlock HorizontalAlignment="Left" Margin="0" VerticalAlignment="Top" FontFamily="Arial" FontSize="18.667" Foreground="#FFE0E0E0" Text="{TemplateBinding Title}" TextWrapping="Wrap" Panel.ZIndex="2" Visibility="Collapsed"/>
<Path Fill="Black" Stretch="Fill" Stroke="{x:Null}" Margin="0" VerticalAlignment="Stretch" Height="Auto" Grid.Column="1" Grid.Row="0" Data="M0.5,0.5 L39.5,39.5 0.5,39.5 z"/>
<Border Background="Black" Margin="0" VerticalAlignment="Stretch" Height="Auto" Grid.Row="0" CornerRadius="10,0,0,0"/>
<!-- <Rectangle Fill="Black" Stroke="Black" Margin="0" VerticalAlignment="Stretch" Height="Auto" Grid.Row="0"/> -->
<Rectangle Stroke="{x:Null}" Margin="0" Height="Auto" Opacity="0.5" Grid.ColumnSpan="2" Grid.Row="3" Grid.RowSpan="1">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF222222" Offset="0"/>
<GradientStop Color="#FFB3B3B3" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle Fill="Black" Stroke="Black" Margin="0" Grid.ColumnSpan="2" Grid.Row="1"/>
<Rectangle Fill="{TemplateBinding Background}" Stroke="Black" Margin="0" Height="Auto" Panel.ZIndex="-7" Grid.ColumnSpan="2" Grid.Row="2" Grid.RowSpan="1"/>
<Border x:Name="bdr" Style="{StaticResource formOuterBorderStyle}" Margin="0" Grid.ColumnSpan="2" Grid.RowSpan="3" d:LayoutOverrides="Width, Height" d:IsHidden="True" Visibility="Collapsed"/>
<Grid Margin="3" Grid.ColumnSpan="2" Grid.RowSpan="3">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" MinHeight="77" />
<RowDefinition MinHeight="400" />
</Grid.RowDefinitions>
<Border Style="{StaticResource formTitleBorderStyle}" BorderBrush="{x:Null}">
<StackPanel Margin="0">
<TextBlock Text="{Binding ViewModelFriendlyName}" Style="{StaticResource formTitleStyle}" />
<TextBlock Margin="11,0,0,0" Text="{Binding BreadcrumbTrail}" Style="{StaticResource formBreadcrumbStyle}" />
</StackPanel>
</Border>
<Rectangle Grid.Row="1" Style="{StaticResource formBackgroundRectangleStyle}" Visibility="Collapsed" />
<!--Put the form below here-->
<ContentPresenter x:Name="ContentPresenterX" Grid.Row="1" Margin="0" />
<!--Put the form above here-->
</Grid>
</Grid>
</AdornerDecorator>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I guess I really just want to know why I now have to tell the control to use the contentpresenter to present the content, when previously it know that is what I wanted, and also how I do it.
Any thoughts?
Cory
Added Content={TemplateBinding Property=Content} to ContentPresenter.
MSDN Forum post regarding this issue suggested adding the ContentPropertyAttribute setter to the controls codebehind, but I could not get that to work.
Cory