From 9d1660270272180cd71147d6ddd53d1382643d2e Mon Sep 17 00:00:00 2001
From: wenxiangchao <wenxiangchao@ihengxin.com.cn>
Date: 星期一, 02 十一月 2026 18:00:14 +0800
Subject: [PATCH] merge: 并入远程 Initial commit 作为历史根节点

---
 HMI.UI/MDI/Workspace.xaml.cs |  366 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 366 insertions(+), 0 deletions(-)

diff --git a/HMI.UI/MDI/Workspace.xaml.cs b/HMI.UI/MDI/Workspace.xaml.cs
new file mode 100644
index 0000000..01ae0a9
--- /dev/null
+++ b/HMI.UI/MDI/Workspace.xaml.cs
@@ -0,0 +1,366 @@
+锘縰sing 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<Position> positions { get; set; } = new List<Position>();
+    }
+    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; }
+    }
+    /// <summary>
+    /// Workspace.xaml 鐨勪氦浜掗�昏緫
+    /// </summary>
+    public partial class Workspace : UserControl
+    {
+
+        public Workspace()
+        {
+            InitializeComponent();
+        }
+
+        private WorkspaceSetting setting;
+
+        private Dictionary<string, InnerWindow> nameMap
+            = new Dictionary<string, InnerWindow>();
+
+        private Dictionary<string, Position> positionMap
+            = new Dictionary<string, Position>();
+
+        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<WorkspaceSetting>(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);
+        }
+
+        /// <summary>
+        /// 璁剧疆InnerWindow
+        /// </summary>
+        /// <param name="inner"></param>
+        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<Position> ps = new List<Position>();
+            foreach (var key in positionMap.Keys)
+            {
+                positionMap[key].Key = key;
+                ps.Add(positionMap[key]);
+            }
+
+            XmlHelper.SerializeToXml(SettingPath, ps);
+        }
+
+        /// <summary>
+        /// 搴曢儴MinInnerWindow澶勭悊
+        /// </summary>
+        /// <param name="inner"></param>
+        private void HandleMinInnerWindow(InnerWindow inner)
+        {
+            MinInnerWindow min = new MinInnerWindow(inner);
+            min.MaxEvent += MinInnerWindowMax;
+            min.CloseEvent += MinInnerWindowClose;
+            BottomBar.AddMinWindow(min);
+        }
+
+        /// <summary>
+        /// InnerWindow鐒︾偣浜嬩欢
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void Inner_GotFocus(object sender, RoutedEventArgs e)
+        {
+            CanvasHelper.SetTopZIndex(sender as InnerWindow, WorkArea, typeof(InnerWindow));
+        }
+
+        /// <summary>
+        /// InnerWindow ZIndex鍒囨崲浜嬩欢
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void Inner_ZIndexEvent(object sender, EventArgs e)
+        {
+            CanvasHelper.SetTopZIndex(sender as InnerWindow, WorkArea, typeof(InnerWindow));
+        }
+
+        /// <summary>
+        /// InnerWindow鏈�灏忓寲浜嬩欢
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void InnerWindowMin(object sender, System.EventArgs e)
+        {
+            InnerWindow inner = sender as InnerWindow;
+            inner.Visibility = Visibility.Collapsed;
+            HandleMinInnerWindow(inner);
+        }
+
+        /// <summary>
+        /// InnerWindow鏈�澶у寲浜嬩欢
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// 搴曢儴MinInnerWindow灞曞紑
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        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);
+        }
+
+        /// <summary>
+        /// 搴曢儴MinInnerWin鍏抽棴
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        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<Position> ps = new List<Position>();
+            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<Position> ps = new List<Position>();
+            foreach (var key in positionMap.Keys)
+            {
+                positionMap[key].Key = key;
+                ps.Add(positionMap[key]);
+            }
+            setting.positions = ps;
+            XmlHelper.SerializeToXml(SettingPath, setting);
+        }
+    }
+}

--
Gitblit v1.9.1