using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Tango.Core.Components;
namespace Tango.PPC.Common.Controls
{
///
/// Represents an asynchronous UI element capable of displaying it's content on a thread different from the UI thread.
/// This is possible by XML serialization of the visual content and extracting it to a new window which will be created on a new thread.
/// The window will then be synchronized to the original control position and size.
///
///
/// This new window will override all elements of the main window so use with caution!
///
///
public partial class AsyncAdornerControl : ContentControl
{
private bool _loaded;
private Window _window;
///
/// Initializes a new instance of the class.
///
public AsyncAdornerControl()
{
Loaded += AsyncAdornerControl_Loaded;
IsVisibleChanged += AsyncAdornerControl_IsVisibleChanged;
}
///
/// Handles the IsVisibleChanged event of the AsyncAdornerControl control.
///
/// The source of the event.
/// The instance containing the event data.
private void AsyncAdornerControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (Visibility == Visibility.Visible)
{
ShowWindow();
}
else
{
HideWindow();
}
}
///
/// Raises the event, using the specified information as part of the eventual event data.
///
/// Details of the old and new size involved in the change.
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
SyncBounds();
}
///
/// Handles the Loaded event of the AsyncAdornerControl control.
///
/// The source of the event.
/// The instance containing the event data.
private void AsyncAdornerControl_Loaded(object sender, RoutedEventArgs e)
{
if (!this.IsInDesignMode())
{
var startTime = Process.GetCurrentProcess().StartTime;
if (_loaded) return;
_loaded = true;
var handle = new WindowInteropHelper(System.Windows.Application.Current.MainWindow).Handle;
System.Windows.Application.Current.MainWindow.LocationChanged += MainWindow_LocationChanged;
Visibility v = Visibility;
var xaml = FrameworkElementSerializer.Serialize(Content as FrameworkElement);
object dc = this.DataContext;
Content = null;
var main_dispatcher = System.Windows.Application.Current.Dispatcher;
System.Windows.Application.Current.MainWindow.RegisterForLoadedOrNow((_,__) =>
{
Thread thread = new Thread(() =>
{
main_dispatcher.ShutdownFinished += (x, y) =>
{
if (_window != null)
{
_window.Invoke(() =>
{
_window.Close();
});
}
};
_window = new Window();
_window.WindowStyle = WindowStyle.None;
_window.ResizeMode = ResizeMode.NoResize;
_window.ShowInTaskbar = false;
_window.AllowsTransparency = true;
_window.Background = Brushes.Transparent;
_window.WindowStartupLocation = WindowStartupLocation.Manual;
SyncBounds();
if (v != Visibility.Visible)
{
_window.Opacity = 0;
}
new WindowInteropHelper(_window).Owner = handle;
_window.ShowActivated = false;
var cloned = FrameworkElementSerializer.Deserialize(xaml);
cloned.DataContext = dc;
_window.Content = cloned;
_window.Show();
SyncBounds();
System.Windows.Threading.Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
});
}
}
///
/// Handles the LocationChanged event of the MainWindow control.
///
/// The source of the event.
/// The instance containing the event data.
private void MainWindow_LocationChanged(object sender, EventArgs e)
{
SyncBounds();
}
///
/// Synchronizes the bounds of the window with the bounds of the original control.
///
public void SyncBounds()
{
if (_window != null)
{
this.BeginInvoke(() =>
{
Point location = PointToScreen(new Point(0, 0));
Size size = new Size(ActualWidth, ActualHeight);
_window.BeginInvoke(() =>
{
_window.Top = location.Y;
_window.Left = location.X;
_window.Width = size.Width;
_window.Height = size.Height;
});
});
}
}
///
/// Hides the element window.
///
private void HideWindow()
{
if (_window != null)
{
_window.BeginInvoke(() =>
{
_window.Hide();
});
}
}
///
/// Shows the element window.
///
private void ShowWindow()
{
if (_window != null)
{
_window.BeginInvoke(() =>
{
_window.Opacity = 1;
_window.Show();
});
}
}
}
}