如何有条件地隐藏部分 WPF 控件?

Posted

技术标签:

【中文标题】如何有条件地隐藏部分 WPF 控件?【英文标题】:How to hide part of a WPF control conditionally? 【发布时间】:2013-01-08 14:57:24 【问题描述】:

我在程序集中有一个无法更改的控件,它与 .NET DateTimePicker 非常相似。我想在满足某个条件时隐藏该控件的时间选择器部分(我的 ViewModel 上的属性值)。控件如下所示:

[TemplatePart(Name = "PART_DatePicker", Type = typeof (DatePicker))]
[TemplatePart(Name = "PART_TimePicker", Type = typeof (TimePicker))]
public class MyDateTimePicker : Control    /*...*/

这个答案展示了一种总是隐藏控件的一部分的好方法,但我想动态地做到这一点:

How to hide a part of a WPF control

我想有几种方法可以做到这一点。我想要的是最小的东西(比如链接问题的答案)以及不违反 MVVM 的东西。 System.Interactivity 行为和触发器是公平的游戏。

【问题讨论】:

你不能用模板部分的行为做一个数据触发吗? 我可以绑定到 ViewModel,但我认为您所暗示的几乎是当前答案所暗示的,而且我不知道如何以这种方式隐藏控件的一部分. 不完全是,我建议您按照您链接的相关问题中列出的答案:***.com/a/4754266/7116 有趣。当 ViewModel 上的属性发生更改而不是像示例中那样在 Loaded 上更改时,我如何让该触发器运行? 绝对忘记 MVVM。这是 UI 工作。 【参考方案1】:

创建一个扩展前一个控件的新控件

public sealed class MySuperiorDateTimePicker : MyDateTimePicker 

    //....

添加一个可以绑定到 ViewModel 状态的 DependencyProperty

public static readonly DependencyProperty HideItProperty =
    DependencyProperty.Register(
        "HideIt",
        typeof(bool),
        typeof(MySuperiorDateTimePicker ),
        new UIPropertyMetadata(false, HideItPropertyChanged));
//snip property impl

等待属性改变,然后隐藏你的 UI

private static void HideItPropertyChanged(DependencyObject d,
    DependencyPropertyChangedEventArgs e)

    (d as MySuperiorDateTimePicker).OnHideItChanged((bool)e.OldValue, 
        (bool)e.NewValue);


private void OnHideItChanged(bool oldValue, bool newValue)

    if(BusyTemplate == null)
        return;
    FindTimePicker().Visibility = newValue ? Visibility.Visible : 
        Visibility.Collapsed;


private UIElement FindTimePicker()

    //snip null checks
    return GetTemplateChild("PART_TimePicker") as UIElement;

注意FindTimePicker,因为您的 DP 可能会在控件加载之前发生变化,GetTemplateChild 将返回 null。通常要做的事情是,在OnHideItChanged 中,如果GetTemplateChild 返回null,则使用Dispatcher.BeginInvoke 稍后(ApplicationIdle 或更早)重新运行事件处理程序。

当您发现自己在说“我如何使用 MVVM 进行 UI 工作”时,请停下来重新考虑您的真正目标。 MVVM != 没有代码隐藏,没有自定义控件等。

【讨论】:

您好。首先,我认为这不会破坏 MVVM。我同意,这是严格的 UI 工作,我特别不想做的是在我的 VM 和控件之间有任何引用,这避免了。本来我是这样尝试继承的,只是重写了模板方法,还是不行。我确实对这个解决方案有信心,但我找到了一种更简单的方法,所以我将采用可行的方法。我将在另一个“答案”中详细说明我的答案,并给您提供帮助的要点。谢谢! @JoeB:np。如果您更简单的方法更好,请选择它作为接受的答案! 你的答案更可重用,我的更实用。我的也需要混合。告诉你什么,我会在几周后回来查看,如果我的票数更多,我会改变它。干杯。【参考方案2】:

一种解决方案是在数据模板中定义的 DataTrigger 的帮助下将其隐藏,这样当控件的数据上下文中的某个值设置为 true/false 时,您将隐藏/显示该部分。

快速搜索,我发现了一些您可能会觉得有用的链接: http://zamjad.wordpress.com/2010/06/22/conditionally-hide-controls-from-data-template/ http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/ae2dbfb7-5dd6-4352-bfa1-53634289329d/

【讨论】:

我不确定如何隐藏 PART_TimePicker 这样做,或者是否有可能。 只需按照第一个链接中的示例进行操作即可。为 DataTemplate 创建一个 DataTrigger 并将其绑定到您在 datacontext 中设置的属性。 我了解如何使用 DataTrigger 更改文本框等内容的可见性。这是一个包含多个部分的控件。查看我在问题中提出的链接以及解决方案,如果您的建议在这种情况下有效,我认为他们会这样做。【参考方案3】:

对我有用的解决方案是编辑控件的样式。使用 Blend,我编辑了 DateTimePicker 样式的副本,并向 TimePicker 的 Visibility 添加了一个绑定,该绑定查看我的 VM 并转换枚举的值。

【讨论】:

以上是关于如何有条件地隐藏部分 WPF 控件?的主要内容,如果未能解决你的问题,请参考以下文章

WPF如何把隐藏控件显示出来

如何有条件地更改数据绑定 WPF ListView 的 CellTemplate 中控件的属性?

如何防止屏幕阅读器/旁白阅读隐藏在 WPF 中的控件?

WPF ComboBox控件隐藏倒三角

wpf 设置控件的显示时间

裁剪 WPF 控件