Привязка видимости элемента к свойству ViewModel с поддержкой времени разработки

У меня есть приложение WPF, использующее Caliburn.Micro. Я хочу иметь возможность накладывать на приложение кольцо тени и прогресса (от MahApps.Metro), когда я хочу, чтобы приложение ожидало выполнения некоторой работы в фоновом режиме.

То, что у меня есть в данный момент, действительно работает, но наложение всегда включено во время разработки. мой ShellView окно выглядит так:

<Window ...>
    ...
    <Grid>
        ...
        <Rectangle x:Name="waitShadow" Fill="#3f000000" Stroke="Black" StrokeThickness="0" Visibility="{Binding IsWaiting, Converter={StaticResource BooleanToVisibilityConverter}}" Grid.RowSpan="2"/>
        <ContentControl ... Visibility="{Binding IsWaiting, Converter={StaticResource BooleanToVisibilityConverter}}">
            <Controls:ProgressRing ...> <!-- from MahApps.Metro -->
            </Controls:ProgressRing>
        </ContentControl>
    </Grid>
</Window>

мой ShellViewModel класс имеет публичное свойство bool IsWaiting и когда я установил его true тень и кольцо поднимаются и все отключено. Когда я установил его на false он возвращается к нормальному состоянию, поэтому привязка работает (я использую Fody с надстройкой PropertyChanged). Единственная проблема заключается в том, что Visibility собственность не разрушена во время разработки.

Есть ли лучший способ иметь оверлей, который работает во время разработки?

2 ответа

Решение

Вы можете установить FallbackValue на вашей привязке, что будет Collapse это во время разработки

Visibility="{Binding IsWaiting, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed}"

Вы также можете сделать IsWaiting DependancyProperty и установить там значение по умолчанию, но я считаю, что это самое простое решение.

FallbackValue не всегда работает, т. Е. Если ваш дизайнер на самом деле привязан к данным времени разработки, а FallbackValue на самом деле изменяет поведение привязки во время выполнения, которое во многих ситуациях может быть менее чем желательно. Я сделал расширение для разметки, которое позволяет дизайнерам манипулировать с пользовательским интерфейсом в конструкторе, не беспокоясь о путанице во время выполнения. Я написал об этом здесь: http://www.singulink.com/CodeIndex/post/wpf-visibility-binding-with-design-time-control

Это можно использовать так:

<Grid Visibility="{data:Value {Binding RootObject, Converter={StaticResource NullToVisibilityConverter}}, DesignValue=Visible}">
    <TextBlock Background="Red" Text="Testing visibility" />
</Grid>

Код для ValueExtension выглядит следующим образом (любые обновления или исправления ошибок будут публиковаться в блоге, поэтому я предлагаю проверить там последнюю версию):

public class ValueExtension : MarkupExtension
{
    public object DesignValue { get; set; } = DependencyProperty.UnsetValue;

    [ConstructorArgument("value")]
    public object Value { get; set; } = DependencyProperty.UnsetValue;

    public ValueExtension() { }

    public ValueExtension(object value)
    {
        Value = value;
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var provideValueTarget = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
        var property = provideValueTarget.TargetProperty as DependencyProperty;
        var target = provideValueTarget.TargetObject as DependencyObject;

        if (target == null || property == null)
           return this;

        object value = DesignerProperties.GetIsInDesignMode(target) && DesignValue != DependencyProperty.UnsetValue ? DesignValue : Value;

        if (value == DependencyProperty.UnsetValue || value == null)
            return value;

        if (value is MarkupExtension)
            return ((MarkupExtension)value).ProvideValue(serviceProvider);

        if (property.PropertyType.IsInstanceOfType(value))
            return value;

        return TypeDescriptor.GetConverter(property.PropertyType).ConvertFrom(value);
    }
}
Другие вопросы по тегам