ContextMenuService.Placement doesn't work in setter for MVVM pattern - c#

I have gone through some of the previous similar questions, but am still having issues with the ContextMenuService.Placement. Please suggest.
It worked fine when I followed this approach
<Button x:Name="btn" Content="button" Click="b_Click" >
<Button.ContextMenu >
<ContextMenu >
<MenuItem Header="Open" Command="{Binding OnOpen}" ></MenuItem>
<MenuItem Header="Close" Command="{Binding OnClose}"></MenuItem>
</ContextMenu>
</Button.ContextMenu>
</Button>
private void be_Click(object sender, RoutedEventArgs e)
{
btn.ContextMenu.PlacementTarget = btn;//Like this
btn.ContextMenu.Placement = PlacementMode.Top;//Like this
btn.ContextMenu.DataContext = btn.DataContext;
btn.ContextMenu.IsOpen = true;
}
But it doesn't work with MVVM pattern.
<Button x:Name="btn" VerticalAlignment="Bottom" ContextMenuService.IsEnabled="False">
<Button.Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Style.Triggers>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/>
</BooleanAnimationUsingKeyFrames>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsEnabled">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu Name="AddReportContextMenu" HorizontalAlignment="Right">
<MenuItem Header="Open" Command="{Binding OnOpen}" ></MenuItem>
<MenuItem Header="Close" Command="{Binding OnClose}"></MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
I tried adding it in setter like this
<Setter Property="ContextMenu.PlacementTarget" Value="{Binding ElementName=btn}"></Setter>
<Setter Property="ContextMenu.Placement" Value="Top"></Setter>
Or Like this:
<Setter Property="ContextMenuService.Placement" Value="Top"></Setter>
The placement property worked well with right click like this if ContextMenuService.IsEnabled is not set it false. I had to set it false to make sure that the ContextMenu only worked with Left Click.
<Button x:Name="btn" ContextMenuService.Placement="Top">
Thank you!

Related

How to add button group instead radio button

I want to ad button group instead radio button.. there is three buttons. all three buttons are same color(blue). when user click on 1st button it will change that button color as red. But when user click on second button, first button must turn into blue color and clicked button(2nd button) must turn in to red. In my code that's not change. Help me
<Button Background="#0D47A1" Command="{Binding LanguageChangeCommand}" CommandParameter="Sinhala" Content="සිංහල" Grid.Column="3" HorizontalAlignment="Left" Margin="0,10,0,0" Grid.Row="3" FontSize="20" VerticalAlignment="Top" Foreground="White" Height="37" Width="81">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Button.Background).(SolidColorBrush.Color)" To="#2E8B57"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
<Button.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="10"/>
</Style>
</Button.Resources>
</Button>
<Button Command="{Binding LanguageChangeCommand}" Background="#0D47A1" CommandParameter="English" Content="English" Grid.Column="3" HorizontalAlignment="Left" Margin="110,15,0,0" Grid.Row="3" FontSize="20" VerticalAlignment="Top">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Button.Background).(SolidColorBrush.Color)" To="#2E8B57"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
<Button.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="10"/>
</Style>
</Button.Resources>
</Button>
<Button Command="{Binding LanguageChangeCommand}" Background="#0D47A1" CommandParameter="Tamil" Content="தமிழ்" Grid.Column="3" HorizontalAlignment="Left" Margin="215,15,0,0" Grid.Row="3" FontSize="20" VerticalAlignment="Top" Foreground="#DDFDF9F9">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Button.Background).(SolidColorBrush.Color)" To="#2E8B57"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
<Button.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="10"/>
</Style>
</Button.Resources>
</Button>
Button Group? Another idea is ListBox with styled ListBoxItem.
<ListBox VerticalAlignment="Top">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="border"
Padding="3" Background="SkyBlue"
BorderBrush="DeepSkyBlue" BorderThickness="1">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="OrangeRed" />
<Setter TargetName="border" Property="Background" Value="HotPink" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBoxItem Content="1" />
<ListBoxItem Content="2" IsSelected="True" />
<ListBoxItem Content="3" />
<ListBoxItem Content="4" />
</ListBox>
The benefit of ListBox is that you can use binding and easily to get the value of selected "button" by the user.

"No target method found" error using cal:Message.Attach in WPF Context Menu

I am using Caliburn.Micro. I have tried the solutions I found for this problem but is no good. I have the following XAML code for my design:
<Grid x:Name="ActionGrid">
<MenuItem Header="Action" FontFamily="Open Sans" FontSize="14" HorizontalContentAlignment="Right" Foreground="White" x:Name="miAction" Margin="5" Background="#FF166FC4" Tag="{Binding DataContext}">
<MenuItem.Style>
<Style TargetType="{x:Type MenuItem}">
<Style.Triggers>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
<Setter Property="Tag" Value="{Binding Path=DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=MenuItem}}"/>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}">
<MenuItem Header="Remove Group" cal:Message.Attach="RemoveClicked()" />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</MenuItem.Style>
</MenuItem>
</Grid>
<UserControl.DataContext>
<vm:TransactionViewModel/>
</UserControl.DataContext>
Everytime I click on the Item, it returns No Method Found for RemoveClicked. I don't know what I did wrong. Please help me point it out.
Tag="{Binding DataContext}" should be Tag="{Binding}" and the cal:Action.TargetWithoutContext attached property should be set on the MenuItem. Then it works if you right click on the MenuItem to open the ContextMenu:
<MenuItem Header="Action" FontFamily="Open Sans" FontSize="14" HorizontalContentAlignment="Right" Foreground="White" x:Name="miAction"
Margin="5" Background="#FF166FC4" Tag="{Binding}">
<MenuItem.Style>
<Style TargetType="{x:Type MenuItem}">
<Style.Triggers>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Remove Group"
cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"
cal:Message.Attach="RemoveClicked()" />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</MenuItem.Style>
</MenuItem>
Use an EventTrigger to open the ContextMenu on left click doesn't work with bindings and this has nothing to do with Caliburn.Micro:
WPF Context menu on left click
You may replace the EventTrigger with an attached behaviour.
I'm not sure, but you can test this:
<MenuItem Header="Remove Group" cal:Message.Attach="RemoveClicked" />

C# WPF, how to make a label with a delete button on it?

I'm trying to make a File Attachment function in my program, i have 2 types of attachments (Personal/Professional documents). Picture below.
What i want to do now, is make the uploaded files appear in a vertical list (below the label & button in each groupbox) as a label with a delete button, i dont know what this function is called. I would like something like the keywords/tags function (like on stackoverflow, youtube...) Picture below.
Like:
Drivers License [X]
Passport [X]
Visa [X]
As the user can quickly see what files he have alredy uploaded, and quickly remove a file if he made a mistake.
What i have tried so far, is making a stackpanel divided into 2 columns, text on one side, and buttons on the other side, but i didnt get the result that i wanted. Problem is that i dont even know what this function is called, im sure Theres some tutorial somewhere out there, but its hard to search for something you dont know the name of.
Use ListView with the style:
<Style x:Key="ListViewPlate" TargetType="{x:Type ListView}">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel Width="{Binding (FrameworkElement.ActualWidth),
RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"
ItemWidth="{Binding (ListView.View).ItemWidth,
RelativeSource={RelativeSource AncestorType=ListView}}"
MinWidth="{Binding ItemWidth, RelativeSource={RelativeSource Self}}"
ItemHeight="{Binding (ListView.View).ItemHeight,
RelativeSource={RelativeSource AncestorType=ListView}}" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
And ListView ItemTemplate - in order to works with the delete button use Command (that would require using a Prism), command would transfer selected item as a context.
<DataTemplate x:Key="ListViewPlateItem">
<WrapPanel>
<Border Background="Black" />
<Border BorderBrush="Goldenrod" BorderThickness="2">
<TextBlock HorizontalAlignment="Center" Text="{Binding Name}" VerticalAlignment="Center" />
</Border>
<Border BorderBrush="Goldenrod" BorderThickness="2">
<Button Command="{Binding ElementName = ListViewElement, Path = DataContext.Command"} CommandParameter={"Binding"}">
<Button.Background>
<ImageBrush ImageSource="yourImage.png" TitleMode="None"/>
</Button.Background>
</Button>
</Border>
</WrapPanel>
</DataTemplate>
You can made style and ItemTemplate a ResourceDictionary, and then use it
<ListView ItemTemplate="{StaticResource ListViewPlateItem}" Style="{StaticResource ListViewPlate}"/>
Here is UserControl that is looking like
Xaml code
<UserControl x:Class="ButtonLikeInSO.SpecialTextPresenterWithButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="150" x:Name="This">
<UserControl.Resources>
<SolidColorBrush x:Key="GrayButtonBackGround" Color="Gainsboro"/>
<SolidColorBrush x:Key="RedButtonBackground" Color="Tomato"/>
<Style x:Key="ChangeContentOnMouseOverWithAnimationWhenPressed" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Background" Value="{StaticResource GrayButtonBackGround}"/>
<Setter Property="Foreground" Value="Black"></Setter>
<Setter Property="ToolTip" Value="Delete Uploading"/>
<Setter Property="ToolTipService.Placement" Value="Top"/>
<Setter Property="Opacity" Value="0.8"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="LayoutRoot" RenderTransformOrigin="0.5 0.5" Margin="2">
<Grid.RenderTransform>
<ScaleTransform></ScaleTransform>
</Grid.RenderTransform>
<Ellipse x:Name="MyBorder" Fill="{TemplateBinding Background}" Stroke="Gray" StrokeThickness="1"/>
<Ellipse x:Name="RectangleVisibleOnMouseMove" Opacity="0" Fill="{StaticResource RedButtonBackground}" Stroke="Black" StrokeThickness="1"/>
<Path x:Name="ButtonPath"
Margin="5"
Stroke="{TemplateBinding Foreground}"
StrokeThickness="1.5"
StrokeStartLineCap="Square"
StrokeEndLineCap="Square"
Stretch="Uniform"
VerticalAlignment="Center"
HorizontalAlignment="Center" Data="M0,0 L1,1 M0,1 L1,0">
</Path>
</Grid>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="RectangleVisibleOnMouseMove"
Storyboard.TargetProperty="(FrameworkElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0.0" />
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1.0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="MyBorder"
Storyboard.TargetProperty="(FrameworkElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1.0" />
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="0.0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="RectangleVisibleOnMouseMove"
Storyboard.TargetProperty="(FrameworkElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1.0" />
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="0.0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="MyBorder"
Storyboard.TargetProperty="(FrameworkElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0.0" />
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1.0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Button.PreviewMouseDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot"
Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1.0" />
<EasingDoubleKeyFrame KeyTime="0:0:0.10" Value="0.8" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot"
Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1.0" />
<EasingDoubleKeyFrame KeyTime="0:0:0.10" Value="0.8" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Button.PreviewMouseUp">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot"
Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0.8" />
<EasingDoubleKeyFrame KeyTime="0:0:0.10" Value="1.0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot"
Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0.8" />
<EasingDoubleKeyFrame KeyTime="0:0:0.10" Value="1.0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Button.IsPressed" Value="True">
<Setter Property="Foreground" Value="White"></Setter>
</Trigger>
<Trigger Property="IsPressed" Value="False">
<Setter Property="Foreground" Value="Black"></Setter>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="1.0"></Setter>
</Trigger>
</Style.Triggers>
</Style>
<DataTemplate x:Key="TextWithDeleteButton">
<Border BorderThickness="1" BorderBrush="Gainsboro">
<Grid Background="{Binding ElementName=This, Path=Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding ElementName=This, Path=Text}" MaxWidth="150" Margin="5,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Center"
TextTrimming="WordEllipsis" />
<Button Grid.Column="1" Margin="0" Width="20" Height="20" HorizontalAlignment="Center" VerticalAlignment="Center" Command="{Binding ElementName=This, Path=DeleteCommand}" Style="{StaticResource ChangeContentOnMouseOverWithAnimationWhenPressed}"></Button>
</Grid>
</Border>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ContentControl ContentTemplate="{StaticResource TextWithDeleteButton}"></ContentControl>
</Grid>
Code behind
public partial class SpecialTextPresenterWithButton : UserControl
{
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof (string),
typeof (SpecialTextPresenterWithButton), new PropertyMetadata(default(string)));
public static readonly DependencyProperty DeleteCommandProperty = DependencyProperty.Register("DeleteCommand",
typeof (ICommand), typeof (SpecialTextPresenterWithButton), new PropertyMetadata(default(ICommand)));
public SpecialTextPresenterWithButton()
{
InitializeComponent();
}
public string Text
{
get { return (string) GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public ICommand DeleteCommand
{
get { return (ICommand) GetValue(DeleteCommandProperty); }
set { SetValue(DeleteCommandProperty, value); }
}
}
Using
<!--you can use binding to DeleteCommand and Text they are dependancy properties-->
<buttonLikeInSo:SpecialTextPresenterWithButton Background="Aquamarine" DeleteCommand="{Binding DeleteCommand}" HorizontalAlignment="Center" VerticalAlignment="Center" Height="20" Text="LoooooooooooongFileName"/>
Assuming you have some type of View Model with data-binding, this can be quite straight forward. You can have an ObservableCollection of uploaded items. This could just be a simple class holding an identifyer and display name:
public class UploadedFileInfo
{
public int Id { get; set; }
public string DisplayName { get; set; }
}
in View Model:
ObservableCollection<UploadedFileInfo> UploadedFiles { get; set; }
Now you can bind a ItemsControl to this collection eg:
<ItemsControl ItemsSource="{Binding UploadedFiles}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border>
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding DisplayName, Mode=OneWay}" />
<Button Command="{Binding Path=DataContext.DeleteFile, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding Id}" />
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This requires a command in the View Model:
public ICommand DeleteFile { get; private set;}
In View Model Constructor:
DeleteFile = new RelayCommand<int>((fileIdToDelete) => deleteFile(fileIdToDelete))
Where deleteFile(int fileToDelete) is a function to delete the file and remove it from the ObservableCollection UploadedFiles
Note, you will have to find the RelayCommand class, there is one on the Microsoft WPF pages, there are also implementations in MVVMLight and other MVVM frameworks that you can use.
EDIT
A binding in an ItemsControl will look for properties on the objects bound to (that is its DataContext)
<Button Command="{Binding DeleteFile}" CommandParameter="{Binding Id}" />
Should have been
<Button Command="{Binding Path=DataContext.DeleteFile, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding Id}" />
Which will look for the ICommand parameter on the main window's DataContext

wpf button storyboard trigger

I am trying to make rectangle animation after clicking on a button.
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
<Button Content="FirstButton" HorizontalAlignment="Left" Height="60" Margin="341,91,0,0" VerticalAlignment="Top" Width="91">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
??? <BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
What i need to write?
<StackPanel>
<Button Name="Button"/>
<Rectangle>
<Rectangle.Style>
<Style TargetType="Rectangle">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Button, Path=IsPressed}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
</StackPanel>

ContextMenu for ListViewItem only

I have a context menu - problem is I need it to only open when a listviewitem is clicked. Right now it will open if I click anywhere in the listview or in the header.
<ListView>
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="More Info" Command="{Binding MoreInfo}" />
</ContextMenu>
</ListView.ContextMenu>
<ListView.View>
<GridView>
<!-- columns and stuff here -->
</GridView>
</ListView.View>
</ListView>
I have tried adding the ContextMenu as a resource and applying it as a style, but this breaks the command (clicking on More Info should open a dialog window, doesnt work this way)
<ListView.Resources>
<ContextMenu x:Key="ItemContextMenu">
<MenuItem Header="More Info" Command="{Binding MoreInfo}" Background="WhiteSmoke" />
</ContextMenu>
</ListView.Resources>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}" >
<Setter Property="ContextMenu" Value="{StaticResource ItemContextMenu}" />
</Style>
</ListView.ItemContainerStyle>
So not sure how to restrict the context menu to only the listviewitem and have the command work.
Use the RelativeSource in the command binding in the template, and it will work:
<ListView.Resources>
<ContextMenu x:Key="ItemContextMenu">
<MenuItem Header="More Info" Command="{Binding Path=DataContext.MoreInfo, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}}" Background="WhiteSmoke" />
</ContextMenu>
</ListView.Resources>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}" >
<Setter Property="ContextMenu" Value="{StaticResource ItemContextMenu}" />
</Style>
</ListView.ItemContainerStyle>
Expanding on this very helpful post...If your ContextMenu has custom buttons or other objects within a ControlTemplate, I have combined the answer above with the answer from Closing ContextMenu with Templated MenuItems so that when a user clicks on the Button, the ContextMenu closes normally only using XAML. This took about 10 hours to put together. Hope it saves you time. Supports MVVM ICommand usage. I also used the Style for the ContextMenu from [this post][2] to elminate the 90's look.
<ListView.Resources>
<ContextMenu x:Key="ItemContextMenu" Style="{StaticResource HorizontalContextMenu}">
<MenuItem>
<MenuItem.Template>
<ControlTemplate>
<Grid MinHeight="50" MinWidth="50">
<Button Style="{StaticResource CloseAppButton}" Command="{Binding Path=DataContext.DeleteCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}}" >
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(ContextMenu.IsOpen)" Storyboard.Target="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ContextMenu}}">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<sys:Boolean>False</sys:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
</ControlTemplate>
</MenuItem.Template>
</MenuItem>
<MenuItem>
<MenuItem.Template>
<ControlTemplate>
<Grid MinHeight="50" MinWidth="50">
<Button Style="{StaticResource AddButton}" Command="{Binding Path=DataContext.TestCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}}" >
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(ContextMenu.IsOpen)" Storyboard.Target="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ContextMenu}}">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<sys:Boolean>False</sys:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
</ControlTemplate>
</MenuItem.Template>
</MenuItem>
<MenuItem>
<MenuItem.Template>
<ControlTemplate>
<Grid MinHeight="50" MinWidth="50">
<Button Style="{StaticResource PluginInfoButton}" Command="{Binding Path=DataContext.TestCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}}" >
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(ContextMenu.IsOpen)" Storyboard.Target="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ContextMenu}}">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<sys:Boolean>False</sys:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
</ControlTemplate>
</MenuItem.Template>
</MenuItem>
</ContextMenu>
</ListView.Resources>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}" >
<Setter Property="ContextMenu" Value="{StaticResource ItemContextMenu}" />
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>

Categories