WPF 容器将所有子控件变为只读
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20357191/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF container to turn all child controls to read-only
提问by user1211286
I would like to have a WPF container (panel, user control, etc.) that exposes a property to turn all children to read-only if set. This should pretty much be like setting a parent control to IsEnabled=false, which also disables all children. What children and which of their properties should be considered is fixed (e.g. TextBox.ReadOnly, DataGrid.ReadOnly, ...).
我想要一个 WPF 容器(面板、用户控件等),它公开一个属性以将所有子项设置为只读。这应该很像将父控件设置为 IsEnabled=false,这也会禁用所有子控件。应该考虑哪些子项及其哪些属性是固定的(例如 TextBox.ReadOnly、DataGrid.ReadOnly、...)。
I have tried to create such a control, which essentially iterates all children of the visual tree (recursively) and deals with the controls accordingly.
我试图创建这样一个控件,它基本上迭代视觉树的所有子项(递归)并相应地处理控件。
This works fine, except for the case where further changes would affect the visual tree, so that new children are added. This is true for a ContentControl or ItemsControl. If children are added to the visual tree after I went though them, they obviously are not read-only.
这工作正常,除了进一步更改会影响视觉树的情况,以便添加新子项。这对于 ContentControl 或 ItemsControl 是正确的。如果在我通过它们之后将子项添加到可视化树中,它们显然不是只读的。
I have bee trying to find a good event to react on (basically detect new children in the visual tree), but was unable to find something appropriate. UpdateLayout is fired, but way to often to go through the visual tree each time.
我一直试图找到一个好的事件来做出反应(基本上检测视觉树中的新孩子),但无法找到合适的东西。UpdateLayout 被触发,但每次都经常通过可视化树的方式。
Is there a way to solve this? Is there probably another approach to getting all (relevant) children recursively set to read-only through a binding on a parent element?
有没有办法解决这个问题?是否有另一种方法可以通过父元素上的绑定将所有(相关)子项递归设置为只读?
(And no: I would not want to bind all children read-only properties to the global binding instead. The point is to have a single element/part that propagates this to all children)
(并且不:我不想将所有子级只读属性绑定到全局绑定。关键是有一个元素/部分将其传播给所有子级)
采纳答案by Clemens
You may do this with an attached property that provides 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
}
}
You would use it in XAML like this:
您可以像这样在 XAML 中使用它:
<StackPanel local:ReadOnlyPanel.IsReadOnly="{Binding IsChecked, ElementName=cb}">
<CheckBox x:Name="cb" Content="ReadOnly"/>
<TextBox Text="Hello"/>
</StackPanel>

