Search code examples
c#.netxamlwinui-3

How can i bind to my viewModel inside my ItemTemplate?


<ItemsRepeater
    x:Name="ChannelList"
    ItemsSource="{x:Bind ViewModel.ChannelSource}">
    <DataTemplate x:Name="ChannelTemplate">
        <Border
            Margin="0,0,0,10"
            BorderBrush="LightGray"
            BorderThickness="1">
            <StackPanel
                Orientation="Horizontal"
                Margin="10"
                Spacing="20">
                <!--content-->
                <TextBlock
                    Grid.Row="0"
                    Grid.ColumnSpan="2"
                    HorizontalAlignment="Center"> 
                    <Run Text="Kanal: " />
                    <Run Text="{Binding ChannelId}" />
                </TextBlock>
                <Button
                    Grid.Column="0"
                    Grid.Row="1"
                    HorizontalAlignment="Left"
                    Content="Start" />
                <Button
                    Grid.Column="1"
                    Grid.Row="1"
                    HorizontalAlignment="Right"
                    Content="Stop" />
                <Button
                    Grid.Row="2"
                    Grid.ColumnSpan="2"
                    HorizontalAlignment="Center"
                    Content="Kanal Entfernen"
                    Command="{Binding ??}" />
            </StackPanel>
        </Border>
    </DataTemplate>
</ItemsRepeater>

I wanted to bind inside my item template, but i could not figure out how to do this. Normal x:Bind or Binding does not work. Any suggestions?


Solution

  • This is a known issue with ItemsRepeaters. But lucky for us, there's a workaround.

    I'm sure that this will be fixed someday but for the moment:

    using CommunityToolkit.Mvvm.ComponentModel;
    using CommunityToolkit.Mvvm.Input;
    using System.Collections.ObjectModel;
    
    namespace WinUI3App;
    
    public partial class Channel : ObservableObject
    {
        [ObservableProperty]
        private int channelId;
    
        public ViewModel? Parent { get; set; }
    }
    
    public partial class ViewModel : ObservableObject
    {
        [ObservableProperty]
        private ObservableCollection<Channel> channelSource = new();
    
        public ViewModel()
        {
            channelSource.Add(new Channel { ChannelId = 1, Parent = this });
            channelSource.Add(new Channel { ChannelId = 2, Parent = this });
            channelSource.Add(new Channel { ChannelId = 3, Parent = this });
        }
    
        [RelayCommand]
        private void RemoveChannel(Channel channel)
        {
            ChannelSource.Remove(channel);
        }
    }
    

    Note: You can use x:Bind by setting x:DataType of DataTemplate.

    <Page
        x:Class="WinUI3App.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:local="using:WinUI3App"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
        mc:Ignorable="d">
        <Grid>
            <ItemsRepeater
                x:Name="ChannelList"
                ItemsSource="{x:Bind ViewModel.ChannelSource}">
                <DataTemplate
                    x:Name="ChannelTemplate"
                    x:DataType="local:Channel">
                    <Border
                        Margin="0,0,0,10"
                        BorderBrush="LightGray"
                        BorderThickness="1">
                        <StackPanel
                            Margin="10"
                            Orientation="Horizontal"
                            Spacing="20">
                            <!--  content  -->
                            <TextBlock
                                Grid.Row="0"
                                Grid.ColumnSpan="2"
                                HorizontalAlignment="Center">
                                <Run Text="Kanal: " />
                                <Run Text="{x:Bind ChannelId}" />
                            </TextBlock>
                            <Button
                                Grid.Row="1"
                                Grid.Column="0"
                                HorizontalAlignment="Left"
                                Content="Start" />
                            <Button
                                Grid.Row="1"
                                Grid.Column="1"
                                HorizontalAlignment="Right"
                                Content="Stop" />
                            <Button
                                Grid.Row="2"
                                Grid.ColumnSpan="2"
                                HorizontalAlignment="Center"
                                Command="{x:Bind Parent.RemoveChannelCommand}"
                                CommandParameter="{x:Bind}"
                                Content="Kanal Entfernen" />
                        </StackPanel>
                    </Border>
                </DataTemplate>
            </ItemsRepeater>
        </Grid>
    </Page>
    

    BTW, if you can use ListView or GridView instead of ItemsRepeater, you could do it this way.