Tim Long
Tim Long

Reputation: 13778

WPF Design Time Data and Data Templates

I'm developing a WPF user control and I want it to display some design-time data. It's proving to be quite a challenge to get things just right and I could really use your help.

Here's my control so far, basically a <ListBox>:

<UserControl x:Class="TA.Weather.UI.Wpf.WorkingSetEditor"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             Loaded="HandleLoadedEvent"
             >
    <Grid d:DataContext="{d:DesignData Source=/SampleData/WorkingSet.xaml}">
        <ListBox x:Name="WorkingSetListBox"  >
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition MinWidth="30" />
                    <ColumnDefinition MinWidth="30" />
                    <ColumnDefinition MinWidth="30" />
                    <ColumnDefinition MinWidth="30" />
                    <ColumnDefinition MinWidth="30" />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" TextAlignment="Center"
                           Text="{Binding Path=[0].Limits.StationId}"></TextBlock>
                <TextBlock Grid.Column="1" TextAlignment="Center"
                           Text="{Binding Path=[0].Limits.SensorId}"></TextBlock>
                <TextBlock Grid.Column="2" TextAlignment="Center"
                           Text="{Binding Path=[0].Limits.SensorName}"></TextBlock>
                <TextBlock Grid.Column="3" TextAlignment="Center"
                           Text="{Binding Path=[0].Limits.LowerLimit}"></TextBlock>
                <TextBlock Grid.Column="4" TextAlignment="Center"
                           Text="{Binding Path=[0].Limits.UpperLimit}"></TextBlock>
                <CheckBox Grid.Column="5" x:Name="MonitoredCheckBox"
                          IsChecked="{Binding Path=[1].Monitored}"/>
            </Grid>
        </ListBox>
    </Grid>
</UserControl>

I figured out how to create the design-time data in another XAML file, and set the build action to DesignDataWithDesignTimeCreatableTypes. The type is essentially just a DTO so it seems OK to create instances at design time. So here's the data file, containing an List<SensorState> with two members:

<generic:List x:TypeArguments="ws:SensorState"
              xmlns:ws="clr-namespace:TA.Weather.Core;assembly=TA.Weather.Core"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:generic="clr-namespace:System.Collections.Generic;assembly=mscorlib">
    <ws:SensorState IdleTimeout="300" LastUpdate="2015-08-19T03:39:00.000Z" Monitored="False"
                    WithinAcceptableLimits="False">
        <ws:SensorState.Limits>
            <ws:SensorLimits StationId="12-34-56-78-90-12" SensorId="1" SensorName="Inside Temperature"
                             LowerLimit="-10" UpperLimit="30" />
        </ws:SensorState.Limits>
    </ws:SensorState>
    <ws:SensorState IdleTimeout="300" LastUpdate="2015-08-19T03:39:00.000Z" Monitored="True"
                    WithinAcceptableLimits="False">
        <ws:SensorState.Limits>
            <ws:SensorLimits StationId="12-34-56-78-90-12" SensorId="1" SensorName="Inside Temperature"
                             LowerLimit="-10" UpperLimit="30" />
        </ws:SensorState.Limits>
    </ws:SensorState>
</generic:List>

Thus far, this gets me a user control that looks like this: User control with design-time data

So, success of sorts. However, there are two questions at this point:

There's more. I want to use a DataTemplate to create a nicer look for the data; a bit later on there is going to be a slider control for setting the limits, etc. so here's how I've tried to use a template:

<UserControl x:Class="TA.Weather.UI.Wpf.WorkingSetEditor"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:core="clr-namespace:TA.Weather.Core;assembly=TA.Weather.Core"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             Loaded="HandleLoadedEvent"
             >
    <Grid d:DataContext="{d:DesignData Source=/SampleData/WorkingSet.xaml}">
        <Grid.Resources>
            <DataTemplate x:Key="WorkingSetTemplate">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition MinWidth="30" />
                        <ColumnDefinition MinWidth="30" />
                        <ColumnDefinition MinWidth="30" />
                        <ColumnDefinition MinWidth="30" />
                        <ColumnDefinition MinWidth="30" />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Column="0" TextAlignment="Center"
                           Text="{Binding Path=[0].Limits.StationId}"></TextBlock>
                    <TextBlock Grid.Column="1" TextAlignment="Center"
                           Text="{Binding Path=[0].Limits.SensorId}"></TextBlock>
                    <TextBlock Grid.Column="2" TextAlignment="Center"
                           Text="{Binding Path=[0].Limits.SensorName}"></TextBlock>
                    <TextBlock Grid.Column="3" TextAlignment="Center"
                           Text="{Binding Path=[0].Limits.LowerLimit}"></TextBlock>
                    <TextBlock Grid.Column="4" TextAlignment="Center"
                           Text="{Binding Path=[0].Limits.UpperLimit}"></TextBlock>
                    <CheckBox Grid.Column="5" x:Name="MonitoredCheckBox"
                          IsChecked="{Binding Path=[1].Monitored}"/>
                </Grid>

            </DataTemplate>
        </Grid.Resources>
        <ListBox x:Name="WorkingSetListBox" ItemTemplate="{DynamicResource WorkingSetTemplate}">
        </ListBox>
    </Grid>
</UserControl>

So basically, I've moved the <Grid> out of the <ListBox> and into the <DataTemplate> resource. As soon as I do this, the design-time data vanishes and I'm left with just a blank control in the designer. So my third question becomes:

You can probably tell that I have almost no experience with WPF... I must admit I am struggling with binding expressions a little bit, they seem like some sort of arcane magic with little rhyme or reason to them. I think maybe I'm missing an important concept somewhere. I hope you can give me a few wise words to push me in the right direction.

Upvotes: 0

Views: 511

Answers (0)

Related Questions