I'm trying to understand the details of WPF,but hit a stumbling block. I know that Selector is an abstract class that inherits from ItemsControl and adds the ability to select from its children. I know that ItemsControls have ItemTemplates that can set a child item's appearance and a panel that arranges those items. I know that there is often an ItemContainer that (at least in the case of a ListBoxItem) has an IsSelected property, which I believe can trigger the ListBox selection changed event (that might not be the right name).
What I absolutely can't figure out is, what changes the state of IsSelected internally? You click on an item, so there is probably a mouse down or preview mouse down or something...then a hit test?
I've been combing through ListBox, TabControl, and Selector source code at https://referencesource.microsoft.com/ trying to find the source of the click...is it on the panel? Is there some outside source? Do I have a fundamental misunderstanding of what's going on here?
ListBoxItem has overridden OnMouseLeftButtonDown
and OnMouseRightButtonDown
methods that call a private HandleMouseButtonDown
method, which in turn calls an internal NotifyListItemClicked
method of the ListBox class, which finally sets the item's IsSelected
property.
Copied from the reference source:
internal void NotifyListItemClicked(ListBoxItem item, MouseButton mouseButton)
{
// When a ListBoxItem is left clicked, we should take capture
// so we can auto scroll through the list.
if (mouseButton == MouseButton.Left && Mouse.Captured != this)
{
Mouse.Capture(this, CaptureMode.SubTree);
SetInitialMousePosition(); // Start tracking mouse movement
}
switch (SelectionMode)
{
case SelectionMode.Single:
{
if (!item.IsSelected)
{
item.SetCurrentValueInternal(IsSelectedProperty, BooleanBoxes.TrueBox);
}
else if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
item.SetCurrentValueInternal(IsSelectedProperty, BooleanBoxes.FalseBox);
}
UpdateAnchorAndActionItem(ItemInfoFromContainer(item));
}
break;
case SelectionMode.Multiple:
MakeToggleSelection(item);
break;
case SelectionMode.Extended:
// Extended selection works only with Left mouse button
if (mouseButton == MouseButton.Left)
{
if ((Keyboard.Modifiers & (ModifierKeys.Control | ModifierKeys.Shift)) == (ModifierKeys.Control | ModifierKeys.Shift))
{
MakeAnchorSelection(item, false);
}
else if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
MakeToggleSelection(item);
}
else if ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)
{
MakeAnchorSelection(item, true);
}
else
{
MakeSingleSelection(item);
}
}
else if (mouseButton == MouseButton.Right) // Right mouse button
{
// Shift or Control combination should not trigger any action
// If only Right mouse button is pressed we should move the anchor
// and select the item only if element under the mouse is not selected
if ((Keyboard.Modifiers & (ModifierKeys.Control | ModifierKeys.Shift)) == 0)
{
if (item.IsSelected)
UpdateAnchorAndActionItem(ItemInfoFromContainer(item));
else
MakeSingleSelection(item);
}
}
break;
}
}