c# - Contenedor de WPF para convertir todos los controles secundarios a solo lectura
children visual-tree (1)
Me gustaría tener un contenedor de WPF (panel, control de usuario, etc.) que exponga una propiedad para convertir a todos los hijos a solo lectura, si están establecidos. Esto debería ser como establecer un control padre en IsEnabled = false, que también deshabilita a todos los hijos. Los hijos y cuáles de sus propiedades deben considerarse son fijos (por ejemplo, TextBox.ReadOnly, DataGrid.ReadOnly, ...).
He intentado crear un control de este tipo, que esencialmente itera a todos los hijos del árbol visual (recursivamente) y se ocupa de los controles en consecuencia.
Esto funciona bien, excepto en el caso de que más cambios afecten el árbol visual, de modo que se agreguen nuevos hijos. Esto es cierto para un ContentControl o ItemsControl. Si se agregan niños al árbol visual después de que los revisé, obviamente no son de solo lectura.
He estado tratando de encontrar un buen evento para reaccionar (básicamente detectar nuevos niños en el árbol visual), pero no pude encontrar algo apropiado. UpdateLayout se dispara, pero a menudo se recorre el árbol visual cada vez.
¿Hay una manera de resolver esto? ¿Hay probablemente otro enfoque para que todos los hijos (relevantes) se configuren de forma recursiva en solo lectura mediante un enlace en un elemento principal?
(Y no: no me gustaría vincular todas las propiedades de solo lectura de los hijos a la vinculación global en su lugar. El punto es tener un solo elemento / parte que propague esto a todos los hijos)
Puede hacer esto con una propiedad adjunta que proporciona herencia de valor :
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
}
}
Lo usarías en XAML así:
<StackPanel local:ReadOnlyPanel.IsReadOnly="{Binding IsChecked, ElementName=cb}">
<CheckBox x:Name="cb" Content="ReadOnly"/>
<TextBox Text="Hello"/>
</StackPanel>