【问题标题】:WPF container to turn all child controls to read-onlyWPF容器将所有子控件变为只读
【发布时间】:2013-12-19 20:48:02
【问题描述】:

我想要一个 WPF 容器(面板、用户控件等),它公开一个属性,以便在设置后将所有子项变为只读。这应该很像将父控件设置为 IsEnabled=false,这也会禁用所有子控件。应该考虑哪些子项及其属性是固定的(例如 TextBox.ReadOnly、DataGrid.ReadOnly、...)。

我试图创建这样一个控件,它本质上迭代可视树的所有子级(递归)并相应地处理控件。

这工作正常,除了进一步更改会影响视觉树的情况,以便添加新的子级。这适用于 ContentControl 或 ItemsControl。如果孩子在我浏览完之后被添加到可视化树中,它们显然不是只读的。

我一直试图找到一个好的事件来做出反应(基本上是在视觉树中检测到新的孩子),但无法找到合适的东西。 UpdateLayout 已被触发,但每次都经常通过可视化树。

有没有办法解决这个问题?是否有另一种方法可以通过父元素上的绑定将所有(相关)子级递归设置为只读?

(不:我不想将所有子级只读属性绑定到全局绑定。关键是要有一个元素/部分将其传播给所有子级)

【问题讨论】:

  • 我从来没有真正退后一步想过“新视觉儿童”的问题。的确,这是一个很好的问题。
  • 我想你最好的办法是让 ViewModel 在修改集合或其他内容时发出属性更改通知 (NotifyPropertyChange(() => IsReadOnly);),而不是尝试走可视化树路线
  • 你需要把它作为一个依赖属性来做。依赖属性允许继承,这是您正在寻找的。 IsEnabled 是一个依赖属性,IsReadOnly 不是。

标签: c# wpf children visual-tree


【解决方案1】:

您可以使用提供value inheritance 的附加属性来执行此操作:

public class ReadOnlyPanel
{
    public static readonly DependencyProperty IsReadOnlyProperty =
        DependencyProperty.RegisterAttached(
            "IsReadOnly", typeof(bool), typeof(ReadOnlyPanel),
            new FrameworkPropertyMetadata(false,
                FrameworkPropertyMetadataOptions.Inherits, ReadOnlyPropertyChanged));

    public static bool GetIsReadOnly(DependencyObject o)
    {
        return (bool)o.GetValue(IsReadOnlyProperty);
    }

    public static void SetIsReadOnly(DependencyObject o, bool value)
    {
        o.SetValue(IsReadOnlyProperty, value);
    }

    private static void ReadOnlyPropertyChanged(
        DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        if (o is TextBox)
        {
            ((TextBox)o).IsReadOnly = (bool)e.NewValue;
        }
        // other types here
    }
}

您可以像这样在 XAML 中使用它:

<StackPanel local:ReadOnlyPanel.IsReadOnly="{Binding IsChecked, ElementName=cb}">
    <CheckBox x:Name="cb" Content="ReadOnly"/>
    <TextBox Text="Hello"/>
</StackPanel>

【讨论】:

  • 我记得最初尝试过这种方法,但在性能方面并没有产生可接受的结果,但这是一个很好的解决方案。
  • 当然可能会对性能产生影响。来自MSDN但是,请注意,将属性指定为可继承确实有一些性能考虑。如果该属性没有既定的本地值,或者没有通过样式、模板或数据绑定获得的值,则可继承属性会将其分配的属性值提供给逻辑树中的所有子元素。
  • 非常好。不过,我正在努力应对性能影响。发表了另一篇文章如何防止将属性传播到 DataGrid 中,因为如果我可以将 DataGrid 切换为只读,我不希望单个单元格是只读的。
  • 这是一个很好的例子。但是我可以知道我们可以通过代码设置 isreadonly 吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-25
  • 1970-01-01
  • 2011-04-06
  • 1970-01-01
相关资源
最近更新 更多