Search code examples
c#data-bindingdatacontextwinui-3

How do I get the context of a UI element inside an ItemsRepeater in WinUI3


I'm developing an application using WinUI3 and C#. I want to add dynamic settings rendering for shortcuts into my application. Therefore I use an ItemsRepeater together with a DataTemplate to render multiple settings panels. This all seems to work.

XAML:

<Grid>
    <StackPanel Orientation="Vertical">
        <ItemsRepeater ItemsSource="{x:Bind _keyboardShortcuts}">
            <ItemsRepeater.ItemTemplate>
                <DataTemplate x:DataType="dmgmt:KeyboardShortcut">
                    <Border x:Name="bdrKeyboardShortcutBorder" Background="{ThemeResource SystemChromeMediumHighColor}" CornerRadius="10" Margin="10">
                        <Grid Margin="10" HorizontalAlignment="Stretch">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <TextBlock Grid.Column="0" Text="Execute Code" VerticalAlignment="Center"/>
                            <StackPanel Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Center" Orientation="Horizontal">
                                <ComboBox Width="150" Margin="10,0,10,0" ItemsSource="{x:Bind Path=dmgmt:KeyboardShortcut.AvailableVirtualKeyModifiers}" SelectionChanged="ComboBoxModifier_SelectionChanged" Loaded="ComboBoxModifier_Loaded"/>
                                <ComboBox Width="150" Margin="10,0,10,0" ItemsSource="{x:Bind Path=dmgmt:KeyboardShortcut.AvailableVirtualKeyCodes}" SelectionChanged="ComboBoxKey_SelectionChanged" Loaded="ComboBoxKey_Loaded"/>
                            </StackPanel>
                        </Grid>
                    </Border>
                </DataTemplate>
            </ItemsRepeater.ItemTemplate>
        </ItemsRepeater>
    </StackPanel>
</Grid>

Referenced C# List (private property in page class):

private List<KeyboardShortcut> _keyboardShortcuts { get; set; } = new()
{
    PyruxSettings.Keybinds.StartShortcut,
    PyruxSettings.Keybinds.StepShortcut,
    PyruxSettings.Keybinds.ResetShortcut,
    PyruxSettings.Keybinds.PeakGoalLayoutShortcut,
    PyruxSettings.Keybinds.SaveShortcut
};

Now I want to reference back to the original list item that triggered rendering the Element, in order to assign a default value to the combo-boxes. (i.e. get the shortcut the combobox belongs to).

The issue is that from my research you're supposed to use FrameworkElement.DataContext, i.e. ComboBox.DataContext or Border.DataContext.

However, on all child elements in the ItemsRepeater, the DataContext is simply null:

enter image description here

How do I go about referencing back to the original item/how do I make the datacontext actually have the appropriate value?


Solution

  • You can use the ItemsRepeater's ElementPrepared event:

    private void ItemsRepeater_ElementPrepared(ItemsRepeater sender, ItemsRepeaterElementPreparedEventArgs args)
    {
        if (args.Element is FrameworkElement element)
        {
            element.DataContext = _keyboardShortcuts[args.Index];
        }
    }