16

I'm an experienced C# developer but a WPF newbie. Basic question (I think) that I can't find an answer to by web searching. Here's the simplified use case...

I want to display a string in a WPF TextBlock. So I write some C# code in codebehind of my XAML control...

public class MyCoolControl : UserControl
{
   public void InitializeMyCoolControl()
   {
      this.DataContext = "SomeStringOnlyAvailableAtRuntime"; // Perhaps from a database or something...
   }
}

And I set up my XAML like this:

<UserControl ... snip...>
   <!-- Bind the textblock to whatever's in the DataContext -->
   <TextBlock Text="{Binding}"></TextBlock>
</UserControl>

Works great, I can see the value "SomeStringOnlyAvailableAtRuntime" when I execute my application. However, I don't see anything at Design Time using Visual Studio 2008's XAML Designer.

How can I see a placeholder value (anything) for the textblock at design time?

Thanks!

-Mike

Mike
  • 5,560
  • 12
  • 41
  • 52

5 Answers5

25

I often use FallbackValue on the binding to have something to look at while I design user controls. For example:

<TextBlock Text={Binding Path=AverageValue, FallbackValue=99.99} />

However, since FallbackValue is not just applied at design time, this might not be appropriate if you want to use FallbackValue at run time for other reasons.

Anthony Brien
  • 6,106
  • 7
  • 43
  • 56
2

In your example you might need to use TargetNullValue, not FallbackValue as the binding expression is likely to be null as the DataContext is null at design time.

FallBackValue is used if the Path given in the binding does not exist, but as no path is specified I'd assume the DataContext would then be evaluated as null.

<UserControl ... snip...>
  <!-- Bind the textblock to whatever's in the DataContext -->   
    <TextBlock Text="{Binding TargetNullValue=Nothing to see}"></TextBlock>
</UserControl>

Also note that .NET Framework 3.5 SP1 is needed as these two additional properties were added in SP1.

Rhys
  • 4,511
  • 2
  • 23
  • 32
1

Both of TargetNullValue and FallbackValue are have function in runtime, so they are not good placeholder choices.
TargetNullValue: if target property value is equals TargetNullValue, the source property will be set as null, and if the source property is null, the target property will be set as TargetNullValue.
FallbackValue: if the source of Binding is null or failed to convert source property to target property, the target property will be set as FallbackValue.

You can create a custom MarkupExtension to show placeholder in designer, and do the normal binding in runtime

My code:

//Coding by Squirrel Downy(Flithor)
public class PlaceHolderBinding : MarkupExtension
{
    /// <summary>
    /// Show placeholder in designer, if null than ignore it
    /// </summary>
    public object PlaceHolder { get; set; }
    /// <summary>
    /// Binding works in runtime
    /// </summary>
    public BindingBase Binding { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        //if no binding
        if (Binding == null) throw new ArgumentNullException("Binding");

        //get target info
        var target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
        if (target == null) throw new InvalidOperationException("Only support as Binding");

        //get target object and check is DependencyObject
        if (!(target.TargetObject is DependencyObject targetObject))
            throw new InvalidOperationException("Only support on DependencyObject");

        //if target in designer, return placeholder
        if (DesignerProperties.GetIsInDesignMode(targetObject))
            return PlaceHolder;

        //get target property and check is DependencyProperty
        if (!(target.TargetProperty is DependencyProperty targetProp))
            throw new InvalidOperationException("Only support on DependencyProperty");

        //set binding and return binding provide value
        BindingOperations.SetBinding(targetObject, targetProp, Binding);
        return Binding.ProvideValue(serviceProvider);
    }
}
0

Isn't the best option in this scenario to have a MultiValueConverter or ViewModel object handle the object load and update a dependency property for you?

Gusdor
  • 14,001
  • 2
  • 52
  • 64
  • Not sure I understand, can you explain a little bit more? – Mike Mar 05 '10 at 17:43
  • Rather than databinding to your state dependant resource directly, bind to an object that is responsible for loading said resource. When the XAML is first loaded, your resource will not be present and the binding will return an empty image, or an object that says 'loading...'. When the load is complete, an implementation of INotifyPropertyChanged should notify the databinding that the resource has changed to a loaded version. In this scenario it is probably worth authoring a Markup Extension for your loader type so that you can declare the whole operation inline. – Gusdor Mar 10 '10 at 15:59
0

I don't know of a way to do this with Visual Studio's editor, but you can do this with Expression Blend.

Here's and article describing how to achieve this.

I do hope that MS merge the functionality of Blend and Visual Studio together because having one package do one thing and another something else is a bit silly. Especially when they're from the same company.

Cameron MacFarland
  • 70,676
  • 20
  • 104
  • 133