Corrado's Blog 2.0

Online thoughts of a technology funatic

Beware of generated XAML in UWP

I admit, this is s strange blog post title but that’s what this post is going to talk about.

I’m working on a UWP app that has different min and target runtimes:

image

After doing some UI work with Visual Studio & Blend I’ve discovered that the app was crashing on machines without Anniversary edition installed. At the end of a debuggin session I’ve found the reason: The XAML template generated by the tools contains incompatible elements (resources mainly, but also new properties) that are not present on previous builds.

To give you an example, this is an extract from a ComboBox default template, generated by Blend when you use the Template->Edit copy feature:

10586

<Setter Property="Foreground"

Value="{ThemeResource SystemControlForegroundBaseHighBrush}" />

14393 (Anniversary)

<Setter Property="Foreground"

Value="{ThemeResource ComboBoxForeground}" />

The reason of this is because the tools generate the template from the Target version SDK and not the Min version SDK that might even not be present.

The team said that they’re going to give you some warnings in the future when situations like this happen, but in the meantime, at least when you’re doing design work, be sure to selected, the min target version SDK otherwise you might end up in troubles.

XAML relative binding trick

MVVM newcomers find creating a UI like this (a simple ListView containing a button that removes current row) quite intricated.

image

This because, while you can add a command to the item bound to each row, it’s more convenient to have a common DeleteCommand on parent ViewModel that accepts the Item to remove from the collection feeding the list.

Here’s our ViewModel:

public class MyViewModel { private RelayCommand<ReportUnit> deleteCommand; public MyViewModel() { this.Items = new ObservableCollection<ReportUnit>(); for (int i = 0; i < 10; i++) { this.Items.Add(new ReportUnit() { Name = $"Item {i}" }); } } public RelayCommand<ReportUnit> DeleteCommand { get { return this.deleteCommand ?? (this.deleteCommand = new RelayCommand<ReportUnit>((o) => { this.Items.Remove(o); })); } } public ObservableCollection<ReportUnit> Items { get; private set; } } public class ReportUnit { public string Name { get; set; } }

And here’s the page XAML:

<Page x:Class="DemoBinding.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Page.Resources> <Style x:Key="ListItemContainerStyle" TargetType="ListViewItem"> <Setter Property="HorizontalContentAlignment" Value="Stretch" /> </Style> </Page.Resources> <Grid x:Name="RootGrid"> <ListView ItemsSource="{Binding Items}" ItemTemplate="{StaticResource MyItemTemplate}" ItemContainerStyle="{StaticResource ListItemContainerStyle}"> </ListView> </Grid> </Page>

The “magic” is of course inside MyItemTemplate:

<DataTemplate x:Key="MyItemTemplate"> <Grid d:DesignWidth="568.775" Height="80" d:DesignHeight="100"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="100" /> </Grid.ColumnDefinitions> <TextBlock TextWrapping="Wrap" Text="{Binding Name}" VerticalAlignment="Center" FontSize="26.667" /> <Button Grid.Column="1" Content="Delete" HorizontalAlignment="Stretch" Command="{Binding DataContext.DeleteCommand, ElementName=RootGrid}" CommandParameter="{Binding}" VerticalAlignment="Stretch" Margin="5" /> </Grid> </DataTemplate>

As you see, the  button ‘steal’ the DataContext of RootGrid element and invokes MyViewModel’s DeleteCommand while passing its own DataContext as CommandParameter.

Simple and clean. Smile

The tale of a GridViewItem customization

Once upon a time, in a galaxy not so far away, there was a guy (me Smile) who was working on a Windows Store 8.1 application and was asked to create a GridView whose items should look like this picture:

image

The guy (again, me) thought: What’s the problem, did it many times! and he started setting a data source:

public class Item
    {
        public string Text { get; set; }
    }

    public class DemoViewModel
    {
        public DemoViewModel()
        {
            this.Items = new List<Item>();
            for (int i = 0; i < 10; i++)
            {
                this.Items.Add(new Item() { Text = "Item " + i });
            }
        }

        public IList<Item> Items { get; set; }
    }

He then added a GridView to a page, bound the data source and created a simple ItemTemplate:

<Page x:Class="GridViewDemo.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:GridViewDemo"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">
    <Page.Resources>
        <local:DemoViewModel x:Key="vm"></local:DemoViewModel>
        <DataTemplate x:Key="MyItemTemplate">
            <Grid Width="100"
                  Height="60">
                <TextBlock HorizontalAlignment="Center"
                           TextWrapping="Wrap"
                           Text="{Binding Text}"
                           VerticalAlignment="Center" />
            </Grid>
        </DataTemplate>
        
    </Page.Resources>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
          DataContext="{StaticResource vm}">
        <GridView ItemsSource="{Binding Items}"
                  ItemTemplate="{StaticResource MyItemTemplate}"
                   />
    </Grid>
</Page>

Run the solution and he got something quite close to what he was asked to realize:

image

Ok, just a couple of customizations and we’re done, he thought…

Let’s start with the selected background: The guy knows that background brush is managed inside ItemContainerStyle so he fired up Blend 2013, edited GridView’s ItemContainerStyle and here’s what he got:

image

Just a simple GridViewItemPresenter that has a series of Brush properties that give you the opportunity to customize several container aspects

image

In his case he needed to customize the color of SelectedBackground so, since it is bound to a resource named ListViewItemSelectedBackgroundThemeBrush he added a Brush resource with the same name inside Page resources and selected state was done, here’s updated result:

<SolidColorBrush x:Key="ListViewItemSelectedBackgroundThemeBrush"
                         Color="Orange"></SolidColorBrush>

image

But a question started to rise in his mind: “How to i set default (gray) background color?” there’s no Background color exposed by GridViewItemPresenter nor he can set it inside ItemTemplate otherwise it wouldn’t change when item is selected.

He tried lookind inside MSDN docs hoping to find a brush key that controls item default background but he had no luck Sad smile and navigated a lot the Internet until he realized he did something similar in the past for a Windows 8.0 application.

He then opened that old source code and discovered what has changed: The GridViewItemPresenter has been introduced in Windows 8.1, here’s how ItemContainerStyle looks in Windows 8.0:

image

Since you have access to all the elements composing the GridViewItem what the guy did was copying the style into Windows 8.1 app and edited VisualStateManager states (I’m sure, dear reader, you know how to do that…)

So, here’s final result:

image

The guy secretly told me that he wasn’t happy for such solution, probably GridViewItemPresenter has been introduced to improve GridView’s performances but he found no other easier way to solve the puzzle.

Based on a true story… Smile

PS: In case you need Windows 8.0 GridView’s ItemContainerStyle you can get it here.

Debug design time issues in Blend 2013

In 2010 (wow! that’s a long time ago…) I blogged about how to debug Blend design time exceptions, since then things have changed, Blend and Visual studio designer merged and so the XAML designer is now hosted in a separate process named XDesProc.exe (at least in Windows Store applications)

Laurent Bugnion has a detailed blog post about how to attach Visual Studio debugger to Blend to debug a Windows Store application at design time so i won’t repeat it here, the reason of this post is to integrate it with another step required when you use Visual Studio 2013 and Blend 2013.

Since with latest release PDB are no longer copied to cache location used by designer your simbols won’t be loaded and your attach procedure won’t work.

The solution is very easy, just point the debugger symbols to the proper PDB files of your application and everything will work as expected.

To point the PDBs just use: Tools –> Options-> Debugger

image

Then add the folder where your app’s PDB file resides.