Привязка видимости элемента к свойству 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);
}
}