mirror of
https://github.com/microsoft/PowerToys.git
synced 2024-12-01 01:49:06 +08:00
Replace ResultItem usercontrol with listbox to improve ui performance
This commit is contained in:
parent
729640d6ec
commit
4736921d05
53
Wox/ImagePathConverter.cs
Normal file
53
Wox/ImagePathConverter.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Wox
|
||||
{
|
||||
public class ImagePathConverter : IMultiValueConverter
|
||||
{
|
||||
private static ImageSource GetIcon(string fileName)
|
||||
{
|
||||
Icon icon = Icon.ExtractAssociatedIcon(fileName);
|
||||
return System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(
|
||||
icon.Handle,
|
||||
new Int32Rect(0, 0, icon.Width, icon.Height),
|
||||
BitmapSizeOptions.FromEmptyOptions());
|
||||
}
|
||||
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
string path = values[0].ToString();
|
||||
string pluginDirectory = values[1].ToString();
|
||||
|
||||
string resolvedPath = string.Empty;
|
||||
if (!string.IsNullOrEmpty(path) && path.Contains(":\\") && File.Exists(path))
|
||||
{
|
||||
resolvedPath = path;
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(path) && File.Exists(pluginDirectory + path))
|
||||
{
|
||||
resolvedPath = pluginDirectory + path;
|
||||
}
|
||||
|
||||
if (resolvedPath.ToLower().EndsWith(".exe") || resolvedPath.ToLower().EndsWith(".lnk"))
|
||||
{
|
||||
return GetIcon(resolvedPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new BitmapImage(new Uri(resolvedPath));
|
||||
}
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -40,7 +40,6 @@ namespace Wox
|
||||
InitialTray();
|
||||
hook.KeyPressed += OnHotKey;
|
||||
hook.RegisterHotKey(XModifierKeys.Alt, Keys.Space);
|
||||
resultCtrl.resultItemChangedEvent += resultCtrl_resultItemChangedEvent;
|
||||
ThreadPool.SetMaxThreads(30, 10);
|
||||
InitProgressbarAnimation();
|
||||
try
|
||||
@ -106,11 +105,6 @@ namespace Wox
|
||||
notifyIcon.ContextMenu = new System.Windows.Forms.ContextMenu(childen);
|
||||
}
|
||||
|
||||
private void resultCtrl_resultItemChangedEvent()
|
||||
{
|
||||
resultCtrl.Margin = resultCtrl.GetCurrentResultCount() > 0 ? new Thickness { Top = grid.Margin.Top } : new Thickness { Top = 0 };
|
||||
}
|
||||
|
||||
private void OnHotKey(object sender, KeyPressedEventArgs e)
|
||||
{
|
||||
if (!IsVisible)
|
||||
@ -301,8 +295,10 @@ namespace Wox
|
||||
});
|
||||
resultCtrl.Dispatcher.Invoke(new Action(() =>
|
||||
{
|
||||
var t1 = Environment.TickCount;
|
||||
List<Result> l = list.Where(o => o.OriginQuery != null && o.OriginQuery.RawQuery == tbQuery.Text).ToList();
|
||||
resultCtrl.AddResults(l);
|
||||
Debug.WriteLine("Time:" + (Environment.TickCount - t1) + " Count:" + l.Count);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,49 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:wox="clr-namespace:Wox"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="300">
|
||||
<ScrollViewer x:Name="sv" Template="{DynamicResource ScrollViewerControlTemplate}" MaxHeight="300" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel x:Name="pnlContainer"/>
|
||||
</ScrollViewer>
|
||||
<UserControl.Resources>
|
||||
<wox:ImagePathConverter x:Key="ImagePathConverter"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<ListBox x:Name="lbResults" ScrollViewer.HorizontalScrollBarVisibility="Hidden" SelectionChanged ="lbResults_SelectionChanged" Focusable="False" KeyboardNavigation.DirectionalNavigation="Cycle" SelectionMode="Single" BorderBrush="Transparent" Background="Transparent" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling">
|
||||
<ListBox.Resources>
|
||||
<!--SelectedItem with focus-->
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#4F6180"/>
|
||||
<!--SelectedItem without focus-->
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="#4F6180"/>
|
||||
</ListBox.Resources>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5" Cursor="Hand">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="32"></ColumnDefinition>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image x:Name="imgIco" Width="32" Height="32" HorizontalAlignment="Left" >
|
||||
<Image.Source>
|
||||
<MultiBinding Converter="{StaticResource ImagePathConverter}">
|
||||
<MultiBinding.Bindings>
|
||||
<Binding Path="IcoPath" />
|
||||
<Binding Path="PluginDirectory" />
|
||||
</MultiBinding.Bindings>
|
||||
</MultiBinding>
|
||||
</Image.Source>
|
||||
</Image>
|
||||
<Grid Margin="5 0 5 0" Grid.Column="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"></RowDefinition>
|
||||
<RowDefinition x:Name="SubTitleRowDefinition"></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Style="{DynamicResource ItemTitleStyle}" VerticalAlignment="Center" x:Name="tbTitle" Text="{Binding Title}"></TextBlock>
|
||||
<TextBlock Style="{DynamicResource ItemSubTitleStyle}" Grid.Row="1" x:Name="tbSubTitle" Text="{Binding SubTitle}"></TextBlock>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,9 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Controls;
|
||||
using Wox.Helper;
|
||||
using Wox.Plugin;
|
||||
using Point = System.Windows.Point;
|
||||
|
||||
namespace Wox
|
||||
{
|
||||
@ -11,70 +11,37 @@ namespace Wox
|
||||
{
|
||||
public bool Dirty { get; set; }
|
||||
|
||||
public delegate void ResultItemsChanged();
|
||||
|
||||
public event ResultItemsChanged resultItemChangedEvent;
|
||||
|
||||
protected virtual void OnResultItemChangedEvent()
|
||||
{
|
||||
ResultItemsChanged handler = resultItemChangedEvent;
|
||||
if (handler != null) handler();
|
||||
}
|
||||
|
||||
public void AddResults(List<Result> results)
|
||||
{
|
||||
if (results.Count == 0) return;
|
||||
|
||||
if (Dirty)
|
||||
{
|
||||
Dirty = false;
|
||||
pnlContainer.Children.Clear();
|
||||
lbResults.Items.Clear();
|
||||
}
|
||||
|
||||
for (int i = 0; i < results.Count; i++)
|
||||
foreach (var result in results)
|
||||
{
|
||||
Result result = results[i];
|
||||
if (!CheckExisted(result))
|
||||
{
|
||||
ResultItem control = new ResultItem(result);
|
||||
pnlContainer.Children.Insert(GetInsertLocation(result.Score), control);
|
||||
int position = GetInsertLocation(result.Score);
|
||||
lbResults.Items.Insert(position, result);
|
||||
}
|
||||
}
|
||||
|
||||
lbResults.UpdateLayout();
|
||||
SelectFirst();
|
||||
pnlContainer.UpdateLayout();
|
||||
|
||||
double resultItemHeight = 0;
|
||||
if (pnlContainer.Children.Count > 0)
|
||||
{
|
||||
var resultItem = pnlContainer.Children[0] as ResultItem;
|
||||
if (resultItem != null)
|
||||
resultItemHeight = resultItem.ActualHeight;
|
||||
}
|
||||
pnlContainer.Height = pnlContainer.Children.Count * resultItemHeight;
|
||||
OnResultItemChangedEvent();
|
||||
}
|
||||
|
||||
private bool CheckExisted(Result result)
|
||||
{
|
||||
return pnlContainer.Children.Cast<ResultItem>().Any(child => child.Result.Equals(result));
|
||||
}
|
||||
|
||||
private int GetInsertLocation(int currentScore)
|
||||
{
|
||||
int location = pnlContainer.Children.Count;
|
||||
if (pnlContainer.Children.Count == 0) return 0;
|
||||
if (currentScore > ((ResultItem)pnlContainer.Children[0]).Result.Score) return 0;
|
||||
int location = lbResults.Items.Count;
|
||||
if (lbResults.Items.Count == 0) return 0;
|
||||
if (currentScore > ((Result)lbResults.Items[0]).Score) return 0;
|
||||
|
||||
for (int index = 1; index < pnlContainer.Children.Count; index++)
|
||||
for (int index = 1; index < lbResults.Items.Count; index++)
|
||||
{
|
||||
ResultItem next = pnlContainer.Children[index] as ResultItem;
|
||||
ResultItem prev = pnlContainer.Children[index - 1] as ResultItem;
|
||||
Result next = lbResults.Items[index] as Result;
|
||||
Result prev = lbResults.Items[index - 1] as Result;
|
||||
if (next != null && prev != null)
|
||||
{
|
||||
if ((currentScore >= next.Result.Score && currentScore <= prev.Result.Score))
|
||||
if ((currentScore >= next.Score && currentScore <= prev.Score))
|
||||
{
|
||||
if (currentScore == next.Result.Score)
|
||||
if (currentScore == next.Score)
|
||||
{
|
||||
location = index + 1;
|
||||
}
|
||||
@ -89,40 +56,10 @@ namespace Wox
|
||||
return location;
|
||||
}
|
||||
|
||||
public int GetCurrentResultCount()
|
||||
{
|
||||
return pnlContainer.Children.Count;
|
||||
}
|
||||
|
||||
public int GetCurrentSelectedResultIndex()
|
||||
{
|
||||
for (int i = 0; i < pnlContainer.Children.Count; i++)
|
||||
{
|
||||
var resultItemControl = pnlContainer.Children[i] as ResultItem;
|
||||
if (resultItemControl != null && resultItemControl.Selected)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void UnSelectAll()
|
||||
{
|
||||
for (int i = 0; i < pnlContainer.Children.Count; i++)
|
||||
{
|
||||
var resultItemControl = pnlContainer.Children[i] as ResultItem;
|
||||
if (resultItemControl != null && resultItemControl.Selected)
|
||||
{
|
||||
resultItemControl.Selected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectNext()
|
||||
{
|
||||
int index = GetCurrentSelectedResultIndex();
|
||||
if (index == pnlContainer.Children.Count - 1)
|
||||
int index = lbResults.SelectedIndex;
|
||||
if (index == lbResults.Items.Count - 1)
|
||||
{
|
||||
index = -1;
|
||||
}
|
||||
@ -131,95 +68,44 @@ namespace Wox
|
||||
|
||||
public void SelectPrev()
|
||||
{
|
||||
int index = GetCurrentSelectedResultIndex();
|
||||
int index = lbResults.SelectedIndex;
|
||||
if (index == 0)
|
||||
{
|
||||
index = pnlContainer.Children.Count;
|
||||
index = lbResults.Items.Count;
|
||||
}
|
||||
Select(index - 1);
|
||||
}
|
||||
|
||||
private void Select(int index)
|
||||
{
|
||||
if (pnlContainer.Children.Count > 0)
|
||||
{
|
||||
int oldIndex = GetCurrentSelectedResultIndex();
|
||||
|
||||
UnSelectAll();
|
||||
var resultItemControl = pnlContainer.Children[index] as ResultItem;
|
||||
if (resultItemControl != null)
|
||||
{
|
||||
resultItemControl.Selected = true;
|
||||
|
||||
double scrollPosition = 0;
|
||||
Point newItemBottomPoint = resultItemControl.TranslatePoint(new Point(0, resultItemControl.ActualHeight), pnlContainer);
|
||||
scrollPosition = newItemBottomPoint.Y;
|
||||
if (index == 0)
|
||||
{
|
||||
sv.ScrollToTop();
|
||||
return;
|
||||
}
|
||||
if (index == pnlContainer.Children.Count - 1)
|
||||
{
|
||||
sv.ScrollToBottom();
|
||||
return;
|
||||
}
|
||||
|
||||
if (index < oldIndex)
|
||||
{
|
||||
//move up and old item is at the top of the scroll view
|
||||
var scrollPostionY = sv.VerticalOffset - sv.VerticalOffset%resultItemControl.ActualHeight +
|
||||
resultItemControl.ActualHeight;
|
||||
if (newItemBottomPoint.Y - scrollPostionY == 0)
|
||||
{
|
||||
scrollPosition = sv.VerticalOffset - resultItemControl.ActualHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//move down and old item is at the bottom of scroll view
|
||||
double scrollPostionY = (sv.ActualHeight + sv.VerticalOffset) - (sv.ActualHeight + sv.VerticalOffset)%resultItemControl.ActualHeight;
|
||||
if (scrollPostionY == newItemBottomPoint.Y - resultItemControl.ActualHeight)
|
||||
{
|
||||
scrollPosition = newItemBottomPoint.Y - sv.ActualHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sv.ScrollToVerticalOffset(scrollPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectFirst()
|
||||
private void SelectFirst()
|
||||
{
|
||||
Select(0);
|
||||
}
|
||||
|
||||
private void Select(int index)
|
||||
{
|
||||
if (index >= 0 && index < lbResults.Items.Count)
|
||||
{
|
||||
lbResults.SelectedItem = lbResults.Items.GetItemAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
public Result AcceptSelect()
|
||||
{
|
||||
int index = GetCurrentSelectedResultIndex();
|
||||
int index = lbResults.SelectedIndex;
|
||||
if (index < 0) return null;
|
||||
|
||||
var resultItemControl = pnlContainer.Children[index] as ResultItem;
|
||||
if (resultItemControl != null)
|
||||
var result = lbResults.Items[index] as Result;
|
||||
if (result != null)
|
||||
{
|
||||
if (resultItemControl.Result.Action != null)
|
||||
if (result.Action != null)
|
||||
{
|
||||
resultItemControl.Result.Action(new ActionContext()
|
||||
result.Action(new ActionContext()
|
||||
{
|
||||
SpecialKeyState = new KeyboardListener().CheckModifiers()
|
||||
});
|
||||
}
|
||||
|
||||
return resultItemControl.Result;
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -232,9 +118,15 @@ namespace Wox
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
pnlContainer.Children.Clear();
|
||||
pnlContainer.Height = 0;
|
||||
OnResultItemChangedEvent();
|
||||
lbResults.Items.Clear();
|
||||
}
|
||||
|
||||
private void lbResults_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (e.AddedItems.Count > 0)
|
||||
{
|
||||
lbResults.ScrollIntoView(e.AddedItems[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -125,6 +125,7 @@
|
||||
<Compile Include="Helper\PluginInstaller.cs" />
|
||||
<Compile Include="Helper\WoxException.cs" />
|
||||
<Compile Include="Helper\KeyboardListener.cs" />
|
||||
<Compile Include="ImagePathConverter.cs" />
|
||||
<Compile Include="Msg.xaml.cs">
|
||||
<DependentUpon>Msg.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
Loading…
Reference in New Issue
Block a user