I have a MainPage with a MainViewModel. The page consists of a ListView displaying a list of persons, and I want to show different views (templates) in a ContentControl depending on user actions. Specifically, when a user clicks on a ListView item, I want to display a view template for viewing the person's details. If the user clicks an "Edit" button, I want to display a template for editing the person's details. Finally, when the user clicks a "New" button, I want to display a template for creating a new person record.
How can I accomplish this in my PersonPage using WinUI 3?
I try with this code will show the text App1.Core.Models.Person
MainPage.xaml
<Page
x:Class="App1.Views.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"
xmlns:vm="using:App1.ViewModels"
xmlns:tm="using:App1.Templates"
xmlns:m="using:App1.Core.Models"
mc:Ignorable="d">
<Page.DataContext>
<vm:MainViewModel />
</Page.DataContext>
<Grid>
<Grid.Resources>
<DataTemplate x:Key="visitEmptyTemplate">
<StackPanel Orientation="Vertical" Background="Violet">
<TextBlock Text="Empty" Foreground="Violet"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="visitEditTemplate">
<StackPanel Background="blue">
<TextBlock Text="Edits" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{StaticResource SubtitleTextBlockStyle}" Foreground="Blue"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="visitNewTemplate">
<StackPanel Background="Green">
<TextBlock Text="News" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{StaticResource SubtitleTextBlockStyle}" Foreground="Green"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="visitViewTemplate" x:DataType="vm:MainViewModel">
<StackPanel Orientation="Vertical" Background="Indigo">
<TextBlock Text="{x:Bind SelectedPerson.Name, Mode=OneWay}" Foreground="Indigo"/>
<TextBox Text="Hello"/>
</StackPanel>
</DataTemplate>
<tm:VisitTemplateSelector
x:Key="visitTemplateSelector"
VisitEmptyTemplate="{StaticResource visitEmptyTemplate}"
VisitEditTemplate="{StaticResource visitEditTemplate}"
VisitNewTemplate="{StaticResource visitNewTemplate}"
VisitViewTemplate="{StaticResource visitViewTemplate}"/>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<CommandBar DefaultLabelPosition="Collapsed">
<AppBarButton x:Name="NewButton" Icon="Add" Command="{Binding NewVisitCommand}" />
<AppBarButton x:Name="EditButton" Icon="Edit" Command="{Binding EditVisitCommand}" />
</CommandBar>
<SplitView Grid.Row="1" IsPaneOpen="True" DisplayMode="Inline">
<SplitView.Pane>
<ListView
ItemsSource="{x:Bind ViewModel.PersonList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.SelectedPerson, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectionChanged="{x:Bind ViewModel.ListViewSelectionChanged}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="m:Person">
<Border>
<TextBlock Text="{x:Bind Name, Mode=OneWay}"/>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</SplitView.Pane>
<Grid>
<ContentControl x:Name="ContentView"
ContentTemplateSelector="{StaticResource visitTemplateSelector}"
Content="{x:Bind ViewModel.SelectedPerson, Mode=OneWay}" />
</Grid>
</SplitView>
</Grid>
</Page>
VisitTemplateSelector.cs
public class VisitTemplateSelector : DataTemplateSelector
{
public DataTemplate? VisitEditTemplate { get; set; }
public DataTemplate? VisitEmptyTemplate { get; set; }
public DataTemplate? VisitNewTemplate { get; set; }
public DataTemplate? VisitViewTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
if (item is MainViewModel mv)
{
if (mv.SelectedPerson is not null && mv.SelectedView == MainViewModel.ViewMode.Edit)
{
return VisitEditTemplate;
}
if (mv.SelectedPerson is null)
{
return VisitEmptyTemplate;
}
if (mv.SelectedPerson is null && mv.SelectedView == MainViewModel.ViewMode.New)
{
return VisitNewTemplate;
}
if (mv.SelectedPerson is not null && mv.SelectedView == MainViewModel.ViewMode.View)
{
return VisitViewTemplate;
}
}
return base.SelectTemplateCore(item, container);
}
}
MainViewModel.cs
public partial class MainViewModel : ObservableRecipient
{
public ObservableCollection<Person> PersonList { get; set; } = new ();
public enum ViewMode
{
Empty,
Edit,
New,
View,
}
[ObservableProperty]
ViewMode selectedView;
[ObservableProperty]
Person? selectedPerson;
public MainViewModel()
{
PersonList.Add(new Person() { Name = "Manoj Babu", Phone = "0123456789" });
PersonList.Add(new Person() { Name = "binoj Babu", Phone = "0987456321" });
PersonList.Add(new Person() { Name = "Athira Manoj", Phone = "0123456789" });
PersonList.Add(new Person() { Name = "Laksya Manoj", Phone = "0987456210" });
SelectedView = ViewMode.Empty;
SelectedPerson = null;
}
[RelayCommand]
void NewVisit()
{
SelectedPerson = new Person();
SelectedView = ViewMode.New;
}
[RelayCommand]
void EditVisit()
{
if (SelectedPerson is not null)
{
SelectedView = ViewMode.Edit;
}
}
public void ListViewSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (SelectedPerson is not null)
{
SelectedView = ViewMode.View;
}
}
}
The Result Preview enter image description here
This is one of the ways to achieve this.
Create ViewModels for each mode:
And in your MainViewModel:
Change your
TemplateSelector:Bind the ContentView to the TargetPerson: