WPF переопределяет IsEnabled от родителя
Я просто искал способ включить дочерний элемент управления, в то время как родительский элемент управления имеет IsEnabled = false
.
Все ответы, которые я нашел до сих пор, говорят, что это невозможно - нужно включить родителя и отключить дочерние элементы управления, кроме тех, которые все еще должны быть включены.
Однако, переопределив метаданные для IsEnabledProperty в файле App.xaml.cs, я смог изменить это поведение по умолчанию:
protected override void OnStartup(StartupEventArgs e)
{
UIElement.IsEnabledProperty.OverrideMetadata(typeof(FrameworkElement),
new UIPropertyMetadata(true,IsEnabledChanged, CoerceIsEnabled));
}
private void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var childrenCount = VisualTreeHelper.GetChildrenCount(d);
for (int i = 0; i < childrenCount; ++i)
{
var child = VisualTreeHelper.GetChild(d, i);
child.CoerceValue(UIElement.IsEnabledProperty);
}
}
private object CoerceIsEnabled(DependencyObject d, object basevalue)
{
var parent = VisualTreeHelper.GetParent(d) as FrameworkElement;
if (parent != null && parent.IsEnabled == false)
{
if (d.ReadLocalValue(UIElement.IsEnabledProperty) == DependencyProperty.UnsetValue)
{
return false;
}
}
return basevalue;
}
Теперь вы можете вручную установить свойство IsEnabled
для дочернего элемента, которое переопределяет родительское значение.
Есть ли недостатки такого подхода?
Ответы
Ответ 1
Это работало для моей ситуации над элементом управления, используемым несколько раз с некоторыми небольшими изменениями.
Размещение здесь, чтобы помочь любым будущим поисковым веб-сайтам в подобной ситуации:
- поместил его в статический конструктор вместо события, иначе он попытался установить его несколько раз и бросил "PropertyMetadata уже зарегистрирован для типа" {type} ". исключение.
- Изменен тип, соответствующий элементу управления
код:
Обязательно найдите и замените [CustomControl]
типом имени вашего элемента управления.
static [CustomControl]()
{
UIElement.IsEnabledProperty.OverrideMetadata(typeof([CustomControl]), new UIPropertyMetadata(true, [CustomControl]_IsEnabledChanged, CoerceIsEnabled));
}
private static void [CustomControl]_IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var childrenCount = VisualTreeHelper.GetChildrenCount(d);
for (int i = 0; i < childrenCount; ++i)
{
var child = VisualTreeHelper.GetChild(d, i);
child.CoerceValue(UIElement.IsEnabledProperty);
}
}
private static object CoerceIsEnabled(DependencyObject d, object basevalue)
{
var parent = VisualTreeHelper.GetParent(d) as FrameworkElement;
if (parent != null && parent.IsEnabled == false)
{
if (d.ReadLocalValue(UIElement.IsEnabledProperty) == DependencyProperty.UnsetValue)
{
return false;
}
}
return basevalue;
}
Ответ 2
Недостатком является, по крайней мере, то, что вы нарушаете базовую концепцию, а IsEnabled не используется для предполагаемой области действия. Это обходное решение также делает техническое обслуживание немного более сложным (разработчик должен сначала понять, почему он работает по-другому).
Как явствует из комментариев, я бы сказал, что редизайн этого окна поможет. Особенно, если я хотел бы запретить только редактирование (модификацию данных) в форме, я бы использовал другие свойства, такие как IsReadOnly.
Ответ 3
Другой вариант - переопределить FrameworkPropertyMetadataOptions, чтобы удалить свойство Inherits. У меня была аналогичная проблема с FontSize, и это сработало хорошо:
FontSizeProperty.OverrideMetadata(
typeof(YourControl),
new FrameworkPropertyMetadata(8.0,
FrameworkPropertyMetadataOptions.None, changed));