WPF place popup under toggle button in fixed position - c#

I am trying to build a custom ComboBox which displays a ListView. Here is a screen capture of what I am trying to achieve:
I based most of my code on this very helpful blog, which discusses how to embed a DataGrid (or in my case, a GridView), inside a ComboBox. From a functional point of view, everything is working. However, I can't seem to find a way to get the drop down to be fixed. Ideally, I would like it to appear as above always, regardless of the window size or window position. Currently, the popup tries to be right-aligned, except when the window gets close to the left edge of the screen, at which point the popup migrates inward. The problem, as the XAML below shows, is that the ListView sits inside a Popup, and Popups are not really bound to the normal window, and therefore we cannot directly control their position.
<Window.Resources>
<Style x:Key="ComboBoxTest2" TargetType="{x:Type ComboBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton x:Name="TGButton" Grid.Column="2" Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,
RelativeSource={RelativeSource TemplatedParent}}"
Padding="0,0,50,0">
<ToggleButton.Template>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="30" />
</Grid.ColumnDefinitions>
<Border x:Name="Border" Grid.ColumnSpan="2" CornerRadius="5"
Background="LightGray" BorderBrush="Black" BorderThickness="1" />
<Border x:Name="Border2" Grid.Column="0" CornerRadius="5,0,0,5"
Margin="1" Background="White" BorderBrush="Black"
BorderThickness="0,0,1,0" />
<Path x:Name="Arrow" Grid.Column="1" Fill="Black"
HorizontalAlignment="Center" VerticalAlignment="Center"
Data="M 0 0 L 4 4 L 8 0 Z"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsMouseOver" Value="true">
<Setter TargetName="Border" Property="Background" Value="DarkGray" />
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="true">
<Setter TargetName="Border" Property="Background" Value="DarkGray" />
<Setter TargetName="Border" Property="CornerRadius" Value="5,5,0,0" />
<Setter TargetName="Border2" Property="CornerRadius" Value="5,0,0,0" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
<ContentPresenter Name="ContentSite" IsHitTestVisible="False"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
Margin="3,3,40,3" />
<TextBox x:Name="PART_EditableTextBox" Visibility="Hidden"
IsReadOnly="{TemplateBinding IsReadOnly}" Width="50" />
<Popup Name="Popup" IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True" Focusable="False" PopupAnimation="Slide"
Placement="Relative" VerticalOffset="{TemplateBinding ActualHeight}"
HorizontalOffset="{TemplateBinding ActualWidth}">
<Grid Name="DropDown" SnapsToDevicePixels="True"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border x:Name="DropDownBorder" Background="White" BorderThickness="1"
BorderBrush="Black"/>
<ListView ItemsSource="{TemplateBinding ItemsSource}"
SelectedItem="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=SelectedItem}">
<ListView.View>
<GridView>
<GridViewColumn Header="Key" DisplayMemberBinding="{Binding Key}" />
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<ComboBox x:Name="cBox" Height="30" Width="200" ItemsSource="{Binding Path=People}"
SelectedValue="Selected" DisplayMemberPath="Name" SelectedValuePath="Name"
Style="{StaticResource ComboBoxTest2}"
SelectionChanged="Function_SelectionChanged" />
</Grid>
I have read in a few places that Adorners might be a solution, because they would receive all resize events and could reposition the popup dynamically. Another option might be to use a library like DevExpress, but I am trying to avoid this. By the way, my question is not a duplicate of this one, since the offsets used to place a Popup in XAML are only honored at rendering, not during resizing/moving.

Just change you popup placement options and you should be able to get what you want to display.
MainWindow.xaml
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="300">
<Window.Resources>
<Style x:Key="ComboBoxTest2" TargetType="{x:Type ComboBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton x:Name="TGButton" Grid.Column="2" Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,
RelativeSource={RelativeSource TemplatedParent}}"
Padding="0,0,50,0">
<ToggleButton.Template>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="30" />
</Grid.ColumnDefinitions>
<Border x:Name="Border" Grid.ColumnSpan="2" CornerRadius="5"
Background="LightGray" BorderBrush="Black" BorderThickness="1" />
<Border x:Name="Border2" Grid.Column="0" CornerRadius="5,0,0,5"
Margin="1" Background="White" BorderBrush="Black"
BorderThickness="0,0,1,0" />
<Path x:Name="Arrow" Grid.Column="1" Fill="Black"
HorizontalAlignment="Center" VerticalAlignment="Center"
Data="M 0 0 L 4 4 L 8 0 Z"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsMouseOver" Value="true">
<Setter TargetName="Border" Property="Background" Value="DarkGray" />
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="true">
<Setter TargetName="Border" Property="Background" Value="DarkGray" />
<Setter TargetName="Border" Property="CornerRadius" Value="5,5,0,0" />
<Setter TargetName="Border2" Property="CornerRadius" Value="5,0,0,0" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
<ContentPresenter Name="ContentSite" IsHitTestVisible="False"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
Margin="3,3,40,3" />
<TextBox x:Name="PART_EditableTextBox" Visibility="Hidden"
IsReadOnly="{TemplateBinding IsReadOnly}" Width="50" />
<Popup Name="Popup" IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True" Focusable="False" PopupAnimation="Slide"
Placement="Bottom">
<Grid Name="DropDown" SnapsToDevicePixels="True"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border x:Name="DropDownBorder" Background="White" BorderThickness="1"
BorderBrush="Black"/>
<ListView ItemsSource="{TemplateBinding ItemsSource}"
SelectedItem="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=SelectedItem}">
<ListView.View>
<GridView>
<GridViewColumn Header="Key" DisplayMemberBinding="{Binding Key}" Width="80" />
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="250"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<ComboBox x:Name="cBox" Height="30" Width="200" ItemsSource="{Binding}"
SelectedValue="Selected" DisplayMemberPath="Name" SelectedValuePath="Name"
Style="{StaticResource ComboBoxTest2}"
SelectionChanged="Function_SelectionChanged" />
</Grid>
</Window>
MainWindow.xaml.cs
using System.Linq;
using System.Windows;
using System.Windows.Controls;
namespace WpfApp1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = Enumerable.Range(1, 100).Select(x => new { Key = x, Name = $"Person {x} with really really really really really really really really really really really really really really really really really really really really really really really really really really really really really really really really long name" }).ToList();
}
private void Function_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// do whatever you want
}
}
}
Output:

Related

Button with round edge grid and set disable button color to green

I want to have a button with round edge grid and set disable button color to gray, green otherwise. Attached snippet of code. I don't know how to change the default. If I disable my button, I get the output as the image on the left, however, I want it to look like the image on the right!
<Button x:Name="button" Height="30" Width="100" Margin="825,0,0,0" Background="Transparent"
BorderThickness="0" BorderBrush="Transparent">
<Button.Content>
<Border CornerRadius="12.5" Height="25" Width="95" Margin="0" BorderBrush="Gray"
BorderThickness="4,4,4,4" Background="Gray">
<TextBlock Text="Back" HorizontalAlignment="Center" VerticalAlignment="Top"
Margin="12,0,13,0" Foreground="White"/>
</Border>
</Button.Content>
</Button>
Content is only one part of Button. The rest is determined by Template.
If multiple buttons should have custom apperance, the Template should be set in buttons Style. For one button it can be done inplace:
<Button x:Name="button" Content="Back" Height="30" Width="100" Margin="825,0,0,0" Background="Transparent"
BorderThickness="0" BorderBrush="Transparent">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border CornerRadius="12.5" Height="25" Width="95" Margin="0" BorderBrush="Gray"
BorderThickness="4,4,4,4" Background="Gray">
<TextBlock Text="{TemplateBinding Content}"
HorizontalAlignment="Center" VerticalAlignment="Top"
Margin="12,0,13,0" Foreground="White"/>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
if you are going to reuse the template, declare it as Resource
<Window.Resources>
<ControlTemplate TargetType="Button" x:Key="RoundBtn">
<Border Name="roundBorder" CornerRadius="12.5" Height="25" Width="95" Margin="0" BorderBrush="Gray"
BorderThickness="4,4,4,4" Background="Gray">
<TextBlock Text="{TemplateBinding Content}"
HorizontalAlignment="Center" VerticalAlignment="Top"
Margin="12,0,13,0" Foreground="White"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="roundBorder" Property="Background" Value="Green"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
and set button Template using resource:
<Button x:Name="button" Content="Back" Height="30" Width="100"
Template="{StaticResource RoundBtn}"
Margin="825,0,0,0" Background="Transparent"
BorderThickness="0" BorderBrush="Transparent"/>
This should work for you. I've used an outer grid with a blue background so that I could be sure it was all working, but just remove that and move the style to whichever resources you need to. Explanation as comments within the xaml:
<Grid Background="Blue">
<Grid.Resources>
<!-- Override the default button style, otherwise you get a grey
rectangle behind the ellipse when disabled -->
<Style TargetType="Button" x:Key="MyButtonStyle">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter x:Name="MyContentPresenter"
Content="{TemplateBinding Content}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<Button x:Name="button" Height="30" Width="100"
BorderThickness="0" BorderBrush="Transparent" IsEnabled="false"
Style="{StaticResource MyButtonStyle}">
<Button.Content>
<Border CornerRadius="12.5" Height="25" Width="95">
<Border.Style>
<Style TargetType="Border">
<!-- Button is gray by default, i.e. when enabled -->
<Setter Property="Background" Value="Gray"/>
<Style.Triggers>
<!-- If the button becomes disabled then it becomes green -->
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="Green" />
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock Text="Back" HorizontalAlignment="Center" VerticalAlignment="Center"
Foreground="White"/>
</Border>
</Button.Content>
</Button>
</Grid>

Show popup based on two properties (IsFocused, IsVisible)

I have popup error message box, it opens once the textbox is focused.
The issue when opening dialog window, if you click on the close button (on close I hide the window) the error message stays visible. I tried to add trigger to check the visibility but it didn't work. any idea?
XAML:
<ControlTemplate x:Key="errorToolTipTemplate">
<Grid>
<Border BorderBrush="#EF5B7C" BorderThickness="1" Background="#EF5B7C" Opacity="0.4" IsHitTestVisible="False" x:Name="errorBorder" />
<AdornedElementPlaceholder x:Name="placeholder" />
<Popup x:Name="popup" AllowsTransparency="True"
PopupAnimation="Fade"
Placement="Right"
VerticalOffset="-3"
PlacementTarget="{Binding ElementName=errorBorder}"
IsOpen="{Binding ElementName=placeholder, Path=AdornedElement.IsFocused, Mode=OneWay}">
<Popup.Style>
<Style TargetType="{x:Type Popup}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=errorBorder, Path=IsVisible, Mode=OneWay}" Value="False">
<Setter Property="IsOpen" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</Popup.Style>
<DockPanel>
<Polygon VerticalAlignment="Center"
Points="0,5 5,0 5,10"
Fill="#EF5B7C"
Stretch="Fill" />
<Border Background="White" BorderBrush="#EF5B7C" BorderThickness="1" CornerRadius="4" Padding="2">
<DockPanel>
<Image Height="20" Width="20" VerticalAlignment="Center" Source="Images/C04_32.png" />
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="{StaticResource errorBrush}"
FontWeight="Bold" Margin="2,0,0,0"
Text="{Binding ElementName=placeholder, Path=AdornedElement.ToolTip, Mode=OneWay}" />
</DockPanel>
</Border>
</DockPanel>
</Popup>
</Grid>
</ControlTemplate>
<!--Textbox style-->
<Style TargetType="{x:Type TextBox}">
<Setter Property="Validation.ErrorTemplate" Value="{DynamicResource errorToolTipTemplate}" />
</Style>
Fixed this by adding triggers for the ControlTemplate.
I have add trigger with SourceTarget as the adorner, and TargetName as the popup, and changed the IsOpen property according to the other control visibility.
<ControlTemplate x:Key="errorToolTipTemplate">
<Grid>
<Border BorderBrush="#EF5B7C" BorderThickness="1" Background="#EF5B7C" Opacity="0.4" IsHitTestVisible="False" x:Name="errorBorder" />
<AdornedElementPlaceholder x:Name="placeholder" />
<Popup x:Name="popup" AllowsTransparency="True"
PopupAnimation="Fade"
Placement="Right"
VerticalOffset="-3"
PlacementTarget="{Binding ElementName=errorBorder}"
IsOpen="{Binding ElementName=placeholder, Path=AdornedElement.IsFocused, Mode=OneWay}">
<DockPanel>
<Polygon VerticalAlignment="Center"
Points="0,5 5,0 5,10"
Fill="#EF5B7C"
Stretch="Fill" />
<Border Background="White" BorderBrush="#EF5B7C" BorderThickness="1" CornerRadius="4" Padding="2">
<DockPanel>
<Image Height="20" Width="20" VerticalAlignment="Center" Source="Images/C04_32.png" />
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="{StaticResource errorBrush}"
FontWeight="Bold" Margin="2,0,0,0"
Text="{Binding ElementName=placeholder, Path=AdornedElement.ToolTip, Mode=OneWay}" />
</DockPanel>
</Border>
</DockPanel>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger SourceName="placeholder" Property="IsVisible" Value="False">
<Setter TargetName="popup" Property="IsOpen" Value="False" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>

Making a WPF combobox with rounded corners

In my application, I need to make the combobox that I am using have rounded corners. I started with the XAML posted in the answer to this question and have made some modifications. I decided I didn't like the way that one looked as much, so I tried to style it and make it look a bit more like the default combobox. Now my combobox looks like this: ,
and when dropped down:
The issue is that when the user places their mouse over the combobox, it looks like this: . If I use Snoop, I can see this info:
It says
that the value of that border background is being set to "#FFBEE6FD", which is the color that shows when the mouse is over the combobox. The value source is "ParentTemplateTrigger". My issue is that I don't know where this border is coming from or why it's getting that value. I have tried to add template triggers with setters to set the background to white, but I don't know where to set the value for this mysterious border.
Here is the XAML for my ComboBox:
<ComboBox x:Name="ScanSizesComboBox"
Style="{StaticResource roundedCornersComboBox}"
Grid.ZIndex="4"
ItemsSource="{Binding ScanSizes}"
SelectedItem="{Binding SelectedScanSize, Mode=TwoWay}"
ToolTip="{Binding (Validation.Errors)[0].ErrorContent}"
Margin="0,10,89,0"
HorizontalAlignment="Right"
Width="61"
Height="26"
VerticalAlignment="Top"
Grid.Row="4">
</ComboBox>
And here is the style:
<Style x:Key="ComboBoxTextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<Border Name="ComboBoxTextBoxStyleBorder" CornerRadius="2"
BorderThickness="0,1,0,1"
Margin="0,0,1,1"
Background="{TemplateBinding Background}">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<ScrollViewer x:Name="PART_ContentHost"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="IsReadOnly" Value="True"/>
</Style>
<!--Rounded corners combo box-->
<Style TargetType="{x:Type ComboBox}" x:Key="roundedCornersComboBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Border Name="roundedCornerComboBoxBorder" BorderBrush="#CCCCCC" BorderThickness="1" CornerRadius="3" ClipToBounds="True" Background="White">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<Canvas>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Name="PART_EditableTextBox"
Panel.ZIndex="0"
Style="{StaticResource ComboBoxTextBoxStyle}"
Padding="0,0,0,0"
IsHitTestVisible="False"
Height="{TemplateBinding Height}">
</TextBox>
<ToggleButton Grid.Column="1" Margin="0, 0, 0, 0"
Panel.ZIndex="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
BorderBrush="Transparent"
Background="Transparent"
Height="{TemplateBinding Height}"
Width="60"
IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
HorizontalContentAlignment="Right"
ClickMode="Press">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="true">
<Setter Property="Background"
Value="White" />
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
<Path Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 0 0 L 4 4 L 8 0 Z"
Fill="DodgerBlue" />
</ToggleButton>
<ContentPresenter Name="ContentSite"
Cursor="Arrow"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="3,0,0,0">
</ContentPresenter>
<Popup Name="Popup"
Placement="Bottom"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Slide">
<Grid Name="DropDown"
SnapsToDevicePixels="True"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border
x:Name="DropDownBorder"
BorderThickness="1"
CornerRadius="5"
Background="White"
BorderBrush="Black"/>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
</Canvas>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Ultimately, I would like for the user to be able to place his/her mouse over the combobox, and have it just look the same as it does when it is not highlighted. Any help is appreciated. Thanks.
Continuing from our comments conversation (which generally SO tries to avoid so much noise) this may get on you track.
So if I grab just all the template stuff to a bare bones basic default ComboBox and ComboBoxItem from a fresh WPF app, this is the output. Granted you won't need all of it, but it should ensure to an extent all expected functionality and DOM parts are here for reference so you have all the stuff like Triggers, Template Binding pieces etc, all available.
Notice the various Border and Rectangle elements in the various parts that would need to be altered in order to achieve the rounding of everything. I can't however provide any insight into how it would effect anything with MahApps as my experience with that is pretty limited since I've always just made my own stuff to accomplish what it essentially does.
Hope it helps. It's too long for SO's submission requirements though so here's the PasteBin link.
<Style x:Key="ComboBoxTextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<Border CornerRadius="5,0,0,5"
BorderThickness="1"
Background="{TemplateBinding Background}"
BorderBrush="Black">
<ScrollViewer x:Name="PART_ContentHost"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition MaxWidth="18"/>
</Grid.ColumnDefinitions>
<TextBox Name="PART_EditableTextBox"
Style="{StaticResource ComboBoxTextBoxStyle}"
Padding="5,0,0,0"
Height="{TemplateBinding Height}"/>
<ToggleButton Grid.Column="1" Margin="0"
Height="{TemplateBinding Height}"
Style="{StaticResource ComboBoxButtonStyle}"
Focusable="False"
IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press">
<Path Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 0 0 L 4 4 L 8 0 Z"
Fill="DodgerBlue" />
</ToggleButton>
<ContentPresenter Name="ContentSite"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="5,0,0,0"/>
<Popup Name="Popup"
Placement="Bottom"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Slide">
<Grid Name="DropDown"
SnapsToDevicePixels="True"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border
x:Name="DropDownBorder"
BorderThickness="1"
CornerRadius="5"
Background="Azure"
BorderBrush="Black"/>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Margins of wpf button are highlighted on mouseover

I'm new to WPF and i have small issue. I have a button with XAML:
<Button FontSize="17" Margin="15" Background="White"
BorderThickness="0" BorderBrush="#f6f6f6"
FontWeight="DemiBold"
fluent:KeyTip.Keys="X"
CommandParameter="{Binding}"
Click="OnLoadPluginClick">
<Button.Effect>
<DropShadowEffect Opacity="0.15"/>
</Button.Effect>
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1"
Grid.Row="0" Margin="5,10,0,0" Height="180" Width="180" VerticalAlignment="Top"
Background="{TemplateBinding Background}"
HorizontalAlignment="Left" >
<Grid Height="180" Width="180" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Margin="10,10,0,0" FontSize="15" FontStretch="ExtraCondensed" Height="20" VerticalAlignment="Top"
HorizontalAlignment="Left" Text="{Binding Name}" />
<Image Stretch="Uniform" Width="70" Height="70" Grid.Row="1" HorizontalAlignment="Center"
VerticalAlignment="Center" Source="{Binding ImageSource}" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Button.IsPressed" Value="True">
<Setter TargetName="Border" Property="Background" Value="WhiteSmoke" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect ShadowDepth="0" Color="WhiteSmoke" Opacity="0.6" BlurRadius="20"/>
</Setter.Value>
</Setter>
<!--<Setter TargetName="Border" Property="Background" Value="LightGreen"></Setter>-->
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
As you can see i have my own triggers, but i can't the appeareance i want (shadows when mouse is on button). I get something like this:
as you can see, i have only my margins highlighted with akward gray color...
What i need: when mouse is on button border, the border gets bigger shadow, when border is pressed, it's background is set to WhiteSmoke
Something like this, but with image:
How can i implement this button correctly?
I'll be gratefull for any help.
Set TargetName=Border in the setter tag of IsMouseOver Trigger. It may work..

How to display a Popup above mouse location?

I have a DataGrid control in my application in which I added a custom-defined Popup for some actions.
The basic thing is: I have a matrix of double numbers displayed in a DataGrid. Right clicking on selected cells will make a popup appear, in which the user can type a value then press enter to shift the values selected (all of the values selected will be incremented with the value entered)
Here is the current behavior:
And the XAML code for the popup:
<Style x:Key="ShiftPopupStyle" TargetType="{x:Type Popup}">
<Setter Property="IsOpen" Value="False" />
<Setter Property="StaysOpen" Value="False" />
<Setter Property="AllowsTransparency" Value="True" />
<Setter Property="PopupAnimation" Value="Fade" />
<Setter Property="Placement" Value="Mouse" />
<Setter Property="Child">
<Setter.Value>
<Border BorderBrush="Navy" Background="AliceBlue" BorderThickness="1" CornerRadius="2">
<StackPanel Orientation="Horizontal" Margin="5">
<TextBox Text="{Binding ShiftValue, UpdateSourceTrigger=PropertyChanged}" Width="30" Margin="4" >
<TextBox.InputBindings>
<KeyBinding Command="{Binding ShiftCommand}" Key="Enter" />
</TextBox.InputBindings>
</TextBox>
<Button Content="Shift" Margin="0,4,0,4"
Command="{Binding ShiftCommand}"/>
</StackPanel>
</Border>
</Setter.Value>
</Setter>
</Style>
And here is how I open the Popup, this method is located in my custom DataGrid (I use a custom DataGrid able to display values from a 2D Array):
protected override void OnMouseRightButtonUp(System.Windows.Input.MouseButtonEventArgs e)
{
if (!this.IsReadOnly)
{
this.shiftPopup.IsOpen = true;
}
base.OnMouseRightButtonUp(e);
}
Now, I need to add a ContextMenu to my DataGrid. When I try to add a ContextMenu directly on the DataGrid, I can see it before the grid is initialized, but afterwards, only the Popup shows up. No ContextMenu at all.
I was expecting them to be at the same location, but the ContextMenu just won't appear.
Ideally what I'd need is an Office-like ContextMenu:
In which my shift Popup would appear above the mouse pointer, and my ContextMenu at the usual position.
If needed, I wouldn't care having a fixed layout (layout above/contextmenu under, whatever the mouse position is).
Would you have any idea on how to do so?
Alternatively, I was thinking about including the Popup content in the contextMenu, hoping it won't end up being ugly.
Thanks for your help!
The idea is to override default ContextMenu template.
Result:
Add reference to PresentationFramework.Aero.dll and try this code:
<Window
x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:theme="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
Title="MainWindow"
Height="350" Width="525">
<Window.Resources>
<Style x:Key="MenuStyle" TargetType="{x:Type ContextMenu}" BasedOn="{StaticResource {x:Type ContextMenu}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContextMenu}">
<StackPanel>
<theme:SystemDropShadowChrome Name="Shdw2" Color="Transparent" SnapsToDevicePixels="true">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding ShiftValue, UpdateSourceTrigger=PropertyChanged}"
Width="30" Margin="4">
<TextBox.InputBindings>
<KeyBinding Command="{Binding ShiftCommand}" Key="Enter" />
</TextBox.InputBindings>
</TextBox>
<Button Content="Shift" Margin="0,4,0,4" Command="{Binding ShiftCommand}" />
</StackPanel>
</Border>
</theme:SystemDropShadowChrome>
<theme:SystemDropShadowChrome Name="Shdw" Color="Transparent" SnapsToDevicePixels="true">
<Border Name="ContextMenuBorder"
Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Rectangle Fill="#F1F1F1" HorizontalAlignment="Left" Width="28" Margin="2"
RadiusX="2" RadiusY="2" />
<Rectangle HorizontalAlignment="Left" Width="1" Margin="30,2,0,2"
Fill="#E2E3E3" />
<Rectangle HorizontalAlignment="Left" Width="1" Margin="31,2,0,2" Fill="White" />
<ScrollViewer Name="ContextMenuScrollViewer" CanContentScroll="true"
Grid.ColumnSpan="2" Margin="1,0"
Style="{DynamicResource {ComponentResourceKey TypeInTargetAssembly={x:Type FrameworkElement}, ResourceId=MenuScrollViewer}}">
<Grid RenderOptions.ClearTypeHint="Enabled">
<Canvas Height="0" Width="0" HorizontalAlignment="Left"
VerticalAlignment="Top">
<Rectangle
Height="{Binding ElementName=ContextMenuBorder,Path=ActualHeight}"
Width="{Binding ElementName=ContextMenuBorder,Path=ActualWidth}"
Fill="{Binding ElementName=ContextMenuBorder,Path=Background}" />
</Canvas>
<ItemsPresenter Name="ItemsPresenter"
Margin="{TemplateBinding Padding}" KeyboardNavigation.DirectionalNavigation="Cycle"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Grid>
</ScrollViewer>
</Grid>
</Border>
</theme:SystemDropShadowChrome>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="HasDropShadow" Value="true">
<Setter TargetName="Shdw" Property="Margin" Value="0,0,5,5" />
<Setter TargetName="Shdw" Property="Color" Value="#71000000" />
<Setter TargetName="Shdw2" Property="Margin" Value="0,0,5,5" />
<Setter TargetName="Shdw2" Property="Color" Value="#71000000" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<DataGrid IsReadOnly="True">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding}" />
</DataGrid.Columns>
<DataGrid.ContextMenu>
<ContextMenu Style="{StaticResource MenuStyle}">
<MenuItem Header="Item 1"></MenuItem>
<MenuItem Header="Item 2"></MenuItem>
<MenuItem Header="Item 3"></MenuItem>
</ContextMenu>
</DataGrid.ContextMenu>
<System:String>One</System:String>
<System:String>Two</System:String>
<System:String>Three</System:String>
</DataGrid>
</Grid>
</Window>

Categories

Resources