18

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

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

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

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

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

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

4

1 回答 1

15

您可以使用提供值继承的附加属性来执行此操作:

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>
于 2013-12-03T17:13:09.867 回答