frochet38
Topic Author
Posts: 13
Joined: 14 Jun 2020, 11:14

ListBox Code behind SetSelected called only when selecting item with right mouse button

24 Jul 2020, 15:37

Hi,

I'm trying to make a ListBox containing some custom items with a ViewModel code-behind.
My code and XAML are quite similar to the QuestLog Noesis sample, but I got that very strange behaviour:

My property for selecting the current listbox item is called only when clicking on right mouse button, left mouse button does nothing. and I don't understand why.

Here is my listBox on XAML side :

   <ControlTemplate x:Key="Car4LooksItemTemplate" TargetType="{x:Type ListBoxItem}">
        <StackPanel Orientation="Vertical">
            <Button Width="130" Height="137" Foreground="Red" BorderBrush="Red" Background="#80F2F2F2" Opacity="1.0" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Center" HorizontalAlignment="Center">
                <StackPanel Width="116" Height="134" Background="{StaticResource BandeauColor}" Orientation="Horizontal" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                    <Canvas Width="85" Height="130" Background="{StaticResource BandeauColor}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                        <Rectangle Width="14" Height="14" Canvas.Left="-25" Fill="{Binding DefaultColor}" Stroke="{Binding DefaultColor}" StrokeThickness="0" Margin="90,19,0,0" />
                            <Viewbox Width="85" Height="95" Canvas.Top="17">
                            <Image Source="{Binding Image}" RenderTransformOrigin="0.5,0.5">
                                <Image.RenderTransform>
                                    <TransformGroup>
                                        <ScaleTransform/>
                                        <SkewTransform/>
                                        <RotateTransform Angle="270"/>
                                        <TranslateTransform/>
                                    </TransformGroup>
                                </Image.RenderTransform>
                            </Image>
                        </Viewbox>
                    </Canvas>
                    <TextBlock Text="{Binding Name}" TextAlignment="Center" Width="100" Height="12" Margin="-40,0,0,0" FontSize="10" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="#FF000000" Background="#00000000" FontWeight="Bold" TextTrimming="CharacterEllipsis">
                        <TextBlock.RenderTransform>
                            <TransformGroup>
                                <ScaleTransform/>
                                <SkewTransform/>
                                <RotateTransform Angle="270"/>
                            </TransformGroup>
                        </TextBlock.RenderTransform>
                    </TextBlock>
                    <TextBlock Text="{Binding Number}" TextAlignment="Center" Width="100" Height="13" Margin="-85,0,0,0" FontSize="11" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="#FF808080" Background="#00000000" FontWeight="Bold">
                        <TextBlock.RenderTransform>
                            <TransformGroup>
                                <ScaleTransform/>
                                <SkewTransform/>
                                <RotateTransform Angle="270"/>
                            </TransformGroup>
                        </TextBlock.RenderTransform>
                    </TextBlock>
                </StackPanel>
            </Button>
            <Rectangle Fill="Black" Margin="0,0,0,0" Stroke="Black" Width="70" Height="2" HorizontalAlignment="Center" />
        </StackPanel>

		</ControlTemplate>
        <Style x:Key="Car4LooksItemStyle" TargetType="{x:Type ListBoxItem}">
        <Setter Property="Focusable" Value="False"/>
        <Setter Property="Template" Value="{StaticResource Car4LooksItemTemplate}"/>
        </Style>
		
    <ControlTemplate x:Key="Template.ListBox" TargetType="ListBox">
        <ScrollViewer Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" Focusable="False">
            <ItemsPresenter />
        </ScrollViewer>
    </ControlTemplate>

    <Style x:Key="Car4LooksListStyle" TargetType="{x:Type ListBox}">
        <Setter Property="SelectionMode" Value="Single"/>
        <Setter Property="ScrollViewer.CanContentScroll" Value="True"/>
        <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden"/>
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden"/>
        <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
        <Setter Property="VirtualizingPanel.VirtualizationMode" Value="Recycling"/>
        <Setter Property="VirtualizingPanel.ScrollUnit" Value="Pixel"/>
        <Setter Property="KeyboardNavigation.DirectionalNavigation" Value="Contained"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>

        <Setter Property="Template" Value="{StaticResource Template.ListBox}"/>
    </Style>

	(...)
	
	<ListBox x:Name="TopLeftMakeupSelector" 
                         Style="{StaticResource Car4LooksListStyle}"
                         ItemContainerStyle="{StaticResource Car4LooksItemStyle}" 
                         ItemsSource="{Binding LooksTopLeft}"
                         SelectedItem="{Binding SelectedLookTopLeft}"
                         DisplayMemberPath="Name" 
                         Height="540"
                         Width="136">
                </ListBox>
And here is my ViewModel implementation (simplified) :

////////////////////////////////////////////////////////////////////////////////////////////////////
struct ViewModel::Look : public BaseComponent
{
public:
	String Name;
	Ptr<ImageSource> Image;
	String Number;
	String Description;
	Ptr<Brush> DefaultColor;

private:
	NS_IMPLEMENT_INLINE_REFLECTION(Look, BaseComponent)
	{
		NsProp("Name", &Look::Name);
		NsProp("Image", &Look::Image);
		NsProp("Number", &Look::Number);
		NsProp("Description", &Look::Description);
		NsProp("DefaultColor", &Look::DefaultColor);
	}
};

ViewModel::ViewModel()
{
	_LooksTopLeft = *new ObservableCollection<Look>();

	Ptr<ImageSource> image0 = *new BitmapImage("5eac6aeea60a650017b21177-compressed.png");
	Ptr<ImageSource> image1 = *new BitmapImage("5eac6b63a60a650017b211af-compressed.png");

	Ptr<Brush> color0 = *new SolidColorBrush(Color::Red);
	Ptr<Brush> color1 = *new SolidColorBrush(Color::Green);

	{
		Ptr<Look> q = *new Look();
		q->Name = "EYES TO KILL";
		q->Image = image0;
		q->Description = "Ldolor ac leo convallis";
		q->Number = "12";
		q->DefaultColor = color0;

		_LooksTopLeft->Add(q);
	}
	{
		Ptr<Look> q = *new Look();
		q->Name = "NEO NUDE BLUSH";
		q->Image = image1;
		q->Description = "Nullam volutpat felis";
		q->Number = "26";
		q->DefaultColor = color1;

		_LooksTopLeft->Add(q);
	}
	_selectedLookTopLeft = _LooksTopLeft->Get(0);
}

(...)

////////////////////////////////////////////////////////////////////////////////////////////////////
void ViewModel::SetSelectedLookTopLeft(Look* value)
{
	if (_selectedLookTopLeft != value)
	{
		_selectedLookTopLeft = value;
		OnPropertyChanged("SelectedLookTopLeft");
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
ViewModel::Look* ViewModel::GetSelectedLookTopLeft() const
{
	return _selectedLookTopLeft;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
NS_BEGIN_COLD_REGION

NS_IMPLEMENT_REFLECTION(ViewModel)
{
	NsProp("LooksTopLeft", &ViewModel::_LooksTopLeft);
	NsProp("SelectedLookTopLeft", &ViewModel::GetSelectedLookTopLeft, &ViewModel::SetSelectedLookTopLeft);
}

Where the ViewModel deelecration is (also simoplified) :
class ViewModel : public NoesisApp::NotifyPropertyChangedBase
{
public:
    ViewModel();

private:
	struct Look;

	void SetSelectedLookTopLeft(Look* value);
	Look* GetSelectedLookTopLeft() const;

	Noesis::Ptr<Noesis::ObservableCollection<Look>> _LooksTopLeft;
	Look* _selectedLookTopLeft;
NS_DECLARE_REFLECTION(ViewModel, NotifyPropertyChangedBase)
};
When i set a breakpoint in the SetSelectedLookTopLeft method, if I left click on a listbox item, nothing happens, if I right click on the item, it's selected and the breakpoint is reached.
What can I do to be able to select items on left mouse click ??

Thanks a lot,

Frank
 
User avatar
sfernandez
Site Admin
Posts: 2984
Joined: 22 Dec 2011, 19:20

Re: ListBox Code behind SetSelected called only when selecting item with right mouse button

27 Jul 2020, 20:48

You defined a ListBoxItem template that consists of a Button covering the entire item space, so everytime you click on the item you are clicking the Button, not selecting the ListBoxItem.
When you right-click on the item the Button is not handling the event (Click is only raised on left-clicks) and it reaches the ListBoxItem, so then it gets selected.

Is there any reason why you need to have a Button as the template for the ListBoxItem?
 
frochet38
Topic Author
Posts: 13
Joined: 14 Jun 2020, 11:14

Re: ListBox Code behind SetSelected called only when selecting item with right mouse button

29 Jul 2020, 09:40

Hi sfernandez,

You're completely right, when replacing the button by a stack panel, I get the code-behind methods called, but I loose the "button pressing effect" when I select an item.
I suppose I can get back the effect by using some trigger-based field, but, as I'm a begginer in XAML, and using a button was a convinient shortcut to get this effect for me.
I will try to get back the pressing effect using some triggering code.

Thanks
 
User avatar
sfernandez
Site Admin
Posts: 2984
Joined: 22 Dec 2011, 19:20

Re: ListBox Code behind SetSelected called only when selecting item with right mouse button

29 Jul 2020, 11:38

The ListBoxItem template can (should) have triggers (or visual states) to represent the different states of the control: IsMouseOver, IsSelected, IsFocused...

For example, our ListBoxItem template does the following: https://github.com/Noesis/Managed/blob/ ... 1788-L1807
 
frochet38
Topic Author
Posts: 13
Joined: 14 Jun 2020, 11:14

Re: ListBox Code behind SetSelected called only when selecting item with right mouse button

29 Jul 2020, 12:10

Thanks,
It seems I have some control using triggers like the ones your're pointing out.
Nevertheless, I'd like to simulate a "button pushed" status when the user is cliking on an item, and I can't find a property I can use with a trigger like "IsMouseCliked" telling the user is left clicking on the item. Is there one ?
 
User avatar
sfernandez
Site Admin
Posts: 2984
Joined: 22 Dec 2011, 19:20

Re: ListBox Code behind SetSelected called only when selecting item with right mouse button

29 Jul 2020, 13:06

ListBoxItem does not provide an IsPressed property, but you can use an EventTrigger with MouseDown/MouseUp events to fire an animation that can change the appearance accordingly.
 
frochet38
Topic Author
Posts: 13
Joined: 14 Jun 2020, 11:14

Re: ListBox Code behind SetSelected called only when selecting item with right mouse button

29 Jul 2020, 17:21

I finally made this work using :
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseDown" >
                        <ei:ChangePropertyAction PropertyName="Background" Value="{DynamicResource Brush.Item.Over}"/>
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseUp" >
                        <ei:ChangePropertyAction PropertyName="Background" Value="{DynamicResource Brush.Item.UnSelected}"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
Thanks a lot for the help
 
User avatar
sfernandez
Site Admin
Posts: 2984
Joined: 22 Dec 2011, 19:20

Re: ListBox Code behind SetSelected called only when selecting item with right mouse button

29 Jul 2020, 22:13

You're welcome, marking this as solved.

Who is online

Users browsing this forum: Google [Bot] and 3 guests