using HMI.Core.Util; using HMI.UI.Converter; using HMI.UI.DpUtil; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Data; namespace HMI.UI.MDI { public class WorkspaceSetting { public bool IsLocked { get; set; } public List positions { get; set; } = new List(); } public class Position { public string Key { get; set; } public double Left { get; set; } public double Top { get; set; } public double Width { get; set; } public double Height { get; set; } } /// /// Workspace.xaml 的交互逻辑 /// public partial class Workspace : UserControl { public Workspace() { InitializeComponent(); } private WorkspaceSetting setting; private Dictionary nameMap = new Dictionary(); private Dictionary positionMap = new Dictionary(); public static readonly DependencyProperty SettingPathProperty = DependencyProperty.Register( "SettingPath", typeof(string), typeof(Workspace), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnSettingChanged))); private static void OnSettingChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e) { if (dp is Workspace ws && e.Property == SettingPathProperty) { try { if (!File.Exists(e.NewValue.ToString())) { throw new Exception("Empty Workspace Setting."); } ws.setting = XmlHelper.DeserializeFromXml(e.NewValue.ToString()); if (ws?.setting != null) { ws.IsLocked = ws.setting.IsLocked; ws.positionMap = ws.setting.positions.ToDictionary(p => p.Key, p => p); } else { ws.positionMap.Clear(); } } catch { ws.setting = new WorkspaceSetting(); ws.positionMap.Clear(); } } } private CanvasPosition GetPositionByIndex(int index) { double step = 15; return new CanvasPosition { Left = (index + 1) * step, Top = (index + 1) * step, Width = 0.75 * ActualWidth, Height = 0.75 * ActualHeight }; } public string SettingPath { get => (string)GetValue(SettingPathProperty); set => SetValue(SettingPathProperty, value); } private int InnerWindowCount = 0; public void AddInnerWindow(InnerWindow innerWindow) { AddInnerWindow(innerWindow, GetPositionByIndex(WorkArea.Children.Count)); } public void AddInnerWindow(InnerWindow innerWindow, CanvasPosition canvasPosition) { HandleInnerWindow(innerWindow); UpdatePosition(innerWindow, canvasPosition); } public void AddInnerWindow(string key, InnerWindow innerWindow) { if (nameMap.ContainsKey(key)) { throw new Exception("Key Exists"); } if (positionMap.ContainsKey(key)) { var position = positionMap[key]; AddInnerWindow(innerWindow, new CanvasPosition { Left = position.Left * WorkArea.ActualWidth, Top = position.Top * WorkArea.ActualHeight, Width = position.Width * WorkArea.ActualWidth, Height = position.Height * WorkArea.ActualHeight }); } else { AddInnerWindow(innerWindow); } nameMap.Add(key, innerWindow); } public void UpdatePosition(InnerWindow inner, CanvasPosition position) { inner.canvasPosition = position; inner.Width = position.Width; inner.Height = position.Height; Canvas.SetLeft(inner, position.Left); Canvas.SetTop(inner, position.Top); } /// /// 设置InnerWindow /// /// private void HandleInnerWindow(InnerWindow inner) { inner.MinEvent += InnerWindowMin; inner.MaxEvent += InnerWindowMax; inner.LockEvent += Inner_LockEvent; inner.ZIndexEvent += Inner_ZIndexEvent; inner.GotFocus += Inner_GotFocus; inner.AttachToCanvas(WorkArea); inner.CanResize = !IsLoaded; Binding binding = new Binding("IsLocked") { Source = this, Mode = BindingMode.OneWay, Converter = new ReverseBoolConverter(), UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }; inner.SetBinding(InnerWindow.CanResizeProperty, binding); inner.Zindex = InnerWindowCount++; } private void Inner_LockEvent(object sender, EventArgs e) { var inner = sender as InnerWindow; var left = Canvas.GetLeft(inner) / WorkArea.ActualWidth; var top = Canvas.GetTop(inner) / WorkArea.ActualHeight; var width = inner.ActualWidth / WorkArea.ActualWidth; var height = inner.ActualHeight / WorkArea.ActualHeight; positionMap[inner.Title] = new Position { Left = left, Top = top, Width = width, Height = height }; List ps = new List(); foreach (var key in positionMap.Keys) { positionMap[key].Key = key; ps.Add(positionMap[key]); } XmlHelper.SerializeToXml(SettingPath, ps); } /// /// 底部MinInnerWindow处理 /// /// private void HandleMinInnerWindow(InnerWindow inner) { MinInnerWindow min = new MinInnerWindow(inner); min.MaxEvent += MinInnerWindowMax; min.CloseEvent += MinInnerWindowClose; BottomBar.AddMinWindow(min); } /// /// InnerWindow焦点事件 /// /// /// private void Inner_GotFocus(object sender, RoutedEventArgs e) { CanvasHelper.SetTopZIndex(sender as InnerWindow, WorkArea, typeof(InnerWindow)); } /// /// InnerWindow ZIndex切换事件 /// /// /// private void Inner_ZIndexEvent(object sender, EventArgs e) { CanvasHelper.SetTopZIndex(sender as InnerWindow, WorkArea, typeof(InnerWindow)); } /// /// InnerWindow最小化事件 /// /// /// private void InnerWindowMin(object sender, System.EventArgs e) { InnerWindow inner = sender as InnerWindow; inner.Visibility = Visibility.Collapsed; HandleMinInnerWindow(inner); } /// /// InnerWindow最大化事件 /// /// /// private void InnerWindowMax(object sender, System.EventArgs e) { InnerWindow inner = sender as InnerWindow; if (inner.WindowState == WindowState.Maximized) { Canvas.SetLeft(inner, inner.canvasPosition.Left); Canvas.SetTop(inner, inner.canvasPosition.Top); inner.Width = inner.canvasPosition.Width; inner.Height = inner.canvasPosition.Height; inner.WindowState = WindowState.Normal; } else { inner.canvasPosition.Left = Canvas.GetLeft(inner); inner.canvasPosition.Top = Canvas.GetTop(inner); inner.canvasPosition.Width = inner.ActualWidth; inner.canvasPosition.Height = inner.ActualHeight; Canvas.SetLeft(inner, 0); Canvas.SetTop(inner, 0); inner.Width = WorkArea.ActualWidth; inner.Height = WorkArea.ActualHeight; inner.WindowState = WindowState.Maximized; } } /// /// 底部MinInnerWindow展开 /// /// /// private void MinInnerWindowMax(object sender, System.EventArgs e) { MinInnerWindow min = sender as MinInnerWindow; min.Inner.Visibility = Visibility.Visible; CanvasHelper.SetTopZIndex(min.Inner, WorkArea, typeof(InnerWindow)); BottomBar.RemoveMinWindow(min); } /// /// 底部MinInnerWin关闭 /// /// /// private void MinInnerWindowClose(object sender, System.EventArgs e) { MinInnerWindow min = sender as MinInnerWindow; BottomBar.RemoveMinWindow(min); } private void MenuItem_Click(object sender, RoutedEventArgs e) { foreach (var inner in nameMap.Values) { var left = Canvas.GetLeft(inner) / WorkArea.ActualWidth; var top = Canvas.GetTop(inner) / WorkArea.ActualHeight; var width = inner.ActualWidth / WorkArea.ActualWidth; var height = inner.ActualHeight / WorkArea.ActualHeight; positionMap[inner.Title] = new Position { Left = left, Top = top, Width = width, Height = height }; } List ps = new List(); foreach (var key in positionMap.Keys) { positionMap[key].Key = key; ps.Add(positionMap[key]); } setting.positions = ps; XmlHelper.SerializeToXml(SettingPath, setting); } public static readonly DependencyProperty IsLockedProperty = DependencyProperty.Register( "IsLocked", typeof(bool), typeof(Workspace), new FrameworkPropertyMetadata(false)); public bool IsLocked { get => (bool)GetValue(IsLockedProperty); private set { if (setting != null) { setting.IsLocked = value; } SetValue(IsLockedProperty, value); } } private void MenuItem_Checked(object sender, RoutedEventArgs e) { IsLocked = !IsLocked; foreach (var inner in nameMap.Values) { var left = Canvas.GetLeft(inner) / WorkArea.ActualWidth; var top = Canvas.GetTop(inner) / WorkArea.ActualHeight; var width = inner.ActualWidth / WorkArea.ActualWidth; var height = inner.ActualHeight / WorkArea.ActualHeight; positionMap[inner.Title] = new Position { Left = left, Top = top, Width = width, Height = height }; } List ps = new List(); foreach (var key in positionMap.Keys) { positionMap[key].Key = key; ps.Add(positionMap[key]); } setting.positions = ps; XmlHelper.SerializeToXml(SettingPath, setting); } } }