0

コンテキスト メニューを定義する DataTemplate があります。

<DataTemplate>
    <TextBlock>
        <TextBlock.ContextMenu>
            <ContextMenu>
                <MenuItem Command="{Binding SendToRecycleBin}" Header="Delete">
            </ContextMenu>
        </TextBlock.ContextMenu>
    </TextBlock>
</DataTemplate>

XAML のみを使用して、ユーザーがコンテキスト メニューを開くときに Shift キーを押した場合にのみ表示される別のメニュー項目をコンテキスト メニューに追加したいと考えています (おそらく、新しい添付プロパティ App.PowerUserOnly を作成しますか?)。

<MenuItem Command="{Binding Delete}" Header="Permanently Delete"
                                     local:App.PowerUserOnly="true">

これは XAML でのみ実行できますか (そうであれば、どのように?)、またはコード ビハインドを使用する必要がありますか?

編集: コンテキスト メニューを開くときに Shift キーを押したままにすると、Windows シェルにも詳細オプションが表示されます。私はその行動をエミュレートしようとしています。たとえば、アプリケーションの高度なオプションの 1 つは、別のユーザーとして実行することです。

人々の提案をテストするのに役立つように、コードを単純化しました。プロジェクトは、ShiftContextMenu という名前のデフォルトの WPF アプリケーションを使用して VS2010 で作成されます。App.xaml および App.xaml.cs ファイルは変更されていません。

MainWindow.xaml:

<Window x:Class="ShiftContextMenu.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <DataTemplate x:Key="DummyItemTemplate">
            <TextBlock Text="{Binding Name}">
                <TextBlock.ContextMenu>
                    <ContextMenu>
                        <MenuItem Command="{Binding SendToRecycleBin}" Header="Delete" />
                        <MenuItem Command="{Binding Delete}" Header="Permanently Delete" />
                    </ContextMenu>
                </TextBlock.ContextMenu>
            </TextBlock>
        </DataTemplate>
    </Window.Resources>
    <TreeView Name="tvMain" ItemTemplate="{StaticResource DummyItemTemplate}" ItemsSource="{Binding DummyItems}" />
</Window>

MainWindow.xaml.cs:

using System.Collections.Generic;
using System.Windows;
using System.Collections.ObjectModel;

namespace ShiftContextMenu
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            DummyItem[] dummyItems = new DummyItem[] {
                new DummyItem("First"),
                new DummyItem("Second"),
                new DummyItem("Third")
            };
            DummyItems = new ReadOnlyCollection<DummyItem>(new List<DummyItem>(dummyItems));
            this.DataContext = this;
            InitializeComponent();
        }

        public ReadOnlyCollection<DummyItem> DummyItems { get; protected set; }
    }
}

ViewModelBase.cs:

using System.ComponentModel;

namespace ShiftContextMenu
{
    public class ViewModelBase : INotifyPropertyChanged
    {
        protected PropertyChangedEventHandler _propertyChangedEvent;

        protected void SendPropertyChanged(string propertyName)
        {
            if (_propertyChangedEvent != null)
            {
                _propertyChangedEvent(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged
        {
            add
            {
                _propertyChangedEvent += value;
            }
            remove
            {
                _propertyChangedEvent -= value;
            }
        }
    }
}

DummyItem.cs:

using System;
using System.Windows.Input;
using System.Windows;

namespace ShiftContextMenu
{
    public class DummyItem : ViewModelBase
    {
        public string Name { get; protected set; }

        public DummyItem(string name)
        {
            Name = name;
            _sendToRecycleBinCommand = new SendToRecycleBinCommand();
            _deleteCommand = new DeleteCommand();
        }

        protected SendToRecycleBinCommand _sendToRecycleBinCommand;
        protected DeleteCommand _deleteCommand;

        public ICommand SendToRecycleBin { get { return _sendToRecycleBinCommand; } }
        public ICommand Delete { get { return _deleteCommand; } }

        protected class SendToRecycleBinCommand : ICommand
        {
            public void Execute(object parameter)
            {
                MessageBox.Show("Send To Recycle Bin");
            }

            public bool CanExecute(object parameter)
            {
                return true;
            }

            public event EventHandler CanExecuteChanged { add { } remove { } }
        }

        protected class DeleteCommand : ICommand
        {
            public void Execute(object parameter)
            {
                MessageBox.Show("Permanently Delete");
            }

            public bool CanExecute(object parameter)
            {
                return true;
            }

            public event EventHandler CanExecuteChanged { add { } remove { } }
        }
    }
}
4

2 に答える 2

2

kmatyaszek の答えは機能しましたが、ViewModel を変更する必要がありませんでした。そのため、質問で提案した添付の依存関係プロパティを作成することになりました。

public static readonly DependencyProperty PowerUserOnlyProperty =
    DependencyProperty.RegisterAttached(
        "PowerUserOnly", 
        typeof(bool), 
        typeof(App), 
        new UIPropertyMetadata(false, new PropertyChangedCallback(PUOChanged)));

public static bool GetPowerUserOnly(MenuItem obj)
{
    return (bool)obj.GetValue(PowerUserOnlyProperty);
}

public static void SetPowerUserOnly(MenuItem obj, bool value)
{
    obj.SetValue(PowerUserOnlyProperty, value);
}

public static void PUOChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    MenuItem menuItem = sender as MenuItem;
    if (menuItem == null) return;

    bool value = (bool)e.NewValue;
    if (!value) return;

    new PowerUserOnlyHelper(menuItem);
}

public class PowerUserOnlyHelper
{
    public MenuItem Item { get; protected set; }

    public PowerUserOnlyHelper(MenuItem menuItem)
    {
        Item = menuItem;

        ContextMenu parent = VisualUpwardSearch<ContextMenu>(menuItem);
        if (parent != null)
        {
            parent.Opened += new RoutedEventHandler(OnContextMenuOpened);
        }
    }

    protected void OnContextMenuOpened(object sender, RoutedEventArgs e)
    {
        Visibility v;
        if ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)
        {
            v = Visibility.Visible;
        }
        else v = Visibility.Collapsed;

        Item.Visibility = v;
    }
}

public static T VisualUpwardSearch<T>(DependencyObject source)
    where T : DependencyObject
{
    DependencyObject returnVal = source;
    DependencyObject tempReturnVal;

    while (returnVal != null && !(returnVal is T))
    {
        tempReturnVal = null;
        if (returnVal is Visual || returnVal is Visual3D)
        {
            tempReturnVal = VisualTreeHelper.GetParent(returnVal);
        }
        if (tempReturnVal == null)
        {
            returnVal = LogicalTreeHelper.GetParent(returnVal);
        }
        else
        {
            returnVal = tempReturnVal;
        }
    }

    return returnVal as T;
}
于 2012-10-30T20:48:30.367 に答える
2

Windows シェル動作の解決策:

このソリューションでは、次の 2 つのアセンブリを使用しています。

  1. System.Windows.Interactivity
  2. System.Windows.Forms

次の名前空間をウィンドウに追加します。

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

DataTemplate は次のようになります。

<DataTemplate x:Key="DummyItemTemplate">
            <TextBlock Text="{Binding Name}">
                <TextBlock.ContextMenu>
                    <ContextMenu> 
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="Opened">
                                <i:InvokeCommandAction Command="{Binding ShowMoreOptions}" />
                            </i:EventTrigger>
                            <i:EventTrigger EventName="Closed">
                                <i:InvokeCommandAction Command="{Binding HideMoreOptions}" />
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                        <MenuItem Command="{Binding SendToRecycleBin}" Header="Delete" />
                        <MenuItem Command="{Binding Delete}" Header="Permanently Delete">
                        <MenuItem.Style>
                            <Style TargetType="MenuItem">
                                <Setter Property="Visibility" Value="Collapsed" />
                                <Style.Triggers>
                                    <DataTrigger Binding="{Binding IsVisibleDelete}" Value="True">
                                        <Setter Property="Visibility" Value="Visible" />
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </MenuItem.Style>    
                    </MenuItem>
                    </ContextMenu>
                </TextBlock.ContextMenu>
            </TextBlock>
        </DataTemplate>

クラスでDummyItemは、2 つのコマンドと 1 つのプロパティを追加する必要があります。

private bool _isVisibleDelete;
public bool IsVisibleDelete
{
    get { return _isVisibleDelete; }
    set { _isVisibleDelete = value; SendPropertyChanged("IsVisibleDelete"); }
}

public ICommand ShowMoreOptions { get; private set; }
private void OnShowMoreOptions()
{
    if (System.Windows.Forms.Control.ModifierKeys == System.Windows.Forms.Keys.Shift)
        IsVisibleDelete = true;
}

public ICommand HideMoreOptions { get; private set; }
private void OnHideMoreOptions()
{
    IsVisibleDelete = false;
}

私の例では、アセンブリDelegateCommandから使用しています。Microsoft.Practices.Prism

だからDummyItem私は持っています:

 ShowMoreOptions = new DelegateCommand(this.OnShowMoreOptions);
 HideMoreOptions = new DelegateCommand(this.OnHideMoreOptions);

2 番目の解決策では、このメニューを動的に変更できます。

あなたはそのようなことを試すことができます:

XAML ファイル:

<TextBlock>
            <TextBlock.ContextMenu>
                <ContextMenu>
                    <ContextMenu.InputBindings>
                        <KeyBinding Modifiers="Shift" Key="Shift" Command="{Binding ShowMoreOptions}" />
                    </ContextMenu.InputBindings>
                    <MenuItem Command="{Binding SendToRecycleBin}" Header="Delete" />
                    <MenuItem Command="{Binding Delete}" Header="Permanently Delete">
                        <MenuItem.Style>
                            <Style TargetType="MenuItem">
                                <Setter Property="Visibility" Value="Collapsed" />
                                <Style.Triggers>
                                    <DataTrigger Binding="{Binding IsVisibleDelete}" Value="True">
                                        <Setter Property="Visibility" Value="Visible" />
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </MenuItem.Style>    
                    </MenuItem>
                </ContextMenu>
            </TextBlock.ContextMenu>
        </TextBlock>

ViewModel クラスでは、プロパティとコマンドを追加してMenyItem可視性プロパティを変更する必要があります。

private bool _isVisibleDelete;
public bool IsVisibleDelete
{
    get { return _isVisibleDelete; }
    set { _isVisibleDelete = value; RaisePropertyChanged(() => IsVisibleDelete); }
}

public ICommand ShowMoreOptions { get; private set; }
private void OnShowMoreOptions()
{
    IsVisibleDelete = !IsVisibleDelete;
}
于 2012-10-25T15:57:01.193 に答える