Databinding for plugin tab + faster image load

This commit is contained in:
bao-qian
2016-05-22 05:30:38 +01:00
parent 708dba6cb1
commit 7056be0870
22 changed files with 286 additions and 274 deletions

View File

@@ -87,7 +87,7 @@ namespace Wox.Core.Plugin
API = API API = API
}); });
}); });
pair.InitTime = milliseconds; pair.Metadata.InitTime = milliseconds;
InternationalizationManager.Instance.UpdatePluginMetadataTranslations(pair); InternationalizationManager.Instance.UpdatePluginMetadataTranslations(pair);
}); });
@@ -167,8 +167,8 @@ namespace Wox.Core.Plugin
results = pair.Plugin.Query(query) ?? results; results = pair.Plugin.Query(query) ?? results;
UpdatePluginMetadata(results, metadata, query); UpdatePluginMetadata(results, metadata, query);
}); });
pair.QueryCount += 1; metadata.QueryCount += 1;
pair.AvgQueryTime = pair.QueryCount == 1 ? milliseconds : (pair.AvgQueryTime + milliseconds) / 2; metadata.AvgQueryTime = metadata.QueryCount == 1 ? milliseconds : (metadata.AvgQueryTime + milliseconds) / 2;
} }
catch (Exception e) catch (Exception e)
{ {

View File

@@ -22,6 +22,7 @@ namespace Wox.Core.UserSettings
metadata.ActionKeywords = settings.ActionKeywords; metadata.ActionKeywords = settings.ActionKeywords;
metadata.ActionKeyword = settings.ActionKeywords[0]; metadata.ActionKeyword = settings.ActionKeywords[0];
} }
metadata.Disabled = settings.Disabled;
} }
else else
{ {

View File

@@ -20,7 +20,10 @@ namespace Wox.Infrastructure.Image
{ {
TopUsedImages[path] = 1; TopUsedImages[path] = 1;
} }
}
public void Cleanup()
{
if (TopUsedImages.Count > MaxCached) if (TopUsedImages.Count > MaxCached)
{ {
var images = TopUsedImages.OrderByDescending(o => o.Value) var images = TopUsedImages.OrderByDescending(o => o.Value)

View File

@@ -43,6 +43,7 @@ namespace Wox.Infrastructure.Image
public static void Save() public static void Save()
{ {
_cache.Cleanup();
_storage.Save(); _storage.Save();
} }
@@ -115,11 +116,6 @@ namespace Wox.Infrastructure.Image
var img = Load(i.Key); var img = Load(i.Key);
if (img != null) if (img != null)
{ {
// todo happlebao magic
// the image created on other threads can be accessed from main ui thread,
// this line made it possible
// should be changed the Dispatcher.InvokeAsync in the future
img.Freeze();
ImageSources[i.Key] = img; ImageSources[i.Key] = img;
} }
}); });
@@ -185,9 +181,9 @@ namespace Wox.Infrastructure.Image
path = ErrorIcon; path = ErrorIcon;
} }
} }
ImageSources[path] = image; ImageSources[path] = image;
_cache.Add(path); _cache.Add(path);
image.Freeze();
} }
return image; return image;
} }

View File

@@ -1,25 +0,0 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace Wox.Infrastructure.Image
{
public class ImagePathConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || value == DependencyProperty.UnsetValue)
{
return null;
}
var image = ImageLoader.Load(value.ToString());
return image;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
}

View File

@@ -78,7 +78,6 @@
<Compile Include="Hotkey\KeyEvent.cs" /> <Compile Include="Hotkey\KeyEvent.cs" />
<Compile Include="Image\ImageCache.cs" /> <Compile Include="Image\ImageCache.cs" />
<Compile Include="Image\ImageLoader.cs" /> <Compile Include="Image\ImageLoader.cs" />
<Compile Include="Image\ImagePathConverter.cs" />
<Compile Include="Logger\Log.cs" /> <Compile Include="Logger\Log.cs" />
<Compile Include="Storage\ISavable.cs" /> <Compile Include="Storage\ISavable.cs" />
<Compile Include="Storage\PluginJsonStorage.cs" /> <Compile Include="Storage\PluginJsonStorage.cs" />

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Weavers>
<PropertyChanged />
</Weavers>

View File

@@ -1,9 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Newtonsoft.Json;
using PropertyChanged;
namespace Wox.Plugin namespace Wox.Plugin
{ {
[ImplementPropertyChanged]
[JsonObject(MemberSerialization.OptOut)]
public class PluginMetadata public class PluginMetadata
{ {
private string _pluginDirectory; private string _pluginDirectory;
@@ -13,9 +16,8 @@ namespace Wox.Plugin
public string Version { get; set; } public string Version { get; set; }
public string Language { get; set; } public string Language { get; set; }
public string Description { get; set; } public string Description { get; set; }
public string Website { get; set; } public string Website { get; set; }
public bool Disabled { get; set; }
public string ExecuteFilePath { get; private set;} public string ExecuteFilePath { get; private set;}
public string ExecuteFileName { get; set; } public string ExecuteFileName { get; set; }
@@ -31,7 +33,6 @@ namespace Wox.Plugin
} }
} }
[Obsolete("Use ActionKeywords instead, because Wox now support multiple action keywords. This will be remove in v1.3.0")]
public string ActionKeyword { get; set; } public string ActionKeyword { get; set; }
public List<string> ActionKeywords { get; set; } public List<string> ActionKeywords { get; set; }
@@ -45,5 +46,12 @@ namespace Wox.Plugin
[Obsolete("Use IcoPath")] [Obsolete("Use IcoPath")]
public string FullIcoPath => IcoPath; public string FullIcoPath => IcoPath;
[JsonIgnore]
public long InitTime { get; set; }
[JsonIgnore]
public long AvgQueryTime { get; set; }
[JsonIgnore]
public int QueryCount { get; set; }
} }
} }

View File

@@ -5,11 +5,7 @@
public IPlugin Plugin { get; internal set; } public IPlugin Plugin { get; internal set; }
public PluginMetadata Metadata { get; internal set; } public PluginMetadata Metadata { get; internal set; }
internal long InitTime { get; set; }
internal long AvgQueryTime { get; set; }
internal int QueryCount { get; set; }
public override string ToString() public override string ToString()
{ {

View File

@@ -12,6 +12,8 @@
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion> <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<TargetFrameworkProfile /> <TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@@ -44,6 +46,10 @@
</Reference> </Reference>
<Reference Include="PresentationCore" /> <Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" /> <Reference Include="PresentationFramework" />
<Reference Include="PropertyChanged, Version=1.51.0.0, Culture=neutral, PublicKeyToken=ee3ee20bcf148ddd, processorArchitecture=MSIL">
<HintPath>..\packages\PropertyChanged.Fody.1.51.0\lib\dotnet\PropertyChanged.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Xaml" /> <Reference Include="System.Xaml" />
@@ -75,8 +81,17 @@
<None Include="packages.config" /> <None Include="packages.config" />
<None Include="README.md" /> <None Include="README.md" />
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup>
<Content Include="FodyWeavers.xml" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Fody.1.29.2\build\dotnet\Fody.targets" Condition="Exists('..\packages\Fody.1.29.2\build\dotnet\Fody.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Fody.1.29.2\build\dotnet\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Fody.1.29.2\build\dotnet\Fody.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild"> <Target Name="BeforeBuild">

View File

@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Fody" version="1.29.2" targetFramework="net452" developmentDependency="true" />
<package id="JetBrains.Annotations" version="10.1.4" targetFramework="net452" /> <package id="JetBrains.Annotations" version="10.1.4" targetFramework="net452" />
<package id="Newtonsoft.Json" version="8.0.3" targetFramework="net452" /> <package id="Newtonsoft.Json" version="8.0.3" targetFramework="net452" />
<package id="PropertyChanged.Fody" version="1.51.0" targetFramework="net452" developmentDependency="true" />
<package id="System.Runtime" version="4.0.0" targetFramework="net452" /> <package id="System.Runtime" version="4.0.0" targetFramework="net452" />
</packages> </packages>

View File

@@ -70,6 +70,9 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.Plugin.Shell", "Plugins\Wox.Plugin.Shell\Wox.Plugin.Shell.csproj", "{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.Plugin.Shell", "Plugins\Wox.Plugin.Shell\Wox.Plugin.Shell.csproj", "{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}"
EndProject EndProject
Global Global
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64 Debug|x64 = Debug|x64

View File

@@ -38,7 +38,7 @@ namespace Wox
private void OnStartup(object sender, StartupEventArgs e) private void OnStartup(object sender, StartupEventArgs e)
{ {
Stopwatch.Debug("Startup Time", () => Stopwatch.Normal("Startup Time", () =>
{ {
RegisterDispatcherUnhandledException(); RegisterDispatcherUnhandledException();

4
Wox/FodyWeavers.xml Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Weavers>
<PropertyChanged />
</Weavers>

View File

@@ -31,16 +31,13 @@
<Button.Content> <Button.Content>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5" <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5"
Cursor="Hand" UseLayoutRounding="False"> Cursor="Hand" UseLayoutRounding="False">
<Grid.Resources>
<image:ImagePathConverter x:Key="ImageConverter" />
</Grid.Resources>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="32" /> <ColumnDefinition Width="32" />
<ColumnDefinition /> <ColumnDefinition />
<ColumnDefinition Width="0" /> <ColumnDefinition Width="0" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Image x:Name="imgIco" Width="32" Height="32" HorizontalAlignment="Left" <Image x:Name="imgIco" Width="32" Height="32" HorizontalAlignment="Left"
Source="{Binding IcoPath,Converter={StaticResource ImageConverter},IsAsync=True}" /> Source="{Binding Image ,IsAsync=True}" />
<Grid Margin="5 0 5 0" Grid.Column="1" HorizontalAlignment="Stretch"> <Grid Margin="5 0 5 0" Grid.Column="1" HorizontalAlignment="Stretch">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition /> <RowDefinition />

View File

@@ -5,7 +5,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:wox="clr-namespace:Wox" xmlns:wox="clr-namespace:Wox"
xmlns:vm="clr-namespace:Wox.ViewModel" xmlns:vm="clr-namespace:Wox.ViewModel"
xmlns:woxPlugin="clr-namespace:Wox.Plugin;assembly=Wox.Plugin"
xmlns:image="clr-namespace:Wox.Infrastructure.Image;assembly=Wox.Infrastructure" xmlns:image="clr-namespace:Wox.Infrastructure.Image;assembly=Wox.Infrastructure"
x:Class="Wox.SettingWindow" x:Class="Wox.SettingWindow"
mc:Ignorable="d" mc:Ignorable="d"
@@ -15,11 +14,8 @@
WindowStartupLocation="CenterScreen" WindowStartupLocation="CenterScreen"
Height="600" Width="800" PreviewKeyDown="Window_PreviewKeyDown" Height="600" Width="800" PreviewKeyDown="Window_PreviewKeyDown"
d:DataContext="{d:DesignInstance vm:SettingWindowViewModel}"> d:DataContext="{d:DesignInstance vm:SettingWindowViewModel}">
<Window.Resources>
<image:ImagePathConverter x:Key="ImageConverter" />
</Window.Resources>
<TabControl Height="auto" SelectedIndex="{Binding SelectedTab}"> <TabControl Height="auto" SelectedIndex="{Binding SelectedTab}">
<TabItem Header="{DynamicResource general}"> <TabItem Header="{DynamicResource general}" Height="24" VerticalAlignment="Top">
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<CheckBox IsChecked="{Binding Settings.StartWoxOnSystemStartup}" Margin="10"> <CheckBox IsChecked="{Binding Settings.StartWoxOnSystemStartup}" Margin="10">
<TextBlock Text="{DynamicResource startWoxOnSystemStartup}" /> <TextBlock Text="{DynamicResource startWoxOnSystemStartup}" />
@@ -36,7 +32,7 @@
<CheckBox Margin="10" IsChecked="{Binding Settings.IgnoreHotkeysOnFullscreen}"> <CheckBox Margin="10" IsChecked="{Binding Settings.IgnoreHotkeysOnFullscreen}">
<TextBlock Text="{DynamicResource ignoreHotkeysOnFullscreen}" /> <TextBlock Text="{DynamicResource ignoreHotkeysOnFullscreen}" />
</CheckBox> </CheckBox>
<CheckBox Margin="10" IsChecked="{Binding Settings.AutoUpdates}" <CheckBox Margin="10" IsChecked="{Binding Settings.AutoUpdates}"
Checked="OnAutoStartupChecked" Unchecked="OnAutoStartupUncheck"> Checked="OnAutoStartupChecked" Unchecked="OnAutoStartupUncheck">
<TextBlock Text="{DynamicResource autoUpdates}" /> <TextBlock Text="{DynamicResource autoUpdates}" />
</CheckBox> </CheckBox>
@@ -44,108 +40,116 @@
<TextBlock Text="{DynamicResource language}" /> <TextBlock Text="{DynamicResource language}" />
<ComboBox Margin="10 0 0 0" Width="120" SelectionChanged="OnLanguageChanged" <ComboBox Margin="10 0 0 0" Width="120" SelectionChanged="OnLanguageChanged"
ItemsSource="{Binding Languages}" SelectedValue="{Binding Settings.Language}" ItemsSource="{Binding Languages}" SelectedValue="{Binding Settings.Language}"
DisplayMemberPath="Display" SelectedValuePath = "LanguageCode" /> DisplayMemberPath="Display" SelectedValuePath="LanguageCode" />
</StackPanel> </StackPanel>
<StackPanel Orientation="Horizontal" Margin="10"> <StackPanel Orientation="Horizontal" Margin="10">
<TextBlock Text="{DynamicResource maxShowResults}" /> <TextBlock Text="{DynamicResource maxShowResults}" />
<ComboBox Margin="10 0 0 0" Width="45" ItemsSource="{Binding MaxResultsRange}" SelectedItem="{Binding Settings.MaxResultsToShow}"/> <ComboBox Margin="10 0 0 0" Width="45" ItemsSource="{Binding MaxResultsRange}"
SelectedItem="{Binding Settings.MaxResultsToShow}" />
</StackPanel> </StackPanel>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock Margin="10" Text="{DynamicResource pythonDirectory}" /> <TextBlock Margin="10" Text="{DynamicResource pythonDirectory}" />
<TextBox Width="300" Margin="10" Text="{Binding Settings.PluginSettings.PythonDirectory}"/> <TextBox Width="300" Margin="10" Text="{Binding Settings.PluginSettings.PythonDirectory}" />
<Button Margin="10" Click="OnSelectPythonDirectoryClick" Content="{DynamicResource selectPythonDirectory}" /> <Button Margin="10" Click="OnSelectPythonDirectoryClick"
Content="{DynamicResource selectPythonDirectory}" />
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
</TabItem> </TabItem>
<TabItem Header="{DynamicResource plugin}" Selector.Selected="OnPluginTabSelected"> <TabItem Header="{DynamicResource plugin}">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="39.5" /> <ColumnDefinition Width="200" />
<ColumnDefinition Width="160.5"/>
<ColumnDefinition /> <ColumnDefinition />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<DockPanel Grid.Column="0" Grid.ColumnSpan="2"> <DockPanel Grid.Column="0">
<TextBlock DockPanel.Dock="Top" Margin="10" HorizontalAlignment="Left" Cursor="Hand" <TextBlock DockPanel.Dock="Top" Margin="10" Cursor="Hand"
MouseUp="tbMorePlugins_MouseUp" Foreground="Blue" MouseUp="OnMorePluginsClicked" Foreground="Blue"
Text="{DynamicResource browserMorePlugins}" /> Text="{DynamicResource browserMorePlugins}" />
<ListBox x:Name="PluginsListBox" Margin="10, 0, 10, 10" <ListBox SelectedIndex="0" SelectedItem="{Binding SelectedPlugin}"
SelectionChanged="OnPluginsSelectionChanged" ItemsSource="{Binding MetadataViewModels}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10, 0, 10, 10" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
ScrollViewer.HorizontalScrollBarVisibility="Disabled" Grid.IsSharedSizeScope="True"> <ListBox.ItemTemplate>
<ListBox.Resources> <DataTemplate>
<DataTemplate DataType="{x:Type woxPlugin:PluginPair}"> <StackPanel Orientation="Horizontal" Margin="3">
<Grid Height="36" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="3"> <Image Source="{Binding Image, IsAsync=True}"
<Grid.ColumnDefinitions> Width="32" Height="32" />
<ColumnDefinition Width="32" /> <StackPanel Margin="3 0 3 0">
<ColumnDefinition /> <TextBlock Text="{Binding Metadata.Name}"
</Grid.ColumnDefinitions> ToolTip="{Binding Metadata.Name}" />
<Image Width="32" Height="32" HorizontalAlignment="Left" <TextBlock Text="{Binding Metadata.Description}"
Source="{Binding Metadata.IcoPath,Converter={StaticResource ImageConverter},IsAsync=True}" /> ToolTip="{Binding Metadata.Description}"
<Grid Margin="3 0 3 0" Grid.Column="1" HorizontalAlignment="Stretch"> Opacity="0.5" />
<Grid.RowDefinitions> </StackPanel>
<RowDefinition /> </StackPanel>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock VerticalAlignment="Center" ToolTip="{Binding Metadata.Name}"
x:Name="tbTitle" Text="{Binding Metadata.Name}" />
<TextBlock ToolTip="{Binding Metadata.Description}"
Grid.Row="1" x:Name="tbSubTitle"
Text="{Binding Metadata.Description}" Opacity="0.5" />
</Grid>
</Grid>
</DataTemplate> </DataTemplate>
</ListBox.Resources> </ListBox.ItemTemplate>
</ListBox> </ListBox>
</DockPanel> </DockPanel>
<Grid Margin="0" Grid.Column="2"> <Grid Grid.Column="1">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<ContentControl Grid.ColumnSpan="1" Grid.Row="0" Margin="10 10 10 0"> <ContentControl DataContext="{Binding Path=SelectedPlugin}"
Grid.ColumnSpan="1" Grid.Row="0" Margin="10 10 10 0">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="48" /> <ColumnDefinition Width="48" />
<ColumnDefinition /> <ColumnDefinition />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Image Width="48" Height="48" HorizontalAlignment="Left" VerticalAlignment="Top" <Image Source="{Binding Image, IsAsync=True}"
x:Name="PluginIcon" /> Width="48" Height="48" HorizontalAlignment="Left" VerticalAlignment="Top" />
<Grid Margin="10,0,0,0" Grid.Column="1" HorizontalAlignment="Stretch"> <Grid Margin="10,0,0,0" Grid.Column="1" HorizontalAlignment="Stretch">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition /> <RowDefinition />
<RowDefinition /> <RowDefinition />
<RowDefinition /> <RowDefinition />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<DockPanel Grid.Row="0"> <Grid Grid.Row="0">
<TextBlock x:Name="PluginTitle" Text="Plugin Title" Cursor="Hand" <Grid.ColumnDefinitions>
MouseUp="PluginTitle_OnMouseUp" <ColumnDefinition />
ToolTip="{Binding Source=pluginTitle, Path=Text}" FontSize="24" /> <ColumnDefinition />
<TextBlock Opacity="0.5" VerticalAlignment="Bottom" HorizontalAlignment="Right" </Grid.ColumnDefinitions>
x:Name="PluginAuthor" Text="{DynamicResource author}" /> <TextBlock Text="{Binding Metadata.Name}"
</DockPanel> ToolTip="{Binding Metadata.Name}"
<TextBlock Grid.Row="1" x:Name="PluginSubTitle" Opacity="0.5" Grid.Column="0"
ToolTip="{Binding Source=pluginSubTitle, Path=Text}" /> Cursor="Hand" MouseUp="OnPluginNameClick" FontSize="24"
HorizontalAlignment="Left" />
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right"
VerticalAlignment="Bottom" Opacity="0.5">
<TextBlock Text="{DynamicResource author}" />
<TextBlock Text=": " />
<TextBlock Text="{Binding Metadata.Author}" ToolTip="{Binding Metadata.Author}" />
</StackPanel>
</Grid>
<TextBlock Text="{Binding Metadata.Description}"
ToolTip="{Binding Metadata.Description}"
Grid.Row="1" Opacity="0.5" />
<DockPanel Grid.Row="2" Margin="0 10 0 8"> <DockPanel Grid.Row="2" Margin="0 10 0 8">
<CheckBox x:Name="DisablePlugin" Click="OnDisablePluginClicked"> <CheckBox IsChecked="{Binding Metadata.Disabled}" Checked="OnPluginToggled"
Unchecked="OnPluginToggled">
<TextBlock Text="{DynamicResource disable}" /> <TextBlock Text="{DynamicResource disable}" />
</CheckBox> </CheckBox>
<TextBlock Margin="20 0 0 0" <TextBlock Text="{DynamicResource actionKeywords}"
x:Name="PluginActionKeywordsTitle" Visibility="{Binding ActionKeywordsVisibility}"
Text="{DynamicResource actionKeywords}" /> Margin="20 0 0 0" />
<TextBlock Margin="5 0 0 0" ToolTip="Change Action Keywords" Cursor="Hand" <TextBlock Text="{Binding ActionKeywordsText}"
MouseUp="PluginActionKeywords_OnMouseUp" Foreground="Blue" Text="keys" Visibility="{Binding ActionKeywordsVisibility}"
x:Name="PluginActionKeywords" /> ToolTip="Change Action Keywords"
<TextBlock Margin="10 0 0 0" Text="Initialize time: 0ms" x:Name="PluginInitTime" /> Margin="5 0 0 0" Cursor="Hand" Foreground="Blue"
<TextBlock Margin="10 0 0 0" Text="Query time: 0ms" x:Name="PluginQueryTime" /> MouseUp="OnPluginActionKeywordsClick" />
<TextBlock HorizontalAlignment="Right" Cursor="Hand" <TextBlock Text="{Binding InitilizaTime}" Margin="10 0 0 0" />
MouseUp="tbOpenPluginDirecoty_MouseUp" Foreground="Blue" <TextBlock Text="{Binding QueryTime}" Margin="10 0 0 0" />
Text="{DynamicResource pluginDirectory}" x:Name="OpenPluginDirecoty" /> <TextBlock Text="{DynamicResource pluginDirectory}"
HorizontalAlignment="Right" Cursor="Hand"
MouseUp="OnPluginDirecotyClick" Foreground="Blue" />
</DockPanel> </DockPanel>
</Grid> </Grid>
</Grid> </Grid>
</ContentControl> </ContentControl>
<ContentControl x:Name="PluginContentPanel" Grid.ColumnSpan="1" Grid.Row="1" Margin="0" <ContentControl Content="{Binding SettingProvider}"
Grid.ColumnSpan="1" Grid.Row="1"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" /> HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</Grid> </Grid>
</Grid> </Grid>

View File

@@ -6,7 +6,6 @@ using System.Linq;
using System.Net; using System.Net;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
@@ -20,8 +19,6 @@ using Wox.Core.Resource;
using Wox.Core.UserSettings; using Wox.Core.UserSettings;
using Wox.Helper; using Wox.Helper;
using Wox.Infrastructure.Hotkey; using Wox.Infrastructure.Hotkey;
using Wox.Infrastructure.Image;
using Wox.Infrastructure.Logger;
using Wox.Plugin; using Wox.Plugin;
using Wox.ViewModel; using Wox.ViewModel;
using Stopwatch = Wox.Infrastructure.Stopwatch; using Stopwatch = Wox.Infrastructure.Stopwatch;
@@ -31,17 +28,19 @@ namespace Wox
public partial class SettingWindow public partial class SettingWindow
{ {
private const string StartupPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"; private const string StartupPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
public readonly IPublicAPI _api; public readonly IPublicAPI _api;
bool settingsLoaded; bool settingsLoaded;
private Dictionary<ISettingProvider, Control> featureControls = new Dictionary<ISettingProvider, Control>();
private bool themeTabLoaded; private bool themeTabLoaded;
private Settings _settings; private Settings _settings;
private SettingWindowViewModel _viewModel;
public SettingWindow(IPublicAPI api, SettingWindowViewModel viewModel) public SettingWindow(IPublicAPI api, SettingWindowViewModel viewModel)
{ {
InitializeComponent(); InitializeComponent();
_settings = viewModel.Settings; _settings = viewModel.Settings;
DataContext = viewModel; DataContext = viewModel;
_viewModel = viewModel;
_api = api; _api = api;
ResultListBoxPreview.DataContext = new ResultsViewModel(_settings); ResultListBoxPreview.DataContext = new ResultsViewModel(_settings);
Loaded += Setting_Loaded; Loaded += Setting_Loaded;
@@ -448,179 +447,58 @@ namespace Wox
#region Plugin #region Plugin
private void OnPluginsSelectionChanged(object sender, SelectionChangedEventArgs _) private void OnPluginToggled(object sender, RoutedEventArgs e)
{ {
var id = _viewModel.SelectedPlugin.Metadata.ID;
var pair = PluginsListBox.SelectedItem as PluginPair; _settings.PluginSettings.Plugins[id].Disabled = _viewModel.SelectedPlugin.Metadata.Disabled;
string pluginId = string.Empty;
List<string> actionKeywords = null;
if (pair == null) return;
actionKeywords = pair.Metadata.ActionKeywords;
PluginAuthor.Visibility = Visibility.Visible;
PluginInitTime.Text =
string.Format(InternationalizationManager.Instance.GetTranslation("plugin_init_time"), pair.InitTime);
PluginQueryTime.Text =
string.Format(InternationalizationManager.Instance.GetTranslation("plugin_query_time"),
pair.AvgQueryTime);
if (actionKeywords.Count > 1)
{
PluginActionKeywordsTitle.Visibility = Visibility.Collapsed;
PluginActionKeywords.Visibility = Visibility.Collapsed;
}
else
{
PluginActionKeywordsTitle.Visibility = Visibility.Visible;
PluginActionKeywords.Visibility = Visibility.Visible;
}
OpenPluginDirecoty.Visibility = Visibility.Visible;
PluginTitle.Text = pair.Metadata.Name;
PluginTitle.Cursor = Cursors.Hand;
PluginActionKeywords.Text = string.Join(Query.ActionKeywordSeperater, actionKeywords.ToArray());
PluginAuthor.Text = InternationalizationManager.Instance.GetTranslation("author") + ": " +
pair.Metadata.Author;
PluginSubTitle.Text = pair.Metadata.Description;
pluginId = pair.Metadata.ID;
PluginIcon.Source = ImageLoader.Load(pair.Metadata.IcoPath);
var customizedPluginConfig = _settings.PluginSettings.Plugins[pluginId];
DisablePlugin.IsChecked = customizedPluginConfig != null && customizedPluginConfig.Disabled;
PluginContentPanel.Content = null;
var settingProvider = pair.Plugin as ISettingProvider;
if (settingProvider != null)
{
Control control;
if (!featureControls.TryGetValue(settingProvider, out control))
{
var multipleActionKeywordsProvider = settingProvider as IMultipleActionKeywords;
if (multipleActionKeywordsProvider != null)
{
multipleActionKeywordsProvider.ActionKeywordsChanged += (o, e) =>
{
// update in-memory data
PluginManager.UpdateActionKeywordForPlugin(pair, e.OldActionKeyword, e.NewActionKeyword);
// update persistant data
_settings.PluginSettings.UpdateActionKeyword(pair.Metadata);
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("succeed"));
};
}
featureControls.Add(settingProvider, control = settingProvider.CreateSettingPanel());
}
PluginContentPanel.Content = control;
control.HorizontalAlignment = HorizontalAlignment.Stretch;
control.VerticalAlignment = VerticalAlignment.Stretch;
control.Width = Double.NaN;
control.Height = Double.NaN;
}
} }
private void OnDisablePluginClicked(object sender, RoutedEventArgs e) private void OnPluginActionKeywordsClick(object sender, MouseButtonEventArgs e)
{
var checkBox = (CheckBox)e.Source;
var pair = (PluginPair)PluginsListBox.SelectedItem;
var id = pair.Metadata.ID;
if (checkBox.IsChecked != null)
{
var disabled = (bool)checkBox.IsChecked;
_settings.PluginSettings.Plugins[id].Disabled = disabled;
}
else
{
Log.Warn($"IsChecked for checkbox is null for plugin: {pair.Metadata.Name}");
}
}
private void PluginActionKeywords_OnMouseUp(object sender, MouseButtonEventArgs e)
{ {
if (e.ChangedButton == MouseButton.Left) if (e.ChangedButton == MouseButton.Left)
{ {
var pair = PluginsListBox.SelectedItem as PluginPair; var id = _viewModel.SelectedPlugin.Metadata.ID;
if (pair != null) ActionKeywords changeKeywordsWindow = new ActionKeywords(id, _settings);
{ changeKeywordsWindow.ShowDialog();
//third-party plugin
string id = pair.Metadata.ID;
ActionKeywords changeKeywordsWindow = new ActionKeywords(id, _settings);
changeKeywordsWindow.ShowDialog();
PluginPair plugin = PluginManager.GetPluginForId(id);
if (plugin != null)
PluginActionKeywords.Text = string.Join(Query.ActionKeywordSeperater,
pair.Metadata.ActionKeywords.ToArray());
}
} }
} }
private void PluginTitle_OnMouseUp(object sender, MouseButtonEventArgs e) private void OnPluginNameClick(object sender, MouseButtonEventArgs e)
{ {
if (e.ChangedButton == MouseButton.Left) if (e.ChangedButton == MouseButton.Left)
{ {
var pair = PluginsListBox.SelectedItem as PluginPair; if (e.ChangedButton == MouseButton.Left)
if (pair != null)
{ {
//third-party plugin var website = _viewModel.SelectedPlugin.Metadata.Website;
if (!string.IsNullOrEmpty(pair.Metadata.Website)) if (!string.IsNullOrEmpty(website))
{ {
try var uri = new Uri(website);
{ if (Uri.CheckSchemeName(uri.Scheme))
Process.Start(pair.Metadata.Website);
}
catch
{ {
Process.Start(website);
} }
} }
} }
} }
} }
private void tbOpenPluginDirecoty_MouseUp(object sender, MouseButtonEventArgs e) private void OnPluginDirecotyClick(object sender, MouseButtonEventArgs e)
{ {
if (e.ChangedButton == MouseButton.Left) if (e.ChangedButton == MouseButton.Left)
{ {
var pair = PluginsListBox.SelectedItem as PluginPair; var directory = _viewModel.SelectedPlugin.Metadata.PluginDirectory;
if (pair != null) if (!string.IsNullOrEmpty(directory) && Directory.Exists(directory))
{ {
//third-party plugin Process.Start(directory);
if (!string.IsNullOrEmpty(pair.Metadata.Website))
{
try
{
Process.Start(pair.Metadata.PluginDirectory);
}
catch
{
}
}
} }
} }
} }
private void tbMorePlugins_MouseUp(object sender, MouseButtonEventArgs e) private void OnMorePluginsClicked(object sender, MouseButtonEventArgs e)
{ {
Process.Start("http://www.getwox.com/plugin"); Process.Start("http://www.getwox.com/plugin");
} }
public void OnPluginTabSelected(object sender, RoutedEventArgs e)
{
var plugins = PluginManager.AllPlugins;
//move all disabled to bottom
plugins.Sort(delegate (PluginPair a, PluginPair b)
{
int res = _settings.PluginSettings.Plugins[a.Metadata.ID].Disabled ? 1 : 0;
res += _settings.PluginSettings.Plugins[b.Metadata.ID].Disabled ? -1 : 0;
return res;
});
PluginsListBox.ItemsSource = new CompositeCollection
{
new CollectionContainer
{
Collection = plugins
}
}; ;
PluginsListBox.SelectedIndex = 0;
}
#endregion #endregion
#region Proxy #region Proxy
@@ -738,5 +616,6 @@ namespace Wox
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri)); Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
e.Handled = true; e.Handled = true;
} }
} }
} }

View File

@@ -0,0 +1,34 @@
using System.Windows;
using System.Windows.Media;
using Wox.Plugin;
using PropertyChanged;
using Wox.Core.Resource;
using Wox.Infrastructure.Image;
namespace Wox.ViewModel
{
[ImplementPropertyChanged]
public class PluginViewModel
{
public PluginPair PluginPair { get; set; }
public PluginMetadata Metadata { get; set; }
public IPlugin Plugin { get; set; }
private readonly Internationalization _translator = InternationalizationManager.Instance;
public ImageSource Image => ImageLoader.Load(Metadata.IcoPath);
public Visibility ActionKeywordsVisibility => Metadata.ActionKeywords.Count > 1 ? Visibility.Collapsed : Visibility.Visible;
public string InitilizaTime => string.Format(_translator.GetTranslation("plugin_init_time"), Metadata.InitTime);
public string QueryTime => string.Format(_translator.GetTranslation("plugin_query_time"), Metadata.AvgQueryTime);
public string ActionKeywordsText
{
get
{
var text = string.Join(Query.ActionKeywordSeperater, Metadata.ActionKeywords);
return text;
}
}
}
}

View File

@@ -1,10 +1,9 @@
using System; using System;
using Wox.Core.Plugin; using System.Windows.Media;
using Wox.Core.Resource; using System.Windows;
using Wox.Infrastructure; using Wox.Infrastructure.Image;
using Wox.Infrastructure.Hotkey;
using Wox.Plugin; using Wox.Plugin;
using Wox.Storage;
namespace Wox.ViewModel namespace Wox.ViewModel
{ {
@@ -37,7 +36,14 @@ namespace Wox.ViewModel
public string PluginID => RawResult.PluginID; public string PluginID => RawResult.PluginID;
public string IcoPath => RawResult.IcoPath; public ImageSource Image
{
get
{
var image = ImageLoader.Load(RawResult.IcoPath);
return image;
}
}
public int Score public int Score
{ {

View File

@@ -1,28 +1,60 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using Microsoft.Win32; using PropertyChanged;
using Wox.Core.Plugin; using Wox.Core.Plugin;
using Wox.Core.Resource; using Wox.Core.Resource;
using Wox.Core.UserSettings; using Wox.Core.UserSettings;
using Wox.Infrastructure.Storage; using Wox.Infrastructure.Storage;
using Wox.Plugin;
using static System.String;
namespace Wox.ViewModel namespace Wox.ViewModel
{ {
[ImplementPropertyChanged]
public class SettingWindowViewModel public class SettingWindowViewModel
{ {
private const string StartupPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"; public Settings Settings { get; set; }
private readonly JsonStrorage<Settings> _storage; private readonly JsonStrorage<Settings> _storage;
public Settings Settings { get; set; } private readonly Dictionary<ISettingProvider, Control> _featureControls = new Dictionary<ISettingProvider, Control>();
public List<Language> Languages => InternationalizationManager.Instance.LoadAvailableLanguages(); public List<Language> Languages => InternationalizationManager.Instance.LoadAvailableLanguages();
public IEnumerable<int> MaxResultsRange => Enumerable.Range(2, 16); public IEnumerable<int> MaxResultsRange => Enumerable.Range(2, 16);
public Tab SelectedTab { get; set; } = Tab.General; public Tab SelectedTab { get; set; } = Tab.General;
public PluginViewModel SelectedPlugin { get; set; }
public IList<PluginViewModel> MetadataViewModels
{
get
{
var plugins = PluginManager.AllPlugins;
var settings = Settings.PluginSettings.Plugins;
plugins.Sort((a, b) =>
{
var d1 = settings[a.Metadata.ID].Disabled;
var d2 = settings[b.Metadata.ID].Disabled;
if (d1 == d2)
{
return Compare(a.Metadata.Name, b.Metadata.Name, StringComparison.CurrentCulture);
}
else
{
return d1.CompareTo(d2);
}
});
var metadatas = plugins.Select(p => new PluginViewModel
{
PluginPair = p,
Metadata = p.Metadata,
Plugin = p.Plugin
}).ToList();
return metadatas;
}
}
public SettingWindowViewModel() public SettingWindowViewModel()
{ {
@@ -30,6 +62,45 @@ namespace Wox.ViewModel
Settings = _storage.Load(); Settings = _storage.Load();
} }
public Control SettingProvider
{
get
{
var settingProvider = SelectedPlugin.Plugin as ISettingProvider;
if (settingProvider != null)
{
Control control;
if (!_featureControls.TryGetValue(settingProvider, out control))
{
var multipleActionKeywordsProvider = settingProvider as IMultipleActionKeywords;
if (multipleActionKeywordsProvider != null)
{
multipleActionKeywordsProvider.ActionKeywordsChanged += (o, e) =>
{
// update in-memory data
PluginManager.UpdateActionKeywordForPlugin(SelectedPlugin.PluginPair, e.OldActionKeyword,
e.NewActionKeyword);
// update persistant data
Settings.PluginSettings.UpdateActionKeyword(SelectedPlugin.Metadata);
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("succeed"));
};
}
_featureControls.Add(settingProvider, control = settingProvider.CreateSettingPanel());
}
control.HorizontalAlignment = HorizontalAlignment.Stretch;
control.VerticalAlignment = VerticalAlignment.Stretch;
return control;
}
else
{
return new Control();
}
}
}
public void Save() public void Save()
{ {
_storage.Save(); _storage.Save();

View File

@@ -118,6 +118,10 @@
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="PresentationUI, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" /> <Reference Include="PresentationUI, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="PropertyChanged, Version=1.51.0.0, Culture=neutral, PublicKeyToken=ee3ee20bcf148ddd, processorArchitecture=MSIL">
<HintPath>..\packages\PropertyChanged.Fody.1.51.0\lib\dotnet\PropertyChanged.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="ReachFramework" /> <Reference Include="ReachFramework" />
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="Splat, Version=1.6.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Splat.1.6.2\lib\Net45\Splat.dll</HintPath> <HintPath>..\packages\Splat.1.6.2\lib\Net45\Splat.dll</HintPath>
@@ -167,6 +171,7 @@
<Compile Include="Storage\UserSelectedRecord.cs" /> <Compile Include="Storage\UserSelectedRecord.cs" />
<Compile Include="ViewModel\BaseViewModel.cs" /> <Compile Include="ViewModel\BaseViewModel.cs" />
<Compile Include="ViewModel\MainViewModel.cs" /> <Compile Include="ViewModel\MainViewModel.cs" />
<Compile Include="ViewModel\PluginViewModel.cs" />
<Compile Include="ViewModel\ResultViewModel.cs" /> <Compile Include="ViewModel\ResultViewModel.cs" />
<Compile Include="ViewModel\ResultsViewModel.cs" /> <Compile Include="ViewModel\ResultsViewModel.cs" />
<Compile Include="ViewModel\SettingWindowViewModel.cs" /> <Compile Include="ViewModel\SettingWindowViewModel.cs" />
@@ -228,6 +233,7 @@
<Resource Include="Images\app_error.png"> <Resource Include="Images\app_error.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Resource> </Resource>
<Resource Include="FodyWeavers.xml" />
<Content Include="Languages\en.xaml"> <Content Include="Languages\en.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@@ -442,4 +448,11 @@ cd "$(TargetDir)" &amp; del /s /q *.xml
</Target> </Target>
<Target Name="AfterBuild"> <Target Name="AfterBuild">
</Target> </Target>
<Import Project="..\packages\Fody.1.29.2\build\dotnet\Fody.targets" Condition="Exists('..\packages\Fody.1.29.2\build\dotnet\Fody.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Fody.1.29.2\build\dotnet\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Fody.1.29.2\build\dotnet\Fody.targets'))" />
</Target>
</Project> </Project>

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="DeltaCompressionDotNet" version="1.0.0" targetFramework="net452" /> <package id="DeltaCompressionDotNet" version="1.0.0" targetFramework="net452" />
<package id="Fody" version="1.29.2" targetFramework="net452" developmentDependency="true" />
<package id="InputSimulator" version="1.0.4.0" targetFramework="net452" /> <package id="InputSimulator" version="1.0.4.0" targetFramework="net452" />
<package id="JetBrains.Annotations" version="10.1.4" targetFramework="net452" /> <package id="JetBrains.Annotations" version="10.1.4" targetFramework="net452" />
<package id="Mono.Cecil" version="0.9.6.1" targetFramework="net452" /> <package id="Mono.Cecil" version="0.9.6.1" targetFramework="net452" />
@@ -8,6 +9,7 @@
<package id="NHotkey" version="1.2.1" targetFramework="net452" /> <package id="NHotkey" version="1.2.1" targetFramework="net452" />
<package id="NHotkey.Wpf" version="1.2.1" targetFramework="net452" /> <package id="NHotkey.Wpf" version="1.2.1" targetFramework="net452" />
<package id="NuGet.CommandLine" version="3.4.3" targetFramework="net452" developmentDependency="true" /> <package id="NuGet.CommandLine" version="3.4.3" targetFramework="net452" developmentDependency="true" />
<package id="PropertyChanged.Fody" version="1.51.0" targetFramework="net452" developmentDependency="true" />
<package id="SharpZipLib" version="0.86.0" targetFramework="net452" /> <package id="SharpZipLib" version="0.86.0" targetFramework="net452" />
<package id="Splat" version="1.6.2" targetFramework="net452" /> <package id="Splat" version="1.6.2" targetFramework="net452" />
<package id="squirrel.windows" version="1.4.0" targetFramework="net452" /> <package id="squirrel.windows" version="1.4.0" targetFramework="net452" />