Compiled binding,Page Resources and Visual States

I have tried to find the cleanest way in terms of reusability, less code repeating, functionality, etc. And after plenty of experiments the following is the one I consider more interesting. First I explain how to use directly from the page, and after from a datatemplate.

Page Resources

When we define a double in XAML like a resource, you will be able to use as a resource just once, also you will able to change on runtime using the VisualStateTriggers, but the Controls referenced to it won’t get the updates, because we only have StaticResources in UWP and no DynamicResources. Also a x:Double cannot have a Name in the Page Resources Section.

Having this in mind, you can define tons of dependency properties in your XAML Page code behind and bind it but makes the code less clean. So what can we do, let’s create XAML Properties.

To begin let’s define the DoubleProperty which represents a double in the XAML world, that means a DependencyObject:

public class DoubleProperty : DependencyObject
    {
        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register(nameof(Value), typeof(double), typeof(DoubleProperty),
                new PropertyMetadata(DependencyProperty.UnsetValue));
    }

Now we can use it as a real resource because now can have a name in the Page Resources.

<Page.Resources>
        <c:DoubleProperty x:Name="HeaderFontSize" x:Key="HeaderFontSize" Value="24.0"/>
        <c:DoubleProperty x:Name="DescriptionFontSize" x:Key="DescriptionFontSize" Value="14.0"/>
</Page.Resources>

Compiled binding

Now in case we want to create a TextBlock with one of the defined font sizes:


<TextBlock Text="Sections"  FontSize="{x:Bind HeaderFontSize.Value, Mode=OneWay}" />

Visual States

And now let’s create the Visual States Section

<VisualStateManager.VisualStateGroups>
    <VisualStateGroup x:Name="VisualStates" >
        <VisualState x:Name="Full">
            <VisualState.StateTriggers>
                <AdaptiveTrigger MinWindowWidth="600" />
            </VisualState.StateTriggers>
        </VisualState>
        <VisualState x:Name="Small">
            <VisualState.StateTriggers>
                <AdaptiveTrigger MinWindowWidth="0" />
            </VisualState.StateTriggers>
            <VisualState.Setters>
                <Setter Target="DescriptionFontSize.Value" Value="12"/>
                <Setter Target="HeaderFontSize.Value" Value="18"/>
            </VisualState.Setters>
        </VisualState>
    </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

Where we can easily change the values because this resources have x:Name. Now when you run the app you will see how it adapts the fontsize according to the Windows Width.

Now, the WOW part, at least IMHO, because there is not an official way to do it at the moment.

Data Templates

First we need to define a Current static property of the Page in the constructor, it is the only code behind you need:

public static HomeView Current { get; set; }
public HomeView()
{
    Current = this;
    this.InitializeComponent();
}

Now we can bind to it from a DataTemplate for instance:

<DataTemplate x:Key="SampleDataTemplate" x:DataType="m:SectionInfo">
   <Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="240"/>
    </Grid.RowDefinitions>
    <TextBlock Text="{x:Bind Name, Mode=OneWay}" FontSize="{x:Bind local:HomeView.Current.HeaderFontSize.Value, Mode=OneWay}"  />
    <TextBlock Grid.Row="1" Text="{x:Bind Description, Mode=OneWay}" FontSize="{x:Bind local:HomeView.Current.DescriptionFontSize.Value, Mode=OneWay}" />
   </Grid>
</DataTemplate>

So now with this we can bind double values and get their updates on the go, and if we have values, can we have any other type. Why not a generic object, let’s continue defining GeneryProperty:

public class GenericProperty : DependencyObject
{
    public object Value
    {
        get { return (object)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }

    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register(nameof(Value), typeof(object), typeof(GenericProperty), 
            new PropertyMetadata(DependencyProperty.UnsetValue));
}

In the page resources section let’s add a Brush:

<c:GenericProperty x:Name="CustomColor" x:Key="CustomColor">
    <c:GenericProperty.Value>
      <SolidColorBrush Color="Blue"/>
   </c:GenericProperty.Value>
</c:GenericProperty>

And in the Visual States Section:

<VisualStateManager.VisualStateGroups>
    <VisualStateGroup x:Name="VisualStates" >
        <VisualState x:Name="Full">
            <VisualState.StateTriggers>
                <AdaptiveTrigger MinWindowWidth="600" />
            </VisualState.StateTriggers>
                </VisualState>
                <VisualState x:Name="Small">
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="0" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="DescriptionFontSize.Value" Value="12"/>
                        <Setter Target="HeaderFontSize.Value" Value="18"/>
                        <Setter Target="CustomColor.Value">
                            <Setter.Value>
                                <SolidColorBrush Color="Orange"/>
                            </Setter.Value>
                        </Setter>
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

And finally, having casting in compiled binding, we can do the following:

<Grid  Background="{x:Bind (Brush)local:HomeView.Current.CustomColor.Value, Mode=OneWay}" >
...
</Grid>

I have tested this with the latest insider release 14905, I understand it works from the Anniversary Update.

Conclusions

This is just the beginning, now we have methods and casting, we can make practically everything directly from XAML just adding that Current property. I think this article solves plenty of questions about DynamicResources, how to bind a resource, etc.

You can get the source here CompiledBindingExamples

Hope you find it useful and as always follow me at @juanpaexpedite to know interesting UWP stuff. Now I am preparing a new dev oriented App I hope finish it in few weeks.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s