reuse viewer window

This commit is contained in:
Paddy Xu
2017-05-16 18:32:36 +03:00
parent f6843eef93
commit a672e441d0
8 changed files with 126 additions and 150 deletions

View File

@@ -56,6 +56,8 @@ namespace QuickLook.Plugin.VideoViewer
mediaElement.Stop();
_context.ShowNotification("", "An error occurred while loading the video.");
throw new Exception();
}
public void LoadAndPlay(string path)

View File

@@ -20,22 +20,27 @@
</Window.Background>
<Border x:Name="windowBorder" BorderThickness="1" BorderBrush="#FF7B7B7B">
<Grid>
<DockPanel x:Name="windowPanel" Opacity="1">
<DockPanel x:Name="windowPanel">
<DockPanel.Style>
<Style TargetType="{x:Type DockPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding ContextObject.IsBusy, ElementName=mainWindow}" Value="False">
<DataTrigger Binding="{Binding ContextObject.IsBusy, ElementName=mainWindow, Mode=OneWay}" Value="False">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="0"
To="1"
BeginTime="0:0:0"
Duration="0:0:0.1" />
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1"
BeginTime="0:0:0" Duration="0:0:0.05" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0"
BeginTime="0:0:0" Duration="0:0:0" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
@@ -52,37 +57,52 @@
</Grid>
</DockPanel>
<Grid>
<local:ViewContentContainer x:Name="viewContentContainer" />
<ContentControl x:Name="container" />
</Grid>
</DockPanel>
<Grid x:Name="busyIndicatorLayer" Visibility="Hidden">
<Grid x:Name="busyIndicatorLayer">
<Grid.Style>
<Style TargetType="{x:Type Grid}">
<Style.Triggers>
<DataTrigger Binding="{Binding ContextObject.IsBusy, ElementName=mainWindow}" Value="False">
<DataTrigger Binding="{Binding ContextObject.IsBusy, ElementName=mainWindow, Mode=OneWay}" Value="False">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ParallelTimeline>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="1"
To="0"
BeginTime="0:0:0"
Duration="0:0:0.1" />
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0"
BeginTime="0:0:0" Duration="0:0:0.05" />
<ObjectAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0:0:0.1"
Value="{x:Static Visibility.Collapsed}" />
<DiscreteObjectKeyFrame KeyTime="0:0:0.05"
Value="{x:Static Visibility.Hidden}" />
</ObjectAnimationUsingKeyFrames>
</ParallelTimeline>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ParallelTimeline>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1"
BeginTime="0:0:0" Duration="0:0:0" />
<ObjectAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0:0:0"
Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
</ParallelTimeline>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<control:BusyDecorator x:Name="busyDecorator" IsBusyIndicatorShowing="True" VerticalAlignment="Center"
<!--IsBusyIndicatorShowing="{Binding IsVisible, ElementName=busyIndicatorLayer}"-->
<control:BusyDecorator x:Name="busyDecorator"
IsBusyIndicatorShowing="True"
VerticalAlignment="Center"
HorizontalAlignment="Center" />
</Grid>
</Grid>

View File

@@ -2,7 +2,8 @@
using System.Diagnostics;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Threading;
using QuickLook.ExtensionMethods;
using QuickLook.Helpers;
using QuickLook.Plugin;
@@ -11,7 +12,7 @@ namespace QuickLook
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
internal partial class MainWindow : Window, IDisposable
internal partial class MainWindow : Window
{
internal MainWindow()
{
@@ -20,31 +21,23 @@ namespace QuickLook
InitializeComponent();
// revert designer changes
windowPanel.Opacity = 0d;
busyIndicatorLayer.Visibility = Visibility.Visible;
busyIndicatorLayer.Opacity = 1d;
// do not set TopMost property if we are now debugging. it makes debugging painful...
if (!Debugger.IsAttached)
Topmost = true;
// restore changes by Designer
windowPanel.Opacity = 0d;
busyIndicatorLayer.Visibility = Visibility.Visible;
Loaded += (sender, e) => AeroGlassHelper.EnableBlur(this);
buttonCloseWindow.MouseLeftButtonUp += (sender, e) => Close();
buttonCloseWindow.MouseLeftButtonUp += (sender, e) => { Hide(); };
titleBarArea.PreviewMouseLeftButtonDown += DragMoveCurrentWindow;
}
public ContextObject ContextObject { get; }
public void Dispose()
{
GC.SuppressFinalize(this);
ContextObject?.Dispose();
// stop the background thread
busyDecorator?.Dispose();
}
public ContextObject ContextObject { get; private set; }
private void DragMoveCurrentWindow(object sender, MouseButtonEventArgs e)
{
@@ -71,17 +64,37 @@ namespace QuickLook
Width = ContextObject.PreferredSize.Width + windowBorder.BorderThickness.Left +
windowBorder.BorderThickness.Right;
Left = (SystemParameters.VirtualScreenWidth - Width) / 2;
Top = (SystemParameters.VirtualScreenHeight - Height) / 2;
ResizeMode = ContextObject.CanResize ? ResizeMode.CanResizeWithGrip : ResizeMode.NoResize;
base.Show();
if (!ContextObject.Focusable)
WindowHelper.SetNoactivate(new WindowInteropHelper(this));
//if (!ContextObject.Focusable)
// WindowHelper.SetNoactivate(new WindowInteropHelper(this));
}
private new void Hide()
{
container.Content = null;
// clean up plugin and refresh ContextObject for next use
ContextObject.ViewerPlugin?.Dispose();
ContextObject.Reset();
GC.Collect();
// revert UI changes
ContextObject.IsBusy = true;
Left -= 10000;
Dispatcher.Delay(100, _ => base.Hide());
}
internal void BeginShow(IViewer matchedPlugin, string path)
{
ContextObject.CurrentContentContainer = viewContentContainer;
ContextObject.CurrentContentContainer = container;
ContextObject.ViewerPlugin = matchedPlugin;
// get window size before showing it
@@ -89,12 +102,19 @@ namespace QuickLook
Show();
matchedPlugin.View(path, ContextObject);
// load plugin, do not block UI
Dispatcher.BeginInvoke(new Action(() => matchedPlugin.View(path, ContextObject)),
DispatcherPriority.Render);
}
~MainWindow()
internal bool BeginHide()
{
Dispose();
if (Visibility != Visibility.Visible)
return false;
Hide();
return true;
}
}
}

View File

@@ -2,6 +2,7 @@
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using QuickLook.Annotations;
namespace QuickLook.Plugin
@@ -9,12 +10,12 @@ namespace QuickLook.Plugin
/// <summary>
/// A runtime object which allows interaction between this plugin and QuickLook.
/// </summary>
public class ContextObject : INotifyPropertyChanged, IDisposable
public class ContextObject : INotifyPropertyChanged
{
private bool _isBusy = true;
private string _title = "";
internal ViewContentContainer CurrentContentContainer;
internal ContentControl CurrentContentContainer;
internal IViewer ViewerPlugin;
/// <summary>
@@ -35,8 +36,8 @@ namespace QuickLook.Plugin
/// </summary>
public object ViewerContent
{
get => CurrentContentContainer.container.Content;
set => CurrentContentContainer.container.Content = value;
get => CurrentContentContainer.Content;
set => CurrentContentContainer.Content = value;
}
/// <summary>
@@ -67,10 +68,8 @@ namespace QuickLook.Plugin
/// </summary>
public bool Focusable { get; set; } = false;
public void Dispose()
public void DisposePlugin()
{
GC.SuppressFinalize(this);
ViewerPlugin?.Dispose();
ViewerPlugin = null;
}
@@ -105,7 +104,6 @@ namespace QuickLook.Plugin
var heightRatio = max.Height * maxRatio / size.Height;
var ratio = Math.Min(widthRatio, heightRatio);
if (ratio > 1) ratio = 1;
PreferredSize = new Size {Width = size.Width * ratio, Height = size.Height * ratio};
@@ -121,15 +119,20 @@ namespace QuickLook.Plugin
return new Size(SystemParameters.VirtualScreenWidth, SystemParameters.VirtualScreenHeight);
}
internal void Reset()
{
Title = "";
ViewerContent = null;
IsBusy = true;
PreferredSize = new Size();
CanResize = true;
Focusable = false;
}
[NotifyPropertyChangedInvocator]
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
~ContextObject()
{
Dispose();
}
}
}

View File

@@ -101,9 +101,6 @@
<Compile Include="Plugin\IViewer.cs" />
<Compile Include="Helpers\DpiHelpers.cs" />
<Compile Include="TrayIcon.cs" />
<Compile Include="ViewContentContainer.xaml.cs">
<DependentUpon>ViewContentContainer.xaml</DependentUpon>
</Compile>
<Compile Include="Plugin\ContextObject.cs" />
<Compile Include="Helpers\WindowHelper.cs" />
<Compile Include="ViewWindowManager.cs" />
@@ -134,10 +131,6 @@
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="ViewContentContainer.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Styles\BusyDecorator.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>

View File

@@ -1,15 +0,0 @@
<UserControl x:Class="QuickLook.ViewContentContainer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:local="clr-namespace:QuickLook"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<ContentControl x:Name="container">
<Label Content="ContentControl Placeholder" VerticalContentAlignment="Center"
HorizontalContentAlignment="Center" Background="LightGray" />
</ContentControl>
</Grid>
</UserControl>

View File

@@ -1,15 +0,0 @@
using System.Windows.Controls;
namespace QuickLook
{
/// <summary>
/// Interaction logic for ViewContentContainer.xaml
/// </summary>
public partial class ViewContentContainer : UserControl
{
public ViewContentContainer()
{
InitializeComponent();
}
}
}

View File

@@ -15,7 +15,31 @@ namespace QuickLook
{
private static ViewWindowManager _instance;
private MainWindow _viewWindow;
private readonly MainWindow _viewWindow;
internal ViewWindowManager()
{
_viewWindow = new MainWindow();
_viewWindow.Closed += (sender, e) =>
{
if (App.RunningAsViewer)
Application.Current.Shutdown();
};
}
internal void InvokeRoutine()
{
if (!WindowHelper.IsFocusedControlExplorerItem())
if (!WindowHelper.IsFocusedWindowSelf())
return;
if (_viewWindow.BeginHide())
return;
var path = GetCurrentSelection();
InvokeViewer(path);
}
internal void InvokeViewer(string path)
{
@@ -29,43 +53,15 @@ namespace QuickLook
BeginShowNewWindow(matchedPlugin, path);
}
internal void InvokeRoutine()
{
if (!WindowHelper.IsFocusedControlExplorerItem())
if (!WindowHelper.IsFocusedWindowSelf())
return;
if (CloseCurrentWindow())
return;
var path = GetCurrentSelection();
InvokeViewer(path);
}
private void BeginShowNewWindow(IViewer matchedPlugin, string path)
{
_viewWindow = new MainWindow();
_viewWindow.Closed += (sender2, e2) =>
{
if (App.RunningAsViewer)
{
Application.Current.Shutdown();
return;
}
_viewWindow.Dispose();
_viewWindow = null;
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
};
try
{
_viewWindow.BeginShow(matchedPlugin, path);
}
catch (Exception e) // if current plugin failed, switch to default one.
{
_viewWindow.Close();
_viewWindow.BeginHide();
Debug.WriteLine(e.ToString());
Debug.WriteLine(e.StackTrace);
@@ -81,34 +77,6 @@ namespace QuickLook
throw;
}
}
#pragma warning disable 1058
catch // Catch SEH exceptions here.
#pragma warning restore 1058
{
_viewWindow.Close();
if (matchedPlugin.GetType() != PluginManager.GetInstance().DefaultPlugin)
{
matchedPlugin.Dispose();
matchedPlugin = PluginManager.GetInstance().DefaultPlugin.CreateInstance<IViewer>();
BeginShowNewWindow(matchedPlugin, path);
}
else
{
throw;
}
}
}
private bool CloseCurrentWindow()
{
if (_viewWindow != null)
{
_viewWindow.Close();
return true;
}
return false;
}
private string GetCurrentSelection()