I want to make a button like this:
The first image is a normal button, but the second is a button with mouseEnter event fired. The bottom part of the button in the second image is not clickable and it acts like a tool tip. How can I make this kind of a button? Do I need to use a tool tip? Please give me some code examples.
EDIT:
Here's F Ruffel's code which I modified:
<HeaderedContentControl BorderBrush="Black">
<HeaderedContentControl.Header>
<TextBlock Text="Header Placeholder" Margin="5" />
</HeaderedContentControl.Header>
<StackPanel>
<TextBlock Text="Content Placeholder Line 1" Margin="5" HorizontalAlignment="Center"/>
<TextBlock Text="Content Placeholder Line 2" Margin="5" HorizontalAlignment="Center"/>
<TextBlock Text="Content Placeholder Line 3" Margin="5" HorizontalAlignment="Center"/>
</StackPanel>
<HeaderedContentControl.Style>
<Style TargetType="{x:Type HeaderedContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type HeaderedContentControl}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Border x:Name="headerBorder" Grid.Row="0" Grid.Column="0" BorderThickness="1" BorderBrush="{TemplateBinding BorderBrush}">
<Grid Name="Header">
<Rectangle Fill="White"/>
<ContentPresenter x:Name="contentPresenter" Content="{TemplateBinding Header}"/>
</Grid>
</Border>
<Border x:Name="contentBorder" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" BorderThickness="1" BorderBrush="{TemplateBinding BorderBrush}" Visibility="Collapsed">
<ContentPresenter />
</Border>
<Border x:Name="cutOutBorder" Grid.Row="0" Grid.Column="1" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0,0,0,1" Visibility="Collapsed" />
</Grid>
<ControlTemplate.Triggers>
<Trigger SourceName="Header" Property="IsMouseOver" Value="True">
<Setter TargetName="headerBorder" Property="BorderThickness" Value="1,1,1,0" />
<Setter TargetName="contentBorder" Property="BorderThickness" Value="1,0,1,1" />
<Setter TargetName="contentBorder" Property="Visibility" Value="Visible" />
<Setter TargetName="cutOutBorder" Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</HeaderedContentControl.Style>
</HeaderedContentControl>
</StackPanel>
Now the last problem is: the expanded part pushes all controls down, and that's what I don't want. Please modify this code to make the extended part overlay controls that are below it, just like in the image.
What I like about WPF is that there is a hundred and one ways to do the same thing. In addition to the suggestions above, you could easily style a HeaderedContentControl to give the desired look and behaviour:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<HeaderedContentControl BorderBrush="Black">
<HeaderedContentControl.Header>
<TextBlock Text="Header Placeholder" Margin="5" />
</HeaderedContentControl.Header>
<StackPanel>
<TextBlock Text="Content Placeholder Line 1" Margin="5" HorizontalAlignment="Center"/>
<TextBlock Text="Content Placeholder Line 2" Margin="5" HorizontalAlignment="Center"/>
<TextBlock Text="Content Placeholder Line 3" Margin="5" HorizontalAlignment="Center"/>
</StackPanel>
<HeaderedContentControl.Style>
<Style TargetType="{x:Type HeaderedContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type HeaderedContentControl}">
<Grid x:Name="outerGrid" Background="Transparent">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Border x:Name="headerBorder" Grid.Row="0" Grid.Column="0" BorderThickness="1" BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter x:Name="contentPresenter" Content="{TemplateBinding Header}"/>
</Border>
<Border x:Name="contentBorder" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" BorderThickness="1" BorderBrush="{TemplateBinding BorderBrush}" Visibility="Collapsed">
<ContentPresenter />
</Border>
<Border x:Name="cutOutBorder" Grid.Row="0" Grid.Column="1" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0,0,0,1" Visibility="Collapsed" Background="Transparent" />
</Grid>
</Grid>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="UIElement.MouseLeftButtonUp" SourceName="contentPresenter">
<BeginStoryboard x:Name="makeVisibleBeginStoryboard">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="headerBorder" Storyboard.TargetProperty="BorderThickness">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Thickness Left="1" Top="1" Right="1" Bottom="0" />
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="contentBorder" Storyboard.TargetProperty="BorderThickness">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Thickness Left="1" Top="0" Right="1" Bottom="1" />
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="contentBorder" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="cutOutBorder" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="UIElement.MouseLeave" SourceName="outerGrid">
<StopStoryboard BeginStoryboardName="makeVisibleBeginStoryboard" />
</EventTrigger>
<EventTrigger RoutedEvent="UIElement.MouseEnter" SourceName="cutOutBorder">
<StopStoryboard BeginStoryboardName="makeVisibleBeginStoryboard" />
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</HeaderedContentControl.Style>
</HeaderedContentControl>
</StackPanel>
</Window>
This solution simulates a cut-out portion (which is just a cell in a Grid). It uses an EventTrigger so that content is visible when the Header is clicked, and content is made invisible when the mouse leaves the Grid hosting the content, or if it enters the cut-out portion.
Although I think this achieves what you are after, I would recommend investigating other approaches like ToolTip, Adorner, or a even custom control. Using animations like this always feels like over-kill to me :)
I would suggest you to add an adorner to your button and make it visible on Mouse Enter event and just remove the adorner on Mouse Leave event. In case you are new to Adorner's you can look at the brief overview here and few custom samples here-
http://msdn.microsoft.com/en-us/library/ms743737.aspx
http://denisvuyka.wordpress.com/2007/10/15/wpf-simple-adorner-usage-with-drag-and-resize-operations/
This could be an Expander styled appropriately. Here is an image how it normally looks like, but with templates and styles you can drastically alter the appearance of controls. The behaviour looks like an expander that just expands on hover instead of click, though.
I've got a small example that I build myself once. In CSS set #loginBox to display:none. Then when a.loginButton is clicked, let javascript (e.g. jQuery) change display to display:block
<div id="head-login">
<span>Klanten login</span>
<div class="clear"></div>
<div id="loginBox">
<form id="loginForm" action="http://www.dennishunink.nl/dqr/app/login-check.php" method="post">
<fieldset id="body">
<fieldset>
<label for="email">Email Adres</label>
<input type="text" name="email" id="email" />
</fieldset>
<fieldset>
<label for="password">Wachtwoord</label>
<input type="password" name="password" id="password" />
</fieldset>
<input type="submit" id="login" value="Log in" />
<label for="checkbox"><input type="checkbox" id="checkbox" />Onthoudt mij</label>
</fieldset>
<span>Wachtwoord vergeten?</span>
</form>
</div>
</div>
</div>
Related
I have used a custom data grid control that adds a TextBox to the column headers for filtering. Unfortunately, i have faced a problem when i tried to bind Visiblilty property of DataGridRow to Text property of TextBox (called filterTextBox); see the bellow code. The object received in the converter method "SearchColumnToVisibilityConverter" has the value "DependencyProperty.UnsetValue".
<ControlTemplate TargetType="{x:Type local:SimpuDataGrid}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<StackPanel Orientation="Vertical" DataContext="{TemplateBinding DataContext}">
<TextBox Width="200" Margin="2" HorizontalAlignment="Left" x:Name="txtFullTextSearch"
Visibility="{TemplateBinding EnableFullTextSearch,
Converter={StaticResource BooleanToVisibilityConverter}}" />
<DataGrid x:Name="simpuGrid"
ItemsSource="{TemplateBinding ItemsSource}" CanUserAddRows="{TemplateBinding CanUserAddRows}"
CanUserDeleteRows="{TemplateBinding CanUserDeleteRows}"
AutoGenerateColumns="{TemplateBinding AutoGenerateColumns}">
<DataGrid.Resources>
<!--Custom Column Header template to show extra elements in the header-->
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<!--Let's keep the top section grid to contain the DataGridHeaderBorder, and left+right thumbs.-->
<Grid x:Name="fullHeader" Background="{StaticResource normalBrushBack}">
<!--Here is the theme based DataGridHeaderBorder. I've used Aero here.-->
<aero:DataGridHeaderBorder x:Name='HeaderBorder' SortDirection="{TemplateBinding SortDirection}" IsHovered="{TemplateBinding IsMouseOver}" IsPressed="{TemplateBinding IsPressed}" IsClickable="{TemplateBinding CanUserSort}" BorderThickness="0,0,1,1" BorderBrush="{TemplateBinding Foreground}" Background="Transparent" SeparatorVisibility="{TemplateBinding SeparatorVisibility}" SeparatorBrush="#FFC9CACA">
<!--We will put 3 elements inside the border: Content of header, a drop down button, and a sort order indicator.-->
<Grid Margin="0,0,0,0">
<Grid.RowDefinitions>
<!--For ContentPresenter-->
<RowDefinition Height="*" />
<!--For drop down button-->
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<!--For ContentPresenter-->
<ColumnDefinition Width="*" />
<!--For sort order indicator-->
<ColumnDefinition Width="12" />
</Grid.ColumnDefinitions>
<!--Content of the header.-->
<ContentPresenter Grid.Row="0" Grid.Column="0" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" Cursor="{TemplateBinding Cursor}" >
<ContentPresenter.Content>
<MultiBinding Converter="{StaticResource headerConverter}">
<MultiBinding.Bindings>
<Binding ElementName="filterTextBox" Path="Text" />
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Content" />
</MultiBinding.Bindings>
</MultiBinding>
</ContentPresenter.Content>
</ContentPresenter>
<!--A textbox filter-->
<TextBox x:Name="filterTextBox" Background="White" Grid.Row="1" Grid.ColumnSpan="2" />
<!--A sort order arrow icon.-->
<Path x:Name="SortArrow" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Center" Width="8" RenderTransformOrigin=".5,.5" Visibility="Visible" Fill="{TemplateBinding Foreground}" Stretch="Uniform" Data="F1 M -5.215,6.099L 5.215,6.099L 0,0L -5.215,6.099 Z" />
</Grid>
</aero:DataGridHeaderBorder>
<Thumb x:Name="PART_LeftHeaderGripper" HorizontalAlignment="Left" Style="{StaticResource ColumnHeaderGripperStyle}" />
<Thumb x:Name="PART_RightHeaderGripper" HorizontalAlignment="Right" Style="{StaticResource ColumnHeaderGripperStyle}" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="SortDirection" Value="Descending">
<Setter TargetName="SortArrow" Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="180" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property='IsMouseOver' SourceName="fullHeader" Value='True'>
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation BeginTime="00:00:00" Duration="00:00:00.20000"
Storyboard.TargetName="HoverRectangle"
Storyboard.TargetProperty="(UIElement.Opacity)"
To='1.0' />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation BeginTime="00:00:00" Duration="00:00:00.20000"
Storyboard.TargetName="HoverRectangle"
Storyboard.TargetProperty="(UIElement.Opacity)"
To='0' />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--End of custom DataGridColumnHeader template-->
</DataGrid.Resources>
<DataGrid.ItemContainerStyle>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="Visibility">
<Setter.Value>
<MultiBinding Converter="{StaticResource SearchColumnToVisibilityConverter}">
<Binding ElementName="filterTextBox" Path="Text"/>
<Binding BindsDirectlyToSource="True"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</DataGrid.ItemContainerStyle>
</DataGrid>
</StackPanel>
</Border>
</ControlTemplate>
I hope someone could help me!
Thanks
I'm sorry the title is badly worded and change it if you must, but this is what I am trying to achieve.
I have styled a combobox and added some items:
When an item is selected I wish only the title to be displayed, at the moment the whole content is displayed:
I have been playing around with using Tags to define the textblock with text "Title" as a header and display that however it's not working :(.
Here is the XAML Styling within app.xaml, I haven’t placed in a resource dictionary yet as I’m just testing:
<Application x:Class="WpfApplication14.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication14"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ControlTemplate x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}">
<Grid Height="50" Width="200">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Border x:Name="NormalBorder"
Background="#FF4F4F4F"
Grid.ColumnSpan="2"
BorderBrush="White"
BorderThickness="1.5"
CornerRadius="10,10,10,10"
/>
<Border x:Name="MouseOverBorder"
Background="#737373"
BorderBrush="White"
Grid.ColumnSpan="2"
BorderThickness="1.5"
CornerRadius="10,10,10,10"
Opacity="0"
/>
<Border x:Name="PressedBorder"
Background="#262626"
Grid.ColumnSpan="2"
CornerRadius="10,10,10,10"
Opacity="0"
/>
<Path
x:Name="Arrow"
Grid.Column="1"
Fill="White"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M0,0 L0,2 L4,6 L8,2 L8,0 L4,4 z"
/>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition From="Normal" To="MouseOver" GeneratedDuration="0:0:0.15"/>
<VisualTransition From="MouseOver" To="Normal" GeneratedDuration="0:0:0.15"/>
<VisualTransition From="Normal" To="Checked" GeneratedDuration="0:0:0.05"/>
<VisualTransition From="Checked" To="MouseOver" GeneratedDuration="0:0:0.05"/>
<VisualTransition From="MouseOver" To="Checked" GeneratedDuration="0:0:0.05"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="MouseOverBorder" Storyboard.TargetProperty="Opacity">
<EasingDoubleKeyFrame Value="1" KeyTime="0:0:0.15"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Checked">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="PressedBorder" Storyboard.TargetProperty="Opacity">
<EasingDoubleKeyFrame Value="1" KeyTime="0:0:0.05"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
<Style x:Key="ComboBox" TargetType="ComboBox">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid Height="50" Width="200">
<ToggleButton
Name="ToggleButton"
Template="{StaticResource ComboBoxToggleButton}"
Grid.Column="2"
Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press">
</ToggleButton>
<ContentPresenter x:Name="Content" Content="{TemplateBinding SelectionBoxItem}" Margin="5,0,0,0" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<Popup
Name="Popup"
Placement="Bottom"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
Height="400" Width="190"
PopupAnimation="Slide">
<Grid Name="DropDown"
SnapsToDevicePixels="True">
<Border
x:Name="DropDownBorder"
Background="#FF3F3F3F"
BorderThickness="1"
BorderBrush="#888888"/>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="ComboBoxItem" x:Key="ComboBoxItem">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="#262626"/>
<Setter Property="Height" Value="50"/>
<Setter Property="Width" Value="200"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Grid Height="50" Width="200" Margin="0,2,0,2">
<Border x:Name="DropDownNormalBorder"
Background="{TemplateBinding Background}"
Height="50" Width="200"
/>
<Border x:Name="DropDownMouseOverBorder"
Background="#808080"
Grid.ColumnSpan="2"
Opacity="0"
/>
<ContentPresenter HorizontalAlignment="Left" VerticalAlignment="Center" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition From="Normal" To="MouseOver" GeneratedDuration="0:0:0.15"/>
<VisualTransition From="MouseOver" To="Normal" GeneratedDuration="0:0:0.15"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="DropDownMouseOverBorder" Storyboard.TargetProperty="Opacity">
<EasingDoubleKeyFrame Value="1" KeyTime="0:0:0.15"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
Here is the mainwindow.xaml, the combobox item is repeated four times in the screenshot above:
<Window x:Class="WpfApplication14.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication14"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid Background="Black">
<ComboBox Style="{DynamicResource ComboBox}" Height="50" Width="200">
<ComboBoxItem Style="{DynamicResource ComboBoxItem}">
<Grid>
<StackPanel Orientation="Horizontal">
<Image Source="C:\Users\ceefax\Documents\Visual Studio 2015\Projects\WpfApplication14\WpfApplication14\spanner-clip-art.png"
Height="40" Width="40" />
<StackPanel Orientation="Vertical" Margin="5,0,0,0">
<TextBlock FontWeight="Bold">Title</TextBlock>
<TextBlock>Content</TextBlock>
</StackPanel>
</StackPanel>
</Grid>
</ComboBoxItem>
</ComboBox>
</Grid>
You can use a Combined Template.
<Window x:Class="WpfApplication14.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication14"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary>
<DataTemplate x:Key="NormalItemTemplate" >
<Grid>
<StackPanel Orientation="Horizontal">
<Image Source="C:\Users\ceefax\Documents\Visual Studio 2015\Projects\WpfApplication14\WpfApplication14\spanner-clip-art.png"
Height="40" Width="40" />
<StackPanel Orientation="Vertical" Margin="5,0,0,0">
<TextBlock FontWeight="Bold">Title</TextBlock>
<TextBlock>Content</TextBlock>
</StackPanel>
</StackPanel>
</Grid>
</DataTemplate>
<DataTemplate x:Key="SelectionBoxTemplate" >
<Grid>
<StackPanel Orientation="Horizontal">
<Image Source="C:\Users\ceefax\Documents\Visual Studio 2015\Projects\WpfApplication14\WpfApplication14\spanner-clip-art.png"
Height="40" Width="40" />
<StackPanel Orientation="Vertical" Margin="5,0,0,0">
<TextBlock FontWeight="Bold">Title</TextBlock>
</StackPanel>
</StackPanel>
</Grid>
</DataTemplate>
<DataTemplate x:Key="CombinedTemplate">
<ContentPresenter x:Name="Presenter"
Content="{Binding}"
ContentTemplate="{StaticResource NormalItemTemplate}" />
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource FindAncestor,ComboBoxItem,1}}"
Value="{x:Null}">
<Setter TargetName="Presenter" Property="ContentTemplate"
Value="{StaticResource SelectionBoxTemplate}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
<Grid Background="Black">
<ComboBox ItemsSource="{Binding Items}" SelectedItem="{Binding Item}"
ItemTemplate="{StaticResource CombinedTemplate}"
Height="50" Width="200">
</ComboBox>
</Grid>
</Window>
Note Binding Items and Item.
I have a DropDownButton (a component from the Extended WPF Toolkit) that has a ListView as dropdown content. I would like to close the Popup part as soon as the user selects an item. I thought I could achieve this through an event trigger with ListView.SelectionChanged as source event, and DropDownButton.IsOpen as target property which I would set to false.
But then I'm getting the following exception when I select an item:
Cannot resolve all property references in the property path 'IsOpen'. Verify that applicable objects support the properties.
Here is my XAML:
<ListView.Triggers>
<EventTrigger RoutedEvent="ListView.SelectionChanged" SourceName="MyListView">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames
Storyboard.Target="{Binding Source={RelativeSource Mode=FindAncestor,AncestorType=xctk:DropDownButton}}"
Storyboard.TargetProperty="IsOpen"
FillBehavior="HoldEnd">
<DiscreteBooleanKeyFrame Value="False" KeyTime="0:0:1" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</ListView.Triggers>
Can anybody tell me what I'm doing wrong?
For those interested, here is a relatively simple solution that does not involve any code-behind.
<Window x:Class="PopupDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style x:Key="MyPopupMenu" TargetType="MenuItem" >
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="MenuItem">
<Border x:Name="Border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid >
<ContentPresenter ContentSource="Header" />
<Rectangle x:Name="overlay"
Fill="Black"
IsHitTestVisible="False"
Visibility="Hidden"
Opacity="0.1" >
</Rectangle>
<Popup IsOpen="{Binding Path=IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" Placement="Bottom" x:Name="SubMenuPopup" Focusable="false" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}">
<Border x:Name="SubMenuBorder"
Background="White"
BorderBrush="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type Menu}}}"
BorderThickness="1" Padding="2,2,2,2">
<Grid x:Name="SubMenu" Grid.IsSharedSizeScope="True">
<!-- StackPanel holds children of the menu. This is set by IsItemsHost=True -->
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Cycle"/>
</Grid>
</Border>
</Popup>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True" >
<Setter TargetName="overlay" Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<DockPanel LastChildFill="False">
<Menu DockPanel.Dock="Top" Background="Transparent">
<MenuItem Style="{StaticResource MyPopupMenu}" >
<MenuItem.Header>
<Border Background="#3382cc" BorderThickness="12 4" BorderBrush="#3382cc">
<StackPanel Orientation="Horizontal">
<TextBlock Text="My Popup Menu" Foreground="White" />
</StackPanel>
</Border>
</MenuItem.Header>
<MenuItem Header="Alfa" />
<MenuItem Header="Bravo" />
<MenuItem Header="Charlie" />
<MenuItem Header="Delta" />
<MenuItem Header="Echo" />
</MenuItem>
</Menu>
</DockPanel>
</Window>
I insert a Tabcontrol into a BorderControl. The Tabcontrol used seperate styles. Right now the Close Button inside Tabcontrol can refer to itself. So when click it the TabControl is closed I guess so. Is it possible to refer the button to the Border control outside so that when close the Border control is collpased?
<DockPanel LastChildFill="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160" MinWidth="100"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Margin="5,5,0,5" BorderBrush="Aqua" BorderThickness="1">
<TabControl Margin="0,15,0,0" Style="{StaticResource StandardTabControl}" >
<TabItem Header="Start">
</TabItem>
</TabControl>
</Border>
<GridSplitter Grid.Column="1" Background="Transparent" Width="6" HorizontalAlignment="Center"></GridSplitter>
<Border Grid.Column="2" BorderBrush="Aqua" BorderThickness="1" Margin="0,5,5,5"></Border>
</Grid>
</DockPanel>
After click the close button
And part of the styles of TabControl.
<Button Grid.Column="1" Height="15" Width="15" HorizontalAlignment="Center" VerticalAlignment="Center">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<Ac:CloseTabItemAction TabItem="{Binding RelativeSource={RelativeSource AncestorType=TabItem}}"
TabControl="{Binding RelativeSource={RelativeSource AncestorType=TabControl}}">
</Ac:CloseTabItemAction>
</i:EventTrigger>
</i:Interaction.Triggers>
<!--A lot more about styles-->
</Button>
here is a solution using control template triggers in pure xaml
<DockPanel LastChildFill="True">
<Control>
<Control.Template>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160"
MinWidth="100"
x:Name="column" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Margin="5,5,0,5"
BorderBrush="Aqua"
BorderThickness="1">
<TabControl Margin="0,15,0,0"
Style="{StaticResource StandardTabControl}"
x:Name="tabControl">
<TabItem Header="Start">
</TabItem>
</TabControl>
</Border>
<GridSplitter Grid.Column="1"
Background="Transparent"
Width="6"
HorizontalAlignment="Center"></GridSplitter>
<Border Grid.Column="2"
BorderBrush="Aqua"
BorderThickness="1"
Margin="0,5,5,5"></Border>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding HasItems,ElementName=tabControl}"
Value="false">
<Setter TargetName="column"
Property="MinWidth"
Value="0" />
<Setter TargetName="column"
Property="Width"
Value="0" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Control.Template>
</Control>
</DockPanel>
based on the assumption that when CloseTabItemAction will be called it will remove the TabItem from the TabControl, the trigger will detect the same based on HasItems property and will collapse the column if there are no items
EDIT
based on the comments here are the finding. while resizing GridSplitter sets a Local value to the ColumnDefinition's Width property which have higher precedence than the Trigger values so the Trigger effectively fails to modify the value.
the solution proposed is to use Animation to set the desired value as Animations has higher precedence then the Local value, and the desired value is applied to the property.
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding HasItems,ElementName=T1}"
Value="false">
<Setter TargetName="Co0"
Property="MinWidth"
Value="0" />
<Setter TargetName="G1"
Property="Width"
Value="0" />
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Co0"
Storyboard.TargetProperty="Width">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<GridLength>0</GridLength>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</ControlTemplate.Triggers>
in the above code I also make the splitter width to 0 so that there is no empty space on the left
I have a simple style for label controls. I'd like to define a control template inside the style with a button, which could be clicked and would set the visibility property of the label to 'Hidden'. Something like this:
<Style x:Key="MessageLabel_WithCloseButton" TargetType="{x:Type Label}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<Border BorderThickness="1" Padding="4" CornerRadius="3"
BorderBrush="Gray" Background="#FFA11616">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0"/>
<Button Grid.Column="1" Width="16" Height="16" Padding="2" FontSize="9" Content="X">
<!-- THIS IS WRONG! HOW TO CREATE A TRIGGER FOR THIS BUTTON
HERE AND HOW TO REFER TO THE LABEL? -->
<Button.Triggers>
<Trigger Property="Button.IsPressed" Value="True">
<Setter Property="Visibility" Value="Hidden" />
</Trigger>
</Button.Triggers>
</Button>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The problem is I'm not sure how to handle the click with a trigger and also how to set a property of the label that contains the button.
Thanks.
I authored this with Blend 4. Essentially you want to handle the "PreviewMouseButtonUp" event on your button with an EventTrigger. The EventTrigger will start a Storyboard which animates the UIElement.Visibility property to "Hidden" at the top of the Visual Tree for your label's style.
To get control over the content in the button, you can use the Tag Property on the label control. Otherwise, you will have to create another dependency property, and that means subclassing Label.
Inside the style, then, the <Button/> looks like this:
<Button x:Name="button" Grid.Column="1" Padding="2"
FontSize="9"
Content="{Binding Path=Tag, RelativeSource={RelativeSource TemplatedParent}}"/>
...and since you can put anything into a Tag property you can do this:
<Label x:Name="label" Content="Label"
Style="{DynamicResource MessageLabel_WithCloseButton}">
<Label.Tag>
<StackPanel>
<TextBlock>WOOT</TextBlock>
<TextBlock>WOOT</TextBlock>
</StackPanel>
</Label.Tag>
</Label>
Here is a modified complete style (I also modified some things for better automatic sizing:
<Style x:Key="MessageLabel_WithCloseButton" TargetType="{x:Type Label}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<ControlTemplate.Resources>
<Storyboard x:Key="OnClick1">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="border">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Hidden</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<Border x:Name="border" BorderThickness="1" Padding="4" CornerRadius="3"
BorderBrush="Gray" Background="#FFA11616">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0" VerticalAlignment="Center" Margin="0,0,3,0"/>
<Button x:Name="button" Grid.Column="1" Padding="2" FontSize="9" Content="{Binding Path=Tag, RelativeSource={RelativeSource TemplatedParent}}"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="UIElement.PreviewMouseLeftButtonUp" SourceName="button">
<BeginStoryboard x:Name="OnClick1_BeginStoryboard" Storyboard="{StaticResource OnClick1}"/>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Note, too, that the EventTrigger is on your ControlTemplate and not on the Button in your tree. But that might be just the way Blend generates the code.
You can use a ToggleButton instead of the normal Button and then just use the IsChecked property for the Trigger:
<Style x:Key="MessageLabel_WithCloseButton" TargetType="{x:Type Label}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<Border BorderThickness="1" Padding="4" CornerRadius="3"
BorderBrush="Gray" Background="#FFA11616">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0"/>
<ToggleButton x:Name="CloseButton" Grid.Column="1" Width="16" Height="16" Padding="2" FontSize="9" Content="X"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger SourceName="CloseButton" Property="IsChecked" Value="True">
<Setter Property="Visibility" Value="Hidden" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>