65.9K
CodeProject 正在变化。 阅读更多。
Home

用于复合条件参数的分组可勾选菜单

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (2投票s)

2011年11月28日

CPOL

4分钟阅读

viewsIcon

17641

downloadIcon

243

一种基于菜单的用户界面筛选解决方案,其中第一级显示筛选条件,后续级别以越来越细粒度的分辨率选项提供可选值。

Sample Image

引言

处理大型数据集通常需要某种形式的筛选机制。我曾多次发现以下筛选方法(对 UI 和代码设计都很有用)派上用场。我的目标是实现一种基于菜单的用户界面筛选解决方案,其中第一级显示筛选条件,后续级别以越来越细粒度的分辨率选项提供可选值。每个条件**只能有一个**筛选值或**没有**筛选值,其中“没有”表示不进行筛选。我还希望有一个视觉指示器来显示是否正在应用任何筛选*

以下是一些可能使它更清楚的屏幕截图

* 了解我的目标的一个更快的方法是下载并运行示例项目……

背景

UI 方面

使用菜单作为筛选参数选择平台,其优点是占用最少的客户区域,同时向用户提供有关筛选条件的详细信息(随着菜单展开,信息越详细)。

实现

建议的实现 fortemente 基于**附加属性**。这允许在视图中实现所有功能,并且仅通过**绑定**将相关信息传递给 ViewModel。在 ViewModel 中,例如,使用筛选/搜索命令和 LINQ/lambda,可以为显示填充结果绑定的列表(在此示例中未实现)。

附加属性 (AP)

下一段是为不熟悉**附加属性**的读者准备的。如果您熟悉此概念,可以跳到“使用代码”部分。

这里有一段引述

附加属性 (AP) 的概念是 WPF 最具创新性的功能之一,也是利用率最低的功能之一。

--WPF Control Development Unleashed/SAMS

我将尝试通过一个“真实生活”的示例来传达 AP 的概念,而不是解释 WPF 中的 AP 是什么(您可以在任何 WPF 书籍中找到)。

想象一个定制的办公桌互联网订单表单,其中有几行可以让用户指定其属性。

  • Color
  • 宽度
  • 高度
  • 深度

底部有一个提交按钮,按下该按钮会发送此表单,并因此会构建(实例化)一张新桌子。

一切都很好,除了……您想要一些抽屉……

在“启用了 AP 的现实”中,您需要做的就是拿出您的“魔法笔”并写下另一行。现在表单看起来像这样

  • 颜色-绿色
  • 宽度-100
  • 高度-50
  • 深度-50
  • 抽屉数量

抽屉数量的默认值为零,因此如果您希望桌子没有抽屉,可以省略其值。

我们在这里实际做的是**对现有的“初始化表单”进行了修改/定制/扩展**。

为了让事情更有趣——假设我们希望高度值随着我们在抽屉数量属性中设置的每个额外抽屉而增加 20 厘米。幸运的是,就像为抽屉数量属性设置默认值一样,我们也可以设置一个回调,当其值发生变化时就会触发。在那里,我们可以像这样更新高度属性

Height=_BaseHeight+(NumberOfDrawers*20)

我希望这个小比喻能帮助您初步了解 AP 在 WPF 中的作用。

我发现附加属性在两种情况下特别有用

  1. 功能扩展。
  2. 为非依赖属性的属性启用**绑定/动画**;在那里,AP(它们是**可绑定的**/**可动画的**,因为它们是依赖属性)充当代理。

使用代码

为了实现所需的功能,我使用 AP 扩展了MenuItem元素。

在 XAML 中

每个条件顶层MenuItem都设置了IsGroupValueHolder AP 为True(用于代码实现目的),并将Value设置为绑定的 ViewModel 的Matching属性。

<MenuItem Header="Rating" local:CheckGroupHelper.IsGroupValueHolder="True" 
    Style="{StaticResource CheckGroupChildStyle}" 
    local:CheckGroupHelper.Value=
       "{Binding Rating,Mode=OneWayToSource}">

每个条件底层可勾选值MenuItem都将Value设置为某个预定义参数。

<MenuItem Header="5" Style="{StaticResource CheckGroupChildStyleLeaf}" local:CheckGroupHelper.Value="5">

在样式内部

'CheckGroupChildStyleLeaf' - **IsCheckable** 设置为True(允许用户勾选),**IsChecked** 通过绑定设置为我们自己的**IsCheckGroupChecked AP**(我们监控其值更改)。

'CheckGroupChildStyle' - IsCheckable 设置为**False**,星号可见性由**绑定**到**Value** AP 控制,使用**AnyString2Asterisk** 转换器。

在代码中(CheckGroupHelper

IsCheckGroupCheckedChanged中(仅对“叶子”MenuItem相关)

如果勾选

  1. 取消勾选此条件组中当前勾选的值(这将导致一个空值冒泡到组的值持有者)。
  2. MenuItem micc = GetGroupCurrentlyCheckedLeaf(mi);
    if (micc != null)
    {
        micc.IsChecked = false;
    }
  3. 冒泡此“叶子”值。
  4. mi.Parent.SetValue(CheckGroupHelper.ValueProperty, 
              obj.GetValue(CheckGroupHelper.ValueProperty));

如果未勾选:冒泡空值。

mi.Parent.SetValue(CheckGroupHelper.ValueProperty, "");

ValueChanged

  • 将值冒泡到MenuItem树的上方。
  • 不要将空值冒泡到条件顶层MenuItemIsGroupValueHolder =True)之外,如果任何其他条件顶层MenuItem有一个值(因此,“Filters”MenuItem仍然显示它有一个值!)。

关注点

  1. 我希望通过这个简单的演示,我已成功展示了如何使用AttachedPropertys,以最少的代码实现特殊的 UI 功能,同时保持干净的 MVVM 基础结构。
  2. 在此应用程序的早期版本中,我使用了“命名组”方法(就像单选按钮的GroupName属性一样)。
  3. 这种方法虽然提供了很大的设计灵活性,但对于这种情况来说是冗余的。这里的组是根据MenuItems的层次结构聚集和定义的。

© . All rights reserved.