Пользовательский атрибут видимости во время разработки в WPF

У меня есть сложное окно с различными элементами управления, которые видны или свернуты в зависимости от логических значений. Я хочу добавить пользовательский атрибут, чтобы отображать все эти элементы управления во время разработки. Моя реализация атрибута выглядит так:

public static class CustomAttributes
{
    private static bool? _inDesignMode;

    public static readonly DependencyProperty Visibility = DependencyProperty.RegisterAttached(
        "Visibility",
        typeof(Visibility),
        typeof(CustomAttributes),
        new PropertyMetadata(VisibilityChanged));

    private static bool InDesignMode
    {
        get
        {
            if (!_inDesignMode.HasValue)
            {
                var prop = DesignerProperties.IsInDesignModeProperty;
                _inDesignMode =
                  (bool)DependencyPropertyDescriptor.FromProperty(prop, typeof(FrameworkElement)).Metadata.DefaultValue;
            }

            return _inDesignMode.Value;
        }
    }

    public static Visibility GetVisibility(DependencyObject dependencyObject)
    {
        return (Visibility)dependencyObject.GetValue(Visibility);
    }

    public static void SetVisibility(DependencyObject dependencyObject, Visibility value)
    {
        dependencyObject.SetValue(Visibility, value);
    }

    private static void VisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (!InDesignMode)
            return;

        d.SetValue(Control.VisibilityProperty, e.NewValue);
    }
}

В XAML я использую это так:

<Button Visibility="{Binding SomeBoolValue, Converter={StaticResource BoolToVisibility}}"
        helper:CustomAttributes.Visibility="Visible" 
/>

Однако, похоже, это не работает. Я использую некоторые другие настраиваемые атрибуты, подобные этому, и они выполняют свою работу, но видимость не срабатывает, она просто остается свернутой в представлении дизайна. Что мне не хватает?

Редактировать:

Спасибо, что указали мне правильное направление. Решение моей проблемы не требовало пользовательского атрибута, как я сначала предполагал. Чтобы добиться желаемого поведения во время разработки, я изменил реализацию преобразователя, как это предлагается в принятом ответе ниже.


person gedvrk    schedule 27.05.2021    source источник
comment
Я думаю, вам нужно установить Visibility только из помощника, привязать bool к дополнительному свойству helper:CustomAttributes и установить Visible только тогда, когда два свойства имеют значение true/Visible.   -  person Genusatplay    schedule 27.05.2021
comment
Другой способ - использовать мультибиндинг > stackoverflow.com/questions/2959885/   -  person Genusatplay    schedule 27.05.2021


Ответы (1)


Подумайте немного глубже о созданной вами логике.

У UI-элемента нет ДВУХ свойств Visibility, он единственный.
Но вы хотите манипулировать этим свойством двумя способами одновременно: через привязку и присоединенное свойство.
Таким образом, вы создали между собой конкуренцию за это свойство.
И свойство примет то значение, которое будет присвоено ему последним.

Прикрепленное свойство будет активировано только один раз при инициализации кнопки (из примера).
И привязка будет активирована при изменении контекста данных и/или его свойства SomeBoolValue.
Но контекст данных Окно устанавливается позже, чем инициализация элементов пользовательского интерфейса этого Окна.

Я вижу несколько решений.
Самое простое, если вам нужно ВСЕГДА показывать элементы в режиме дизайна, это добавить соответствующую логику в конвертер.
В самом простом виде пример такого конвертера:

/// <summary>Bool to Visibility converter.</summary>
[ValueConversion(typeof(bool), typeof(Visibility))]
public class BooleanToVisibilityConverter : IValueConverter
{
    public static bool IsDesignMode { get; } = DesignerProperties.GetIsInDesignMode(new DependencyObject());

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is bool val)
            return IsDesignMode || val 
                ? Visibility.Visible
                : Visibility.Collapsed;

        return DependencyProperty.UnsetValue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
person EldHasp    schedule 27.05.2021