mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-28 14:20:47 +08:00
fix(candidate-interaction): unify active candidate navigation for pointer and keyboard interactions across candidate lists
This commit is contained in:
@@ -728,6 +728,13 @@ public partial class CascaderView : TemplatedControl,
|
||||
protected override void OnPointerMoved(PointerEventArgs e)
|
||||
{
|
||||
base.OnPointerMoved(e);
|
||||
if (e.Pointer.Type == PointerType.Mouse &&
|
||||
GetContainerFromEventSource(e.Source) is { } activeCandidate &&
|
||||
activeCandidate.IsVisible && activeCandidate.IsEnabled && !activeCandidate.IsLoading)
|
||||
{
|
||||
SetKeyboardCandidate(activeCandidate);
|
||||
}
|
||||
|
||||
if (e.Source is Visual source)
|
||||
{
|
||||
if (ExpandTrigger == CascaderViewExpandTrigger.Hover)
|
||||
@@ -950,7 +957,8 @@ public partial class CascaderView : TemplatedControl,
|
||||
|
||||
for (var i = 0; i < levelList.ItemCount; i++)
|
||||
{
|
||||
if (levelList.ContainerFromIndex(i) is CascaderViewItem item && item.IsEnabled)
|
||||
if (levelList.ContainerFromIndex(i) is CascaderViewItem item &&
|
||||
item.IsVisible && item.IsEnabled && !item.IsLoading)
|
||||
{
|
||||
candidates.Add(item);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,18 @@ internal class CascaderViewFilterList : ListBox
|
||||
protected override void OnPointerMoved(PointerEventArgs e)
|
||||
{
|
||||
base.OnPointerMoved(e);
|
||||
ClearCandidate();
|
||||
if (e.Pointer.Type != PointerType.Mouse ||
|
||||
GetContainerFromEventSource(e.Source) is not CascaderViewFilterListItem listItem)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var index = IndexFromContainer(listItem);
|
||||
if (index >= 0 && index < ItemCount &&
|
||||
Items[index] is CascaderViewFilterListItemData itemData && itemData.IsEnabled)
|
||||
{
|
||||
SetCandidate(index);
|
||||
}
|
||||
}
|
||||
|
||||
internal bool TryMoveCandidate(int delta)
|
||||
|
||||
@@ -15,9 +15,20 @@
|
||||
</ControlTheme.BasedOn>
|
||||
|
||||
<Style Selector="^:is(atom|CascaderViewFilterListItem)">
|
||||
<Style Selector="^[IsSelected=False][IsCandidateSelected=True]">
|
||||
<Style Selector="^:pointerover:not(:disabled)">
|
||||
<Setter Property="Foreground" Value="{atom:ListBoxTokenResource ItemColor}" />
|
||||
<Setter Property="Background" Value="{atom:ListBoxTokenResource ItemBgColor}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[IsSelected=False][IsCandidateSelected=True]:not(:disabled)">
|
||||
<Setter Property="Foreground" Value="{atom:ListBoxTokenResource ItemHoverColor}" />
|
||||
<Setter Property="Background" Value="{atom:ListViewTokenResource ItemHoverBgColor}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[IsSelected=True]:not(:disabled)">
|
||||
<Setter Property="Foreground" Value="{atom:ListBoxTokenResource ItemSelectedColor}" />
|
||||
<Setter Property="Background" Value="{atom:ListBoxTokenResource ItemSelectedBgColor}" />
|
||||
</Style>
|
||||
</Style>
|
||||
</ControlTheme>
|
||||
</ResourceDictionary>
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
</Style>
|
||||
|
||||
<Style Selector="^:pointerover">
|
||||
<Setter Property="Background" Value="{atom:CascaderTokenResource OptionHoverBg}" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[IsExpanded=False][IsCandidateSelected=True]">
|
||||
|
||||
@@ -613,6 +613,16 @@ public class ComboBox : AvaloniaComboBox,
|
||||
PseudoClasses.Set(StdPseudoClass.Pressed, true);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPointerMoved(PointerEventArgs e)
|
||||
{
|
||||
base.OnPointerMoved(e);
|
||||
if (IsDropDownOpen && e.Pointer.Type == PointerType.Mouse &&
|
||||
GetContainerFromEventSource(e.Source) is ComboBoxItem comboBoxItem)
|
||||
{
|
||||
TrySetCandidateFromContainer(comboBoxItem);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPointerReleased(PointerReleasedEventArgs e)
|
||||
{
|
||||
@@ -1087,6 +1097,19 @@ public class ComboBox : AvaloniaComboBox,
|
||||
}
|
||||
|
||||
private void SetCandidateSelectedIndex(int index)
|
||||
{
|
||||
if (SetCandidateSelectedIndexCore(index) && index != -1)
|
||||
{
|
||||
ScrollIntoView(index);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetCandidateSelectedIndexWithoutScroll(int index)
|
||||
{
|
||||
SetCandidateSelectedIndexCore(index);
|
||||
}
|
||||
|
||||
private bool SetCandidateSelectedIndexCore(int index)
|
||||
{
|
||||
if (_candidateSelectedIndex == index)
|
||||
{
|
||||
@@ -1094,17 +1117,30 @@ public class ComboBox : AvaloniaComboBox,
|
||||
{
|
||||
ClearCandidateItemVisualSelection();
|
||||
}
|
||||
return;
|
||||
else
|
||||
{
|
||||
SelectCandidateItemVisual(index);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ClearCandidateItemVisualSelection();
|
||||
_candidateSelectedIndex = index;
|
||||
SelectCandidateItemVisual(_candidateSelectedIndex);
|
||||
|
||||
if (_candidateSelectedIndex != -1)
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TrySetCandidateFromContainer(ComboBoxItem comboBoxItem)
|
||||
{
|
||||
var index = IndexFromContainer(comboBoxItem);
|
||||
if (index < 0 || !IsCandidateItemSelectable(index))
|
||||
{
|
||||
ScrollIntoView(_candidateSelectedIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
SetCandidateSelectedIndexWithoutScroll(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ClearCandidateItemSelection()
|
||||
|
||||
@@ -26,13 +26,13 @@
|
||||
<Setter Property="CornerRadius" Value="{atom:SharedTokenResource BorderRadiusSM}" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
|
||||
<Style Selector="^:pointerover">
|
||||
<Setter Property="Foreground" Value="{atom:ComboBoxTokenResource ItemHoverColor}" />
|
||||
<Style Selector="^:pointerover:not(:disabled)">
|
||||
<Setter Property="Foreground" Value="{atom:ComboBoxTokenResource ItemColor}" />
|
||||
<Setter Property="Background"
|
||||
Value="{atom:ComboBoxTokenResource ItemHoverBgColor}" />
|
||||
Value="{atom:ComboBoxTokenResource ItemBgColor}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[IsSelected=False][IsCandidateSelected=True]">
|
||||
<Style Selector="^[IsSelected=False][IsCandidateSelected=True]:not(:disabled)">
|
||||
<Setter Property="Foreground" Value="{atom:ComboBoxTokenResource ItemHoverColor}" />
|
||||
<Setter Property="Background"
|
||||
Value="{atom:ComboBoxTokenResource ItemHoverBgColor}" />
|
||||
|
||||
@@ -46,7 +46,17 @@ public class CandidateList : ListBox, ICandidateList
|
||||
public object? CandidateSelectedItem
|
||||
{
|
||||
get => _candidateSelectedItem;
|
||||
set => SetAndRaise(CandidateSelectedItemProperty, ref _candidateSelectedItem, value);
|
||||
set
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
ClearActiveCandidate();
|
||||
}
|
||||
else if (!TrySetCandidateItemSelected(value))
|
||||
{
|
||||
ClearActiveCandidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int _candidateSelectedIndex = -1;
|
||||
@@ -54,7 +64,17 @@ public class CandidateList : ListBox, ICandidateList
|
||||
public int CandidateSelectedIndex
|
||||
{
|
||||
get => _candidateSelectedIndex;
|
||||
set => SetAndRaise(CandidateSelectedIndexProperty, ref _candidateSelectedIndex, value);
|
||||
set
|
||||
{
|
||||
if (value < 0)
|
||||
{
|
||||
ClearActiveCandidate();
|
||||
}
|
||||
else if (!TrySetCandidateItemSelected(value))
|
||||
{
|
||||
ClearActiveCandidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int MaxCount
|
||||
@@ -95,8 +115,6 @@ public class CandidateList : ListBox, ICandidateList
|
||||
static CandidateList()
|
||||
{
|
||||
SelectedItemProperty.Changed.AddClassHandler<CandidateList>((list, args) => list.HandleSelectItemChanged(args));
|
||||
CandidateSelectedIndexProperty.Changed.AddClassHandler<CandidateList>((list, args) => list.HandleCandidateSelectedIndexChanged(args));
|
||||
CandidateSelectedItemProperty.Changed.AddClassHandler<CandidateList>((list, args) => list.HandleCandidateSelectedItemChanged(args));
|
||||
SelectionChangedEvent.AddClassHandler<CandidateList>((list, args) => list.HandleSelectionChanged());
|
||||
|
||||
ItemsPanelProperty.OverrideDefaultValue<CandidateList>(DefaultPanel);
|
||||
@@ -150,36 +168,10 @@ public class CandidateList : ListBox, ICandidateList
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCandidateSelectedIndexChanged(AvaloniaPropertyChangedEventArgs e)
|
||||
{
|
||||
var oldIndex = e.GetOldValue<int>();
|
||||
var newIndex = e.GetNewValue<int>();
|
||||
if (newIndex == -1)
|
||||
{
|
||||
ClearCandidateItemSelection(oldIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
TrySetCandidateItemSelected(newIndex, oldIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCandidateSelectedItemChanged(AvaloniaPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.NewValue == null)
|
||||
{
|
||||
if (e.OldValue != null && ContainerFromItem(e.OldValue) is CandidateListItem listItem)
|
||||
{
|
||||
SetCandidateItemSelectedIfChanged(listItem, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TrySetCandidateItemSelected(e.NewValue);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TrySetCandidateItemSelected(object item)
|
||||
=> TrySetCandidateItemSelectedCore(item);
|
||||
|
||||
private bool TrySetCandidateItemSelectedCore(object item)
|
||||
{
|
||||
var index = Items.IndexOf(item);
|
||||
if (index == -1)
|
||||
@@ -187,47 +179,39 @@ public class CandidateList : ListBox, ICandidateList
|
||||
return false;
|
||||
}
|
||||
|
||||
return TrySetCandidateItemSelected(index);
|
||||
return TrySetCandidateItemSelectedCore(index);
|
||||
}
|
||||
|
||||
public bool TrySetCandidateItemSelected(int index)
|
||||
{
|
||||
return TrySetCandidateItemSelected(index, CandidateSelectedIndex);
|
||||
}
|
||||
=> TrySetCandidateItemSelectedCore(index);
|
||||
|
||||
private bool TrySetCandidateItemSelected(int index, int oldIndex)
|
||||
private bool TrySetCandidateItemSelectedCore(int index)
|
||||
{
|
||||
if (index < 0 || index > ItemCount - 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (oldIndex != -1 && oldIndex != index)
|
||||
|
||||
var candidateItem = Items[index];
|
||||
var candidateContainer = ContainerFromIndex(index) as CandidateListItem;
|
||||
if (!IsCandidateAvailable(candidateItem, candidateContainer))
|
||||
{
|
||||
ClearCandidateItemSelection(oldIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
Control? candidateContainer = null;
|
||||
if (ItemsPanelRoot is CandidateVirtualizingStackPanel virtualizingStackPanel)
|
||||
var changed = SetActiveCandidate(index, candidateItem, candidateContainer);
|
||||
if (changed && ItemsPanelRoot is CandidateVirtualizingStackPanel virtualizingStackPanel)
|
||||
{
|
||||
candidateContainer = virtualizingStackPanel.ScrollCandidateItemIntoView(index);
|
||||
if (virtualizingStackPanel.ScrollCandidateItemIntoView(index) is CandidateListItem realizedContainer)
|
||||
{
|
||||
candidateContainer = realizedContainer;
|
||||
}
|
||||
}
|
||||
|
||||
candidateContainer ??= ContainerFromIndex(index);
|
||||
if (candidateContainer is CandidateListItem childContainer)
|
||||
{
|
||||
SetCandidateItemSelectedIfChanged(childContainer, true);
|
||||
}
|
||||
|
||||
var candidateSelectedItem = Items[index];
|
||||
if (!Equals(CandidateSelectedItem, candidateSelectedItem))
|
||||
{
|
||||
SetCurrentValue(CandidateSelectedItemProperty, candidateSelectedItem);
|
||||
}
|
||||
if (CandidateSelectedIndex != index)
|
||||
{
|
||||
SetCurrentValue(CandidateSelectedIndexProperty, index);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -248,6 +232,82 @@ public class CandidateList : ListBox, ICandidateList
|
||||
item.SetCurrentValue(CandidateListItem.IsCandidateSelectedProperty, isSelected);
|
||||
}
|
||||
}
|
||||
|
||||
private bool TrySetCandidateFromContainer(CandidateListItem listItem)
|
||||
{
|
||||
var index = IndexFromContainer(listItem);
|
||||
if (index < 0 || index >= ItemCount || !IsCandidateAvailable(Items[index], listItem))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return SetActiveCandidate(index, Items[index], listItem);
|
||||
}
|
||||
|
||||
private bool SetActiveCandidate(int index, object? candidateItem, CandidateListItem? candidateContainer)
|
||||
{
|
||||
if (CandidateSelectedIndex == index && ReferenceEquals(CandidateSelectedItem, candidateItem))
|
||||
{
|
||||
if (candidateContainer is not null)
|
||||
{
|
||||
SetCandidateItemSelectedIfChanged(candidateContainer, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ClearCandidateItemSelection(CandidateSelectedIndex);
|
||||
SetAndRaise(CandidateSelectedItemProperty, ref _candidateSelectedItem, candidateItem);
|
||||
SetAndRaise(CandidateSelectedIndexProperty, ref _candidateSelectedIndex, index);
|
||||
if (candidateContainer is not null)
|
||||
{
|
||||
SetCandidateItemSelectedIfChanged(candidateContainer, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool IsCandidateAvailable(object? item, CandidateListItem? container)
|
||||
{
|
||||
if (item is IListItemData itemData && !itemData.IsEnabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsSingleMode() && SelectedItems?.Count >= MaxCount && SelectedItems.Contains(item) == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return container is null || container.IsEnabled && container.IsVisible;
|
||||
}
|
||||
|
||||
private void ClearActiveCandidateIfUnavailable()
|
||||
{
|
||||
if (CandidateSelectedIndex < 0 ||
|
||||
CandidateSelectedIndex >= ItemCount ||
|
||||
!IsCandidateAvailable(Items[CandidateSelectedIndex], ContainerFromIndex(CandidateSelectedIndex) as CandidateListItem))
|
||||
{
|
||||
ClearActiveCandidate();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearActiveCandidate()
|
||||
{
|
||||
if (CandidateSelectedIndex == -1 && CandidateSelectedItem is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ClearCandidateItemSelection(CandidateSelectedIndex);
|
||||
if (CandidateSelectedItem is not null && ContainerFromItem(CandidateSelectedItem) is CandidateListItem itemContainer)
|
||||
{
|
||||
SetCandidateItemSelectedIfChanged(itemContainer, false);
|
||||
}
|
||||
|
||||
SetAndRaise(CandidateSelectedIndexProperty, ref _candidateSelectedIndex, -1);
|
||||
SetAndRaise(CandidateSelectedItemProperty, ref _candidateSelectedItem, null);
|
||||
}
|
||||
|
||||
private void ResetScrollViewer()
|
||||
{
|
||||
@@ -305,6 +365,7 @@ public class CandidateList : ListBox, ICandidateList
|
||||
{
|
||||
NotifyCommit();
|
||||
ClearState();
|
||||
ClearActiveCandidate();
|
||||
}
|
||||
|
||||
private void HandleMultiModeCommit()
|
||||
@@ -338,7 +399,9 @@ public class CandidateList : ListBox, ICandidateList
|
||||
|
||||
if (_candidateSelectedIndex == -1)
|
||||
{
|
||||
CandidateSelectedIndex = SelectedIndex != -1 ? FindNextEnabledIndex(SelectedIndex, -1) : ItemCount - 1;
|
||||
CandidateSelectedIndex = FindNextEnabledIndex(
|
||||
SelectedIndex != -1 ? SelectedIndex : 0,
|
||||
-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -355,7 +418,9 @@ public class CandidateList : ListBox, ICandidateList
|
||||
|
||||
if (_candidateSelectedIndex == -1)
|
||||
{
|
||||
CandidateSelectedIndex = SelectedIndex != -1 ? FindNextEnabledIndex(SelectedIndex, 1) : 0;
|
||||
CandidateSelectedIndex = FindNextEnabledIndex(
|
||||
SelectedIndex != -1 ? SelectedIndex : -1,
|
||||
1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -383,6 +448,7 @@ public class CandidateList : ListBox, ICandidateList
|
||||
{
|
||||
NotifyCancel();
|
||||
ClearState();
|
||||
ClearActiveCandidate();
|
||||
}
|
||||
|
||||
protected virtual void NotifyCancel()
|
||||
@@ -421,9 +487,23 @@ public class CandidateList : ListBox, ICandidateList
|
||||
{
|
||||
if (IsSingleMode())
|
||||
{
|
||||
if (item is CandidateListItem candidateListItem)
|
||||
{
|
||||
TrySetCandidateFromContainer(candidateListItem);
|
||||
}
|
||||
NotifyCommit();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPointerMoved(PointerEventArgs e)
|
||||
{
|
||||
base.OnPointerMoved(e);
|
||||
if (e.Pointer.Type == PointerType.Mouse &&
|
||||
GetContainerFromEventSource(e.Source) is CandidateListItem candidateListItem)
|
||||
{
|
||||
TrySetCandidateFromContainer(candidateListItem);
|
||||
}
|
||||
}
|
||||
|
||||
private int FindNextEnabledIndex(int startIndex, int delta)
|
||||
{
|
||||
@@ -457,7 +537,7 @@ public class CandidateList : ListBox, ICandidateList
|
||||
}
|
||||
}
|
||||
|
||||
if (ContainerFromIndex(index) is ListBoxItem listBoxItem && listBoxItem.IsEnabled)
|
||||
if (IsCandidateAvailable(Items[index], ContainerFromIndex(index) as CandidateListItem))
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -472,27 +552,22 @@ public class CandidateList : ListBox, ICandidateList
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
if (change.Property == MaxCountProperty ||
|
||||
if (change.Property == MaxCountProperty ||
|
||||
change.Property == SelectedItemsProperty)
|
||||
{
|
||||
ConfigureOptionsForMaxCount();
|
||||
ClearActiveCandidateIfUnavailable();
|
||||
}
|
||||
|
||||
if (change.Property == SelectedItemsProperty)
|
||||
{
|
||||
ConfigureEmptyIndicator();
|
||||
}
|
||||
if (change.Property == FilterValueProperty ||
|
||||
if (change.Property == ItemsSourceProperty || change.Property == ItemCountProperty ||
|
||||
change.Property == FilterValueProperty ||
|
||||
change.Property == FilterProperty)
|
||||
{
|
||||
if (CandidateSelectedIndex != -1)
|
||||
{
|
||||
CandidateSelectedIndex = -1;
|
||||
}
|
||||
if (CandidateSelectedItem is not null)
|
||||
{
|
||||
CandidateSelectedItem = null;
|
||||
}
|
||||
ClearActiveCandidate();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -522,14 +597,7 @@ public class CandidateList : ListBox, ICandidateList
|
||||
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnDetachedFromVisualTree(e);
|
||||
if (CandidateSelectedIndex != -1)
|
||||
{
|
||||
CandidateSelectedIndex = -1;
|
||||
}
|
||||
if (CandidateSelectedItem is not null)
|
||||
{
|
||||
CandidateSelectedItem = null;
|
||||
}
|
||||
ClearActiveCandidate();
|
||||
}
|
||||
|
||||
#region 虚拟化上下文管理
|
||||
@@ -545,6 +613,10 @@ public class CandidateList : ListBox, ICandidateList
|
||||
candidateListItem,
|
||||
virtualListItem.VirtualIndex == CandidateSelectedIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCandidateItemSelectedIfChanged(candidateListItem, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-4
@@ -8,13 +8,20 @@
|
||||
</ControlTheme.BasedOn>
|
||||
|
||||
<Style Selector="^:is(atom|CandidateListItem)">
|
||||
<Style Selector="^[IsSelected=False][IsCandidateSelected=True]">
|
||||
<Style Selector="^:pointerover:not(:disabled)">
|
||||
<Setter Property="Foreground" Value="{atom:ListBoxTokenResource ItemColor}" />
|
||||
<Setter Property="Background" Value="{atom:ListBoxTokenResource ItemBgColor}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[IsSelected=False][IsCandidateSelected=True]:not(:disabled)">
|
||||
<Setter Property="Foreground" Value="{atom:ListBoxTokenResource ItemHoverColor}" />
|
||||
<Setter Property="Background" Value="{Binding ItemHoverBg, RelativeSource={RelativeSource Self}}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^[IsSelected=True]">
|
||||
<Setter Property="Background" Value="{Binding ItemHoverBg, RelativeSource={RelativeSource Self}}" />
|
||||
<Style Selector="^[IsSelected=True]:not(:disabled)">
|
||||
<Setter Property="Foreground" Value="{atom:ListBoxTokenResource ItemSelectedColor}" />
|
||||
<Setter Property="Background" Value="{Binding ItemSelectedBg, RelativeSource={RelativeSource Self}}" />
|
||||
</Style>
|
||||
</Style>
|
||||
|
||||
</ControlTheme>
|
||||
</ControlTheme>
|
||||
|
||||
Reference in New Issue
Block a user