如何使用 XAML 在 Panel 或 GroupBox 等整个容器上设置 IsReadOnly / IsEnabled?

Posted

技术标签:

【中文标题】如何使用 XAML 在 Panel 或 GroupBox 等整个容器上设置 IsReadOnly / IsEnabled?【英文标题】:How to set IsReadOnly / IsEnabled on entire container like Panel or GroupBox using XAML? 【发布时间】:2012-04-20 12:41:00 【问题描述】:

我有一个MVVM 应用程序,它包含多个视图,其中包含一些基于用户权限、视图/编辑模式和对象状态的复杂IsReadOnly 规则。

我想为同一容器中的整个控件组设置IsReadOnly 和/或IsEnabled 属性(GroupBox / StackPanel / Grid / UserControl / 等)。此属性的值将在 ViewModel 中定义。

每个 UserControl 有 3-6 个不同的 SomeGroupIsReadOnly 属性(具有大量输入控件,如 TextBoxRadioButtonsComboBoxes 和一些 DataGrids),我正在寻找一个通用的、MVVM 友好的解决方案,这将允许我在每个容器的基础上重用绑定,而不是为每个单独的控件单独指定它们。

如何使用 XAML 在 Panel 或 GroupBox 等容器内的所有控件上设置 IsReadOnly / IsEnabled?

WPF 似乎不支持开箱即用...

编辑

我忘了提到为容器设置 IsEnabled 会禁用 TextBoxes 的一个重要功能 - 能够复制它们的内容。我需要他们处于IsReadOnly=true 状态。如果有解决办法,那我的问题就解决了。

【问题讨论】:

这是我找到的最佳解决方案:dkowalski.com/blog/archive/2010/02/04/… 【参考方案1】:

禁用包含您的控件的面板也会禁用面板内的控件。将 Panel 的 IsEnabled 成员绑定到 ViewModel 上的 bool 属性,并根据您的规则设置它以禁用 Panel 及其所有子项。

Xaml:

<GroupBox IsEnabled="Binding Path=IsGroupEnabled">
    <StackPanel>
        <Button Content="Sample Button"/>
        <TextBox Text="Sample text box"/>
    </StackPanel>
</GroupBox>

【讨论】:

+1 是的,这行得通。但这也禁用了 TextBox,因此用户无法复制内容。我希望 TextBox 为IsReadOnly=true。我已经编辑了问题。 我将创建一个反向布尔转换器并使用 IsGroupEnabled 值将其绑定到 TextBox 进行转换。这是一个很好的帖子:***.com/questions/1039636/…【参考方案2】:

对我们来说行之有效的方法是定义一个表示您的应用程序权限结构的视图模型(在我下面的示例中为 YourPermissionsViewModel)。

然后您可以创建一个自定义面板控件来扩展您选择的任何面板(本示例中为 StackPanel)。这样您就可以添加 IsReadOnly 属性绑定并将它们持久保存到面板的子项中。

XAML 中的面板如下所示:

<local:PanelExtension IsEnabled="Binding YourPermissionsViewModel.IsEnabled" 
                      IsReadOnly="Binding YourPermissionsViewModel.IsReadOnly">
    <TextBox Text="eeny" Width="100" />
    <TextBox Text="meeny" Width="100"/>
    <TextBox Text="miny" Width="100"/>
    <TextBox Text="mo" Width="100" />
    <Label Content="coolio" Width="100" />
</local:PanelExtension>

这里是 StackPanel 扩展控件,其中包含 StackPanel 的所有功能,并附加了一个自定义 IsReadOnly 依赖属性,该属性会更新拥有该属性的任何子控件的相应属性值:

public class PanelExtension : StackPanel

    public bool IsReadOnly
    
        get  return (bool)GetValue(IsReadOnlyProperty); 
        set  SetValue(IsReadOnlyProperty, value); 
    
    public static readonly DependencyProperty IsReadOnlyProperty =
        DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(PanelExtension),
        new PropertyMetadata(new PropertyChangedCallback(OnIsReadOnlyChanged)));

    private static void OnIsReadOnlyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    
        ((PanelExtension)d).OnIsReadOnlyChanged(e);
    

    protected virtual void OnIsReadOnlyChanged(DependencyPropertyChangedEventArgs e)
    
        this.SetIsEnabledOfChildren();
    

    public PanelExtension()
    
        this.Loaded += new RoutedEventHandler(PanelExtension_Loaded);
    

    void PanelExtension_Loaded(object sender, RoutedEventArgs e)
    
        this.SetIsEnabledOfChildren();
    

    private void SetIsEnabledOfChildren()
    
        foreach (UIElement child in this.Children)
        
            var readOnlyProperty = child.GetType().GetProperties().Where(prop => prop.Name.Equals("IsReadOnly")).FirstOrDefault();
            readOnlyProperty.SetValue(child, this.IsReadOnly, null);
        
    

通过这种方法,您可以添加所需的任意数量的自定义属性,它确实为您提供了极大的灵活性,并且使您能够应对在必须对各种元素设置复杂权限时可能遇到的多种情况。

【讨论】:

感谢您的回复,我喜欢将权限封装在 YourPermissionsViewModel 中的想法。我试试看。

以上是关于如何使用 XAML 在 Panel 或 GroupBox 等整个容器上设置 IsReadOnly / IsEnabled?的主要内容,如果未能解决你的问题,请参考以下文章

wpf中,Panel里面的东西如果想保存到本地xaml文件怎么做?

如何获取包含 ItemsControl 内容的 Panel 实例?

如何在 XAML 代码中创建支持其中其他元素的 UserControl

XAML 中的分组列表视图

零基础学习CANoe Panel—— 静态控件(Static Text , Group Box ,Picture Box)

怎样实现panel控件隐藏或显示