1

I am trying to disable certain menu items in a treeview's context menu if the SelectedItem property for the treeview is null. My expectation is that this would be most simple to achieve by binding the SelectedItem property of the TreeView to the IsEnabled property of the MenuItem with a converter in between.

I'm not particularly experienced in WPF yet, so I'm guessing that I am doing something wrong with the binding.

I have found this solution to manually brute force the IsEnabled property whenever the menu is opened, but it doesn't seem an ideal solution to me. It would not be immediately clear to anyone adding new menu items that they need to modify the code behind to disable their new menu item if nothing is selected in the tree view. If what I am trying to achieve with binding (or some other XAML solution) is not possible, I will have go for this brute force solution.

Here's a stripped down example of what I have so far:

MainWindow.xaml

<Window x:Class="treeViewTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:treeViewTest="clr-namespace:treeViewTest"
        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <treeViewTest:NullObjectToDisabledConverter
            x:Key="NullObjectToDisabledConverter" />
    </Window.Resources>

    <Grid>
        <TreeView Name="treeView" MouseLeftButtonDown="treeView_MouseLeftButtonDown">
            <TreeViewItem Header="Parent" IsExpanded="True">
                <TreeViewItem Header="Child" />
            </TreeViewItem>
            <TreeViewItem Header="Sibling" />

            <TreeView.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Copy"
                        IsEnabled="{Binding ElementName=treeView, Path=SelectedItem,
                        Converter={StaticResource NullObjectToDisabledConverter}}" />
                    <MenuItem Header="Paste"
                        IsEnabled="{Binding ElementName=treeView, Path=SelectedItem,
                        Converter={StaticResource NullObjectToDisabledConverter}}" />
                </ContextMenu>
            </TreeView.ContextMenu>
        </TreeView>
    </Grid>
</Window>

MainWindow.xaml.cs

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;

namespace treeViewTest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

        }

        private void treeView_MouseLeftButtonDown(object sender,
            MouseButtonEventArgs e)
        {
            TreeViewItem node = treeView.SelectedItem as TreeViewItem;
            if (node != null)
            {
                node.IsSelected = false;
            }
        }
    }

    public class NullObjectToDisabledConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter,
            CultureInfo culture)
        {
            return (value != null);
        }

        public object ConvertBack(object value, Type targetType, object parameter,
            CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

I've tried returning false in the converter to brute force disable the menu items but the converter is never actually getting called.

Thanks in advance for any help with understanding why this does not work.

Community
  • 1
  • 1
Mick Waites
  • 147
  • 13
  • use x:Reference instead of ElementName since TreeView and ContextMenu are not in the same visualtree the Biniding from ContextMenu can't locate the treeview by name – eran otzap Oct 21 '14 at 08:34
  • @eranotzap I tried x:Reference, but that produced an error at runtime about a circular reference, so I suspect I was doing something else wrong there. Whilst trying to find how to use x:Reference properly, I found a solution [here](http://stackoverflow.com/questions/11781286/binding-an-ancestor-not-working-wpf). My end result is to change the binding to `IsEnabled="{Binding Path=PlacementTarget.SelectedItem, RelativeSource={RelativeSource AncestorType=ContextMenu}, Converter={StaticResource NullObjectToDisabledConverter}}"`. – Mick Waites Oct 21 '14 at 09:20
  • Do you need to disable the whole contexMenu? or just particular menu items? – user1064519 Oct 21 '14 at 09:25
  • @user1064519 Just particular menu items in the main project, the sample code should really have better represented that fact. – Mick Waites Oct 21 '14 at 10:02

1 Answers1

2

here is a workaround using DataTrigger

<TreeView Name="treeView">
    <TreeViewItem Header="Parent"
                  IsExpanded="True">
        <TreeViewItem Header="Child" />
    </TreeViewItem>
    <TreeViewItem Header="Sibling" />
    <TreeView.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Copy"
                      x:Name="copy">
                <MenuItem.Style>
                    <Style TargetType="MenuItem">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding PlacementTarget.SelectedItem,RelativeSource={RelativeSource FindAncestor, AncestorType=ContextMenu}}"
                                         Value="{x:Null}">
                                <Setter Property="IsEnabled"
                                        Value="False" />
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </MenuItem.Style>
            </MenuItem>
            <MenuItem Header="Paste" />
        </ContextMenu>
    </TreeView.ContextMenu>
</TreeView>

this example will disable the first menu item if there is no selected item. same can be applied to others

give it a try and see if this is what you are looking for.

pushpraj
  • 13,458
  • 3
  • 33
  • 50
  • Yes, this works, thanks. I like the fact that it also avoids the need for a converter. I assume it is possible to define this style in a single place and reference it for each menu item that requires it? – Mick Waites Oct 21 '14 at 10:11
  • that's correct @MickWaites, you can define the style and apply to the items you want to get disabled when no item is selected. – pushpraj Oct 21 '14 at 11:25