WPF容器将所有子控件转为只读

时间:2013-12-03 16:59:27

标签: c# wpf children visual-tree

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

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

这种方法很好,除了进一步更改会影响可视树的情况,以便添加新的子项。这对于ContentControl或ItemsControl都是如此。如果孩子们在浏览完毕后被添加到视觉树中,那么它们显然不是只读的。

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

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

(并且没有:我不想将所有子项只读属性绑定到全局绑定。重点是有一个元素/部分将其传播给所有子节点)

1 个答案:

答案 0 :(得分:13)

您可以使用提供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>