4

I like to bind to static properties whenever I can (e.g. when notification is not needed or when model anyway implement INotifyPropertyChanged for other purposes), e.g.:

Visibility="{Binding IsAdministractor, Source={x:Static local:User.Current}, Converter={local:FalseToCollapsedConverter}}"

The problem is that such evaluation works at design-time too, making it hard to work with designer.

Normal bindings doesn't work in design-time and I can utilize FallbackValue to specify design-time only values (I have never yet used FallbackValue in run-time).

Is there an easy way to make binding to static properties invalid (disable them) during design-time?

I can temporarily rename property, e.g. IsAdministrator123, but this is tedious.

Sinatr
  • 20,892
  • 15
  • 90
  • 319
  • Normal bindings work in design-time if you create DataContext or use DesignInstance value. And that normally makes coding easier (IntellisSense work, immeditiate preview, etc) – ASh Jun 24 '16 at 10:42
  • @ASh, I agree you can do it, but that's too much effort. In any case I don't expect designer to show me run-time appearance, fur this I can simply run the software. Not sure how unusual is "normal bindings doesn't work in design-time". – Sinatr Jun 24 '16 at 11:15

3 Answers3

2

You can check if you're in design mode either in the Converter or in the static Current or in the IsAdministractor(typo here?) property and just return whatever state you'd like to see.

EDIT:

Here's some code for a MarkupExtension (untested)

public class BindingWithDesignSupport : MarkupExtension
{
    public BindingWithDesignSupport(){}

    public BindingWithDesignSupport(BindingBase binding)
    {
        Binding = binding;
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return DesignerProperties.GetIsInDesignMode(new DependencyObject()) ? DesignTimeValue : Binding.ProvideValue(serviceProvider);
    }

    public BindingBase Binding { get; set; }

    public object DesignTimeValue { get; set; }
}

you should be able to use it like:

Visibility="{BindingWithDesignSupport {Binding IsAdministractor, Source={x:Static local:User.Current}, Converter={local:FalseToCollapsedConverter}},DesignTimeValue=Visibility.Visible}"
Community
  • 1
  • 1
Markus Hütter
  • 7,796
  • 1
  • 36
  • 63
  • It's good idea to use converter in this case, haven't thought about it. But what about bindings without converter? I don't want to add boilerplate code to each public static property getter. – Sinatr Jun 24 '16 at 11:19
  • Well, _somewhere_ you have to add boilerplate code... About bindings without a converter? You could add a converter to these. This converter would normally return the value unaltered and check if in design mode and return null or its converter parameter or whatever you like. – Markus Hütter Jun 24 '16 at 11:24
  • Another comment to "I like to bind to static properties whenever I can" - that's probably not the best practice... Just a recommendation: use a nice MVVM framework like caliburn.micro. It simplifies so much. – Markus Hütter Jun 24 '16 at 11:26
  • Sweet, chain-able converter to add in xaml prior using any other converter to return invalid input during design-time. Sounds like a solution. – Sinatr Jun 24 '16 at 11:26
  • hmm, if you want to go that far you might actually be better off with a MarkupExtension than a converter, because the converter will add computational time to the bindings, while the MarkupExtension will be a one off thing. – Markus Hütter Jun 24 '16 at 11:28
  • I like your idea of markup-extension to disable binding. I am used to converter-markup-extension template (see my answer). Your code is working, `DesignTimeValue` must be set as static, e.g.: `{x:Static Visibility.Visible}`, as it doesn't support converter automatic conversion from string. Thanks. – Sinatr Jun 24 '16 at 12:07
  • The funny thing is what after using `{x:Static}` (which works in design-time perfectly) it's not compile-able anymore, throwing `Unknown property 'DesignTimeValue' for type 'MS.Internal.Markup.MarkupExtensionParser+UnknownMarkupExtension' encountered while parsing a Markup Extension`. But that's another problem. Not your problem. In worst case I will stick to my converter. – Sinatr Jun 24 '16 at 12:15
  • To fix above problem (which is probably related to using `x:Static`) I had to create another extension which simply return `Visibility.Visible` value (and two more for collapsed and hidden). Then everything seems to work in design-/run-time. – Sinatr Jun 24 '16 at 12:29
  • Excellent... I like the markup extension idea. Here is a more fleshed out version: [Gist: BindingWithDesignSupport.cs](https://gist.github.com/brinko99/e242b79f4eaec30e834c6d3db2bd17d6) – Terrence Feb 08 '18 at 22:11
0

It's possible to attach converter to all such properties, which has FallbackValue (used in design-time) and Converter (to supply run-time converter) properties:

public class RuntimeConverter : MarkupExtension, IValueConverter
{
    public object FallbackValue { get; set; }
    public IValueConverter Converter { get; set; }

    public RuntimeConverter() { }

    public override object ProvideValue(IServiceProvider serviceProvider) => this;

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
            return FallbackValue;
        if (Converter == null)
            return value;
        return Converter.Convert(value, targetType, parameter, culture);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
            return FallbackValue;
        if (Converter == null)
            return value;
        return Converter.ConvertBack(value, targetType, parameter, culture);
    }
}

then in design-time it is possible to change value returned by static property:

<!-- split in multiple lines for readability -->
Visibility="{Binding IsPowerUser, Source={x:Static local:User.Logged},
    Converter={local:RuntimeConverter Converter={local:FalseToCollapsedConverter},
    FallbackValue=Collapsed}}">
Sinatr
  • 20,892
  • 15
  • 90
  • 319
0

You could use design time data to put the design time view model into the state you want to design against.

Or for simple properties you can initialise them with the desired design time value in the viewmodel e.g.

    public bool IsAdministractor { get; set; } = true;
Richard Moore
  • 1,133
  • 17
  • 25