Page 1 of 1

ItemsControl in Listbox breaks Selection

Posted: 01 Apr 2020, 08:37
by rmcq
Hi team,

I've got a Listbox populating from a DataTemplate. Inside this Data Template is an ItemsControl.
The ItemsControl has a DataTemplate containing a Canvas with an Ellipse and Textblock. The Canvas positions are databound so we can position them dynamically.
The Listbox contains 5 items. Only 1 of these (the far right) populates the ItemsControl. The others leave it empty. I have bool to show / hide each of these.
Jump into Native and I populate the data. When I run the game, it looks correct visually but I'm no longer able to scroll left/right to select items in the Listbox.
When I comment out the ItemsControl I can select stuff again.

------

Things I've tried:
- Adding gamepad triggers for Left/Right. I already had these for Up/Down. When I add a breakpoint, Up/Down still get hit but Left/Right don't.
- Adding a DataTemplateSelector so that only the last ListBoxItem has an ItemsControl. I was following the code from this post but breakpoints in the constructor and bound functions never seem to get hit:
viewtopic.php?f=3&t=663&hilit=datatempl ... t=10#p3706
I thought may I need to register it as a component like our extensions but that didn't help either.

------

XAML (before DataTemplateSelector):
<Grid
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
	xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
	xmlns:local="clr-namespace:MatchSettings"
	xmlns:noesis="clr-namespace:NoesisGUIExtensions;assembly=Noesis.GUI.Extensions"
	xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" x:Name="RootGrid" Focusable="True"
	mc:Ignorable="d"
	d:DataContext="{d:DesignInstance {x:Type local:MatchSettingsVM}, IsDesignTimeCreatable=True}"
>
	<Grid.DataContext>
		<local:MatchSettingsVM/>
	</Grid.DataContext>

	<Grid.Resources>
		<DataTemplate x:Key="MatchSettingsTemplate">
			<Grid>
				<Grid Height="328" Width="204" Margin="0,-200,9,0" Visibility="{Binding IconIsVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
					<ItemsControl
						ItemsSource="{Binding Players}"
					>
						<ItemsControl.ItemTemplate>
							<DataTemplate>
								<Canvas>
									<Grid Height="42" Width="42" Canvas.Left="{Binding XPos}" Canvas.Top="{Binding YPos}">
										<Ellipse Stroke="White">
											<Ellipse.Fill>
												<SolidColorBrush Color="{Binding Colour}"/>
											</Ellipse.Fill>
										</Ellipse>
										<TextBlock TextWrapping="Wrap" FontSize="24" TextAlignment="Center" Text="{Binding Label}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
									</Grid>
								</Canvas>
							</DataTemplate>
						</ItemsControl.ItemTemplate>
					</ItemsControl>
				</Grid>
			</Grid>
		</DataTemplate>
    </Grid.Resources>
	<Viewbox>
		<Grid Width="1920" Height="1080">
			<Viewbox x:Name="viewbox" Stretch="Fill" RenderTransformOrigin="0.5,0.5">
				<Viewbox.RenderTransform>
					<TransformGroup>
						<ScaleTransform/>
						<SkewTransform/>
						<RotateTransform/>
						<TranslateTransform/>
					</TransformGroup>
				</Viewbox.RenderTransform>
				<Grid Height="1080" Width="1920">
					<Grid Grid.Column="0">
						<Grid.ColumnDefinitions>
							<ColumnDefinition Width="*"/>
						</Grid.ColumnDefinitions>
						<Grid.RowDefinitions>
							<RowDefinition Height="130*"/>
							<RowDefinition Height="820*"/>
							<RowDefinition Height="130*"/>
						</Grid.RowDefinitions>

						<Grid Grid.Row="1" Margin="253.25,72.25,256.75,12.75">
							<Grid.ColumnDefinitions>
								<ColumnDefinition Width="*"/>
							</Grid.ColumnDefinitions>
							<Grid.RowDefinitions>
								<RowDefinition Height="*"/>
							</Grid.RowDefinitions>

							<Grid Margin="5,0,0,0">
								<Viewbox Margin="0,0,3,0">
									<ListBox x:Name="MatchSettingsGrid"
										ItemsSource="{Binding MatchSettingsList}"
										SelectedItem="{Binding SelectedItem, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
										SelectedIndex="{Binding SelectedIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
										ScrollViewer.HorizontalScrollBarVisibility="Disabled"
										ScrollViewer.VerticalScrollBarVisibility="Disabled"
										ItemTemplate="{StaticResource MatchSettingsTemplate}"
										Focusable="True"
										Background="Transparent"
										BorderBrush="Transparent"
										KeyboardNavigation.ControlTabNavigation="None" RenderTransformOrigin="0.5,0.5"
									>
										<ListBox.RenderTransform>
											<TransformGroup>
												<ScaleTransform/>
												<SkewTransform/>
												<RotateTransform/>
												<TranslateTransform/>
											</TransformGroup>
										</ListBox.RenderTransform>
										<ListBox.ItemsPanel>
											<ItemsPanelTemplate>
												<UniformGrid Rows="1" />
											</ItemsPanelTemplate>
										</ListBox.ItemsPanel>
									</ListBox>
								</Viewbox>
							</Grid>
						</Grid>
					</Grid>
				</Grid>
			</Viewbox>
		</Grid>
	</Viewbox>
	<i:Interaction.Triggers>
        <i:EventTrigger EventName="GotFocus">
            <ei:PlaySoundAction Source="scroll" Volume="1.0"/>
        </i:EventTrigger>
        <i:EventTrigger EventName="Loaded">
            <noesis:SetFocusAction TargetName="MatchSettingsGrid"/>
            <i:InvokeCommandAction Command="{Binding FindStoryboardsCommand}" />
        </i:EventTrigger>
        <noesis:GamepadTrigger FiredOn="ButtonDown" Button="Accept">
            <ei:PlaySoundAction Source="select" Volume="1.0"/>
            <i:InvokeCommandAction Command="{Binding CommandForward}"/>
        </noesis:GamepadTrigger>
        <noesis:GamepadTrigger FiredOn="ButtonDown" Button="Cancel">
            <ei:PlaySoundAction Source="select" Volume="1.0"/>
            <i:InvokeCommandAction Command="{Binding CommandBack}"/>
        </noesis:GamepadTrigger>
        <noesis:GamepadTrigger FiredOn="ButtonDown" Button="Up">
            <ei:PlaySoundAction Source="slider" Volume="1.0"/>
            <i:InvokeCommandAction Command="{Binding CommandKeyUp}"/>
        </noesis:GamepadTrigger>
        <noesis:GamepadTrigger FiredOn="ButtonDown" Button="Down">
            <ei:PlaySoundAction Source="slider" Volume="1.0"/>
            <i:InvokeCommandAction Command="{Binding CommandKeyDown}"/>
        </noesis:GamepadTrigger>
		<noesis:GamepadTrigger FiredOn="ButtonDown" Button="Left">
			<ei:PlaySoundAction Source="slider" Volume="1.0"/>
			<i:InvokeCommandAction Command="{Binding CommandKeyLeft`}"/>
		</noesis:GamepadTrigger>
		<noesis:GamepadTrigger FiredOn="ButtonDown" Button="Right">
			<ei:PlaySoundAction Source="slider" Volume="1.0"/>
			<i:InvokeCommandAction Command="{Binding CommandKeyRight`}"/>
		</noesis:GamepadTrigger>
	</i:Interaction.Triggers>
    <Grid.InputBindings>
        <KeyBinding Key="Esc" Command="{Binding CommandBack}"/>
        <KeyBinding Key="Enter" Command="{Binding CommandForward}"/>
    </Grid.InputBindings>
</Grid>
XAML (after DataTemplateSelector):

<Grid
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
	xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
	xmlns:local="clr-namespace:MatchSettings"
	xmlns:dt="clr-namespace:DataTemplates"
	xmlns:noesis="clr-namespace:NoesisGUIExtensions;assembly=Noesis.GUI.Extensions"
	xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" x:Name="RootGrid" Focusable="True"
	mc:Ignorable="d"
	d:DataContext="{d:DesignInstance {x:Type local:MatchSettingsVM}, IsDesignTimeCreatable=True}"
>
	<Grid.DataContext>
		<local:MatchSettingsVM/>
	</Grid.DataContext>

	<Grid.Resources>
		<DataTemplate x:Key="MatchSettingsTemplate">
			...
		 </DataTemplate>

		<DataTemplate x:Key="MatchSettingsIconTemplate">
			<Grid>
				<Grid Height="328" Width="204" Margin="0,-200,9,0" Visibility="{Binding IconIsVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
					<ItemsControl
						ItemsSource="{Binding Players}"
					>
						<ItemsControl.ItemTemplate>
							<DataTemplate>
								<Canvas>
									<Grid Height="42" Width="42" Canvas.Left="{Binding XPos}" Canvas.Top="{Binding YPos}">
										<Ellipse Stroke="White">
											<Ellipse.Fill>
												<SolidColorBrush Color="{Binding Colour}"/>
											</Ellipse.Fill>
										</Ellipse>
										<TextBlock TextWrapping="Wrap" FontSize="24" TextAlignment="Center" Text="{Binding Label}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
									</Grid>
								</Canvas>
							</DataTemplate>
						</ItemsControl.ItemTemplate>
					</ItemsControl>
				</Grid>
			</Grid>
		</DataTemplate>

		<dt:MatchSettingsTemplateSelector x:Key="matchSettingsTemplateSelector" 
			MatchSettingsTemplate="{StaticResource MatchSettingsTemplate}" 
			MatchSettingsIconTemplate="{StaticResource MatchSettingsIconTemplate}"
		/>

    </Grid.Resources>

	<Viewbox>
		<Grid Width="1920" Height="1080">
			<Viewbox x:Name="viewbox" Stretch="Fill" RenderTransformOrigin="0.5,0.5">
				<Viewbox.RenderTransform>
					<TransformGroup>
						<ScaleTransform/>
						<SkewTransform/>
						<RotateTransform/>
						<TranslateTransform/>
					</TransformGroup>
				</Viewbox.RenderTransform>
				<Grid Height="1080" Width="1920">
					<Grid Grid.Column="0">
						<Grid.ColumnDefinitions>
							<ColumnDefinition Width="*"/>
						</Grid.ColumnDefinitions>
						<Grid.RowDefinitions>
							<RowDefinition Height="130*"/>
							<RowDefinition Height="820*"/>
							<RowDefinition Height="130*"/>
						</Grid.RowDefinitions>
						<Grid Grid.Row="1" Margin="253.25,72.25,256.75,12.75">
							<Grid.ColumnDefinitions>
								<ColumnDefinition Width="*"/>
							</Grid.ColumnDefinitions>
							<Grid.RowDefinitions>
								<RowDefinition Height="*"/>
							</Grid.RowDefinitions>

							<Grid Margin="5,0,0,0">
								<Viewbox Margin="0,0,3,0">
									<ListBox x:Name="MatchSettingsGrid"
										ItemsSource="{Binding MatchSettingsList}"
										SelectedItem="{Binding SelectedItem, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
										SelectedIndex="{Binding SelectedIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
										ScrollViewer.HorizontalScrollBarVisibility="Disabled"
										ScrollViewer.VerticalScrollBarVisibility="Disabled"
										ItemTemplateSelector="{StaticResource matchSettingsTemplateSelector}"
										Focusable="True"
										Background="Transparent"
										BorderBrush="Transparent"
										KeyboardNavigation.ControlTabNavigation="None" RenderTransformOrigin="0.5,0.5"
									>
										<ListBox.RenderTransform>
											<TransformGroup>
												<ScaleTransform/>
												<SkewTransform/>
												<RotateTransform/>
												<TranslateTransform/>
											</TransformGroup>
										</ListBox.RenderTransform>
										<ListBox.ItemsPanel>
											<ItemsPanelTemplate>
												<UniformGrid Rows="1" />
											</ItemsPanelTemplate>
										</ListBox.ItemsPanel>
									</ListBox>
								</Viewbox>
							</Grid>
						</Grid>
					</Grid>
				</Grid>
			</Viewbox>
		</Grid>
	</Viewbox>
	<i:Interaction.Triggers>
        <i:EventTrigger EventName="GotFocus">
            <ei:PlaySoundAction Source="scroll" Volume="1.0"/>
        </i:EventTrigger>
        <i:EventTrigger EventName="Loaded">
            <noesis:SetFocusAction TargetName="MatchSettingsGrid"/>
            <i:InvokeCommandAction Command="{Binding FindStoryboardsCommand}" />
        </i:EventTrigger>
        <noesis:GamepadTrigger FiredOn="ButtonDown" Button="Accept">
            <ei:PlaySoundAction Source="select" Volume="1.0"/>
            <i:InvokeCommandAction Command="{Binding CommandForward}"/>
        </noesis:GamepadTrigger>
        <noesis:GamepadTrigger FiredOn="ButtonDown" Button="Cancel">
            <ei:PlaySoundAction Source="select" Volume="1.0"/>
            <i:InvokeCommandAction Command="{Binding CommandBack}"/>
        </noesis:GamepadTrigger>
        <noesis:GamepadTrigger FiredOn="ButtonDown" Button="Up">
            <ei:PlaySoundAction Source="slider" Volume="1.0"/>
            <i:InvokeCommandAction Command="{Binding CommandKeyUp}"/>
        </noesis:GamepadTrigger>
        <noesis:GamepadTrigger FiredOn="ButtonDown" Button="Down">
            <ei:PlaySoundAction Source="slider" Volume="1.0"/>
            <i:InvokeCommandAction Command="{Binding CommandKeyDown}"/>
        </noesis:GamepadTrigger>
    </i:Interaction.Triggers>
    <Grid.InputBindings>
        <KeyBinding Key="Esc" Command="{Binding CommandBack}"/>
        <KeyBinding Key="Enter" Command="{Binding CommandForward}"/>
    </Grid.InputBindings>
</Grid>
DataTemplateSelector header
#pragma once
#include "NsGui/DataTemplateSelector.h"

namespace Noesis
{
	class DataTemplate;
	class DependencyObject;
}

namespace paNoesisExtensions
{
	class paMatchSettingsTemplateSelector : public Noesis::DataTemplateSelector
	{
		public:
		paMatchSettingsTemplateSelector();
		virtual Noesis::DataTemplate* SelectTemplate(BaseComponent* item, Noesis::DependencyObject* container) override;
		NS_DECLARE_REFLECTION(paMatchSettingsTemplateSelector, Noesis::DataTemplateSelector)

		Noesis::DataTemplate* GetMatchSettingsTemplate() const;
		void SetMatchSettingsTemplate(Noesis::DataTemplate* dataTemplate);

		private:
		Noesis::Ptr<Noesis::DataTemplate> m_matchSettingsTemplate;
		Noesis::Ptr<Noesis::DataTemplate> m_matchSettingsIconTemplate;

	};
}
DataTemplateSelector source
#include "pch.h"
#include "paMatchSettingsTemplateSelector.h"
#include "NsGui/DataTemplate.h"
#include "NsGui/DependencyObject.h"

paNoesisExtensions::paMatchSettingsTemplateSelector::paMatchSettingsTemplateSelector()
{
	m_matchSettingsTemplate = Noesis::MakePtr<Noesis::DataTemplate>();
	m_matchSettingsIconTemplate = Noesis::MakePtr<Noesis::DataTemplate>();
}

Noesis::DataTemplate* paNoesisExtensions::paMatchSettingsTemplateSelector::SelectTemplate(BaseComponent* item, Noesis::DependencyObject* container)
{
	return m_matchSettingsTemplate;
}

Noesis::DataTemplate* paNoesisExtensions::paMatchSettingsTemplateSelector::GetMatchSettingsTemplate() const
{
	return m_matchSettingsTemplate;
}

void paNoesisExtensions::paMatchSettingsTemplateSelector::SetMatchSettingsTemplate(Noesis::DataTemplate* dataTemplate)
{
	m_matchSettingsTemplate.Reset(dataTemplate);
}

//-----------------------------

NS_BEGIN_COLD_REGION

NS_IMPLEMENT_REFLECTION(paNoesisExtensions::paMatchSettingsTemplateSelector)
{
	NsMeta<Noesis::TypeId>("MatchSettingsTemplateSelector");
	NsProp("MatchSettingsTemplate", &paNoesisExtensions::paMatchSettingsTemplateSelector::GetMatchSettingsTemplate, &paNoesisExtensions::paMatchSettingsTemplateSelector::SetMatchSettingsTemplate);
	NsProp("MatchSettingsIconTemplate", &paNoesisExtensions::paMatchSettingsTemplateSelector::m_matchSettingsIconTemplate);
}
------

Any help would be appreciated.

Thank you,
R

Re: ItemsControl in Listbox breaks Selection

Posted: 08 Apr 2020, 09:59
by rmcq
Hey, sorry for the bump. It's been a week. Do you have any ideas or need any more info from me?

Re: ItemsControl in Listbox breaks Selection

Posted: 08 Apr 2020, 12:08
by sfernandez
Hey, sorry for the bump. It's been a week. Do you have any ideas or need any more info from me?
My sorry, we should have answered sooner.
The Listbox contains 5 items. Only 1 of these (the far right) populates the ItemsControl. The others leave it empty. I have bool to show / hide each of these.
Jump into Native and I populate the data. When I run the game, it looks correct visually but I'm no longer able to scroll left/right to select items in the Listbox.
When I comment out the ItemsControl I can select stuff again.
When you say scroll left/right I guess you mean moving the selection (focus) between ListBox items, right?
Have you tried to make the ItemsControl Focusable="False", so keyboard focus doesn't stop on that inner control?
Adding gamepad triggers for Left/Right. I already had these for Up/Down. When I add a breakpoint, Up/Down still get hit but Left/Right don't.
If this was a problem with the focus, gamepad triggers wouldn't work either.
Adding a DataTemplateSelector so that only the last ListBoxItem has an ItemsControl. I was following the code from this post but breakpoints in the constructor and bound functions never seem to get hit: viewtopic.php?f=3&t=663&hilit=datatempl ... t=10#p3706
I thought may I need to register it as a component like our extensions but that didn't help either.
This should work fine once you register your DataTemplateSelector in the factory (so parser could create it).
Have you noticed if there was an error while loading that xaml saying: "Unknown type 'DataTemplates.MatchSettingsTemplateSelector'"?
Maybe you forgot to add the NsMeta<TypeId>("DataTemplates.MatchSettingsTemplateSelector") in the reflection block of that class.

Re: ItemsControl in Listbox breaks Selection

Posted: 14 Apr 2020, 05:57
by rmcq
Wow I feel like a dumb-dumb. All I needed was the Focusable="False". Thanks for the answers.

Re: ItemsControl in Listbox breaks Selection

Posted: 14 Apr 2020, 14:49
by jsantos
Thanks, closing this.