отключить мульти-проверку в контекстном меню wpf - PullRequest
3 голосов
/ 15 апреля 2011

Я хочу отключить мульти-проверку в контексте пунктов меню, просто проверьте один элемент, как?

Ответы [ 2 ]

3 голосов
/ 15 апреля 2011

Вы можете сделать это с помощью кода, как объяснено в ответе DarkSquirrel42. Но если вам нужно многократно используемое решение, возможно, лучше всего реализовать его как прикрепленное поведение, чтобы вы могли использовать его непосредственно в XAML. Вот базовая реализация:

public static class MenuBehavior
{
    [AttachedPropertyBrowsableForType(typeof(MenuItem))]
    public static string GetOptionGroupName(MenuItem obj)
    {
        return (string)obj.GetValue(OptionGroupNameProperty);
    }

    public static void SetOptionGroupName(MenuItem obj, string value)
    {
        obj.SetValue(OptionGroupNameProperty, value);
    }

    public static readonly DependencyProperty OptionGroupNameProperty =
        DependencyProperty.RegisterAttached(
          "OptionGroupName",
          typeof(string),
          typeof(MenuBehavior),
          new UIPropertyMetadata(
            null,
            OptionGroupNameChanged));

    private static void OptionGroupNameChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        var menuItem = o as MenuItem;
        if (menuItem == null)
            return;

        var oldValue = (string)e.OldValue;
        var newValue = (string)e.NewValue;

        if (!string.IsNullOrEmpty(oldValue))
        {
            RemoveFromOptionGroup(menuItem);
        }
        if (!string.IsNullOrEmpty(newValue))
        {
            AddToOptionGroup(menuItem);
        }
    }

    private static Dictionary<string, HashSet<MenuItem>> GetOptionGroups(DependencyObject obj)
    {
        return (Dictionary<string, HashSet<MenuItem>>)obj.GetValue(OptionGroupsPropertyKey.DependencyProperty);
    }

    private static void SetOptionGroups(DependencyObject obj, Dictionary<string, HashSet<MenuItem>> value)
    {
        obj.SetValue(OptionGroupsPropertyKey, value);
    }

    private static readonly DependencyPropertyKey OptionGroupsPropertyKey =
        DependencyProperty.RegisterAttachedReadOnly("OptionGroups", typeof(Dictionary<string, HashSet<MenuItem>>), typeof(MenuBehavior), new UIPropertyMetadata(null));

    private static HashSet<MenuItem> GetOptionGroup(MenuItem menuItem, bool create)
    {
        string groupName = GetOptionGroupName(menuItem);
        if (groupName == null)
            return null;

        if (menuItem.Parent == null)
            return null;

        var optionGroups = GetOptionGroups(menuItem.Parent);
        if (optionGroups == null)
        {
            if (create)
            {
                optionGroups = new Dictionary<string, HashSet<MenuItem>>();
                SetOptionGroups(menuItem.Parent, optionGroups);
            }
            else
            {
                return null;
            }
        }

        HashSet<MenuItem> group;
        if (!optionGroups.TryGetValue(groupName, out group) && create)
        {
            group = new HashSet<MenuItem>();
            optionGroups[groupName] = group;
        }
        return group;
    }

    private static void AddToOptionGroup(MenuItem menuItem)
    {
        var group = GetOptionGroup(menuItem, true);
        if (group == null)
            return;

        if (group.Add(menuItem))
        {
            menuItem.Checked += menuItem_Checked;
            menuItem.Unchecked += menuItem_Unchecked;
        }
    }

    private static void RemoveFromOptionGroup(MenuItem menuItem)
    {
        var group = GetOptionGroup(menuItem, false);
        if (group == null)
            return;

        if (group.Remove(menuItem))
        {
            menuItem.Checked -= menuItem_Checked;
            menuItem.Unchecked -= menuItem_Unchecked;
        }
    }

    static void menuItem_Checked(object sender, RoutedEventArgs e)
    {
        MenuItem menuItem = sender as MenuItem;
        if (menuItem == null)
            return;

        string groupName = GetOptionGroupName(menuItem);
        if (groupName == null)
            return;

        // More than 1 checked option is allowed
        if (groupName.EndsWith("*") || groupName.EndsWith("+"))
            return;

        var group = GetOptionGroup(menuItem, false);
        if (group == null)
            return;

        foreach (var item in group)
        {
            if (item != menuItem)
                item.IsChecked = false;
        }
    }

    static void menuItem_Unchecked(object sender, RoutedEventArgs e)
    {
        MenuItem menuItem = sender as MenuItem;
        if (menuItem == null)
            return;

        string groupName = GetOptionGroupName(menuItem);
        if (groupName == null)
            return;

        // 0 checked option is allowed
        if (groupName.EndsWith("*") || groupName.EndsWith("?"))
            return;

        var group = GetOptionGroup(menuItem, false);
        if (group == null)
            return;

        if (!group.Any(item => item.IsChecked))
            menuItem.IsChecked = true;
    }
}

Использование XAML:

<ContextMenu>
    <MenuItem Header="Choose one" IsEnabled="False" />
    <MenuItem Header="Option 1.1" IsCheckable="True" IsChecked="True"
                my:MenuBehavior.OptionGroupName="group1"/>
    <MenuItem Header="Option 1.2" IsCheckable="True"
                my:MenuBehavior.OptionGroupName="group1"/>
    <MenuItem Header="Option 1.3" IsCheckable="True"
                my:MenuBehavior.OptionGroupName="group1"/>
    <Separator />
    <MenuItem Header="Choose zero or one" IsEnabled="False" />
    <MenuItem Header="Option 2.1" IsCheckable="True" IsChecked="True"
                my:MenuBehavior.OptionGroupName="group2?"/>
    <MenuItem Header="Option 2.2" IsCheckable="True"
                my:MenuBehavior.OptionGroupName="group2?"/>
    <MenuItem Header="Option 2.3" IsCheckable="True"
                my:MenuBehavior.OptionGroupName="group2?"/>
    <Separator />
    <MenuItem Header="Choose one or more" IsEnabled="False" />
    <MenuItem Header="Option 3.1" IsCheckable="True" IsChecked="True"
                my:MenuBehavior.OptionGroupName="group3+"/>
    <MenuItem Header="Option 3.2" IsCheckable="True"
                my:MenuBehavior.OptionGroupName="group3+"/>
    <MenuItem Header="Option 3.3" IsCheckable="True"
                my:MenuBehavior.OptionGroupName="group3+"/>
    <Separator />
    <MenuItem Header="Choose any number" IsEnabled="False" />
    <MenuItem Header="Option 4.1" IsCheckable="True" IsChecked="True"
                my:MenuBehavior.OptionGroupName="group4*"/>
    <MenuItem Header="Option 4.2" IsCheckable="True"
                my:MenuBehavior.OptionGroupName="group4*"/>
    <MenuItem Header="Option 4.3" IsCheckable="True"
                my:MenuBehavior.OptionGroupName="group4*"/>
</ContextMenu>

(my - это пространство имен XML, сопоставленное с пространством имен CLR, в котором вы объявили класс MenuBehavior)

Конечно, есть возможности для улучшений:

  • Возможно, вы захотите включить один вариант (т. Е. Невозможно снять все) DONE
  • В настоящее время имена групп являются глобальными, т. Е. Если вы используете одно и то же имя группы в разных меню, правило «единого выбора» будет применяться ко всем меню. Возможно, вы захотите ограничить его текущим меню DONE

РЕДАКТИРОВАТЬ: я обновил код, чтобы включить улучшения, упомянутые выше:

  • Группы теперь ограничены MenuItem с в том же меню
  • Теперь вы можете определить для каждой группы правила для отмеченных опций:
    • Должна быть отмечена только одна опция (по умолчанию)
    • Должен быть отмечен ноль или одна опция (добавьте ? в конце имени группы)
    • Необходимо проверить одну или несколько опций (добавить + в конце названия группы)
    • Можно проверить любое количество опций (добавьте * в конце названия группы). Это фактически то же самое, что вообще не использовать прикрепленное поведение, но я все равно включил его для полноты ...

Пример использования XAML иллюстрирует различные правила

2 голосов
/ 15 апреля 2011

обрабатывает событие Click MenuItems ...

private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            if (sender is MenuItem)
            {
                IEnumerable<MenuItem> menuItems = null;
                var mi = (MenuItem)sender;
                if (mi.Parent is ContextMenu)
                    menuItems = ((ContextMenu)mi.Parent).Items.OfType<MenuItem>();
                if (mi.Parent is MenuItem)
                    menuItems = ((MenuItem)mi.Parent).Items.OfType<MenuItem>();
                if(menuItems!=null)
                    foreach (var item in menuItems)
                    {
                        if (item.IsCheckable && item != mi)
                            item.IsChecked = false;
                    }
            }
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...