Context Menu on TreeViewItem Calls TreeViewItem's Method? - c#

I have a TreeView setup so that each TreeViewItem has right-click context menu applied as a Style. Something like:
<Grid.Resources>
<ContextMenu x:Key="contextMenu">
<MenuItem Header="Save" IsEnabled="{Binding Path=Saveable}"/>
<MenuItem Header="Copy" IsEnabled="{Binding Path=Copyable}"/>
<MenuItem Header="Remove" IsEnabled="{Binding Path=Removeable}"/>
</ContextMenu>
<Style TargetType="TreeViewItem">
<Setter Property="ContextMenu" Value="{StaticResource contextMenu}" />
</Style>
</Grid.Resources>
Saveable, Copyable and Removeable are properties that come from the object that's used as the TreeViewItem.
What I'm looking for is when the user clicks on a MenuItem, it would click on the appropriate method of the selected object. So clicking on the "Save" MenuItem would call object.Save(), "Copy" calls object.Copy(), etc. But I'm not sure what the syntax would look like, or whether the idea is actually acceptable in terms of typical WPF style. I know I can just create a new event handler in the encompassing window, but I'd prefer the selected item itself to handle the event.
Thoughts?
Thanks!

Unfortunately, I don't think that there is an automated way of doing this. The closest option would be to setup a RoutedUICommand for each item in the ContextMenu, and then create a CommandBinding for each in your class. If you want those to go to the TreeViewItem, you'll probably need to subclass TreeViewItem and set up the CommandBindings there.
The one option that I thought might work would be to add an EventSetter for MenuItem.Click to the TreeViewItem style. However, that did not work - probably because the items in the ContextMenu are in a different visual tree from the TreeViewItems.

Related

Customize DragUI of ListViewItem (UWP)

ListView offers a DragItemsStarting event that comes with according event args. However, unlike DragStartingEventArgs - common to other elements - it does not offer a DragUI, as far as I can tell. My only option is to use DragOver event which is very annoying.
So, I instead said I'll make the ListViewItem's content draggable. However, that backfired because now the Click event doesn't get through anymore, or only very rarely. Simply put, I either can customize the DragUI and not click my ListItems, or the DragUI looks bad, but I retain my functionality.
Is it possible to get a custom DragUI and have the click be handled by the ListView?
You can still utilize DragStarting, but you have to add it to the item content itself within your DataTemplate:
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<Grid CanDrag="True" DragStarting="ItemDragStartingHandler">
...
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
If that causes the click event not working properly, you could try customizing the ListViewItem container itself, which might work. Right-click the ListView in the designer or the Document Outline window, select Edit Additional Templates, and then Edit Generated Item Container. From the last menu select Edit a Copy...
You will get a Style which might be quite long, but within it you will find the the following:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<ListViewItemPresenter DragStarting="ItemDragStartingHandler" x:Name="Root" ...>
You can apply DragStarting event to the ListViewItemPresenter and that might satisfy your needs.

Binding a ContextMenu item's "IsEnabled" to a Button

Is it possible to bind the IsEnabled property of a button to a context menu item that is represented by a NotifyIcon?
When I push the menu item, it starts a method that disables my btnSave. In that case, I would like to "turn off" the MenuItem too. I attempted it this way, but it's not working:
<Window.Resources>
<ContextMenu x:Key="NotifierContextMenu" Placement="MousePoint">
<MenuItem Header="Start" Click="start_timer" IsEnabled="{Binding ElementName=btnSave, Path=IsEnabled}"/>
</ContextMenu>
</Window.Resources>
I believe your problem stems from a ContextMenu not existing within the visual tree, so ElementName bindings will be unsuccessful, unless you take some additional steps to correct the Name Scope, or resolve the DataContext to the visual tree.
Most of the techniques are covered fairly comprehensively in this answer: ElementName Binding from MenuItem in ContextMenu.
I've had success in the past with binding to a named element by reference, in your case, that would look something like this:
<MenuItem Header="Start"
IsEnabled="{Binding IsEnabled, Source={x:Reference btnSave}}"
Click="btnSave_Click"/>

WPF - Need a combination of Tree+Grid, with Context Menu

My application is implemented by a GridView inside a TreeList.
Much to my despair, I discovered that the GridView is very primitive, compared to the widely used DataGrid. I am considering these two options:
(1) Somehow, I replace the GridView with a DataGrid (which supports Context Menu).
(2) Somehow, I add the Context Menu capability to the existent GridView.
Which of the 2 approaches (or another?) would you recommend?
Source code is much appreciated.
TIA.
Based on the linked code, here is the solution:
1 - Add the ContextMenu as a Resource:
<Window.Resources>
<ContextMenu x:Key="ItemsContextMenu" x:Shared="False">
<MenuItem>
<MenuItem.Header>
<TextBlock>
<Run>Context Menu Action for Item</Run>
<Run Text="{Binding Tag.Name}"/>
</TextBlock>
</MenuItem.Header>
</MenuItem>
</ContextMenu>
<!-- other stuff here -->
</Window.Resources>
It is recommended that you set x:Shared="False" to prevent Binding issues related to reusing the resource instance.
2 - Define an ItemContainerStyle for your TreeList that sets the ContextMenu for the TreeListItems:
<tree:TreeList ...>
<!-- other stuff here -->
<tree:TreeList.ItemContainerStyle>
<Style TargetType="{x:Type tree:TreeListItem}">
<Setter Property="ContextMenu" Value="{StaticResource ItemsContextMenu}"/>
</Style>
</tree:TreeList.ItemContainerStyle>
</tree:TreeList>
Notice that I'm using DataBinding in the ContextMenu, which means you have a proper, working DataContext in it. You should be able to use Commands and other stuff in it.

Command not executing in row level ContextMenu on DataGrid in WPF C#

I have my template declared like so -
<DataGrid.Resources>
<ContextMenu x:Key="RowMenu" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Remove" Command="{Binding Cancel}" />
</ContextMenu>
</DataGrid.Resources>
I'm applying the template using row style -
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="ContextMenu" Value="{StaticResource RowMenu}" />
</Style>
</DataGrid.RowStyle>
The menu shows up ok
But the command (on the ItemListViewModel) does not execute when a context menu item is clicked
public class ItemListViewModel : INotifyPropertyChanged
{
public void Cancel()
{
MessageBox.Show("Cancel test");
}
...
}
My binding is otherwise working properly, as I can do things like this -
foreach (ItemListViewModel ul in mylist.SelectedItems)
MessageBox.Show(item.FullDescription);
I've been at this all night trying to figure it out. Just started with WPF today.
Please somebody tell me where I've gone wrong
I don't think you can bind to a simple method. You need to bind to a command that should be an implementation of ICommand interface. In you case you need to create a class that would implement that interface and add property of that class type to your model.
See this example as a reference: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
I decided ListView was better for my needs and I'm using that instead. I'm no longer trying to bind the context menu to the item, but rather have a single context menu for the whole listview and simply enable or disable items in the ContextMenuOpen event where need be.

WPF ContextMenu bind some property to another property of the same control

I have a ContextMenu and a ColumnHeaderStyle defined in Window.Resource section which I use-it to a DataGrid ColumnHeader. My code is something like this:
<ContextMenu x:Key="cm_columnHeaderMenu"/>
<Style x:Key="DefaultColumnHeaderStyle" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="ContextMenu" Value="{StaticResource cm_columnHeaderMenu}" />
</Style>
<DataGrid Grid.Column="2" Grid.Row="1" x:Name="dgridFiles" IsReadOnly="True"
ColumnHeaderStyle="{StaticResource DefaultColumnHeaderStyle}">
I want to know if I can (and if the answer it true, then HOW I can I do it) bind the ContextMenu Visibility property to same control ContextMenu Items.Count > 0 property.
Initially based on some other treeView control selections made there shoud be no items in the context menu, but i wish to add dinamically items in ContextMenu based on selection in treeView. This part is done, the context has those items. On some selections there are no-items, but still on the grid it appears an empty ContextMenu. So I believe the easiest part it would be to bind the Visibility to Items.Count property of the same control.
Sorry if my english is not good enough, I'll try to explain better if i didnt make clear 1st time.
you want to bind via RelativeSource, especially the Self mode.
I think by reading this or this you will be able to achieve your goal.
Then you'll need a binding converter to convert the integer values to the matching type and values of the Visibility property. You'll find a short tutorial here.
Regards
Using this you can bind to the property in the same control
Visibility="{Binding Path=Items.Count, RelativeSource={RelativeSource Self}}"
You also have to use a converter to achieve what you want.
Just in case you need this
Try a converter to convert the value of the item count to a boolean. So you'll end up with something like
<ContextMenu Visibility={Binding RelativeSource={RelativeSource Self},
Converter={StaticResource ItemsToVisibilityConverter}, Path=Items.Count}} />
If that doesn't work, try this with data triggers (you still need a converter anyway, and this shows a converter at work):
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/a8ad8c14-95aa-4ed4-b806-d0ae874a8d26/

Categories