I have a wrap panel that is populated with Image controls at run time. I want to use a context menu to remove images I want to delete.
<toolkit:WrapPanel x:Name="wrap_Panel">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu IsZoomEnabled="false" x:Name="ContextMenu" >
<toolkit:MenuItem x:Name="Delete" Header="Delete" Click="DeleteImage"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
</toolkit:WrapPanel>
This allows me to get the menu up but how do I actually delete the image I pressed?
private void DeleteImage( object sender, RoutedEventArgs e )
{
MenuItem menuItem = sender as MenuItem;
if ( menuItem != null )
{
Image imageItem = menuItem.DataContext as Image;
...
find the imageItem in your collection or list and delete it.
Related
I'm trying to get a "Copy" context menu to display when clicking on the advanced options icon of any property. What do I need to add to make it work?
<xctk:PropertyGrid
x:Name="PropertyGrid"
Grid.Column="1" Margin="8"
ShowSummary="False"
AutoGenerateProperties="True"
HideInheritedProperties="False"
SelectedObject="{Binding InspectedObject}"
SelectedObjectName="{Binding InspectedObject, Converter={StaticResource PropertyGridPropertyNameConverter}}"
SelectedObjectTypeName="{Binding InspectedObject, Converter={StaticResource PropertyGridPropertyTypeConverter}}"
SelectedObjectChanged="PropertyGrid_OnSelectedObjectChanged"
ShowAdvancedOptions="True"
>
<xctk:PropertyGrid.AdvancedOptionsMenu >
<ContextMenu>
<MenuItem Header="Copy" Click="MenuItem_OnClick"></MenuItem>
</ContextMenu>
</xctk:PropertyGrid.AdvancedOptionsMenu>
</xctk:PropertyGrid>
I'd like the "Copy" context item to display and take a click whether or not the property is read only.
In the MenuItem click event handler, you can access property data by property DataContext in sender object.
private void MenuItem_OnClick(object sender, RoutedEventArgs e)
{
MenuItem menuItem = sender as MenuItem;
if (menuItem != null && menuItem.DataContext is PropertyItem)
{
Clipboard.SetData(DataFormats.Text, ((PropertyItem)menuItem.DataContext).Value);
}
}
In the following link, you can find more information about this topic:
https://kmatyaszek.github.io/2018/08/22/extended-wpftoolkit-propertygrid-copybutton.html
I have noticed that this solution works when you clicked (left mouse button) at AdvancedOptionsMenu icon, there is a problem with the right mouse click on the property item. To solve this problem I forked the original repo and I have added copy value menu item to AdvancedOptionsMenu. Check it out: https://github.com/kmatyaszek/wpftoolkit
I'm trying to use PanoramaItem Header for navigation in my App. I named other pages with header names and override HeaderTemplate for Panorama control in my start page.
<controls:Panorama Title="PanoramaApp"
HeaderTemplate="{StaticResource PanoramaHeaderItemTemplate}">
<controls:PanoramaItem Header="Item1">
...
</controls:PanoramaItem>
</controls:Panorama>
and
<DataTemplate x:Key="PanoramaHeaderItemTemplate">
<Button Style="{StaticResource PanoramaHeaderItemStyle}"
Click="PanoramaHeaderItem_Click"/>
</DataTemplate>
My problem is: How to get panorama HeaderItem value in code behind? In this case it would be Item1.
This is my code so far:
private void PanoramaHeaderItem_Click(object sender, RoutedEventArgs e)
{
var button = (Button)sender;
var HeaderName = ???
}
I don't know hot to get that header name and use it to navigate to other page.
you have two options to get the content from the button
Get the DataContext of the button
MyObject myObj = button.DataContext as MyObject;
Get Content property of the button
object content = button.Content;
I have a ListView with ContextMenu on each ListViewItem that has Click event,
how can I detect in the event handler which Item was clicked in this ContextMenu?
I need the item ID.
<Style TargetType="{x:Type ListViewItem}">
.
.
.
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="tv:TreeListViewItem">
<Grid>
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Header="Open in current tab" Click="MenuItemCurrentTab_Click"/>
<MenuItem Header="Open in new tab" Click="MenuItemNewTab_Click"/>
</ContextMenu>
</Grid.ContextMenu>
See this thread..
Following the same way as the answer from the link you would
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Header="Open in current tab"
Click="MenuItemCurrentTab_Click"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Parent}"/>
...
private void MenuItemCurrentTab_Click(object sender, RoutedEventArgs e)
{
MenuItem menuItem = sender as MenuItem;
if (menuItem != null)
{
ContextMenu parentContextMenu = menuItem.CommandParameter as ContextMenu;
if (parentContextMenu != null)
{
ListViewItem listViewItem = parentContextMenu.PlacementTarget as ListViewItem;
}
}
}
UPDATE
Add this to get the parent ListViewItem from the Grid
public T GetVisualParent<T>(object childObject) where T : Visual
{
DependencyObject child = childObject as DependencyObject;
while ((child != null) && !(child is T))
{
child = VisualTreeHelper.GetParent(child);
}
return child as T;
}
private void MenuItemCurrentTab_Click(object sender, RoutedEventArgs e)
{
MenuItem menuItem = sender as MenuItem;
if (menuItem != null)
{
ContextMenu parentContextMenu = menuItem.CommandParameter as ContextMenu;
if (parentContextMenu != null)
{
Grid grid = parentContextMenu.PlacementTarget as Grid;
ListViewItem listViewItem = GetVisualParent<ListViewItem>(grid);
}
}
}
private void MenuItemCurrentTab_Click(object sender, RoutedEventArgs e)
{
MenuItem menuItem = (MenuItem)e.Source;
ContextMenu menu = (ContextMenu)menuItem.Parent;
ListViewItem item = (ListViewItem)menu.PlacementTarget;
// do something with item
}
But it's probably better idea to create single ContextMenu, give it proper name, and use it for all list view items.
A recurring problem, with many attempts to solve but all have their drawbacks. The accepted answer here, for instance, supposes that each ListViewItem has its own ContextMenu. This works but, especially with a larger number of list items, has a considerable cost in XAML complexity and can be slow. And really isn't necessary at all. If we only use a single ContextMenu on the ListView itself, some other solutions suggest to use
<MenuItem CommandParameter="{Binding PlacementTarget.SelectedItem, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
which seems to solve the problem at first sight (PlacementTarget points to the ListView, its SelectedItem points to the list item, so the menu item handler can use the CommandParameter to get the originating list item), but, unfortunately, fails if the ListView has multiple selection enabled (SelectedItem will point to one of the items selected but not necessarily the one currently clicked) or if we use ListView.PreviewMouseRightButtonDown to disable the selection on right-click (which is, arguably, the only logical thing to do with multiple selections).
There is, however, an approach that has all the benefits:
single ContextMenu on the ListView itself;
works with all selection schemes, single, multiple, disabled;
even with multiple selection, it will pass the currently hovered item to the handler.
Consider this ListView:
<ListView ContextMenuOpening="ListView_ContextMenuOpening">
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Menu1" Click="Menu1_Click" CommandParameter="{Binding Parent, RelativeSource={RelativeSource Self}}" />
</ContextMenu>
</ListView.ContextMenu>
</ListView>
The CommandParameter is used to pass the parent of the MenuItem, ie. the ContextMenu itself. But the main trick comes in the menu opening handler:
private void ListView_ContextMenuOpening(object sender, ContextMenuEventArgs e) {
var menu = (e.Source as FrameworkElement).ContextMenu;
menu.Tag = (FrameworkElement)e.OriginalSource;
}
Inside this handler, we still know the original source of the event, the root FrameworkElement of the list item DataTemplate. Let's store it in the Tag of the menu for later retrieval.
private void Menu1_Click(object sender, RoutedEventArgs e) {
if (sender is MenuItem menu)
if (menu.CommandParameter is ContextMenu context)
if (context.Tag is FrameworkElement item)
if (item.DataContext is DataType data) {
//process data
}
}
In the menu click handler, we can look up the original ContextMenu we stored in the command parameter, from that we can look up the root FrameworkElement of the list item that we stored just before, and finally get the object stored in the list item (of type DataType).
ListViewItem item = myListView.SelectedItem as ListViewItem;
Seems to work just fine as the item is selected when you right-click it.
I have a ListView in my WPF UserControl using an ItemTemplate to display the items. Within the template is a button. When I select one item and then click on the button of another item, the previously selected item is still selected. I wonder how to automatically select the item the button is in when the button is clicked.
Xaml
<UserControl.Resources>
<DataTemplate x:Key="ItemTemplate">
<Border>
<Grid>
<!-- lots of stuff go here -->
<Button Click="MyButton_Click">Clickme</Button>
</Grid>
</Border>
</DataTemplate>
</UserControl.Resources>
<ListView x:Name="_listView"
ItemTemplate="{StaticResource ItemTemplate}">
</ListView>
C# Code behind
void MyButton_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show( string.Format( "clicked on {0}",
this._listView.SelectedItem.ToString() ) ) ;
}
I would do it by getting the data context of the sender object. Assuming your listview is a list of objects of type MyObject... then something like this would allow you to reference the selected object.
void MyButton_Click(object sender, RoutedEventArgs e)
{
Button b = sender as Button;
if (b == null)
{
return;
}
MyObject o = b.DataContext as MyObject;
if (o != null)
{
// Put stuff for my object here
}
}
When you press the button your click / mouse down event is handled by the button and therefore does not route through to the ListView control.
A possible way to solve this is to manually set the listview.SelectedItem in the button click event.
I have a menu in wpf that has an input box and a button on it. Once the user clicks the button I need to close the menu.
Is there a way to do this?
<Menu x:Name="MainMenu">
<MenuItem Header="Main">
<MenuItem Header="SubMenu" x:Name="SubMenu">
<StackPanel Orientation="Horizontal">
<TextBox Width="50" x:Name="TextBox" />
<Button Content="Click Me and Close" x:Name="Button" IsDefault="True"/>
</StackPanel>
</MenuItem>
</MenuItem>
Thanks,
Jon
Get hold of the MenuItem and do:
_menuItem.IsSubmenuOpen = false;
Easy way to get hold of it:
<Button x:Name="_button" Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MenuItem}, AncestorLevel=2}"/>
Code-behind:
_button.Click += delegate
{
(_button.Tag as MenuItem).IsSubmenuOpen = false;
};
I find that using IsSubmenuOpen doesn't properly eliminate focus from the Menu containing the MenuItem (especially if the Menu is in a ToolBar - the top-level MenuItem remains Selected even though the menu is "Closed"). I find sending a MouseUp event to the MenuItem works better (in the button's, or nested control's, Click event handler):
private void button_Click(object sender, RoutedEventArgs e) {
Button b = sender as Button;
if (b == null || !(b.Parent is MenuItem))
return;
MenuItem mi = b.Parent as MenuItem;
mi.RaiseEvent(
new MouseButtonEventArgs(
Mouse.PrimaryDevice, 0, MouseButton.Left
)
{RoutedEvent=Mouse.MouseUpEvent}
);
}
Steve thanks for your solution. That is actually right answer, and finally something that really works beside of tons of bad answers over the internet. I have a shorter (and more safe) solution based on your anwser. Because direct parent (e.Parent) of the button is not always MenuItem (from original answer that is StackPanel), your solution will not work. So just set the Name property of the MenuItem (Name="MyMenuItem") and hook this handler on the Button:
private void Button_Click(object sender, RoutedEventArgs e) {
MyMenuItem.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) {
RoutedEvent = Mouse.MouseUpEvent
});
}