Show popup based on two properties (IsFocused, IsVisible) - c#

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>

Related

WPF place popup under toggle button in fixed position

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:

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>

Default ErrorTemplate displays alongside with a custom ErrorTemplate

I have a custom Validation.ErrorTemplate and for some reason, WPF displays both my custom error template and the default one. They both show the same error as expected, however I don't want to display the default ErrorTemplate.
My code:
<Style TargetType="TextBox" x:Key="MyTextBox">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Grid>
<Border BorderBrush="red" BorderThickness="1" Background="#11FF0000" IsHitTestVisible="False" x:Name="errorBorder"/>
<AdornedElementPlaceholder x:Name="placeholder" />
<Popup AllowsTransparency="True" HorizontalAlignment="Right" HorizontalOffset="0" VerticalOffset="0" PopupAnimation="Fade" Placement="Right"
PlacementTarget="{Binding ElementName=errorBorder}" IsOpen="{Binding ElementName=placeholder, Path=AdornedElement.IsFocused, Mode=OneWay}">
<StackPanel Orientation="Horizontal">
<Polygon VerticalAlignment="Center" Points="0,4,4,4" Fill="red" Stretch="Fill" Stroke="red"
StrokeThickness="2" />
<Border Background="red" CornerRadius="0" Padding="4">
<TextBlock HorizontalAlignment="Center" Foreground="white" FontWeight="Bold" Margin="2,0,0,0"
Text="{Binding ElementName=placeholder, Path=AdornedElement.ToolTip, Mode=OneWay}" />
</Border>
</StackPanel>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
</Style.Triggers>
</Style>
And this
<Style TargetType="TextBox" BasedOn="{StaticResource MyTextBox}"/>
I'd like to know if anyone knows why WPF displays both my error template and the default one.
EDIT
http://i58.tinypic.com/a14k6q.png - the picture with both errors showing
It is because you defined ErrorTemplate and also defiend a Validation.HasError trigger in your style, you could use one of them. If you want to use the ErrorTemplate you need to remove the trigger, and change the Text binding to "Path=AdornedElement.Validation.Errors).CurrentItem.ErrorContent" then you will just see the result from ErrorTemplate:
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Grid>
<Border/>
<AdornedElementPlaceholder x:Name="placeholder" />
<Popup>
<StackPanel>
<Polygon/>
<Border>
<TextBlock Text="{Binding ElementName=placeholder,
Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent,
Mode=OneWay}" />
</Border>
</StackPanel>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>

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