1

I have a problem on an UWP project I'm currently working on :

I have a viewmodel like this :

public class HomePageViewModel : INotifyPropertyChanged
{
     public event PropertyChangedEventHandler PropertyChanged;

      public ObservableCollection<WidgetViewModel> Widgets { get; } = new ObservableCollection<WidgetViewModel>();

      public HomePageViewModel()
      {
      }

      public void OnNotifyPropertyChanged([CallerMemberName]string propertyName = "")
      {
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
}

And the WidgetViewModel is defined like this :

public class WidgetViewModel : INotifyPropertyChanged
{
      private string group;

      public string Group
      {
           get=>group;
           set
           {
                 group=value;
                 OnNotifyPropertyChanged();
           }
      }

      public event PropertyChangedEventHandler PropertyChanged;

      public ObservableCollection<ItemViewModel> Items { get; } = new ObservableCollection<ItemViewModel>();

      public WidgetPageViewModel()
      {
      }

      public void OnNotifyPropertyChanged([CallerMemberName]string propertyName = "")
      {
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
}

And my ItemViewModel is defined like this :

public class ItemViewModel : INotifyPropertyChanged
{
      private string name;

      public event PropertyChangedEventHandler PropertyChanged;

      public string Name
      {
         get=>name;
         set
         {
            name = value;
            OnNotifyPropertyChanged();
         }
      }

      public ItemViewModel()
      {
      }

      public void OnNotifyPropertyChanged([CallerMemberName]string propertyName = "")
      {
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
}

I have produced this xaml :

<Page x:Class="Project.TestPage"
                       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"
                       xmlns:local="Project"
                       Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
                       mc:Ignorable="d">
    <Grid>
        <Grid.Resources>
            <CollectionViewSource x:Name="TestSource"
                                  IsSourceGrouped="True"
                                  Source="{Binding Widgets}" />
            <local:ItemTemplateSelector x:Key="ItemTemplateSelector">
                    <local:ItemTemplateSelector.WidgetTemplate>
                          <DataTemplate>
                              <local:TestItemsControl ItemTemplateSelector="{StaticResource ItemTemplateSelector}"
                                            ItemsSource="{Binding Items}">
                                  <local:TestItemsControl.ItemContainerStyle>
                                     <Style TargetType="local:TestItem">
                                          <Setter Property="HorizontalAlignment" Value="Stretch" />
                                          <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                                          <Setter Property="VerticalAlignment" Value="Stretch" />
                                          <Setter Property="VerticalContentAlignment" Value="Stretch" />
                                     </Style>
                                  </local:TestItemsControl.ItemContainerStyle>
                              </local:TestItemsControl>
                          </DataTemplate>
                    </local:ItemTemplateSelector.WidgetTemplate>
                    <local:ItemTemplateSelector.ItemTemplate>
                          <DataTemplate>
                              <TextBlock Text="{Binding Name}" />
                          </DataTemplate>
                    </local:ItemTemplateSelector.ItemTemplate>
            </local:ItemTemplateSelector>
            <x:String x:Key="ChevronGlyph">&#xE26B;</x:String>

            <Style x:Key="TextButtonStyle" TargetType="ButtonBase">
                <Setter Property="MinWidth" Value="0" />
                <Setter Property="MinHeight" Value="0" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ButtonBase">
                            <Grid Background="Transparent">
                                <ContentPresenter x:Name="Text" Content="{TemplateBinding Content}" />
                                <Rectangle x:Name="FocusVisualWhite"
                                           IsHitTestVisible="False"
                                           Opacity="0"
                                           Stroke="{StaticResource FocusVisualWhiteStrokeThemeBrush}"
                                           StrokeDashArray="1,1"
                                           StrokeDashOffset="1.5"
                                           StrokeEndLineCap="Square" />
                                <Rectangle x:Name="FocusVisualBlack"
                                           IsHitTestVisible="False"
                                           Opacity="0"
                                           Stroke="{StaticResource FocusVisualBlackStrokeThemeBrush}"
                                           StrokeDashArray="1,1"
                                           StrokeDashOffset="0.5"
                                           StrokeEndLineCap="Square" />
                                <VisualStateManager.VisualStateGroups>
                                    <VisualStateGroup x:Name="CommonStates">
                                        <VisualState x:Name="Normal" />
                                        <VisualState x:Name="PointerOver">
                                            <Storyboard>
                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
                                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApplicationPointerOverForegroundThemeBrush}" />
                                                </ObjectAnimationUsingKeyFrames>
                                            </Storyboard>
                                        </VisualState>
                                        <VisualState x:Name="Pressed">
                                            <Storyboard>
                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
                                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApplicationPressedForegroundThemeBrush}" />
                                                </ObjectAnimationUsingKeyFrames>
                                            </Storyboard>
                                        </VisualState>
                                        <VisualState x:Name="Disabled">
                                            <Storyboard>
                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
                                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApplicationPressedForegroundThemeBrush}" />
                                                </ObjectAnimationUsingKeyFrames>
                                            </Storyboard>
                                        </VisualState>
                                    </VisualStateGroup>
                                    <VisualStateGroup x:Name="FocusStates">
                                        <VisualState x:Name="Focused">
                                            <Storyboard>
                                                <DoubleAnimation Storyboard.TargetName="FocusVisualWhite"
                                                                 Storyboard.TargetProperty="Opacity"
                                                                 To="1"
                                                                 Duration="0" />
                                                <DoubleAnimation Storyboard.TargetName="FocusVisualBlack"
                                                                 Storyboard.TargetProperty="Opacity"
                                                                 To="1"
                                                                 Duration="0" />
                                            </Storyboard>
                                        </VisualState>
                                        <VisualState x:Name="Unfocused" />
                                    </VisualStateGroup>
                                    <VisualStateGroup x:Name="CheckStates">
                                        <VisualState x:Name="Checked" />
                                        <VisualState x:Name="Unchecked">
                                            <Storyboard>
                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
                                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApplicationSecondaryForegroundThemeBrush}" />
                                                </ObjectAnimationUsingKeyFrames>
                                            </Storyboard>
                                        </VisualState>
                                        <VisualState x:Name="Indeterminate" />
                                    </VisualStateGroup>
                                </VisualStateManager.VisualStateGroups>
                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>

            <Style x:Key="TextPrimaryButtonStyle"
                   BasedOn="{StaticResource TextButtonStyle}"
                   TargetType="ButtonBase">
                <Setter Property="Foreground" Value="{StaticResource ApplicationHeaderForegroundThemeBrush}" />
            </Style>

            <Style x:Key="GroupHeaderTextStyle" TargetType="TextBlock">
                <Setter Property="FontFamily" Value="{StaticResource ContentControlThemeFontFamily}" />
                <Setter Property="TextTrimming" Value="WordEllipsis" />
                <Setter Property="TextWrapping" Value="NoWrap" />
                <Setter Property="Typography.StylisticSet20" Value="True" />
                <Setter Property="Typography.DiscretionaryLigatures" Value="True" />
                <Setter Property="Typography.CaseSensitiveForms" Value="True" />
                <Setter Property="FontSize" Value="26.667" />
                <Setter Property="LineStackingStrategy" Value="BlockLineHeight" />
                <Setter Property="FontWeight" Value="Light" />
                <Setter Property="LineHeight" Value="30" />
                <Setter Property="RenderTransform">
                    <Setter.Value>
                        <TranslateTransform X="-1" Y="6" />
                    </Setter.Value>
                </Setter>
            </Style>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <GridView Grid.Row="1"
                  Padding="116,137,40,46"
                  IsItemClickEnabled="False"
                  ItemTemplateSelector="{StaticResource ItemTemplateSelector}"
                  ItemsSource="{Binding Source={StaticResource TestSource}}"
                  ScrollViewer.HorizontalScrollBarVisibility="Auto"
                  ScrollViewer.HorizontalScrollMode="Enabled"
                  ScrollViewer.VerticalScrollBarVisibility="Disabled"
                  ScrollViewer.VerticalScrollMode="Disabled">
            <GridView.ItemContainerStyle>
                <Style TargetType="GridViewItem">
                    <Setter Property="HorizontalAlignment" Value="Stretch" />
                    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                    <Setter Property="VerticalAlignment" Value="Stretch" />
                    <Setter Property="VerticalContentAlignment" Value="Stretch" />
                </Style>
            </GridView.ItemContainerStyle>
            <GridView.GroupStyle>
                <GroupStyle>
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate>
                            <Button AutomationProperties.Name="Group Title" Style="{StaticResource TextPrimaryButtonStyle}">
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Margin="3,-7,10,10"
                                               Style="{StaticResource GroupHeaderTextStyle}"
                                               Text="{Binding Key}" />
                                    <TextBlock Margin="0,-7,0,10"
                                               FontFamily="Segoe UI Symbol"
                                               Style="{StaticResource GroupHeaderTextStyle}"
                                               Text="{StaticResource ChevronGlyph}" />
                                </StackPanel>
                            </Button>
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>
                    <GroupStyle.Panel>
                        <ItemsPanelTemplate>
                            <VariableSizedWrapGrid Margin="0,0,80,0"
                                                   ItemHeight="200"
                                                   ItemWidth="200"
                                                   Orientation="Vertical" />
                        </ItemsPanelTemplate>
                    </GroupStyle.Panel>
                </GroupStyle>
            </GridView.GroupStyle>
            <GridView.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>
        </GridView>
    </Grid>
</Page>

The ItemTemplateSelector is defined like this :

public sealed class ItemTemplateSelector
        : DataTemplateSelector
    {
        public DataTemplate WidgetTemplate{get;set;}
        public DataTemplate ItemTemplate{get;set;}

        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        protected override DataTemplate SelectTemplateCore(object item)
        {
            if(item is ItemViewModel)
                return ItemTemplate;

            if(item is WidgetViewModel)
               return WidgetTemplate;

            return null;
        }

        protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
        {
             if(item is ItemViewModel)
                return ItemTemplate;

            if(item is WidgetViewModel)
               return WidgetTemplate;

            return null;
        } 
    }
}

And the TestItemsControl is :

public class TestItemsControl : ItemsControl
{
   public TestItemsControl()
   {
        DefaultStyleKey = typeof(TestItemsControl);
   }

    protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return item is TestItem;
        }

        protected override DependencyObject GetContainerForItemOverride()
        {
            return new TestItem();
        }
}

And TestItem is basically :

public class TestItem : ContentControl
{
   public TestItem()
   {
      DefaultStyleKey = typeof(TestItem);
   }

}

And the style for them :


<Style TargetType="local:TestItem">
 
        <Setter Property="HorizontalAlignment" Value="Stretch" />
        <Setter Property="VerticalAlignment" Value="Stretch" />
        <Setter Property="VerticalContentAlignment" Value="Stretch" />
        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:TestItem">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <Grid>
                            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                              Content="{TemplateBinding Content}"
                                              ContentTemplate="{TemplateBinding ContentTemplate}"
                                              ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"
                                              FontFamily="{TemplateBinding FontFamily}"
                                              FontSize="{TemplateBinding FontSize}"
                                              FontStyle="{TemplateBinding FontStyle}"
                                              FontWeight="{TemplateBinding FontWeight}"
                                              Foreground="{TemplateBinding Foreground}" />
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

<Style TargetType="local:TestItemsControl">
        <Setter Property="Padding" Value="0" />
        <Setter Property="Margin" Value="0" />
        <Setter Property="BorderBrush" Value="{ThemeResource ApplicationPageBackgroundThemeBrush}" />
        <Setter Property="Background" Value="{ThemeResource ApplicationPageBackgroundThemeBrush}" />
        <Setter Property="Foreground" Value="Black" />
        <Setter Property="HorizontalAlignment" Value="Stretch" />
        <Setter Property="VerticalAlignment" Value="Stretch" />
        <Setter Property="VerticalContentAlignment" Value="Stretch" />
        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <VariableSizedWrapGrid />
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:TestItemsControl">
                    <Grid x:Name="PART_Root">
                        <Rectangle x:Name="PointerOverRect"
                                   Margin="-2"
                                   Fill="#DE000000"
                                   Opacity="0" />

                        <Border x:Name="PART_Border"
                                Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}">

                            <Grid Margin="{TemplateBinding Padding}">
                                <ItemsPresenter />
                            </Grid>
                        </Border>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal" />
                                <VisualState x:Name="PointerOver">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="PointerOverRect"
                                                         Storyboard.TargetProperty="Opacity"
                                                         To="0.28"
                                                         Duration="0" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="PointerPressed" />
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="PART_Border"
                                                         Storyboard.TargetProperty="Opacity"
                                                         To="0.3"
                                                         Duration="0" />
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

And finally how I create the items :

public class TestPage : Page
{
    public TestPage()
    {
        InitializeComponent();
        var vm = new HomePageViewModel();
        DataContext = vm;

        var widget = new WidgetViewModel();
        widget.Add(new ItemViewModel
                   {
                        Name = "Users"
                   });
         widget.Add(new ItemViewModel
                   {
                        Name = "16"
                   });
         vm.Widgets.Add(widget);
    }
}

I have two problems with that :(

The first problem is : The ItemTemplate is set but it not display the name of the item but this text : "Project.ItemViewModel" and I can't understand why

The second problem is the child doesn't fill its parent container.

To explain what I'm trying to achieve, the basic idea is to have a component which swap its content after a delay.

So here I have a GridView with items and each item could have many contents.

That's why I used a TestItemsControl. It's easier to manage swapping content with it...

Any Ideas?

EDIT : I made some steps. I have one remaining problem. It is : The DataTemplate is set into the container but it is not applied. When I break point on DataTemplateSelector, I see my TestItemContainer and the DataTemplateSelector is set in it, but the item always display a textblock with the text "XXXX.XXXX.ViewModel" And with the datatemplate I need to show the property 'Name' of the ViewModel

Thanks for any help

  • Since the above code is not complete, we can't reproduce this issue. Can you provide some code snippet about how you created your Widgets in code-behind of Page? In addition, may I know why you want to custom the control and what effect you want to achieve? – Faywang - MSFT Jun 26 '20 at 04:13
  • @Faywang-MSFT I edited the question. Maybe this will help – Jérémy Janiszewski Jun 26 '20 at 07:57
  • It seems there is something wrong when you custom ItemsControl, it is not recommended to custom ItemsControl, maybe you could put the ItemsControl into UserControl and add itemsSource dependency property to bind with items. – Faywang - MSFT Jun 29 '20 at 08:39

0 Answers0