mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-09 12:46:47 +02:00
Fixes race conditions with PointerEnter/Exit events conflicting with Selection and unselection. This change provides better encapsulation of the logic to enable a selected item for accelerator (hotkey) events, and allow mouse input on results where the pointer is over.
This commit is contained in:
@@ -8,11 +8,16 @@
|
|||||||
xmlns:ToolkitBehaviors="using:Microsoft.Toolkit.Uwp.UI.Animations.Behaviors"
|
xmlns:ToolkitBehaviors="using:Microsoft.Toolkit.Uwp.UI.Animations.Behaviors"
|
||||||
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
|
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
|
||||||
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
|
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
|
||||||
|
xmlns:converters="using:Microsoft.Toolkit.Uwp.UI.Converters"
|
||||||
d:DesignHeight="300"
|
d:DesignHeight="300"
|
||||||
d:DesignWidth="720">
|
d:DesignWidth="720">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<converters:BoolToObjectConverter x:Key="BoolToVisibilityConverter" TrueValue="Visible" FalseValue="Collapsed"/>
|
||||||
|
</UserControl.Resources>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="PowerBar"
|
x:Name="PowerBar"
|
||||||
Background="{ThemeResource BackdropAcrylicBrush}"
|
Background="{ThemeResource BackdropAcrylicBrush}"
|
||||||
|
Translation="0,0,16"
|
||||||
VerticalAlignment="Top">
|
VerticalAlignment="Top">
|
||||||
<ListView
|
<ListView
|
||||||
x:Name="SuggestionsList"
|
x:Name="SuggestionsList"
|
||||||
@@ -21,28 +26,22 @@
|
|||||||
MinHeight="{Binding Results.MaxHeight}"
|
MinHeight="{Binding Results.MaxHeight}"
|
||||||
AllowFocusOnInteraction="False"
|
AllowFocusOnInteraction="False"
|
||||||
IsItemClickEnabled="True"
|
IsItemClickEnabled="True"
|
||||||
Margin="0"
|
Margin="{ThemeResource AutoSuggestListMargin}"
|
||||||
Padding="{ThemeResource AutoSuggestListPadding}"
|
Padding="{ThemeResource AutoSuggestListPadding}"
|
||||||
ItemsSource="{Binding Results.Results, Mode=OneWay}"
|
ItemsSource="{Binding Results.Results, Mode=OneWay}"
|
||||||
SelectionMode="Single"
|
SelectionMode="Single"
|
||||||
SelectedIndex="{Binding Results.SelectedIndex, Mode=TwoWay}"
|
SelectedIndex="{Binding Results.SelectedIndex, Mode=TwoWay}"
|
||||||
Style="{StaticResource ListViewNoAnimations}">
|
Style="{StaticResource ListViewNoAnimations}"
|
||||||
|
>
|
||||||
<ListView.ItemTemplate>
|
<ListView.ItemTemplate>
|
||||||
<DataTemplate >
|
<DataTemplate >
|
||||||
<Grid Height="72" Width="690" Background="Transparent" RowSpacing="0">
|
<Grid Height="72" Width="690" Background="Transparent" RowSpacing="0">
|
||||||
<Interactivity:Interaction.Behaviors>
|
<Interactivity:Interaction.Behaviors>
|
||||||
<Core:DataTriggerBehavior Binding="{Binding IsSelected}" ComparisonCondition="Equal" Value="true" >
|
|
||||||
<Core:CallMethodAction TargetObject="{Binding ElementName=ShowActionButtons}" MethodName="StartAnimation"/>
|
|
||||||
</Core:DataTriggerBehavior>
|
|
||||||
<Core:DataTriggerBehavior Binding="{Binding IsSelected}" ComparisonCondition="Equal" Value="false">
|
|
||||||
<Core:CallMethodAction TargetObject="{Binding ElementName=HideActionsButtons}" MethodName="StartAnimation"/>
|
|
||||||
</Core:DataTriggerBehavior>
|
|
||||||
<Core:EventTriggerBehavior EventName="PointerEntered">
|
<Core:EventTriggerBehavior EventName="PointerEntered">
|
||||||
<Core:CallMethodAction TargetObject="{Binding ElementName=ShowActionButtons}" MethodName="StartAnimation"/>
|
<Core:InvokeCommandAction Command="{Binding ActivateContextButtonsHoverCommand}"/>
|
||||||
<Core:InvokeCommandAction Command="{Binding LoadContextMenuCommand}"/>
|
|
||||||
</Core:EventTriggerBehavior>
|
</Core:EventTriggerBehavior>
|
||||||
<Core:EventTriggerBehavior EventName="PointerExited">
|
<Core:EventTriggerBehavior EventName="PointerExited">
|
||||||
<Core:CallMethodAction TargetObject="{Binding ElementName=HideActionsButtons}" MethodName="StartAnimation"/>
|
<Core:InvokeCommandAction Command="{Binding DeactivateContextButtonsHoverCommand}"/>
|
||||||
</Core:EventTriggerBehavior>
|
</Core:EventTriggerBehavior>
|
||||||
</Interactivity:Interaction.Behaviors>
|
</Interactivity:Interaction.Behaviors>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@@ -64,16 +63,12 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="0,0,42,0"
|
Margin="0,0,42,0"
|
||||||
Height="46"
|
Height="46"
|
||||||
|
Visibility="{Binding AreContextButtonsActive, Converter={StaticResource BoolToVisibilityConverter}}"
|
||||||
ScrollViewer.VerticalScrollBarVisibility="Disabled"
|
ScrollViewer.VerticalScrollBarVisibility="Disabled"
|
||||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||||
ItemsSource="{Binding ContextMenuItems}"
|
ItemsSource="{Binding ContextMenuItems}"
|
||||||
SelectionMode="Single"
|
SelectionMode="Single"
|
||||||
SelectedIndex="{Binding ContextMenuSelectedIndex}">
|
SelectedIndex="{Binding ContextMenuSelectedIndex}">
|
||||||
|
|
||||||
<Interactivity:Interaction.Behaviors>
|
|
||||||
<ToolkitBehaviors:Fade x:Name="ShowActionButtons" Duration="250" Delay="0" AutomaticallyStart="False" Value="1" />
|
|
||||||
<ToolkitBehaviors:Fade x:Name="HideActionsButtons" Duration="250" Delay="0" AutomaticallyStart="False" Value="0" />
|
|
||||||
</Interactivity:Interaction.Behaviors>
|
|
||||||
<GridView.ItemTemplate>
|
<GridView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Button Command="{Binding Command}" VerticalAlignment="Center" CornerRadius="4" Height="42" Width="42" BorderThickness="1" Style="{ThemeResource ButtonRevealStyle}">
|
<Button Command="{Binding Command}" VerticalAlignment="Center" CornerRadius="4" Height="42" Width="42" BorderThickness="1" Style="{ThemeResource ButtonRevealStyle}">
|
||||||
@@ -87,7 +82,7 @@
|
|||||||
<KeyboardAccelerator
|
<KeyboardAccelerator
|
||||||
Key="{Binding AcceleratorKey}"
|
Key="{Binding AcceleratorKey}"
|
||||||
Modifiers="{Binding AcceleratorModifiers}"
|
Modifiers="{Binding AcceleratorModifiers}"
|
||||||
IsEnabled="{Binding IsEnabled}"
|
IsEnabled="{Binding IsAcceleratorKeyEnabled}"
|
||||||
/>
|
/>
|
||||||
</Button.KeyboardAccelerators>
|
</Button.KeyboardAccelerators>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -12,6 +12,6 @@ namespace Wox.ViewModel
|
|||||||
public ICommand Command { get; set; }
|
public ICommand Command { get; set; }
|
||||||
public string AcceleratorKey { get; set; }
|
public string AcceleratorKey { get; set; }
|
||||||
public string AcceleratorModifiers { get; set; }
|
public string AcceleratorModifiers { get; set; }
|
||||||
public bool IsEnabled { get; set; }
|
public bool IsAcceleratorKeyEnabled { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,12 +17,24 @@ namespace Wox.ViewModel
|
|||||||
{
|
{
|
||||||
public class ResultViewModel : BaseModel
|
public class ResultViewModel : BaseModel
|
||||||
{
|
{
|
||||||
|
public enum ActivationType
|
||||||
|
{
|
||||||
|
Selection,
|
||||||
|
Hover
|
||||||
|
};
|
||||||
|
|
||||||
public List<ContextMenuItemViewModel> ContextMenuItems { get; set; }
|
public List<ContextMenuItemViewModel> ContextMenuItems { get; set; }
|
||||||
|
|
||||||
public ICommand LoadContextMenuCommand { get; set; }
|
public ICommand ActivateContextButtonsHoverCommand { get; set; }
|
||||||
|
public ICommand ActivateContextButtonsSelectionCommand { get; set; }
|
||||||
|
public ICommand DeactivateContextButtonsHoverCommand { get; set; }
|
||||||
|
|
||||||
|
public ICommand DeactivateContextButtonsSelectionCommand { get; set; }
|
||||||
|
|
||||||
public bool IsSelected { get; set; }
|
public bool IsSelected { get; set; }
|
||||||
|
|
||||||
|
public bool AreContextButtonsActive { get; set; }
|
||||||
|
|
||||||
public int ContextMenuSelectedIndex { get; set; }
|
public int ContextMenuSelectedIndex { get; set; }
|
||||||
|
|
||||||
const int NoSelectionIndex = -1;
|
const int NoSelectionIndex = -1;
|
||||||
@@ -34,9 +46,62 @@ namespace Wox.ViewModel
|
|||||||
Result = result;
|
Result = result;
|
||||||
}
|
}
|
||||||
ContextMenuSelectedIndex = NoSelectionIndex;
|
ContextMenuSelectedIndex = NoSelectionIndex;
|
||||||
LoadContextMenuCommand = new RelayCommand(LoadContextMenu);
|
ActivateContextButtonsHoverCommand = new RelayCommand(ActivateContextButtonsHoverAction);
|
||||||
|
ActivateContextButtonsSelectionCommand = new RelayCommand(ActivateContextButtonsSelectionAction);
|
||||||
|
DeactivateContextButtonsHoverCommand = new RelayCommand(DeactivateContextButtonsHoverAction);
|
||||||
|
DeactivateContextButtonsSelectionCommand = new RelayCommand(DeactivateContextButtonsSelectionAction);
|
||||||
}
|
}
|
||||||
public void LoadContextMenu(object sender=null)
|
|
||||||
|
private void ActivateContextButtonsHoverAction(object sender)
|
||||||
|
{
|
||||||
|
ActivateContextButtons(ActivationType.Hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ActivateContextButtonsSelectionAction(object sender)
|
||||||
|
{
|
||||||
|
ActivateContextButtons(ActivationType.Selection);
|
||||||
|
}
|
||||||
|
public void ActivateContextButtons(ActivationType activationType)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (ContextMenuItems == null)
|
||||||
|
{
|
||||||
|
LoadContextMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
AreContextButtonsActive = true;
|
||||||
|
|
||||||
|
if (activationType == ActivationType.Selection)
|
||||||
|
{
|
||||||
|
IsSelected = true;
|
||||||
|
EnableContextMenuAcceleratorKeys();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void DeactivateContextButtonsHoverAction(object sender)
|
||||||
|
{
|
||||||
|
DeactivateContextButtons(ActivationType.Hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeactivateContextButtonsSelectionAction(object sender)
|
||||||
|
{
|
||||||
|
DeactivateContextButtons(ActivationType.Selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeactivateContextButtons(ActivationType activationType)
|
||||||
|
{
|
||||||
|
AreContextButtonsActive = false;
|
||||||
|
|
||||||
|
if (activationType == ActivationType.Selection)
|
||||||
|
{
|
||||||
|
IsSelected = false;
|
||||||
|
DisableContextMenuAcceleratorkeys();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void LoadContextMenu()
|
||||||
{
|
{
|
||||||
var results = PluginManager.GetContextMenusForPlugin(Result);
|
var results = PluginManager.GetContextMenusForPlugin(Result);
|
||||||
var newItems = new List<ContextMenuItemViewModel>();
|
var newItems = new List<ContextMenuItemViewModel>();
|
||||||
@@ -68,19 +133,19 @@ namespace Wox.ViewModel
|
|||||||
ContextMenuItems = newItems;
|
ContextMenuItems = newItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void EnableContextMenu()
|
private void EnableContextMenuAcceleratorKeys()
|
||||||
{
|
{
|
||||||
foreach(var i in ContextMenuItems)
|
foreach(var i in ContextMenuItems)
|
||||||
{
|
{
|
||||||
i.IsEnabled = true;
|
i.IsAcceleratorKeyEnabled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void DisableContextMenu()
|
private void DisableContextMenuAcceleratorkeys()
|
||||||
{
|
{
|
||||||
foreach (var i in ContextMenuItems)
|
foreach (var i in ContextMenuItems)
|
||||||
{
|
{
|
||||||
i.IsEnabled = false;
|
i.IsAcceleratorKeyEnabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,14 +59,11 @@ namespace Wox.ViewModel
|
|||||||
{
|
{
|
||||||
if (_selectedItem != null)
|
if (_selectedItem != null)
|
||||||
{
|
{
|
||||||
_selectedItem.IsSelected = false;
|
_selectedItem.DeactivateContextButtons(ResultViewModel.ActivationType.Selection);
|
||||||
_selectedItem.DisableContextMenu();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_selectedItem = value;
|
_selectedItem = value;
|
||||||
_selectedItem.LoadContextMenu();
|
_selectedItem.ActivateContextButtons(ResultViewModel.ActivationType.Selection);
|
||||||
_selectedItem.EnableContextMenu();
|
|
||||||
_selectedItem.IsSelected = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user