Rework ListViewItemData and RowData members

Improve UI updates due to unnecessary color and selection changes of menus' lists
Fix selection when going back to previous menu via key
This commit is contained in:
Peter Kirmeier 2023-05-09 00:19:29 +02:00
parent 14d0896419
commit bb198a32db
6 changed files with 109 additions and 131 deletions

View file

@ -183,14 +183,9 @@ namespace SystemTrayMenu.Handler
{ {
if (menu != null && itemData != null) if (menu != null && itemData != null)
{ {
ListView dgv = menu.GetDataGridView(); itemData.IsClicking = false;
if (dgv.SelectedItems.Contains(itemData))
{
dgv.SelectedItems.Remove(itemData);
}
itemData.data.IsSelected = false; menu.GetDataGridView().SelectedItems.Remove(itemData);
itemData.data.IsClicking = false;
} }
} }
@ -200,7 +195,7 @@ namespace SystemTrayMenu.Handler
Menu? menuBefore; Menu? menuBefore;
ListViewItemData? rowBefore = focussedRow; ListViewItemData? rowBefore = focussedRow;
bool doClearOldSelection = false; bool doClearOldSelection = false;
bool wasSelected = focussedRow?.data.IsSelected ?? false; bool wasSelected = focussedRow?.IsSelected ?? false;
if (wasSelected) if (wasSelected)
{ {
@ -220,9 +215,9 @@ namespace SystemTrayMenu.Handler
if ((modifiers == ModifierKeys.None) && rowBefore != null && menuBefore != null) if ((modifiers == ModifierKeys.None) && rowBefore != null && menuBefore != null)
{ {
RowData trigger = rowBefore.data; RowData trigger = rowBefore.data;
if (trigger.IsMenuOpen || !trigger.IsPointingToFolder) if (trigger.SubMenu != null || !trigger.IsPointingToFolder)
{ {
trigger.OpenItem(out bool doCloseAfterOpen); rowBefore.OpenItem(out bool doCloseAfterOpen);
if (doCloseAfterOpen) if (doCloseAfterOpen)
{ {
ClosePressed?.Invoke(); ClosePressed?.Invoke();
@ -328,10 +323,10 @@ namespace SystemTrayMenu.Handler
else if (focussedMenu?.ParentMenu != null) else if (focussedMenu?.ParentMenu != null)
{ {
// Next is in opposite key direction and prev is in key direction ==> Select parent/prev menu // Next is in opposite key direction and prev is in key direction ==> Select parent/prev menu
int index = focussedMenu.RowDataParent?.RowIndex ?? -1;
focussedMenu = focussedMenu.ParentMenu; focussedMenu = focussedMenu.ParentMenu;
focussedRow = null; focussedRow = null;
ListView dgv = focussedMenu.GetDataGridView(); if (TrySelectNext(focussedMenu, index) ||
if (TrySelectNext(focussedMenu, dgv.Items.IndexOf(dgv.SelectedItems.Count > 0 ? dgv.SelectedItems[0] : null)) ||
TrySelectNext(focussedMenu, 0)) TrySelectNext(focussedMenu, 0))
{ {
RaiseRowSelectionChanged(menuBefore, rowBefore); RaiseRowSelectionChanged(menuBefore, rowBefore);
@ -426,15 +421,6 @@ namespace SystemTrayMenu.Handler
private void Select(ListView dgv, ListViewItemData itemData) private void Select(ListView dgv, ListViewItemData itemData)
{ {
focussedRow = itemData; focussedRow = itemData;
itemData.data.IsSelected = true;
// TODO: Refresh ListViewItems - optimize out
// ([remove and] add item to procove selection changed handler)
if (dgv.SelectedItems.Contains(itemData))
{
dgv.SelectedItems.Remove(itemData);
}
dgv.SelectedItems.Add(itemData); dgv.SelectedItems.Add(itemData);
} }
} }

View file

@ -42,7 +42,6 @@ namespace SystemTrayMenu.Business
private DateTime deactivatedTime = DateTime.MinValue; private DateTime deactivatedTime = DateTime.MinValue;
private OpenCloseState openCloseState = OpenCloseState.Default; private OpenCloseState openCloseState = OpenCloseState.Default;
private TaskbarPosition taskbarPosition = new WindowsTaskbar().Position; private TaskbarPosition taskbarPosition = new WindowsTaskbar().Position;
private bool searchTextChanging;
private bool showMenuAfterMainPreload; private bool showMenuAfterMainPreload;
private Menu? mainMenu; private Menu? mainMenu;
@ -393,18 +392,14 @@ namespace SystemTrayMenu.Business
Menu? menu = mainMenu; Menu? menu = mainMenu;
if (menu != null) if (menu != null)
{ {
// The main menu gets loaded again // The main menu gets loaded again, reset list
// Clean up menu status of previous one
ListView dgvMainMenu = menu.GetDataGridView(); ListView dgvMainMenu = menu.GetDataGridView();
foreach (ListViewItemData item in dgvMainMenu.Items) foreach (ListViewItemData item in dgvMainMenu.Items)
{ {
RowData rowDataToClear = item.data; item.IsClicking = false;
rowDataToClear.IsMenuOpen = false;
rowDataToClear.IsClicking = false;
rowDataToClear.IsSelected = false;
} }
RefreshSelection(dgvMainMenu); dgvMainMenu.SelectedItem = null;
menu.RelocateOnNextShow = true; menu.RelocateOnNextShow = true;
@ -492,11 +487,8 @@ namespace SystemTrayMenu.Business
// TODO: Main menu should destroy sub menu(s?) when it becomes unusable // TODO: Main menu should destroy sub menu(s?) when it becomes unusable
menu.HideWithFade(false); menu.HideWithFade(false);
ListView? lv = menu.ParentMenu?.GetDataGridView(); // TODO: Remove when setting SubMenu of RowData notifies about value change
if (lv != null) menu.ParentMenu?.RefreshSelection();
{
RefreshSelection(lv);
}
} }
} }
@ -519,7 +511,6 @@ namespace SystemTrayMenu.Business
menu.SearchTextChanging += Menu_SearchTextChanging; menu.SearchTextChanging += Menu_SearchTextChanging;
void Menu_SearchTextChanging() void Menu_SearchTextChanging()
{ {
searchTextChanging = true;
waitToOpenMenu.MouseActive = false; waitToOpenMenu.MouseActive = false;
} }
@ -528,7 +519,6 @@ namespace SystemTrayMenu.Business
{ {
keyboardInput.SearchTextChanged(menu, isSearchStringEmpty); keyboardInput.SearchTextChanged(menu, isSearchStringEmpty);
AdjustMenusSizeAndLocation(menu.Level + 1); AdjustMenusSizeAndLocation(menu.Level + 1);
searchTextChanging = false;
// if any open menu close // if any open menu close
if (!causedByWatcherUpdate) if (!causedByWatcherUpdate)
@ -587,7 +577,6 @@ namespace SystemTrayMenu.Business
menu.ClosePressed += MenusFadeOut; menu.ClosePressed += MenusFadeOut;
ListView dgv = menu.GetDataGridView(); ListView dgv = menu.GetDataGridView();
dgv.SelectionChanged += Dgv_SelectionChanged;
if (menu.Level == 0) if (menu.Level == 0)
{ {
@ -600,10 +589,9 @@ namespace SystemTrayMenu.Business
// Sub Menu (loading) // Sub Menu (loading)
if (IsMainUsable) if (IsMainUsable)
{ {
RefreshSelection(menu.GetDataGridView());
// TODO: Re-enable again? HideOldMenu(menu, true);
menu.ShowWithFade(!IsActiveApp(), false); menu.ShowWithFade(!IsActiveApp(), false);
menu.RefreshSelection();
} }
} }
@ -644,49 +632,6 @@ namespace SystemTrayMenu.Business
} }
} }
private void Dgv_SelectionChanged(object sender, EventArgs e) => RefreshSelection((ListView)sender);
private void RefreshSelection(ListView dgv)
{
dgv.SelectionChanged -= Dgv_SelectionChanged;
foreach (ListViewItemData itemData in dgv.Items)
{
RowData rowData = itemData.data;
if (rowData.IsClicking)
{
itemData.BorderBrush = MenuDefines.ColorIcons;
itemData.BackgroundBrush = MenuDefines.ColorSelectedItem;
dgv.SelectedItems.Add(itemData);
}
else if (rowData.IsMenuOpen)
{
itemData.BorderBrush = MenuDefines.ColorOpenFolderBorder;
itemData.BackgroundBrush = MenuDefines.ColorOpenFolder;
dgv.SelectedItems.Add(itemData);
}
else if (rowData.IsSelected)
{
itemData.BorderBrush = MenuDefines.ColorSelectedItemBorder;
itemData.BackgroundBrush = MenuDefines.ColorSelectedItem;
dgv.SelectedItems.Add(itemData);
}
else
{
itemData.BorderBrush = Brushes.White;
itemData.BackgroundBrush = Brushes.White;
dgv.SelectedItems.Remove(itemData);
}
}
dgv.SelectionChanged += Dgv_SelectionChanged;
if (!searchTextChanging)
{
dgv.InvalidateVisual();
}
}
private void SystemEvents_DisplaySettingsChanged(object? sender, EventArgs e) private void SystemEvents_DisplaySettingsChanged(object? sender, EventArgs e)
{ {
dispatchter.Invoke(() => dispatchter.Invoke(() =>
@ -702,29 +647,14 @@ namespace SystemTrayMenu.Business
}); });
} }
private void HideOldMenu(Menu menuToShow, bool keepOrSetIsMenuOpen = false) private void HideOldMenu(Menu menuToShow)
{ {
Menu? menuPrevious = menuToShow.ParentMenu; Menu? menuPrevious = menuToShow.ParentMenu;
if (menuPrevious != null) if (menuPrevious != null)
{ {
// Clean up menu status IsMenuOpen for previous one
ListView dgvPrevious = menuPrevious.GetDataGridView();
foreach (ListViewItemData item in dgvPrevious.Items)
{
RowData rowDataToClear = item.data;
if (rowDataToClear == menuToShow.RowDataParent)
{
rowDataToClear.IsMenuOpen = keepOrSetIsMenuOpen;
}
else
{
rowDataToClear.IsMenuOpen = false;
}
}
RefreshSelection(dgvPrevious);
menuPrevious.SubMenu?.HideWithFade(true); menuPrevious.SubMenu?.HideWithFade(true);
menuPrevious.RefreshSelection();
} }
} }

View file

@ -152,19 +152,15 @@ namespace SystemTrayMenu.Handler
alreadyOpened = false; alreadyOpened = false;
this.dgv = dgv; this.dgv = dgv;
dgvItemData = itemData; dgv.SelectedItem = dgvItemData = itemData;
dgvItemData.data.IsSelected = true;
dgv.SelectedItem = dgvItemData;
} }
private void ResetData(ListView dgv, ListViewItemData itemData) private void ResetData(ListView dgv, ListViewItemData itemData)
{ {
RowData rowData = itemData.data; itemData.IsClicking = false;
rowData.IsSelected = false;
rowData.IsClicking = false;
dgv.SelectedItem = null;
this.dgv = null; this.dgv = null;
dgvItemData = null; dgv.SelectedItem = dgvItemData = null;
} }
} }
} }

View file

@ -110,12 +110,6 @@ namespace SystemTrayMenu.DataClasses
internal Menu? SubMenu { get; set; } internal Menu? SubMenu { get; set; }
internal bool IsMenuOpen { get; set; } // TODO: Implicitly set when SubMenu != null?
internal bool IsClicking { get; set; }
internal bool IsSelected { get; set; }
internal bool HiddenEntry { get; set; } internal bool HiddenEntry { get; set; }
internal int RowIndex { get; set; } internal int RowIndex { get; set; }
@ -167,7 +161,6 @@ namespace SystemTrayMenu.DataClasses
internal void OpenItem(out bool doCloseAfterOpen, int clickCount = -1) internal void OpenItem(out bool doCloseAfterOpen, int clickCount = -1)
{ {
IsClicking = false;
doCloseAfterOpen = false; doCloseAfterOpen = false;
if (!IsPointingToFolder) if (!IsPointingToFolder)

View file

@ -193,7 +193,7 @@
<EventSetter Event="MouseEnter" Handler="ListViewItem_MouseEnter" /> <EventSetter Event="MouseEnter" Handler="ListViewItem_MouseEnter" />
<EventSetter Event="MouseLeave" Handler="ListViewItem_MouseLeave" /> <EventSetter Event="MouseLeave" Handler="ListViewItem_MouseLeave" />
<EventSetter Event="PreviewMouseDown" Handler="ListViewItem_PreviewMouseDown" /> <EventSetter Event="PreviewMouseDown" Handler="ListViewItem_PreviewMouseDown" />
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListViewxItem_PreviewMouseLeftButtonDown" /> <EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListViewItem_PreviewMouseLeftButtonDown" />
</Style> </Style>
</ListView.ItemContainerStyle> </ListView.ItemContainerStyle>
</ListView> </ListView>

View file

@ -109,7 +109,6 @@ namespace SystemTrayMenu.UserInterface
Level = RowDataParent.Level + 1; Level = RowDataParent.Level + 1;
MainMenu = ParentMenu.MainMenu; MainMenu = ParentMenu.MainMenu;
RowDataParent.SubMenu = this; RowDataParent.SubMenu = this;
RowDataParent.IsMenuOpen = true;
buttonOpenFolder.Visibility = Visibility.Collapsed; buttonOpenFolder.Visibility = Visibility.Collapsed;
buttonSettings.Visibility = Visibility.Collapsed; buttonSettings.Visibility = Visibility.Collapsed;
@ -196,6 +195,7 @@ namespace SystemTrayMenu.UserInterface
}); });
dgv.GotFocus += (_, _) => FocusTextBox(); dgv.GotFocus += (_, _) => FocusTextBox();
dgv.SelectionChanged += ListView_SelectionChanged;
Loaded += (_, _) => Loaded += (_, _) =>
{ {
@ -212,7 +212,6 @@ namespace SystemTrayMenu.UserInterface
if (RowDataParent?.SubMenu == this) if (RowDataParent?.SubMenu == this)
{ {
RowDataParent.SubMenu = null; RowDataParent.SubMenu = null;
RowDataParent.IsMenuOpen = false;
} }
foreach (ListViewItemData item in dgv.Items) foreach (ListViewItemData item in dgv.Items)
@ -395,6 +394,9 @@ namespace SystemTrayMenu.UserInterface
((CollectionView)CollectionViewSource.GetDefaultView(dgv.ItemsSource)).Refresh(); ((CollectionView)CollectionViewSource.GetDefaultView(dgv.ItemsSource)).Refresh();
} }
// TODO: Check if it is implicitly already running due to SelectionChanged event
internal void RefreshSelection() => ListView_SelectionChanged(GetDataGridView(), null);
internal void AddItemsToMenu(List<RowData> data, MenuDataDirectoryState? state, bool startIconLoading) internal void AddItemsToMenu(List<RowData> data, MenuDataDirectoryState? state, bool startIconLoading)
{ {
int foldersCount = 0; int foldersCount = 0;
@ -1176,6 +1178,34 @@ namespace SystemTrayMenu.UserInterface
} }
} }
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs? e)
{
if (e != null)
{
foreach (ListViewItemData itemData in e.AddedItems)
{
itemData.IsSelected = true;
itemData.UpdateColors();
}
foreach (ListViewItemData itemData in e.RemovedItems)
{
itemData.IsSelected = false;
itemData.UpdateColors();
}
}
else
{
// TODO: Refactor item selection to prevent running this loop
ListView lv = (ListView)sender;
foreach (ListViewItemData itemData in lv.Items)
{
itemData.IsSelected = lv.SelectedItems.Contains(itemData);
itemData.UpdateColors();
}
}
}
private void ListViewItem_MouseEnter(object sender, MouseEventArgs e) private void ListViewItem_MouseEnter(object sender, MouseEventArgs e)
{ {
CellMouseEnter?.Invoke(this, (ListViewItemData)((ListViewItem)sender).Content); CellMouseEnter?.Invoke(this, (ListViewItemData)((ListViewItem)sender).Content);
@ -1201,7 +1231,7 @@ namespace SystemTrayMenu.UserInterface
if (e.LeftButton == MouseButtonState.Pressed) if (e.LeftButton == MouseButtonState.Pressed)
{ {
itemData.data.IsClicking = true; itemData.IsClicking = true;
} }
if (e.RightButton == MouseButtonState.Pressed) if (e.RightButton == MouseButtonState.Pressed)
@ -1212,11 +1242,11 @@ namespace SystemTrayMenu.UserInterface
} }
} }
private void ListViewxItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) private void ListViewItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{ {
ListViewItemData itemData = (ListViewItemData)((ListViewItem)sender).Content; ListViewItemData itemData = (ListViewItemData)((ListViewItem)sender).Content;
itemData.data.OpenItem(out bool doClose, e.ClickCount); itemData.OpenItem(out bool doClose, e.ClickCount);
if (e.ClickCount == 1) if (e.ClickCount == 1)
{ {
@ -1251,20 +1281,26 @@ namespace SystemTrayMenu.UserInterface
public Brush? BackgroundBrush public Brush? BackgroundBrush
{ {
get => backgroundBrush; get => backgroundBrush;
set private set
{ {
backgroundBrush = value; if (value != backgroundBrush)
CallPropertyChanged(); {
backgroundBrush = value;
CallPropertyChanged();
}
} }
} }
public Brush? BorderBrush public Brush? BorderBrush
{ {
get => borderBrush; get => borderBrush;
set private set
{ {
borderBrush = value; if (value != borderBrush)
CallPropertyChanged(); {
borderBrush = value;
CallPropertyChanged();
}
} }
} }
@ -1273,8 +1309,11 @@ namespace SystemTrayMenu.UserInterface
get => columnIcon; get => columnIcon;
set set
{ {
columnIcon = value; if (value != columnIcon)
CallPropertyChanged(); {
columnIcon = value;
CallPropertyChanged();
}
} }
} }
@ -1286,13 +1325,47 @@ namespace SystemTrayMenu.UserInterface
internal int SortIndex { get; set; } internal int SortIndex { get; set; }
internal bool IsClicking { get; set; }
internal bool IsSelected { get; set; }
public override string ToString() => nameof(ListViewItemData) + ": " + ColumnText + ", Owner: " + (data.Owner?.ToString() ?? "null");
/// <summary> /// <summary>
/// Triggers an PropertyChanged event of INotifyPropertyChanged. /// Triggers an PropertyChanged event of INotifyPropertyChanged.
/// </summary> /// </summary>
/// <param name="propertyName">Name of the changing property.</param> /// <param name="propertyName">Name of the changing property.</param>
public void CallPropertyChanged([CallerMemberName] string? propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); public void CallPropertyChanged([CallerMemberName] string? propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
public override string ToString() => nameof(ListViewItemData) + ": " + ColumnText + ", Owner: " + (data.Owner?.ToString() ?? "null"); internal void OpenItem(out bool doCloseAfterOpen, int clickCount = -1)
{
IsClicking = false;
data.OpenItem(out doCloseAfterOpen, clickCount);
}
internal void UpdateColors()
{
if (IsClicking)
{
BorderBrush = MenuDefines.ColorIcons;
BackgroundBrush = MenuDefines.ColorSelectedItem;
}
else if (data.SubMenu != null)
{
BorderBrush = MenuDefines.ColorOpenFolderBorder;
BackgroundBrush = MenuDefines.ColorOpenFolder;
}
else if (IsSelected)
{
BorderBrush = MenuDefines.ColorSelectedItemBorder;
BackgroundBrush = MenuDefines.ColorSelectedItem;
}
else
{
BorderBrush = Brushes.White;
BackgroundBrush = Brushes.White;
}
}
} }
} }
} }