Reputation: 53
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"></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
Upvotes: 1
Views: 80