CPF/CPF.Toolkit/Controls/MdiHost.cs

253 lines
10 KiB
C#
Raw Normal View History

2023-11-24 17:31:24 +08:00
using CPF.Controls;
2023-11-28 17:31:16 +08:00
using CPF.Drawing;
using CPF.Platform;
2023-11-29 11:00:06 +08:00
using CPF.Shapes;
2023-11-29 17:07:17 +08:00
using CPF.Toolkit.Dialogs;
2023-11-24 17:31:24 +08:00
using System;
using System.Collections.Generic;
using System.Diagnostics;
2023-11-24 22:58:59 +08:00
using System.Linq;
2023-11-24 17:31:24 +08:00
using System.Text;
namespace CPF.Toolkit.Controls
{
2023-11-28 17:31:16 +08:00
public class MdiHost : Grid
2023-11-24 17:31:24 +08:00
{
public MdiHost()
{
2023-11-28 17:31:16 +08:00
this.TaskBarList = new Collection<UIElement>();
this.Size = SizeField.Fill;
this.Background = "204,204,204";
base.RowDefinitions.Add(new RowDefinition { Height = GridLength.Star });
2023-11-29 17:07:17 +08:00
base.RowDefinitions.Add(new RowDefinition { Height = 35 });
2023-11-28 17:31:16 +08:00
base.Children.Add(this.host);
2023-11-29 17:07:17 +08:00
taskBar = base.Children.Add(new ListBox
2023-11-28 17:31:16 +08:00
{
Size = SizeField.Fill,
Background = "white",
BorderFill = new SolidColorFill { Color = Color.Silver },
BorderThickness = new Thickness(0, 1, 0, 0),
BorderType = BorderType.BorderThickness,
ItemsPanel = new StackPanel { Orientation = Orientation.Horizontal },
ItemTemplate = new ListBoxItem
{
Height = "100%",
Width = 100,
MarginRight = 1,
FontSize = 16f,
BorderFill = "Silver",
BorderThickness = new Thickness(0, 0, 1, 0),
BorderType = BorderType.BorderThickness,
[nameof(ListBoxItem.Content)] = new BindingDescribe("Title")
},
Items = this.TaskBarList,
[nameof(ListBox.SelectedValue)] = new BindingDescribe(this, nameof(this.SelectWindow), BindingMode.TwoWay),
}, row: 1);
this.host.PropertyChanged += Host_PropertyChanged;
this.host.UIElementAdded += Host_UIElementAdded;
this.host.UIElementRemoved += Host_UIElementRemoved;
2023-11-24 17:31:24 +08:00
}
2023-11-29 17:07:17 +08:00
readonly Dictionary<UIElement, MdiWindowRect> normalRect = [];
readonly Panel host = new() { Size = SizeField.Fill };
readonly ListBox taskBar;
2023-11-28 17:31:16 +08:00
Collection<UIElement> TaskBarList { get => GetValue<Collection<UIElement>>(); set => SetValue(value); }
public new UIElementCollection Children => host.Children;
2023-11-29 11:00:06 +08:00
public MdiWindow SelectWindow { get => GetValue<MdiWindow>(); set => SetValue(value); }
2023-11-28 17:31:16 +08:00
2023-11-29 17:07:17 +08:00
[PropertyMetadata(TaskBarPlacement.Bottom)]
public TaskBarPlacement TaskBarPlacement { get => GetValue<TaskBarPlacement>(); set => SetValue(value); }
2023-11-24 17:31:24 +08:00
protected override void OnPropertyChanged(string propertyName, object oldValue, object newValue, PropertyMetadataAttribute propertyMetadata)
{
2023-11-29 11:00:06 +08:00
if (propertyName == nameof(this.SelectWindow) && this.SelectWindow != null)
2023-11-28 17:31:16 +08:00
{
this.Topping(this.SelectWindow);
2023-11-29 11:00:06 +08:00
this.SelectWindow.WindowState = this.normalRect[this.SelectWindow].OldState;
2023-11-28 17:31:16 +08:00
}
2023-11-29 17:07:17 +08:00
else if (propertyName == nameof(this.TaskBarPlacement) && this.taskBar != null)
{
this.RowDefinitions.Clear();
this.ColumnDefinitions.Clear();
switch ((TaskBarPlacement)newValue)
{
case TaskBarPlacement.Top:
this.RowDefinitions.Add(new RowDefinition { Height = 35 });
this.RowDefinitions.Add(new RowDefinition { Height = GridLength.Star });
RowIndex(this.taskBar,0);
RowIndex(this.host, 1);
break;
case TaskBarPlacement.Bottom:
this.RowDefinitions.Add(new RowDefinition { Height = GridLength.Star });
this.RowDefinitions.Add(new RowDefinition { Height = 35 });
RowIndex(this.host,0);
RowIndex(this.taskBar, 1);
break;
}
}
2023-11-28 17:31:16 +08:00
base.OnPropertyChanged(propertyName, oldValue, newValue, propertyMetadata);
}
private void Host_PropertyChanged(object sender, CPFPropertyChangedEventArgs e)
{
if (e.PropertyName.Or(nameof(ActualSize), nameof(Size), nameof(Width), nameof(Height)))
2023-11-24 17:31:24 +08:00
{
2023-11-28 17:31:16 +08:00
foreach (MdiWindow mdi in this.host.Children)
2023-11-24 17:31:24 +08:00
{
2023-11-28 17:31:16 +08:00
if (mdi.WindowState == WindowState.Maximized) continue;
2023-11-24 17:31:24 +08:00
2023-11-28 17:31:16 +08:00
if (mdi.MarginLeft.Value + mdi.ActualSize.Width > this.ActualSize.Width)
2023-11-24 17:31:24 +08:00
{
2023-11-28 17:31:16 +08:00
mdi.MarginLeft = this.ActualSize.Width - mdi.ActualSize.Width;
2023-11-24 17:31:24 +08:00
}
2023-11-28 17:31:16 +08:00
if (mdi.MarginTop.Value + mdi.ActualSize.Height > this.ActualSize.Height)
2023-11-24 17:31:24 +08:00
{
2023-11-28 17:31:16 +08:00
mdi.MarginTop = this.ActualSize.Height - mdi.ActualSize.Height;
2023-11-24 17:31:24 +08:00
}
}
}
}
2023-11-28 17:31:16 +08:00
private void Host_UIElementRemoved(object sender, UIElementRemovedEventArgs e)
{
2023-11-29 17:07:17 +08:00
var view = e.Element as MdiWindow;
view.PropertyChanged -= Element_PropertyChanged;
view.PreviewMouseDown -= Element_PreviewMouseDown;
view.Closing -= View_Closing;
2023-11-28 17:31:16 +08:00
this.TaskBarList.Remove(e.Element);
2023-11-29 11:00:06 +08:00
this.normalRect.Remove(e.Element);
2023-11-28 17:31:16 +08:00
}
private void Host_UIElementAdded(object sender, UIElementAddedEventArgs e)
2023-11-24 17:31:24 +08:00
{
2023-11-28 17:31:16 +08:00
var view = e.Element as MdiWindow;
2023-11-29 11:00:06 +08:00
this.normalRect.Add(e.Element, new MdiWindowRect { Left = 0, Top = 0, Height = 500, Width = 500 });
2023-11-28 17:31:16 +08:00
view.PropertyChanged += Element_PropertyChanged;
view.PreviewMouseDown += Element_PreviewMouseDown;
2023-11-29 17:07:17 +08:00
view.Closing += View_Closing;
2023-11-28 17:31:16 +08:00
this.TaskBarList.Add(view);
e.Element.ZIndex = this.host.Children.Max(x => x.ZIndex) + 1;
2023-11-29 11:00:06 +08:00
this.Topping(view);
2023-11-24 17:31:24 +08:00
}
2023-11-24 22:58:59 +08:00
2023-11-29 17:07:17 +08:00
private void View_Closing(object sender, ClosingEventArgs e)
{
if (e.Cancel) return;
UIElement mdiWindow = null;
if (sender is IClosable closable)
{
mdiWindow = this.host.Children.FirstOrDefault(x => x.DataContext == closable);
}
else if (sender is MdiWindow mdi)
{
mdiWindow = mdi;
}
if (mdiWindow != null)
{
if (mdiWindow == this.SelectWindow)
{
this.BeginInvoke(() =>
{
if (this.host.Children.Count == 0) return;
var index = this.host.Children.Where(x => x.Visibility == Visibility.Visible).Max(x => x.ZIndex);
if (index != -1)
{
this.SelectWindow = this.host.Children.Find(x => x.ZIndex == index) as MdiWindow;
}
});
}
this.host.Children.Remove(mdiWindow);
mdiWindow.Dispose();
}
}
2023-11-24 22:58:59 +08:00
private void Element_PreviewMouseDown(object sender, Input.MouseButtonEventArgs e)
{
2023-11-29 11:00:06 +08:00
var ele = (MdiWindow)sender;
2023-11-28 17:31:16 +08:00
this.Topping(ele);
}
private void Element_PropertyChanged(object sender, CPFPropertyChangedEventArgs e)
{
var view = sender as MdiWindow;
switch (e.PropertyName)
{
case nameof(MdiWindow.WindowState):
2023-11-29 11:00:06 +08:00
switch ((WindowState)e.NewValue)
2023-11-28 17:31:16 +08:00
{
2023-11-29 11:00:06 +08:00
case WindowState.Normal:
var rect = this.normalRect[view];
view.Size = new SizeField(rect.Width, rect.Height);
view.MarginLeft = rect.Left;
view.MarginTop = rect.Top;
break;
case WindowState.Minimized:
view.Visibility = Visibility.Collapsed;
this.SelectWindow = this.host.Children.FindLast(x => x.Visibility == Visibility.Visible) as MdiWindow;
this.normalRect[view].OldState = (WindowState)e.OldValue;
break;
case WindowState.Maximized:
case WindowState.FullScreen:
view.Size = SizeField.Fill;
view.MarginLeft = 0;
view.MarginTop = 0;
break;
2023-11-28 17:31:16 +08:00
}
break;
case nameof(ZIndex):
this.SelectWindow = view;
this.SelectWindow.Visibility = Visibility.Visible;
break;
2023-11-29 11:00:06 +08:00
case nameof(MarginLeft):
if (view.WindowState == WindowState.Normal)
{
var left = (FloatField)e.NewValue;
if (left.Value <= 0) view.MarginLeft = 0;
this.normalRect[view].Left = view.MarginLeft.Value;
}
break;
case nameof(MarginTop):
if (view.WindowState == WindowState.Normal)
{
var top = (FloatField)e.NewValue;
if (top.Value <= 0) view.MarginTop = 0;
this.normalRect[view].Top = view.MarginTop.Value;
}
break;
case nameof(Width):
if (view.WindowState == WindowState.Normal)
{
var size = (FloatField)e.NewValue;
this.normalRect[view].Width = size.Value;
}
break;
case nameof(Height):
if (view.WindowState == WindowState.Normal)
{
var size = (FloatField)e.NewValue;
this.normalRect[view].Height = size.Value;
}
break;
2023-11-28 17:31:16 +08:00
}
}
2023-11-29 11:00:06 +08:00
public void Topping(MdiWindow ele)
2023-11-28 17:31:16 +08:00
{
if (ele == null) return;
2023-11-29 17:07:17 +08:00
ele.Focus();
2023-11-28 17:31:16 +08:00
var index = this.host.Children.Max(x => x.ZIndex);
if (ele.ZIndex == index)
{
ele.Visibility = Visibility.Visible;
return;
}
ele.ZIndex = index + 1;
2023-11-24 22:58:59 +08:00
}
2023-11-24 17:31:24 +08:00
}
}