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(); }); } } } }