/// <summary> /// Set this window to be a child of another window. /// </summary> /// <param name="parent"></param> /// <param name="canBecomeRoot">The boolean determines if the newly set window could become the new parent. Obviously, /// this is true in most cases but when destroying the application you may want to <see cref="SetParent"/> to <c>null</c> /// and don't let it become the new root window.</param> protected virtual void SetParent(SigmaWindow parent, bool canBecomeRoot = true) { if (ReferenceEquals(ParentWindow, parent)) { return; } // remove from parent (if there is any) ParentWindow?.Children.Remove(this); // add to new parent ParentWindow = parent; if (parent == null) { if (canBecomeRoot) { App.MainWindow = this; Monitor.Window = this; } } else { parent.Children.Add(this); } }
/// <summary> /// Finds the root of a given <see cref="SigmaWindow" /> /// </summary> /// <param name="start">The point to begin the search. May not be null. </param> /// <returns>The root window. </returns> private static SigmaWindow FindRoot(SigmaWindow start) { if (start == null) { throw new ArgumentNullException(nameof(start)); } while (start.ParentWindow != null) { start = start.ParentWindow; } return(start); }
/// <summary> /// Execute an action on the element <see ref="start" /> and all children of start. /// This method also maintains the children reference list. (<see cref="Children" />) /// </summary> /// <param name="action">The <see cref="Action" /> that will be executed. </param> /// <param name="start">The element to begin (normally the root and then internally recursive). </param> private static void PropagateActionDownwards(Action <SigmaWindow> action, SigmaWindow start) { action(start); for (int i = 0; i < start.Children.Count; i++) { if (start.Children[i].IsAlive) { PropagateActionDownwards(action, start.Children[i]); } else { start.Children.RemoveAt(i--); } } }
/// <inheritdoc /> public void Dispose() { if (ParentWindow == null) { if (Children.Count > 0) { SigmaWindow newRoot = Children[0]; // set one child as parent newRoot.SetParent(null); // set all others children parent for (int i = 1; i < Children.Count; i++) { Children[i].SetParent(newRoot); } } // its the last window else { OnLastWindowClosed(); } } else { foreach (SigmaWindow child in Children) { child.SetParent(ParentWindow); } } SetParent(null, false); ParentWindow = null; RootElement = null; RootContentElement = null; LoadingIndicatorElement = null; TabControl = null; DialogHost = null; }
/// <summary> /// This method creates the root layout for the window and automatically adds the items that should be in the root panel (i.e. references are required). /// </summary> /// <param name="monitor">The monitor from which the legends are copied. </param> /// <param name="other">The previous <see cref="SigmaWindow"/> - some values propagate automatically to the new window (e.g. tabs).</param> /// <param name="titleBarControl">The <see cref="TitleBarControl"/>, since it belongs to the window itself (not root content).</param> /// <returns>The newly created root panel. (In this case where the tabs etc. are placed)</returns> protected virtual Panel CreateContent(WPFMonitor monitor, SigmaWindow other, out TitleBarControl titleBarControl) { titleBarControl = CreateObjectByFactory <TitleBarControl>(TitleBarFactoryIdentifier); LeftWindowCommands = TitleBar; TabControl = CreateObjectByFactory <TabControlUI <SigmaWindow, TabUI> >(TabControlFactoryIdentifier); if (other == null) { AddTabs(TabControl, monitor.Tabs); } Layout tabLayout = (Layout)TabControl; // ReSharper disable once CoVariantArrayConversion UIElement statusBar = CreateObjectByFactory <UIElement>(StatusBarFactoryIdentifier, monitor.Legends.Values.ToArray()); DockPanel rootLayout = CreateObjectByFactory <DockPanel>(RootPanelFactoryIdentifier); rootLayout.Children.Add(statusBar); DockPanel.SetDock(statusBar, Dock.Bottom); rootLayout.Children.Add(tabLayout); return(rootLayout); }
/// <summary> /// Execute an action statically on a window. /// </summary> /// <param name="window">The window the <see cref="Action"/> will be executed on.</param> /// <param name="action">The <see cref="Action"/> that will be executed.</param> protected static void ExecuteOnWindow(SigmaWindow window, Action <SigmaWindow> action) { action(window); }
/// <summary> /// The constructor for the <see cref="WPFWindow" />. Since <see cref="SigmaWindow" /> /// heavily relies on Dragablz, a <see cref="SigmaWindow" /> has to be created at runtime. /// Therefore every subclass of <see cref="SigmaWindow" /> must implement exactly this constructor /// - otherwise, the <see cref="Dragablz.IInterTabClient" /> specified in /// <see cref="TabControlUI{TWindow,TTabWrapper}" /> /// throws a reflection exception when dragging windows out. /// </summary> /// <param name="monitor">The root <see cref="IMonitor" />.</param> /// <param name="app">The <see cref="Application" /> environment.</param> /// <param name="title">The <see cref="Window.Title" /> of the window.</param> /// <param name="other"><code>null</code> if there is no previous window - otherwise the previous window.</param> protected SigmaWindow(WPFMonitor monitor, Application app, string title, SigmaWindow other) : base(monitor, app) { // if the title should be synced, immediately set it Title = SyncTitle && other != null ? other.Title : title; WindowIndex = _windowCount++; SetIcon(monitor); Children = new List <SigmaWindow>(); if (other == null) { ParameterVisualiser = new ParameterVisualiserManager(); AssignFactories(monitor.Registry, app, monitor); } else { ParameterVisualiser = other.ParameterVisualiser; } SetParent(other); InitialiseDefaultValues(); RootElement = new Grid(); DialogHostIdentifier = BaseDialogHostIdentifier + WindowIndex; DialogHost = new DialogHost { Identifier = DialogHostIdentifier }; // TODO: factory // TODO: style Snackbar = new Snackbar { MessageQueue = new SnackbarMessageQueue(TimeSpan.FromSeconds(2)), HorizontalAlignment = HorizontalAlignment.Stretch }; SnackbarMessageQueue = Snackbar.MessageQueue; LoadingIndicatorElement = CreateObjectByFactory <UIElement>(LoadingIndicatorFactoryIdentifier); RootContentElement = CreateContent(monitor, other, out _titleBar); RootElement.Children.Add(RootContentElement); RootElement.Children.Add(DialogHost); RootElement.Children.Add(Snackbar); RootElement.Children.Add(LoadingIndicatorElement); if (other == null) { NotifyIcon = CreateObjectByFactory <NotifyIcon>(NotifyIconFactoryIdentifier); } else { LoadingIndicatorElement.Visibility = Visibility.Hidden; NotifyIcon = other.NotifyIcon; } Content = RootElement; App.Startup += OnStart; Closing += OnClosing; DependencyPropertyDescriptor.FromProperty(TitleProperty, typeof(Window)).AddValueChanged(this, OnTitleChanged); Closed += OnClosed; }