Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
730bbcae25 | ||
![]() |
36433178c2 | ||
![]() |
0a12d33d15 | ||
![]() |
5eb8c25799 | ||
![]() |
49b1ebcd5c | ||
![]() |
9ab836ff44 | ||
![]() |
a1db3807ff | ||
![]() |
6631fec5e6 | ||
![]() |
807cbdf300 | ||
![]() |
507e844275 | ||
![]() |
b79e63da71 | ||
![]() |
235e8ec59e | ||
![]() |
db457dac7b | ||
![]() |
2004876770 | ||
![]() |
763a3893d6 | ||
![]() |
a6fc04e737 | ||
![]() |
bc5e6be81e | ||
![]() |
c439a46e38 | ||
![]() |
8decf9e554 | ||
![]() |
40efe5292f | ||
![]() |
313f8fd79b | ||
![]() |
25ce5d78ba | ||
![]() |
2cd339388f | ||
![]() |
f673ced43a |
2
AndroidTest/Resources/Resource.designer.cs
generated
2
AndroidTest/Resources/Resource.designer.cs
generated
@ -14,7 +14,7 @@ namespace AndroidTest
|
||||
{
|
||||
|
||||
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "13.2.2.120")]
|
||||
public partial class Resource
|
||||
{
|
||||
|
||||
|
2
CPF.Android/Resources/Resource.designer.cs
generated
2
CPF.Android/Resources/Resource.designer.cs
generated
@ -14,7 +14,7 @@ namespace CPF.Android
|
||||
{
|
||||
|
||||
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "13.2.2.120")]
|
||||
public partial class Resource
|
||||
{
|
||||
|
||||
|
21
CPF.Toolkit.Demo/CPF.Toolkit.Demo.csproj
Normal file
21
CPF.Toolkit.Demo/CPF.Toolkit.Demo.csproj
Normal file
@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CPF.Linux\CPF.Linux.csproj" />
|
||||
<ProjectReference Include="..\CPF.Mac\CPF.Mac.csproj" />
|
||||
<ProjectReference Include="..\CPF.Skia\CPF.Skia.csproj" />
|
||||
<ProjectReference Include="..\CPF.Toolkit\CPF.Toolkit.csproj" />
|
||||
<ProjectReference Include="..\CPF.Windows\CPF.Windows.csproj" />
|
||||
<ProjectReference Include="..\CPF\CPF.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
145
CPF.Toolkit.Demo/MainView.cs
Normal file
145
CPF.Toolkit.Demo/MainView.cs
Normal file
@ -0,0 +1,145 @@
|
||||
using CPF;
|
||||
using CPF.Animation;
|
||||
using CPF.Charts;
|
||||
using CPF.Controls;
|
||||
using CPF.Drawing;
|
||||
using CPF.Shapes;
|
||||
using CPF.Styling;
|
||||
using CPF.Svg;
|
||||
using CPF.Toolkit.Controls;
|
||||
using CPF.Toolkit.Dialogs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace CPF.Toolkit.Demo
|
||||
{
|
||||
public class MainView : Window
|
||||
{
|
||||
MainViewModel vm = new MainViewModel();
|
||||
protected override void InitializeComponent()
|
||||
{
|
||||
Title = "标题";
|
||||
Width = 1280;
|
||||
Height = 720;
|
||||
Background = null;
|
||||
this.DataContext = this.CommandContext = vm;
|
||||
this.CanResize = true;
|
||||
|
||||
Children.Add(new WindowFrame(this, new WrapPanel
|
||||
{
|
||||
Orientation = Orientation.Horizontal,
|
||||
Size = SizeField.Fill,
|
||||
Children =
|
||||
{
|
||||
new Button
|
||||
{
|
||||
Content = "alert",
|
||||
Commands = { { nameof(Button.Click),(s,e) => vm.Dialog.Alert("这是一条测试消息") } }
|
||||
},
|
||||
new Button
|
||||
{
|
||||
Content = "Sucess",
|
||||
Commands = { { nameof(Button.Click),(s,e) => vm.Dialog.Sucess("这是一条测试消息") } }
|
||||
},
|
||||
new Button
|
||||
{
|
||||
Content = "Error",
|
||||
Commands = { { nameof(Button.Click),(s,e) => vm.Dialog.Error("这是一条测试消息") } }
|
||||
},
|
||||
new Button
|
||||
{
|
||||
Content = "Ask",
|
||||
Commands = { { nameof(Button.Click),(s,e) => vm.Dialog.Ask("这是一条测试消息") } }
|
||||
},
|
||||
new Button
|
||||
{
|
||||
Content = "Warn",
|
||||
Commands = { { nameof(Button.Click),(s,e) => vm.Dialog.Warn("这是一条测试消息") } }
|
||||
},
|
||||
new Button
|
||||
{
|
||||
Content = "关闭窗体",
|
||||
Commands = { { nameof(Button.Click),(s,e) => vm.Test() } }
|
||||
},
|
||||
new Button
|
||||
{
|
||||
Content = "loading",
|
||||
Commands = { { nameof(Button.Click),(s,e) => vm.LoadingTest() } }
|
||||
},
|
||||
new Button
|
||||
{
|
||||
Content = "AsyncButton",
|
||||
Commands =
|
||||
{
|
||||
{ nameof(Button.AsyncClick),async (s,e) => await this.vm.AsyncClick() }
|
||||
}
|
||||
},
|
||||
new Button
|
||||
{
|
||||
Content = "Mdi",
|
||||
Commands =
|
||||
{
|
||||
{ nameof(Button.Click), (s,e) => new TestMdiView().Show() }
|
||||
}
|
||||
},
|
||||
|
||||
new Panel
|
||||
{
|
||||
},
|
||||
new PageControl
|
||||
{
|
||||
Height = 35,
|
||||
PageIndex = 1,
|
||||
PageCount = 100,
|
||||
Width = "100%",
|
||||
},
|
||||
}
|
||||
}));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
internal class MainViewModel : ViewModelBase
|
||||
{
|
||||
public void Test()
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
protected override void OnClose(ClosingEventArgs e)
|
||||
{
|
||||
e.Cancel = this.Dialog.Ask("确定要关闭吗") != "确定";
|
||||
base.OnClose(e);
|
||||
}
|
||||
|
||||
public async void LoadingTest()
|
||||
{
|
||||
await this.ShowLoading(async () =>
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
Debug.WriteLine(1);
|
||||
await Task.Delay(1000);
|
||||
Debug.WriteLine(2);
|
||||
await Task.Delay(1000);
|
||||
Debug.WriteLine(3);
|
||||
});
|
||||
//await this.ShowLoading(Task.Delay(3000));
|
||||
|
||||
//var result = await this.ShowLoading(async () =>
|
||||
//{
|
||||
// await Task.Delay(5000);
|
||||
// return "test";
|
||||
//});
|
||||
this.Dialog.Sucess("test");
|
||||
}
|
||||
|
||||
public async Task AsyncClick()
|
||||
{
|
||||
await Task.Delay(3000);
|
||||
this.Dialog.Alert("test");
|
||||
}
|
||||
}
|
||||
}
|
23
CPF.Toolkit.Demo/Program.cs
Normal file
23
CPF.Toolkit.Demo/Program.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using CPF.Controls;
|
||||
using CPF.Platform;
|
||||
using CPF.Skia;
|
||||
using CPF.Toolkit.Dialogs;
|
||||
using CPF.Windows;
|
||||
|
||||
namespace CPF.Toolkit.Demo
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Application.Initialize(
|
||||
(OperatingSystemType.Windows, new WindowsPlatform(false), new SkiaDrawingFactory { })
|
||||
, (OperatingSystemType.OSX, new CPF.Mac.MacPlatform(), new SkiaDrawingFactory { UseGPU = false })
|
||||
, (OperatingSystemType.Linux, new CPF.Linux.LinuxPlatform(), new SkiaDrawingFactory { UseGPU = false })
|
||||
);
|
||||
|
||||
Application.Run(ViewManager.View<MainView>());
|
||||
}
|
||||
}
|
||||
}
|
139
CPF.Toolkit.Demo/TestMdiView.cs
Normal file
139
CPF.Toolkit.Demo/TestMdiView.cs
Normal file
@ -0,0 +1,139 @@
|
||||
using CPF;
|
||||
using CPF.Animation;
|
||||
using CPF.Charts;
|
||||
using CPF.Controls;
|
||||
using CPF.Drawing;
|
||||
using CPF.Shapes;
|
||||
using CPF.Styling;
|
||||
using CPF.Svg;
|
||||
using CPF.Toolkit.Controls;
|
||||
using CPF.Toolkit.Dialogs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace CPF.Toolkit.Demo
|
||||
{
|
||||
public class TestMdiView : Window
|
||||
{
|
||||
protected override void InitializeComponent()
|
||||
{
|
||||
this.CanResize = true;
|
||||
this.Title = "标题";
|
||||
this.Width = 1280;
|
||||
this.Height = 720;
|
||||
this.Background = null;
|
||||
var frame = this.Children.Add(new WindowFrame(this, new Grid
|
||||
{
|
||||
Size = SizeField.Fill,
|
||||
RowDefinitions =
|
||||
{
|
||||
new RowDefinition{ Height = 30 },
|
||||
new RowDefinition{ },
|
||||
},
|
||||
Children =
|
||||
{
|
||||
new MdiHost
|
||||
{
|
||||
Size = SizeField.Fill,
|
||||
Attacheds = { { Grid.RowIndex,1 } },
|
||||
TaskBarPlacement = TaskBarPlacement.Top,
|
||||
}.Assign(out var host),
|
||||
new WrapPanel
|
||||
{
|
||||
Orientation = Orientation.Horizontal,
|
||||
Size = SizeField.Fill,
|
||||
Children =
|
||||
{
|
||||
new Button
|
||||
{
|
||||
Height = "100%",
|
||||
Content = "New Window",
|
||||
[nameof(Button.Click)] = new CommandDescribe((s,e) => host.Children.Add(new M{ Title = $"Title{host.Children.Count}", })),
|
||||
},
|
||||
new Button
|
||||
{
|
||||
Height = "100%",
|
||||
Content = "任务栏居上",
|
||||
[nameof(Button.Click)] = new CommandDescribe((s,e) => host.TaskBarPlacement = TaskBarPlacement.Top),
|
||||
},
|
||||
new Button
|
||||
{
|
||||
Height = "100%",
|
||||
Content = "任务栏居下",
|
||||
[nameof(Button.Click)] = new CommandDescribe((s,e) => host.TaskBarPlacement = TaskBarPlacement.Bottom),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
//frame.CaptionBackgrund = "white";
|
||||
//frame.CaptionForeground = "black";
|
||||
//frame.ControlBoxStroke = "black";
|
||||
frame.MaximizeBox = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal class M : MdiWindow
|
||||
{
|
||||
protected override void InitializeComponent()
|
||||
{
|
||||
var vm = new MV { Dialog = new DialogService(this.Root as Window) };
|
||||
this.DataContext = vm;
|
||||
this.CommandContext = vm;
|
||||
this.Content = new WrapPanel
|
||||
{
|
||||
Size = SizeField.Fill,
|
||||
Children =
|
||||
{
|
||||
new Button
|
||||
{
|
||||
Content = "close",
|
||||
[nameof(Button.Click)] = new CommandDescribe((s,e) => vm.TestClose())
|
||||
},
|
||||
new Button
|
||||
{
|
||||
Content = "loading",
|
||||
[nameof(Button.AsyncClick)] = new CommandDescribe(async (s,e) => await vm.LoadingTest()),
|
||||
},
|
||||
new Button
|
||||
{
|
||||
Content = "alert",
|
||||
[nameof(Button.Click)] = new CommandDescribe( (s,e) => vm.TestAlert()),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
internal class MV : ViewModelBase
|
||||
{
|
||||
public void TestClose()
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
public void TestAlert()
|
||||
{
|
||||
this.Dialog.Warn("test");
|
||||
}
|
||||
|
||||
public async Task LoadingTest()
|
||||
{
|
||||
var result = await this.ShowLoading(async () =>
|
||||
{
|
||||
await Task.Delay(3000);
|
||||
return "ok";
|
||||
});
|
||||
Debug.WriteLine(result);
|
||||
}
|
||||
|
||||
protected override void OnClose(ClosingEventArgs e)
|
||||
{
|
||||
e.Cancel = this.Dialog.Ask("确定要关闭吗") != "确定";
|
||||
base.OnClose(e);
|
||||
}
|
||||
}
|
||||
}
|
27
CPF.Toolkit/CPF.Toolkit.csproj
Normal file
27
CPF.Toolkit/CPF.Toolkit.csproj
Normal file
@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Images\ask.png" />
|
||||
<None Remove="Images\error.png" />
|
||||
<None Remove="Images\sucess.png" />
|
||||
<None Remove="Images\warn.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Images\ask.png" />
|
||||
<EmbeddedResource Include="Images\error.png" />
|
||||
<EmbeddedResource Include="Images\sucess.png" />
|
||||
<EmbeddedResource Include="Images\warn.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CPF\CPF.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
370
CPF.Toolkit/Controls/MdiHost.cs
Normal file
370
CPF.Toolkit/Controls/MdiHost.cs
Normal file
@ -0,0 +1,370 @@
|
||||
using CPF.Controls;
|
||||
using CPF.Drawing;
|
||||
using CPF.Platform;
|
||||
using CPF.Shapes;
|
||||
using CPF.Styling;
|
||||
using CPF.Toolkit.Dialogs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace CPF.Toolkit.Controls
|
||||
{
|
||||
public class MdiHost : Grid
|
||||
{
|
||||
public MdiHost()
|
||||
{
|
||||
this.TaskBarList = new Collection<UIElement>();
|
||||
this.Size = SizeField.Fill;
|
||||
this.Background = "204,204,204";
|
||||
base.RowDefinitions.Add(new RowDefinition { Height = GridLength.Star });
|
||||
base.RowDefinitions.Add(new RowDefinition { Height = 35 });
|
||||
base.Children.Add(this.host);
|
||||
taskBar = base.Children.Add(new ListBox
|
||||
{
|
||||
Size = SizeField.Fill,
|
||||
Background = "white",
|
||||
BorderFill = "silver",
|
||||
BorderThickness = new Thickness(0, 1, 0, 0),
|
||||
BorderType = BorderType.BorderThickness,
|
||||
ItemsPanel = new StackPanel { Orientation = Orientation.Horizontal },
|
||||
ItemTemplate = new TaskBarItem
|
||||
{
|
||||
[nameof(TaskBarItem.CloseClick)] = new CommandDescribe((s, e) => (s.DataContext as MdiWindow).Close())
|
||||
},
|
||||
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;
|
||||
}
|
||||
readonly Dictionary<UIElement, MdiWindowRect> normalRect = [];
|
||||
readonly Panel host = new() { Size = SizeField.Fill };
|
||||
readonly ListBox taskBar;
|
||||
Collection<UIElement> TaskBarList { get => GetValue<Collection<UIElement>>(); set => SetValue(value); }
|
||||
public new UIElementCollection Children => host.Children;
|
||||
public MdiWindow SelectWindow { get => GetValue<MdiWindow>(); set => SetValue(value); }
|
||||
|
||||
[PropertyMetadata(TaskBarPlacement.Bottom)]
|
||||
public TaskBarPlacement TaskBarPlacement { get => GetValue<TaskBarPlacement>(); set => SetValue(value); }
|
||||
|
||||
protected override void OnPropertyChanged(string propertyName, object oldValue, object newValue, PropertyMetadataAttribute propertyMetadata)
|
||||
{
|
||||
if (propertyName == nameof(this.SelectWindow) && this.SelectWindow != null)
|
||||
{
|
||||
this.Topping(this.SelectWindow);
|
||||
this.SelectWindow.WindowState = this.normalRect[this.SelectWindow].OldState;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
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)))
|
||||
{
|
||||
foreach (MdiWindow mdi in this.host.Children)
|
||||
{
|
||||
if (mdi.WindowState == WindowState.Maximized) continue;
|
||||
|
||||
if (mdi.MarginLeft.Value + mdi.ActualSize.Width > this.ActualSize.Width)
|
||||
{
|
||||
mdi.MarginLeft = this.ActualSize.Width - mdi.ActualSize.Width;
|
||||
}
|
||||
|
||||
if (mdi.MarginTop.Value + mdi.ActualSize.Height > this.ActualSize.Height)
|
||||
{
|
||||
mdi.MarginTop = this.ActualSize.Height - mdi.ActualSize.Height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Host_UIElementRemoved(object sender, UIElementRemovedEventArgs e)
|
||||
{
|
||||
var view = e.Element as MdiWindow;
|
||||
view.PropertyChanged -= Element_PropertyChanged;
|
||||
view.PreviewMouseDown -= Element_PreviewMouseDown;
|
||||
view.Closing -= View_Closing;
|
||||
this.TaskBarList.Remove(e.Element);
|
||||
this.normalRect.Remove(e.Element);
|
||||
}
|
||||
|
||||
private void Host_UIElementAdded(object sender, UIElementAddedEventArgs e)
|
||||
{
|
||||
var view = e.Element as MdiWindow;
|
||||
this.normalRect.Add(e.Element, new MdiWindowRect { Left = 0, Top = 0, Height = 500, Width = 500 });
|
||||
view.PropertyChanged += Element_PropertyChanged;
|
||||
view.PreviewMouseDown += Element_PreviewMouseDown;
|
||||
view.Closing += View_Closing;
|
||||
this.TaskBarList.Add(view);
|
||||
e.Element.ZIndex = this.host.Children.Max(x => x.ZIndex) + 1;
|
||||
this.Topping(view);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
private void Element_PreviewMouseDown(object sender, Input.MouseButtonEventArgs e)
|
||||
{
|
||||
var ele = (MdiWindow)sender;
|
||||
this.Topping(ele);
|
||||
}
|
||||
|
||||
private void Element_PropertyChanged(object sender, CPFPropertyChangedEventArgs e)
|
||||
{
|
||||
var view = sender as MdiWindow;
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
case nameof(MdiWindow.WindowState):
|
||||
|
||||
switch ((WindowState)e.NewValue)
|
||||
{
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
case nameof(ZIndex):
|
||||
this.SelectWindow = view;
|
||||
this.SelectWindow.Visibility = Visibility.Visible;
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public void Topping(MdiWindow ele)
|
||||
{
|
||||
if (ele == null) return;
|
||||
ele.Focus();
|
||||
var index = this.host.Children.Max(x => x.ZIndex);
|
||||
if (ele.ZIndex == index)
|
||||
{
|
||||
ele.Visibility = Visibility.Visible;
|
||||
return;
|
||||
}
|
||||
ele.ZIndex = index + 1;
|
||||
}
|
||||
|
||||
class TaskBarItem : ListBoxItem
|
||||
{
|
||||
public event EventHandler CloseClick
|
||||
{
|
||||
add { AddHandler(value); }
|
||||
remove { RemoveHandler(value); }
|
||||
}
|
||||
|
||||
protected override void InitializeComponent()
|
||||
{
|
||||
this.Size = new SizeField(100, "90%");
|
||||
this.Background = "white";
|
||||
this.BorderFill = "gray";
|
||||
this.BorderStroke = "1";
|
||||
this.CornerRadius = new CornerRadius(2);
|
||||
this.Margin = new ThicknessField(1);
|
||||
this.IsAntiAlias = true;
|
||||
this.UseLayoutRounding = true;
|
||||
this.CommandContext = this;
|
||||
this.Triggers.Add(new Trigger
|
||||
{
|
||||
Property = nameof(IsSelected),
|
||||
Setters =
|
||||
{
|
||||
{ nameof(Background),nameof(Color.DodgerBlue) },
|
||||
{ nameof(Foreground),"white" }
|
||||
}
|
||||
});
|
||||
this.Children.Add(new Grid
|
||||
{
|
||||
Size = SizeField.Fill,
|
||||
ColumnDefinitions =
|
||||
{
|
||||
new ColumnDefinition{ },
|
||||
new ColumnDefinition{ Width = 30 },
|
||||
},
|
||||
Children =
|
||||
{
|
||||
new TextBlock
|
||||
{
|
||||
Height = "auto",
|
||||
TextTrimming = TextTrimming.CharacterEllipsis,
|
||||
TextAlignment = TextAlignment.Center,
|
||||
[nameof(TextBlock.Text)] = new BindingDescribe("Title"),
|
||||
},
|
||||
new Panel
|
||||
{
|
||||
Name = "close",
|
||||
Attacheds = { { Grid.ColumnIndex,1 } },
|
||||
MarginRight = 5,
|
||||
Size = new SizeField(15,15),
|
||||
CornerRadius = new CornerRadius(5),
|
||||
Children =
|
||||
{
|
||||
new Line
|
||||
{
|
||||
MarginLeft = 2,
|
||||
MarginTop = 2,
|
||||
StartPoint = new Point(1, 1),
|
||||
EndPoint = new Point(10, 10),
|
||||
StrokeStyle = "2",
|
||||
IsAntiAlias = true,
|
||||
[nameof(Line.StrokeFill)] = new BindingDescribe(this,nameof(Foreground)),
|
||||
},
|
||||
new Line
|
||||
{
|
||||
MarginLeft = 2,
|
||||
MarginTop = 2,
|
||||
StartPoint = new Point(10, 1),
|
||||
EndPoint = new Point(1, 10),
|
||||
StrokeStyle = "2",
|
||||
IsAntiAlias = true,
|
||||
[nameof(Line.StrokeFill)] = new BindingDescribe(this,nameof(Foreground)),
|
||||
}
|
||||
},
|
||||
Triggers =
|
||||
{
|
||||
new Trigger
|
||||
{
|
||||
Property = nameof(IsMouseOver),
|
||||
Setters =
|
||||
{
|
||||
{ nameof(Background) ,"red" },
|
||||
{ nameof(Foreground) ,"white" },
|
||||
}
|
||||
},
|
||||
},
|
||||
[nameof(Panel.MouseUp)] = new CommandDescribe((s,e) => this.RaiseEvent(e,nameof(this.CloseClick)))
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
class MdiWindowRect
|
||||
{
|
||||
public MdiWindowRect()
|
||||
{
|
||||
|
||||
}
|
||||
public MdiWindowRect(float left, float top, float width, float height)
|
||||
{
|
||||
this.Left = left;
|
||||
this.Top = top;
|
||||
this.Width = width;
|
||||
this.Height = height;
|
||||
}
|
||||
public float Left { get; set; }
|
||||
public float Top { get; set; }
|
||||
public float Width { get; set; }
|
||||
public float Height { get; set; }
|
||||
|
||||
public WindowState OldState { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"left:{this.Left} top:{this.Top} width:{this.Width} height:{this.Height}";
|
||||
}
|
||||
}
|
||||
}
|
||||
public enum TaskBarPlacement
|
||||
{
|
||||
Top,
|
||||
Bottom,
|
||||
}
|
||||
}
|
488
CPF.Toolkit/Controls/MdiWindow.cs
Normal file
488
CPF.Toolkit/Controls/MdiWindow.cs
Normal file
@ -0,0 +1,488 @@
|
||||
using CPF;
|
||||
using CPF.Animation;
|
||||
using CPF.Charts;
|
||||
using CPF.Controls;
|
||||
using CPF.Drawing;
|
||||
using CPF.Input;
|
||||
using CPF.Platform;
|
||||
using CPF.Shapes;
|
||||
using CPF.Styling;
|
||||
using CPF.Svg;
|
||||
using CPF.Toolkit.Dialogs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace CPF.Toolkit.Controls
|
||||
{
|
||||
public class MdiWindow : Control
|
||||
{
|
||||
public MdiWindow()
|
||||
{
|
||||
this.Init();
|
||||
}
|
||||
public WindowState WindowState { get => GetValue<WindowState>(); set => SetValue(value); }
|
||||
public UIElement Content { get => GetValue<UIElement>(); set => SetValue(value); }
|
||||
|
||||
[PropertyMetadata("Title")]
|
||||
public string Title { get => GetValue<string>(); set => SetValue(value); }
|
||||
|
||||
[PropertyMetadata(true)]
|
||||
public bool MaximizeBox { get { return GetValue<bool>(); } set { SetValue(value); } }
|
||||
|
||||
[PropertyMetadata(true)]
|
||||
public bool MinimizeBox { get { return GetValue<bool>(); } set { SetValue(value); } }
|
||||
|
||||
[PropertyMetadata(true)]
|
||||
public bool CloseBox { get { return GetValue<bool>(); } set { SetValue(value); } }
|
||||
|
||||
[UIPropertyMetadata((byte)5, UIPropertyOptions.AffectsMeasure)]
|
||||
public byte ShadowBlur { get { return GetValue<byte>(); } set { SetValue(value); } }
|
||||
|
||||
[PropertyMetadata(true)]
|
||||
public bool CanResize
|
||||
{
|
||||
get => GetValue<bool>();
|
||||
set
|
||||
{
|
||||
SetValue(value);
|
||||
if (!value) this.MaximizeBox = false;
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ClosingEventArgs> Closing;
|
||||
|
||||
|
||||
void Init()
|
||||
{
|
||||
this.Focusable = true;
|
||||
var borderColor = (ViewFill)"152,180,208";
|
||||
var lostFocusBorderColor = (ViewFill)"214,227,241";
|
||||
var dragEnabled = new BindingDescribe(this, nameof(WindowState), BindingMode.OneWay, x =>
|
||||
{
|
||||
if (this.CanResize)
|
||||
{
|
||||
return ((WindowState)x) == WindowState.Normal;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
this.Size = new SizeField(500, 500);
|
||||
this.Background = null;
|
||||
this.MarginLeft = 0;
|
||||
this.MarginTop = 0;
|
||||
this.ClipToBounds = true;
|
||||
this.Children.Add(new Border
|
||||
{
|
||||
Size = SizeField.Fill,
|
||||
Background = "white",
|
||||
BorderType = BorderType.BorderStroke,
|
||||
BorderStroke = "0",
|
||||
//ShadowBlur = ShadowBlur,
|
||||
ShadowColor = Color.FromRgba(0, 0, 0, 150),
|
||||
Child = new Decorator
|
||||
{
|
||||
Size = SizeField.Fill,
|
||||
ClipToBounds = true,
|
||||
Child = new Grid
|
||||
{
|
||||
Size = SizeField.Fill,
|
||||
ColumnDefinitions =
|
||||
{
|
||||
new ColumnDefinition{ Width = "auto" },
|
||||
new ColumnDefinition{ },
|
||||
new ColumnDefinition{ Width = "auto" },
|
||||
},
|
||||
RowDefinitions =
|
||||
{
|
||||
new RowDefinition{ Height = "auto" },
|
||||
new RowDefinition{ Height = 30 },
|
||||
new RowDefinition{ },
|
||||
new RowDefinition{ Height = "auto" },
|
||||
},
|
||||
Children =
|
||||
{
|
||||
new Thumb
|
||||
{
|
||||
Name = "top",
|
||||
Size = "100%,5",
|
||||
Cursor = Cursors.SizeNorthSouth,
|
||||
Attacheds = { { Grid.ColumnIndex,1 } },
|
||||
[nameof(IsEnabled)] = dragEnabled,
|
||||
[nameof(Background)] = new BindingDescribe(this,nameof(IsFocused),BindingMode.OneWay ,x => ((bool)x) ? borderColor : lostFocusBorderColor),
|
||||
[nameof(Thumb.DragDelta)] = new CommandDescribe((s,e) =>
|
||||
{
|
||||
var args = e as DragDeltaEventArgs;
|
||||
if (this.Height.Value - args.VerticalChange > 0)
|
||||
{
|
||||
this.MarginTop += args.VerticalChange;
|
||||
this.Height -= args.VerticalChange;
|
||||
}
|
||||
}),
|
||||
},
|
||||
new Thumb
|
||||
{
|
||||
Name = "left",
|
||||
Size = "5,100%",
|
||||
Cursor = Cursors.SizeWestEast,
|
||||
Attacheds = { { Grid.RowIndex,1 },{ Grid.RowSpan,2 } },
|
||||
[nameof(IsEnabled)] = dragEnabled,
|
||||
[nameof(Background)] = new BindingDescribe(this,nameof(IsFocused),BindingMode.OneWay ,x => ((bool)x) ? borderColor : lostFocusBorderColor),
|
||||
[nameof(Thumb.DragDelta)] = new CommandDescribe((s,e) =>
|
||||
{
|
||||
var args = e as DragDeltaEventArgs;
|
||||
if (this.Width.Value - args.HorizontalChange > 0)
|
||||
{
|
||||
this.MarginLeft += args.HorizontalChange;
|
||||
this.Width -= args.HorizontalChange;
|
||||
}
|
||||
}),
|
||||
},
|
||||
new Thumb
|
||||
{
|
||||
Name = "left_top",
|
||||
Size = SizeField.Fill,
|
||||
Cursor = Cursors.TopLeftCorner,
|
||||
[nameof(IsEnabled)] = dragEnabled,
|
||||
[nameof(Background)] = new BindingDescribe(this,nameof(IsFocused),BindingMode.OneWay ,x => ((bool)x) ? borderColor : lostFocusBorderColor),
|
||||
[nameof(Thumb.DragDelta)] = new CommandDescribe((s,e) =>
|
||||
{
|
||||
var args = e as DragDeltaEventArgs;
|
||||
if (this.Width.Value - args.HorizontalChange > 0 && this.Height.Value - args.VerticalChange > 0)
|
||||
{
|
||||
this.MarginLeft += args.HorizontalChange;
|
||||
this.MarginTop += args.VerticalChange;
|
||||
this.Width -= args.HorizontalChange;
|
||||
this.Height -= args.VerticalChange;
|
||||
}
|
||||
}),
|
||||
},
|
||||
new Thumb
|
||||
{
|
||||
Name = "right",
|
||||
Size = "5,100%",
|
||||
Cursor = Cursors.SizeWestEast,
|
||||
MarginRight = 0,
|
||||
Attacheds = { { Grid.ColumnIndex,2 },{ Grid.RowIndex,1 },{ Grid.RowSpan,2 } },
|
||||
[nameof(IsEnabled)] = dragEnabled,
|
||||
[nameof(Thumb.DragDelta)] = new CommandDescribe((s,e) => this.Width += (e as DragDeltaEventArgs).HorizontalChange),
|
||||
[nameof(Background)] = new BindingDescribe(this,nameof(IsFocused),BindingMode.OneWay ,x => ((bool)x) ? borderColor : lostFocusBorderColor),
|
||||
},
|
||||
new Thumb
|
||||
{
|
||||
Name = "right_top",
|
||||
Size = SizeField.Fill,
|
||||
Cursor = Cursors.TopRightCorner,
|
||||
MarginRight = 0,
|
||||
Attacheds = { { Grid.ColumnIndex,2 } },
|
||||
[nameof(IsEnabled)] = dragEnabled,
|
||||
[nameof(Background)] = new BindingDescribe(this,nameof(IsFocused),BindingMode.OneWay ,x => ((bool)x) ? borderColor : lostFocusBorderColor),
|
||||
[nameof(Thumb.DragDelta)] = new CommandDescribe((s,e) =>
|
||||
{
|
||||
var args = e as DragDeltaEventArgs;
|
||||
if (this.Width.Value - args.HorizontalChange > 0 && this.Height.Value - args.VerticalChange > 0)
|
||||
{
|
||||
this.MarginTop += args.VerticalChange;
|
||||
this.Width += args.HorizontalChange;
|
||||
this.Height -= args.VerticalChange;
|
||||
}
|
||||
}),
|
||||
},
|
||||
new Thumb
|
||||
{
|
||||
Name = "bottom",
|
||||
Size = "100%,5",
|
||||
Cursor = Cursors.SizeNorthSouth,
|
||||
Attacheds = { { Grid.RowIndex,3 },{ Grid.ColumnIndex,1 } },
|
||||
[nameof(IsEnabled)] = dragEnabled,
|
||||
[nameof(Thumb.DragDelta)] = new CommandDescribe((s,e) => this.Height += (e as DragDeltaEventArgs).VerticalChange),
|
||||
[nameof(Background)] = new BindingDescribe(this,nameof(IsFocused),BindingMode.OneWay ,x => ((bool)x) ? borderColor : lostFocusBorderColor),
|
||||
},
|
||||
new Thumb
|
||||
{
|
||||
Name = "left_bottom",
|
||||
Size = SizeField.Fill,
|
||||
Cursor = Cursors.BottomLeftCorner,
|
||||
Attacheds = { { Grid.RowIndex,3 } },
|
||||
[nameof(Background)] = new BindingDescribe(this,nameof(IsFocused),BindingMode.OneWay ,x => ((bool)x) ? borderColor : lostFocusBorderColor),
|
||||
[nameof(IsEnabled)] = dragEnabled,
|
||||
[nameof(Thumb.DragDelta)] = new CommandDescribe((s,e) =>
|
||||
{
|
||||
var args = e as DragDeltaEventArgs;
|
||||
if (this.Width.Value - args.HorizontalChange > 0 && this.Height.Value + args.VerticalChange > 0)
|
||||
{
|
||||
this.MarginLeft += args.HorizontalChange;
|
||||
this.Width -= args.HorizontalChange;
|
||||
this.Height += args.VerticalChange;
|
||||
}
|
||||
}),
|
||||
},
|
||||
new Thumb
|
||||
{
|
||||
Name = "right_bottom",
|
||||
Size = SizeField.Fill,
|
||||
Cursor = Cursors.BottomRightCorner,
|
||||
Attacheds = { { Grid.RowIndex,3 },{ Grid.ColumnIndex,2 } },
|
||||
[nameof(Background)] = new BindingDescribe(this,nameof(IsFocused),BindingMode.OneWay ,x => ((bool)x) ? borderColor : lostFocusBorderColor),
|
||||
[nameof(IsEnabled)] = dragEnabled,
|
||||
[nameof(Thumb.DragDelta)] = new CommandDescribe((s,e) =>
|
||||
{
|
||||
var args = e as DragDeltaEventArgs;
|
||||
if (this.Height.Value + args.VerticalChange > 0 && this.Width.Value + args.HorizontalChange > 0)
|
||||
{
|
||||
this.Width += args.HorizontalChange;
|
||||
this.Height += args.VerticalChange;
|
||||
}
|
||||
}),
|
||||
},
|
||||
new Thumb
|
||||
{
|
||||
Name = "caption",
|
||||
Attacheds = { { Grid.RowIndex,1 },{ Grid.ColumnIndex,1 } },
|
||||
Size = SizeField.Fill,
|
||||
Child = new Panel
|
||||
{
|
||||
Size = SizeField.Fill,
|
||||
Children =
|
||||
{
|
||||
new StackPanel
|
||||
{
|
||||
Orientation = Orientation.Horizontal,
|
||||
MarginLeft = 0,
|
||||
Children =
|
||||
{
|
||||
new TextBlock
|
||||
{
|
||||
[nameof(TextBlock.Text)] = new BindingDescribe(this,nameof(this.Title),BindingMode.OneWay),
|
||||
FontSize = 14,
|
||||
MarginLeft = 10,
|
||||
},
|
||||
}
|
||||
},
|
||||
new StackPanel
|
||||
{
|
||||
Orientation = Orientation.Horizontal,
|
||||
MarginRight = 0,
|
||||
Height = "100%",
|
||||
Children =
|
||||
{
|
||||
new SystemButton
|
||||
{
|
||||
Name = "min",
|
||||
Size = new SizeField(30,"100%"),
|
||||
Content = new Line
|
||||
{
|
||||
MarginLeft = "auto",
|
||||
StartPoint = new Point(1,13),
|
||||
EndPoint = new Point(14,13),
|
||||
StrokeStyle = "2",
|
||||
IsAntiAlias = true,
|
||||
StrokeFill = "black"
|
||||
},
|
||||
[nameof(Visibility)] = new BindingDescribe(this,nameof(MinimizeBox),BindingMode.OneWay,x=>(bool)x?Visibility.Visible: Visibility.Collapsed),
|
||||
[nameof(Button.Click)] = new CommandDescribe((s,e) => this.WindowState = WindowState.Minimized)
|
||||
},
|
||||
new Panel
|
||||
{
|
||||
Height = "100%",
|
||||
[nameof(Visibility)] = new BindingDescribe(this,nameof(MaximizeBox),BindingMode.OneWay,a => (bool)a ? Visibility.Visible : Visibility.Collapsed),
|
||||
Children =
|
||||
{
|
||||
new SystemButton
|
||||
{
|
||||
Name = "max",
|
||||
Size = new SizeField(30,"100%"),
|
||||
Content = new Rectangle
|
||||
{
|
||||
Size = new SizeField(14,12),
|
||||
MarginTop = 5,
|
||||
StrokeStyle = "2",
|
||||
},
|
||||
[nameof(Button.Click)] = new CommandDescribe((s, e) => this.WindowState = WindowState.Maximized),
|
||||
[nameof(Visibility)] =
|
||||
new BindingDescribe(
|
||||
this,
|
||||
nameof(WindowState),
|
||||
BindingMode.OneWay,
|
||||
x => ((WindowState)x).Or(WindowState.Maximized,WindowState.FullScreen) ? Visibility.Collapsed : Visibility.Visible),
|
||||
},
|
||||
new SystemButton
|
||||
{
|
||||
Name = "nor",
|
||||
Visibility = Visibility.Collapsed,
|
||||
Size = new SizeField(30,"100%"),
|
||||
Content = new Panel
|
||||
{
|
||||
Size = SizeField.Fill,
|
||||
Children =
|
||||
{
|
||||
new Rectangle
|
||||
{
|
||||
MarginTop = 10,
|
||||
MarginLeft =8,
|
||||
Size = new SizeField(11,8),
|
||||
StrokeStyle = "1.5",
|
||||
},
|
||||
new Polyline
|
||||
{
|
||||
MarginTop =5,
|
||||
MarginLeft = 12,
|
||||
Points =
|
||||
{
|
||||
new Point(0,3),
|
||||
new Point(0,0),
|
||||
new Point(9,0),
|
||||
new Point(9,7),
|
||||
new Point(6,7)
|
||||
},
|
||||
StrokeStyle = "2"
|
||||
}
|
||||
}
|
||||
},
|
||||
[nameof(Button.Click)] = new CommandDescribe((s, e) => this.WindowState = WindowState.Normal),
|
||||
[nameof(Visibility)] =
|
||||
new BindingDescribe(
|
||||
this,
|
||||
nameof(WindowState),
|
||||
BindingMode.OneWay,
|
||||
x => ((WindowState)x).Or(WindowState.Normal,WindowState.Minimized)? Visibility.Collapsed : Visibility.Visible)
|
||||
}
|
||||
}
|
||||
},
|
||||
new SystemButton
|
||||
{
|
||||
Name = "close",
|
||||
Size = new SizeField(30,"100%"),
|
||||
Content = new Panel
|
||||
{
|
||||
Size = SizeField.Fill,
|
||||
Children =
|
||||
{
|
||||
new Line
|
||||
{
|
||||
MarginTop=4,
|
||||
MarginLeft=8,
|
||||
StartPoint = new Point(1, 1),
|
||||
EndPoint = new Point(14, 13),
|
||||
StrokeStyle = "2",
|
||||
IsAntiAlias=true,
|
||||
},
|
||||
new Line
|
||||
{
|
||||
MarginTop=4,
|
||||
MarginLeft=8,
|
||||
StartPoint = new Point(14, 1),
|
||||
EndPoint = new Point(1, 13),
|
||||
StrokeStyle = "2",
|
||||
IsAntiAlias=true,
|
||||
}
|
||||
}
|
||||
},
|
||||
[nameof(Button.Click)] = new CommandDescribe((ss,ee) => this.Close()),
|
||||
[nameof(Visibility)] = new BindingDescribe(this,nameof(this.CloseBox),BindingMode.OneWay,x=>(bool)x?Visibility.Visible: Visibility.Collapsed)
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
[nameof(Thumb.DragDelta)] = new CommandDescribe((ss,ee)=>
|
||||
{
|
||||
if (this.WindowState.Or(WindowState.Normal))
|
||||
{
|
||||
var arge = ee as DragDeltaEventArgs;
|
||||
this.MarginLeft += arge.HorizontalChange;
|
||||
this.MarginTop += arge.VerticalChange;
|
||||
}
|
||||
}),
|
||||
[nameof(DoubleClick)] = new CommandDescribe((ss,ee) => this.Delay(TimeSpan.FromMilliseconds(150),()=>
|
||||
{
|
||||
if(!this.MaximizeBox) return;
|
||||
if (this.WindowState.Or(WindowState.Maximized,WindowState.Minimized))
|
||||
{
|
||||
this.WindowState = WindowState.Normal;
|
||||
}
|
||||
else if (this.WindowState == WindowState.Normal)
|
||||
{
|
||||
this.WindowState = WindowState.Maximized;
|
||||
}
|
||||
})),
|
||||
[nameof(Background)] = new BindingDescribe(this,nameof(IsFocused),BindingMode.OneWay ,x => ((bool)x) ? borderColor : lostFocusBorderColor)
|
||||
},
|
||||
new Decorator
|
||||
{
|
||||
Attacheds = { { Grid.RowIndex,2 } ,{ Grid.ColumnIndex,1 } },
|
||||
Size = SizeField.Fill,
|
||||
[nameof(Decorator.Child)] = new BindingDescribe(this,nameof(Content))
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
[nameof(ShadowBlur)] = new BindingDescribe(this, nameof(WindowState), BindingMode.OneWay, x => ((WindowState)x).Or(WindowState.Maximized, WindowState.FullScreen) ? 0 : ShadowBlur),
|
||||
Triggers =
|
||||
{
|
||||
new Trigger
|
||||
{
|
||||
Property = nameof(IsFocused),
|
||||
Setters =
|
||||
{
|
||||
{ nameof(ShadowBlur),ShadowBlur },
|
||||
{ nameof(BorderStroke),"1" },
|
||||
{ nameof(BorderFill),"0,0,0,100" },
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(string propertyName, object oldValue, object newValue, PropertyMetadataAttribute propertyMetadata)
|
||||
{
|
||||
if (propertyName == nameof(DataContext) && newValue != null)
|
||||
{
|
||||
if (newValue is IClosable closable)
|
||||
{
|
||||
closable.Closable -= Closable_Closable;
|
||||
closable.Closable += Closable_Closable;
|
||||
}
|
||||
if (newValue is ILoading loading)
|
||||
{
|
||||
loading.CreateLoading(this);
|
||||
}
|
||||
}
|
||||
else if (propertyName == nameof(Content) && newValue != null)
|
||||
{
|
||||
this.Content.Margin = "0";
|
||||
this.Content.ClipToBounds = true;
|
||||
}
|
||||
base.OnPropertyChanged(propertyName, oldValue, newValue, propertyMetadata);
|
||||
}
|
||||
|
||||
private void Closable_Closable(object sender, ClosingEventArgs e)
|
||||
{
|
||||
this.DoClose(sender, e);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (this.Closing != null)
|
||||
{
|
||||
this.DoClose(this, new ClosingEventArgs());
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
void DoClose(object sender, ClosingEventArgs e)
|
||||
{
|
||||
if (this.DataContext is IClosable closable)
|
||||
{
|
||||
closable.OnClosable(sender, e);
|
||||
}
|
||||
this.Closing.Invoke(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
230
CPF.Toolkit/Controls/PageControl.cs
Normal file
230
CPF.Toolkit/Controls/PageControl.cs
Normal file
@ -0,0 +1,230 @@
|
||||
using CPF;
|
||||
using CPF.Animation;
|
||||
using CPF.Charts;
|
||||
using CPF.Controls;
|
||||
using CPF.Drawing;
|
||||
using CPF.Input;
|
||||
using CPF.Shapes;
|
||||
using CPF.Styling;
|
||||
using CPF.Svg;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace CPF.Toolkit.Controls
|
||||
{
|
||||
public class PageControl : Control
|
||||
{
|
||||
public PageControl()
|
||||
{
|
||||
this.Pages = new ObservableCollection<int>();
|
||||
}
|
||||
public int PageIndex { get => GetValue<int>(); set => SetValue(value); }
|
||||
public int PageCount { get => GetValue<int>(); set => SetValue(value); }
|
||||
int pageSize = 10;
|
||||
|
||||
public event EventHandler<IndexEventArgs> PageIndexChanged { add => AddHandler(value); remove => RemoveHandler(value); }
|
||||
|
||||
ObservableCollection<int> Pages { get => GetValue<ObservableCollection<int>>(); set => SetValue(value); }
|
||||
|
||||
protected override void InitializeComponent()
|
||||
{
|
||||
this.Size = SizeField.Fill;
|
||||
this.Children.Add(new StackPanel
|
||||
{
|
||||
Orientation = Orientation.Horizontal,
|
||||
Size = SizeField.Fill,
|
||||
Children =
|
||||
{
|
||||
new Button
|
||||
{
|
||||
Content = "上一页",
|
||||
[nameof(IsEnabled)] = new BindingDescribe(this,nameof(this.PageIndex),BindingMode.OneWay,c => ((int)c) > 1),
|
||||
},
|
||||
new ListBox
|
||||
{
|
||||
ItemTemplate = new PageButton
|
||||
{
|
||||
[nameof(PageIndexChanged)] = new CommandDescribe((s,e) => this.PageIndex = (e as IndexEventArgs).Index)
|
||||
},
|
||||
ItemsPanel = new StackPanel{Orientation = Orientation.Horizontal,},
|
||||
Items = this.Pages,
|
||||
},
|
||||
new TextBlock
|
||||
{
|
||||
Text = "……",
|
||||
[nameof(Visibility)] = new BindingDescribe(this,nameof(this.PageCount),BindingMode.OneWay,c => ((int)c) > this.pageSize ? Visibility.Visible : Visibility.Collapsed)
|
||||
},
|
||||
new Button
|
||||
{
|
||||
Content = "100",
|
||||
[nameof(Visibility)] = new BindingDescribe(this,nameof(this.PageCount),BindingMode.OneWay,c => ((int)c) > this.pageSize ? Visibility.Visible : Visibility.Collapsed)
|
||||
},
|
||||
new Button
|
||||
{
|
||||
Content = "下一页",
|
||||
[nameof(IsEnabled)] = new BindingDescribe(this,nameof(this.PageIndex),BindingMode.OneWay,c => ((int)c) < this.PageCount),
|
||||
},
|
||||
new StackPanel
|
||||
{
|
||||
MarginLeft = 10,
|
||||
Orientation = Orientation.Horizontal,
|
||||
Children =
|
||||
{
|
||||
new TextBlock
|
||||
{
|
||||
Text = "1 ",
|
||||
Foreground = "dodgerblue",
|
||||
},
|
||||
new TextBlock
|
||||
{
|
||||
Text = $"/ 100",
|
||||
},
|
||||
}
|
||||
},
|
||||
new TextBlock
|
||||
{
|
||||
Text = " 到第几 "
|
||||
},
|
||||
new Border
|
||||
{
|
||||
MinHeight = 35,
|
||||
MinWidth = 35,
|
||||
MarginLeft = 2,
|
||||
MarginRight = 2,
|
||||
Child = new TextBox
|
||||
{
|
||||
Width = "100%",
|
||||
Text = "10",
|
||||
TextAlignment = TextAlignment.Center,
|
||||
FontSize = 14,
|
||||
},
|
||||
BorderFill = "silver",
|
||||
BorderStroke = "1",
|
||||
CornerRadius = new CornerRadius(2),
|
||||
IsAntiAlias = true,
|
||||
UseLayoutRounding = true,
|
||||
},
|
||||
new TextBlock
|
||||
{
|
||||
Text = " 页 " ,
|
||||
},
|
||||
new Button
|
||||
{
|
||||
Content = "确定",
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
foreach (var item in this.Find<TextBlock>())
|
||||
{
|
||||
item.FontSize = 14;
|
||||
}
|
||||
|
||||
foreach (var item in Find<Button>())
|
||||
{
|
||||
item.BorderFill = "dodgerblue";
|
||||
item.BorderStroke = "1";
|
||||
item.CornerRadius = new CornerRadius(4);
|
||||
item.Background = "white";
|
||||
item.Foreground = "dodgerblue";
|
||||
item.MinWidth = 35;
|
||||
item.MinHeight = 35;
|
||||
item.MarginRight = 2;
|
||||
item.IsAntiAlias = true;
|
||||
item.UseLayoutRounding = true;
|
||||
if (!int.TryParse(item.Content.ToString(), out var _))
|
||||
{
|
||||
item.Width = 60;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(string propertyName, object oldValue, object newValue, PropertyMetadataAttribute propertyMetadata)
|
||||
{
|
||||
if (propertyName.Or(nameof(this.PageIndex), nameof(this.PageCount)))
|
||||
{
|
||||
this.Pages.Clear();
|
||||
for (int i = 1; i <= this.PageCount; i++)
|
||||
{
|
||||
if (i > this.pageSize)
|
||||
{
|
||||
break;
|
||||
}
|
||||
this.Pages.Add(i);
|
||||
}
|
||||
}
|
||||
base.OnPropertyChanged(propertyName, oldValue, newValue, propertyMetadata);
|
||||
}
|
||||
|
||||
class PageButton : ListBoxItem
|
||||
{
|
||||
public event EventHandler<IndexEventArgs> PageIndexChanged { add => AddHandler(value); remove => RemoveHandler(value); }
|
||||
|
||||
protected override void InitializeComponent()
|
||||
{
|
||||
this.Children.Add(new RadioButton
|
||||
{
|
||||
Size = SizeField.Fill,
|
||||
GroupName = "pageNumber",
|
||||
Template = (ss, ee) =>
|
||||
{
|
||||
var s = ss as RadioButton;
|
||||
s.BorderFill = "dodgerblue";
|
||||
s.BorderStroke = "1";
|
||||
s.CornerRadius = new CornerRadius(4);
|
||||
s.Size = new SizeField(35, 35);
|
||||
s.MarginLeft = 2;
|
||||
s.MarginRight = 2;
|
||||
s.UseLayoutRounding = true;
|
||||
s.IsAntiAlias = true;
|
||||
s.Foreground = "dodgerblue";
|
||||
s.Cursor = Cursors.Hand;
|
||||
ee.Add(new TextBlock
|
||||
{
|
||||
FontSize = 14,
|
||||
[nameof(TextBlock.Text)] = new BindingDescribe(this, nameof(Content)),
|
||||
});
|
||||
s.Triggers.Add(new Trigger
|
||||
{
|
||||
Property = nameof(RadioButton.IsChecked),
|
||||
PropertyConditions = (x) => (bool?)x == true,
|
||||
Setters =
|
||||
{
|
||||
{ nameof(Background) , "dodgerblue" },
|
||||
{ nameof(Foreground) , "white" },
|
||||
},
|
||||
});
|
||||
},
|
||||
[nameof(Content)] = new BindingDescribe(this, nameof(Content)),
|
||||
[nameof(RadioButton.IsChecked)] = new BindingDescribe(new CommandDescribe((s, e) =>
|
||||
{
|
||||
var btn = s as RadioButton;
|
||||
if (btn.IsChecked == true) this.RaiseEvent(new IndexEventArgs(Convert.ToInt32(btn.Content)), nameof(this.PageIndexChanged));
|
||||
})),
|
||||
}.Assign(out var rad));
|
||||
|
||||
//rad.PropertyChanged += Rad_PropertyChanged;
|
||||
}
|
||||
|
||||
private void Rad_PropertyChanged(object sender, CPFPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == "IsChecked" && ((bool?)e.NewValue) == true)
|
||||
{
|
||||
this.RaiseEvent(new IndexEventArgs(Convert.ToInt32((sender as RadioButton).Content)), nameof(this.PageIndexChanged));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public class IndexEventArgs : EventArgs
|
||||
{
|
||||
public IndexEventArgs(int index)
|
||||
{
|
||||
this.Index = index;
|
||||
}
|
||||
public int Index { get; set; }
|
||||
}
|
||||
}
|
156
CPF.Toolkit/Dialogs/DialogView.cs
Normal file
156
CPF.Toolkit/Dialogs/DialogView.cs
Normal file
@ -0,0 +1,156 @@
|
||||
using CPF;
|
||||
using CPF.Animation;
|
||||
using CPF.Charts;
|
||||
using CPF.Controls;
|
||||
using CPF.Drawing;
|
||||
using CPF.Input;
|
||||
using CPF.Shapes;
|
||||
using CPF.Styling;
|
||||
using CPF.Svg;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace CPF.Toolkit.Dialogs
|
||||
{
|
||||
internal class DialogView : Window
|
||||
{
|
||||
public DialogView(string text, string title, DialogType dialogType, string defaultButton, params string[] buttons)
|
||||
{
|
||||
this.Title = title;
|
||||
this.Text = text;
|
||||
this.Buttons = buttons;
|
||||
this.DefaultButton = defaultButton;
|
||||
this.DialogType = dialogType;
|
||||
}
|
||||
|
||||
public DialogType DialogType { get => GetValue<DialogType>(); set => SetValue(value); }
|
||||
public string DefaultButton { get => GetValue<string>(); set => SetValue(value); }
|
||||
public string Text { get => GetValue<string>(); set => SetValue(value); }
|
||||
public string[] Buttons { get => GetValue<string[]>(); set => SetValue(value); }
|
||||
protected override void InitializeComponent()
|
||||
{
|
||||
this.ShowInTaskbar = false;
|
||||
this.MaxWidth = 800;
|
||||
this.MinWidth = 400;
|
||||
this.MaxHeight = 600;
|
||||
this.MinHeight = 250;
|
||||
this.CanResize = false;
|
||||
this.Width = "auto";
|
||||
this.Height = "auto";
|
||||
this.Background = null;
|
||||
var frame = this.Children.Add(new WindowFrame(this, new Grid
|
||||
{
|
||||
Size = SizeField.Fill,
|
||||
RowDefinitions =
|
||||
{
|
||||
new RowDefinition{ Height = "auto" },
|
||||
new RowDefinition{ },
|
||||
new RowDefinition{ Height = 35 },
|
||||
},
|
||||
Children =
|
||||
{
|
||||
new Picture
|
||||
{
|
||||
Stretch = Stretch.None,
|
||||
Bindings =
|
||||
{
|
||||
{
|
||||
nameof(Visibility),
|
||||
nameof(DialogType),
|
||||
this,BindingMode.OneWay,
|
||||
(DialogType t) => t == DialogType.None ? Visibility.Collapsed : Visibility.Visible
|
||||
},
|
||||
{
|
||||
nameof(Picture.Source),
|
||||
nameof(DialogType),
|
||||
this,BindingMode.OneWay,
|
||||
(DialogType t) =>
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case DialogType.Sucess: return "res://CPF.Toolkit/Images/sucess.png";
|
||||
case DialogType.Error:return"res://CPF.Toolkit/Images/error.png";
|
||||
case DialogType.Ask: return"res://CPF.Toolkit/Images/ask.png";
|
||||
case DialogType.Warn:return "res://CPF.Toolkit/Images/warn.png";
|
||||
default:return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new TextBox
|
||||
{
|
||||
Attacheds = { { Grid.RowIndex,1 } },
|
||||
BorderType = BorderType.BorderThickness,
|
||||
BorderStroke = new Stroke(1, DashStyles.Solid),
|
||||
BorderThickness = new Thickness(0,0,0,1),
|
||||
//BorderFill = "Silver",
|
||||
IsReadOnly = true,
|
||||
Size = SizeField.Fill,
|
||||
FontSize = 16,
|
||||
WordWarp = true,
|
||||
TextAlignment = TextAlignment.Center,
|
||||
Bindings =
|
||||
{
|
||||
{ nameof(TextBox.Text),nameof(Text),this,BindingMode.OneWay}
|
||||
}
|
||||
}.Assign(out var textBox),
|
||||
new StackPanel
|
||||
{
|
||||
Height = "100%",
|
||||
Attacheds = { { Grid.RowIndex,2 } },
|
||||
MarginBottom = 4,
|
||||
Orientation = Orientation.Horizontal,
|
||||
}
|
||||
.LoopCreate(this.Buttons.Length, i => new Button
|
||||
{
|
||||
Content = this.Buttons[i],
|
||||
MinWidth = this.Buttons.Length <= 1 ? 80 : 65,
|
||||
Background = "white",
|
||||
BorderFill = "236,236,236",
|
||||
Height = "95%",
|
||||
MarginRight = 5,
|
||||
Commands = { { nameof(Button.Click),(s,e) => this.DialogResult = this.Buttons[i] } }
|
||||
}),
|
||||
}
|
||||
}));
|
||||
frame.ControlBoxStroke = "black";
|
||||
frame.CaptionBackgrund = "white";
|
||||
frame.CaptionForeground = "black";
|
||||
frame.MinimizeBox = false;
|
||||
frame.MaximizeBox = false;
|
||||
|
||||
textBox.TextChanged += TextBox_TextChanged;
|
||||
}
|
||||
|
||||
private void TextBox_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
var textBox = sender as TextBox;
|
||||
if (textBox.Document.Lines.Count > 5)
|
||||
{
|
||||
textBox.TextAlignment = TextAlignment.Left;
|
||||
textBox.Height = "100%";
|
||||
}
|
||||
else
|
||||
{
|
||||
textBox.TextAlignment = TextAlignment.Center;
|
||||
textBox.Height = "auto";
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnKeyUp(KeyEventArgs e)
|
||||
{
|
||||
if (e.Key.Or(Keys.Enter, Keys.Space))
|
||||
{
|
||||
var buttons = this.Find<Button>();
|
||||
var btn = buttons.FirstOrDefault(x => x.IsFocused) ?? buttons.FirstOrDefault(x => x.Content?.ToString() == this.DefaultButton);
|
||||
this.DialogResult = btn.Content.ToString();
|
||||
e.Handled = true;
|
||||
}
|
||||
base.OnKeyUp(e);
|
||||
}
|
||||
}
|
||||
}
|
14
CPF.Toolkit/Dialogs/IClosable.cs
Normal file
14
CPF.Toolkit/Dialogs/IClosable.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using CPF.Controls;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
|
||||
namespace CPF.Toolkit.Dialogs
|
||||
{
|
||||
internal interface IClosable
|
||||
{
|
||||
event EventHandler<ClosingEventArgs> Closable;
|
||||
void OnClosable(object sender, ClosingEventArgs e);
|
||||
}
|
||||
}
|
73
CPF.Toolkit/Dialogs/IDialogService.cs
Normal file
73
CPF.Toolkit/Dialogs/IDialogService.cs
Normal file
@ -0,0 +1,73 @@
|
||||
using CPF.Controls;
|
||||
using CPF.Platform;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CPF.Toolkit.Dialogs
|
||||
{
|
||||
public interface IDialog
|
||||
{
|
||||
IDialogService Dialog { get; set; }
|
||||
}
|
||||
|
||||
public interface IDialogService
|
||||
{
|
||||
string Alert(string text, string title, DialogType dialogType, string defaultButton, params string[] buttons);
|
||||
void Alert(string text);
|
||||
void Sucess(string text);
|
||||
void Error(string text);
|
||||
void Warn(string text);
|
||||
string Ask(string text);
|
||||
}
|
||||
|
||||
public class DialogService : IDialogService
|
||||
{
|
||||
public DialogService(Window owner)
|
||||
{
|
||||
this.owner = owner;
|
||||
}
|
||||
Window owner;
|
||||
|
||||
public string Alert(string text, string title, DialogType dialogType, string defaultButton, params string[] buttons)
|
||||
{
|
||||
var view = new DialogView(text, title, dialogType, defaultButton, buttons);
|
||||
var result = view.ShowDialogSync(owner);
|
||||
return result?.ToString();
|
||||
}
|
||||
|
||||
public void Alert(string text)
|
||||
{
|
||||
this.Alert(text, "消息", DialogType.None, "确定", "确定");
|
||||
}
|
||||
|
||||
public string Ask(string text)
|
||||
{
|
||||
return this.Alert(text, "询问", DialogType.Ask, "确定", "确定", "取消");
|
||||
}
|
||||
|
||||
public void Error(string text)
|
||||
{
|
||||
this.Alert(text, "错误", DialogType.Error, defaultButton: "确定", "确定");
|
||||
}
|
||||
|
||||
public void Sucess(string text)
|
||||
{
|
||||
this.Alert(text, "成功", DialogType.Sucess, "确定", "确定");
|
||||
}
|
||||
|
||||
public void Warn(string text)
|
||||
{
|
||||
this.Alert(text, "警告", DialogType.Warn, "确定", "确定");
|
||||
}
|
||||
}
|
||||
|
||||
public enum DialogType
|
||||
{
|
||||
None,
|
||||
Sucess,
|
||||
Error,
|
||||
Ask,
|
||||
Warn
|
||||
}
|
||||
}
|
13
CPF.Toolkit/Dialogs/ILoading.cs
Normal file
13
CPF.Toolkit/Dialogs/ILoading.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CPF.Toolkit.Dialogs
|
||||
{
|
||||
public interface ILoading
|
||||
{
|
||||
event Func<string, Task, Task<object>> ShowLoadingFunc;
|
||||
event Func<string, Task,Task> ShowLoading;
|
||||
}
|
||||
}
|
BIN
CPF.Toolkit/Images/ask.png
Normal file
BIN
CPF.Toolkit/Images/ask.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 679 B |
BIN
CPF.Toolkit/Images/error.png
Normal file
BIN
CPF.Toolkit/Images/error.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 879 B |
BIN
CPF.Toolkit/Images/sucess.png
Normal file
BIN
CPF.Toolkit/Images/sucess.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 834 B |
BIN
CPF.Toolkit/Images/warn.png
Normal file
BIN
CPF.Toolkit/Images/warn.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 748 B |
63
CPF.Toolkit/ObservableObject.cs
Normal file
63
CPF.Toolkit/ObservableObject.cs
Normal file
@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
|
||||
namespace CPF.Toolkit
|
||||
{
|
||||
public class ObservableObject : INotifyPropertyChanged
|
||||
{
|
||||
readonly ConcurrentDictionary<string, object> Propertys = new ConcurrentDictionary<string, object> { };
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
|
||||
public T GetValue<T>(T defaultValue = default, [CallerMemberName] string propertyName = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(propertyName))
|
||||
{
|
||||
throw new Exception("propertyName不能为空");
|
||||
}
|
||||
if (!this.Propertys.ContainsKey(propertyName))
|
||||
{
|
||||
this.Propertys.TryAdd(propertyName, defaultValue);
|
||||
}
|
||||
return (T)this.Propertys[propertyName];
|
||||
}
|
||||
|
||||
public bool SetValue<T>(T value, [CallerMemberName] string propertyName = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(propertyName))
|
||||
{
|
||||
throw new Exception("propertyName不能为空");
|
||||
}
|
||||
|
||||
if (!this.Propertys.ContainsKey(propertyName))
|
||||
{
|
||||
this.Propertys.TryAdd(propertyName, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
var v = this.GetValue<T>(propertyName: propertyName);
|
||||
if (EqualityComparer<T>.Default.Equals(value, v)) return false;
|
||||
this.Propertys[propertyName] = value;
|
||||
}
|
||||
this.RaisePropertyChanged(propertyName);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetValue<T>(T value, Action<T> action, [CallerMemberName] string propertyName = null)
|
||||
{
|
||||
if (this.SetValue(value, propertyName))
|
||||
{
|
||||
action.Invoke(value);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
}
|
46
CPF.Toolkit/ToolkitHelper.cs
Normal file
46
CPF.Toolkit/ToolkitHelper.cs
Normal file
@ -0,0 +1,46 @@
|
||||
using CPF.Controls;
|
||||
using CPF.Toolkit.Dialogs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CPF.Toolkit
|
||||
{
|
||||
public static class ToolkitHelper
|
||||
{
|
||||
|
||||
internal static void CreateLoading(this ILoading loading,UIElement uIElement)
|
||||
{
|
||||
loading.ShowLoadingFunc += async (message, task) =>
|
||||
{
|
||||
var loadingBox = new LoadingBox { Message = message };
|
||||
var layer = new LayerDialog
|
||||
{
|
||||
Name = "loadingDialog",
|
||||
Content = loadingBox,
|
||||
ShowCloseButton = false,
|
||||
Background = null,
|
||||
};
|
||||
layer.ShowDialog(uIElement);
|
||||
dynamic t = task;
|
||||
var result = await t;
|
||||
loadingBox.Invoke(layer.CloseDialog);
|
||||
return result;
|
||||
};
|
||||
loading.ShowLoading += async (message, task) =>
|
||||
{
|
||||
var loadingBox = new LoadingBox { Message = message };
|
||||
var layer = new LayerDialog
|
||||
{
|
||||
Name = "loadingDialog",
|
||||
Content = loadingBox,
|
||||
ShowCloseButton = false,
|
||||
Background = null,
|
||||
};
|
||||
layer.ShowDialog(uIElement);
|
||||
await task;
|
||||
loadingBox.Invoke(layer.CloseDialog);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
52
CPF.Toolkit/ViewManager.cs
Normal file
52
CPF.Toolkit/ViewManager.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using CPF.Controls;
|
||||
using CPF.Toolkit.Dialogs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CPF.Toolkit
|
||||
{
|
||||
public static class ViewManager
|
||||
{
|
||||
public static T View<T>(params object[] arges) where T : Window
|
||||
{
|
||||
var view = Activator.CreateInstance(typeof(T), arges) as T;
|
||||
view.Closing += View_Closing;
|
||||
view.PropertyChanged += View_PropertyChanged;
|
||||
return view;
|
||||
}
|
||||
|
||||
private static void View_PropertyChanged(object sender, CPFPropertyChangedEventArgs e)
|
||||
{
|
||||
var view = sender as Window;
|
||||
if (e.PropertyName == nameof(Window.DataContext))
|
||||
{
|
||||
if (view.DataContext is IClosable closable)
|
||||
{
|
||||
closable.Closable += (ss, ee) =>
|
||||
{
|
||||
view.Close();
|
||||
};
|
||||
}
|
||||
if (view.DataContext is IDialog dialog)
|
||||
{
|
||||
dialog.Dialog = new DialogService(view);
|
||||
}
|
||||
if (view.DataContext is ILoading loading)
|
||||
{
|
||||
loading.CreateLoading(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void View_Closing(object sender, ClosingEventArgs e)
|
||||
{
|
||||
var view = sender as Window;
|
||||
if (view.DataContext is IClosable closable)
|
||||
{
|
||||
closable.OnClosable(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
50
CPF.Toolkit/ViewModelBase.cs
Normal file
50
CPF.Toolkit/ViewModelBase.cs
Normal file
@ -0,0 +1,50 @@
|
||||
using CPF.Controls;
|
||||
using CPF.Toolkit.Dialogs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CPF.Toolkit
|
||||
{
|
||||
public class ViewModelBase : ObservableObject, IClosable, IDialog, ILoading
|
||||
{
|
||||
event EventHandler<ClosingEventArgs> _close;
|
||||
event Func<string, Task, Task<object>> _showLoadingFunc;
|
||||
event Func<string, Task, Task> _showLading;
|
||||
event EventHandler<ClosingEventArgs> IClosable.Closable { add => this._close += value; remove => this._close -= value; }
|
||||
event Func<string, Task, Task<object>> ILoading.ShowLoadingFunc { add => this._showLoadingFunc += value; remove => this._showLoadingFunc -= value; }
|
||||
event Func<string, Task, Task> ILoading.ShowLoading { add => this._showLading += value; remove => this._showLading -= value; }
|
||||
|
||||
void IClosable.OnClosable(object sender, ClosingEventArgs e) => this.OnClose(e);
|
||||
|
||||
public IDialogService Dialog { get; set; }
|
||||
|
||||
protected void Close()
|
||||
{
|
||||
if (this._close == null) throw new ArgumentNullException();
|
||||
this._close.Invoke(this, new ClosingEventArgs());
|
||||
}
|
||||
|
||||
protected virtual void OnClose(ClosingEventArgs e) { }
|
||||
|
||||
protected async Task ShowLoading(Task task)
|
||||
{
|
||||
if (this._showLading == null) throw new ArgumentNullException();
|
||||
await this._showLading.Invoke("加载中……", task);
|
||||
}
|
||||
|
||||
protected async Task ShowLoading(Func<Task> task)
|
||||
{
|
||||
if (this._showLoadingFunc == null) throw new ArgumentNullException();
|
||||
await this._showLading.Invoke("加载中……", task.Invoke());
|
||||
}
|
||||
|
||||
protected async Task<T> ShowLoading<T>(Func<Task<T>> task)
|
||||
{
|
||||
if (this._showLoadingFunc == null) throw new ArgumentNullException();
|
||||
var result = await this._showLoadingFunc.Invoke("加载中……", task.Invoke());
|
||||
return (T)result;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.ComponentModel;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CPF
|
||||
{
|
||||
@ -163,6 +164,7 @@ namespace CPF
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 右边数据绑定到左边,只传递一次数据
|
||||
/// </summary>
|
||||
@ -451,6 +453,7 @@ namespace CPF
|
||||
public class CommandDescribe
|
||||
{
|
||||
public Action<CpfObject, object> Action { get; set; }
|
||||
public Func<CpfObject, object, Task> AsyncAction { get; set; }
|
||||
|
||||
public string MethodName { get; set; }
|
||||
public object[] Parameters { get; set; }
|
||||
@ -466,6 +469,11 @@ namespace CPF
|
||||
{
|
||||
Action = command;
|
||||
}
|
||||
|
||||
public CommandDescribe(Func<CpfObject, object, Task> command)
|
||||
{
|
||||
this.AsyncAction = command;
|
||||
}
|
||||
/// <summary>
|
||||
/// 定义个命令绑定
|
||||
/// </summary>
|
||||
|
@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CPF
|
||||
{
|
||||
@ -108,6 +109,17 @@ namespace CPF
|
||||
list.Add(new Command { Action = action });
|
||||
}
|
||||
|
||||
public void Add(string eventName, Func<CpfObject, object, Task> action)
|
||||
{
|
||||
List<Command> list;
|
||||
if (!commands.TryGetValue(eventName, out list))
|
||||
{
|
||||
list = new List<Command>();
|
||||
commands.Add(eventName, list);
|
||||
}
|
||||
list.Add(new Command { AsyncAction = action });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// KeyValuePair<string, List<Command>>
|
||||
/// </summary>
|
||||
@ -133,6 +145,6 @@ namespace CPF
|
||||
public object[] Params;
|
||||
//public Relation Relation;
|
||||
public Action<CpfObject, object> Action;
|
||||
public Func<CpfObject, object, Task> AsyncAction;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,8 +16,56 @@ namespace CPF.Controls
|
||||
{
|
||||
protected override void InitializeComponent()
|
||||
{
|
||||
this.Triggers.Add(nameof(IsMouseOver), Relation.Me, null, (nameof(Background), "190,230,253"));
|
||||
this.Triggers.Add(nameof(IsPressed), Relation.Me, null, (nameof(Background), "186,209,226"));
|
||||
//this.MinWidth = 80;
|
||||
//this.MinHeight = 35;
|
||||
//this.MarginRight = 1;
|
||||
this.Triggers.Add(new Trigger
|
||||
{
|
||||
Property = nameof(IsMouseOver),
|
||||
TargetRelation = Relation.Me,
|
||||
PropertyConditions = x => Convert.ToBoolean(x),
|
||||
Setters =
|
||||
{
|
||||
{ nameof(Background),"#E5F1FB" },
|
||||
{ nameof(BorderFill),"#0078D7" },
|
||||
{ nameof(Foreground),"black" },
|
||||
}
|
||||
});
|
||||
this.Triggers.Add(new Trigger
|
||||
{
|
||||
Property = nameof(IsPressed),
|
||||
TargetRelation = Relation.Me,
|
||||
PropertyConditions = x => Convert.ToBoolean(x),
|
||||
Setters =
|
||||
{
|
||||
{ nameof(Background),"204,228,247" },
|
||||
{ nameof(BorderFill),"0,84,153" },
|
||||
}
|
||||
});
|
||||
this.Triggers.Add(new Trigger
|
||||
{
|
||||
Property = nameof(IsFocused),
|
||||
TargetRelation = Relation.Me,
|
||||
PropertyConditions = x => Convert.ToBoolean(x),
|
||||
Setters =
|
||||
{
|
||||
{ nameof(Background),"204,228,247" },
|
||||
{ nameof(BorderFill),"0,120,215" },
|
||||
{ nameof(BorderStroke),"2" },
|
||||
}
|
||||
});
|
||||
this.triggers.Add(new Trigger
|
||||
{
|
||||
Property = nameof(IsEnabled),
|
||||
TargetRelation = Relation.Me,
|
||||
PropertyConditions = x => !Convert.ToBoolean(x),
|
||||
Setters =
|
||||
{
|
||||
{ nameof(Background),"204,204,204" },
|
||||
{ nameof(BorderFill),"191,191,191" },
|
||||
{ nameof(Foreground),"131,131,131" },
|
||||
}
|
||||
});
|
||||
Children.Add(new Border
|
||||
{
|
||||
Name = "contentPresenter",
|
||||
@ -33,11 +81,13 @@ namespace CPF.Controls
|
||||
{
|
||||
base.OnOverrideMetadata(overridePropertys);
|
||||
overridePropertys.Override(nameof(BorderStroke), new UIPropertyMetadataAttribute(typeof(Stroke), "1", UIPropertyOptions.AffectsRender));
|
||||
overridePropertys.Override(nameof(BorderFill), new UIPropertyMetadataAttribute((ViewFill)"#101010", UIPropertyOptions.AffectsRender));
|
||||
overridePropertys.Override(nameof(BorderFill), new UIPropertyMetadataAttribute((ViewFill)"#ADADAD", UIPropertyOptions.AffectsRender));
|
||||
overridePropertys.Override(nameof(IsAntiAlias), new UIPropertyMetadataAttribute(false, UIPropertyOptions.AffectsRender));
|
||||
overridePropertys.Override(nameof(Background), new UIPropertyMetadataAttribute((ViewFill)"221,221,221", UIPropertyOptions.AffectsRender));
|
||||
overridePropertys.Override(nameof(Background), new UIPropertyMetadataAttribute((ViewFill)"#E1E1E1", UIPropertyOptions.AffectsRender));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//protected override void OnPropertyChanged(string propertyName, object oldValue, object newValue, PropertyMetadataAttribute propertyMetadata)
|
||||
//{
|
||||
// base.OnPropertyChanged(propertyName, oldValue, newValue, propertyMetadata);
|
||||
|
@ -4,6 +4,7 @@ using System.Text;
|
||||
using CPF.Input;
|
||||
using CPF.Drawing;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CPF.Controls
|
||||
{
|
||||
@ -72,6 +73,7 @@ namespace CPF.Controls
|
||||
try
|
||||
{
|
||||
OnClick();
|
||||
OnAsyncClick();
|
||||
exceptionThrown = false;
|
||||
}
|
||||
finally
|
||||
@ -128,6 +130,7 @@ namespace CPF.Controls
|
||||
if (l.X >= 0 && l.Y >= 0 && l.X <= r.Width && l.Y <= r.Height)
|
||||
{
|
||||
OnClick();
|
||||
OnAsyncClick();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -159,6 +162,7 @@ namespace CPF.Controls
|
||||
if (ClickMode == ClickMode.Press)
|
||||
{
|
||||
OnClick();
|
||||
OnAsyncClick();
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
@ -177,6 +181,7 @@ namespace CPF.Controls
|
||||
}
|
||||
|
||||
OnClick();
|
||||
OnAsyncClick();
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
@ -222,7 +227,10 @@ namespace CPF.Controls
|
||||
}
|
||||
|
||||
if (shouldClick)
|
||||
{
|
||||
OnClick();
|
||||
OnAsyncClick();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -250,15 +258,10 @@ namespace CPF.Controls
|
||||
IsPressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnClick()
|
||||
{
|
||||
//var p1 = PointToScreen(new Point());
|
||||
//var p4 = PointToScreen(new Point(ActualSize.Width, ActualSize.Height));
|
||||
//var rect = new Rect(p1, p4);
|
||||
//if (rect.Contains(Root.InputManager.MouseDevice.Location))
|
||||
//{
|
||||
OnClick(new RoutedEventArgs(this));
|
||||
//}
|
||||
}
|
||||
|
||||
protected virtual void OnClick(RoutedEventArgs e)
|
||||
@ -266,6 +269,18 @@ namespace CPF.Controls
|
||||
RaiseEvent(e, nameof(Click));
|
||||
}
|
||||
|
||||
protected async Task OnAsyncClick()
|
||||
{
|
||||
await OnAsyncClick(new RoutedEventArgs(this));
|
||||
}
|
||||
|
||||
protected virtual async Task OnAsyncClick(RoutedEventArgs e)
|
||||
{
|
||||
this.IsEnabled = false;
|
||||
await AsyncRaiseEvent(e, nameof(AsyncClick));
|
||||
this.IsEnabled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置 Click 事件何时发生。
|
||||
/// </summary>
|
||||
@ -296,6 +311,12 @@ namespace CPF.Controls
|
||||
add { AddHandler(value); }
|
||||
remove { RemoveHandler(value); }
|
||||
}
|
||||
|
||||
public event AsyncEventHandler<RoutedEventArgs> AsyncClick
|
||||
{
|
||||
add { AddHandler(value); }
|
||||
remove { RemoveHandler(value); }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -27,7 +27,7 @@ namespace CPF.Controls
|
||||
public static IEnumerable<Window> Windows { get { return windows; } }
|
||||
|
||||
IWindowImpl windowImpl;
|
||||
|
||||
bool? isDialog;
|
||||
public event EventHandler Closed
|
||||
{
|
||||
add { AddHandler(value); }
|
||||
@ -314,8 +314,11 @@ namespace CPF.Controls
|
||||
}
|
||||
}
|
||||
|
||||
public bool? IsDialogMode => this.isDialog;
|
||||
|
||||
void SetDialog(bool enable, Window child)
|
||||
{
|
||||
this.isDialog = true;
|
||||
if (dialogChildren == null)
|
||||
{
|
||||
dialogChildren = new HashSet<Window>();
|
||||
|
@ -10,6 +10,7 @@ using CPF.Effects;
|
||||
using System.ComponentModel;
|
||||
using CPF.Controls;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace CPF.Controls
|
||||
{
|
||||
@ -94,10 +95,22 @@ namespace CPF.Controls
|
||||
set { SetValue(value); }
|
||||
}
|
||||
|
||||
[PropertyMetadata(typeof(ViewFill), "white")]
|
||||
public ViewFill ControlBoxStroke { get => GetValue<ViewFill>(); set => SetValue(value); }
|
||||
|
||||
[PropertyMetadata(typeof(ViewFill), "#1E9FFF")]
|
||||
public ViewFill CaptionBackgrund { get => GetValue<ViewFill>(); set => SetValue(value); }
|
||||
|
||||
[PropertyMetadata(typeof(ViewFill), "white")]
|
||||
public ViewFill CaptionForeground { get => GetValue<ViewFill>(); set => SetValue(value); }
|
||||
|
||||
[PropertyMetadata(typeof(FloatField), "35")]
|
||||
public FloatField CaptionHeight { get => GetValue<FloatField>(); set => SetValue(value); }
|
||||
|
||||
|
||||
protected override void InitializeComponent()
|
||||
{
|
||||
|
||||
ViewFill color = "#fff";
|
||||
//ViewFill color = "#fff";
|
||||
ViewFill hoverColor = "255,255,255,40";
|
||||
Width = "100%";
|
||||
Height = "100%";
|
||||
@ -163,9 +176,12 @@ namespace CPF.Controls
|
||||
new Panel
|
||||
{
|
||||
Name = "caption",
|
||||
Background = "#1E9FFF",
|
||||
Width = "100%",
|
||||
Height = "30",
|
||||
Bindings =
|
||||
{
|
||||
{ nameof(Panel.Background),nameof(this.CaptionBackgrund),this},
|
||||
{ nameof(Panel.Height),nameof(this.CaptionHeight),this},
|
||||
},
|
||||
Commands =
|
||||
{
|
||||
{
|
||||
@ -228,9 +244,9 @@ namespace CPF.Controls
|
||||
nameof(TextBlock.Text),
|
||||
nameof(IWindow.Title),
|
||||
Window
|
||||
}
|
||||
},
|
||||
Foreground="#fff"
|
||||
{ nameof(TextBlock.Foreground),nameof(this.CaptionForeground),this }
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
@ -258,7 +274,11 @@ namespace CPF.Controls
|
||||
EndPoint = new Point(14, 13),
|
||||
StrokeStyle = "2",
|
||||
IsAntiAlias=true,
|
||||
StrokeFill=color
|
||||
//StrokeFill=color
|
||||
Bindings =
|
||||
{
|
||||
{ nameof(Line.StrokeFill),nameof(this.ControlBoxStroke),this}
|
||||
}
|
||||
},
|
||||
Bindings=
|
||||
{
|
||||
@ -317,14 +337,16 @@ namespace CPF.Controls
|
||||
Name="max",
|
||||
Width = 30,
|
||||
Height = "100%",
|
||||
Content=
|
||||
new Rectangle
|
||||
Content= new Rectangle
|
||||
{
|
||||
Width=14,
|
||||
Height=12,
|
||||
MarginTop=10,
|
||||
StrokeStyle="2",
|
||||
StrokeFill = color
|
||||
Bindings =
|
||||
{
|
||||
{ nameof(Line.StrokeFill),nameof(this.ControlBoxStroke),this}
|
||||
}
|
||||
},
|
||||
Commands =
|
||||
{
|
||||
@ -378,7 +400,8 @@ namespace CPF.Controls
|
||||
Width=11,
|
||||
Height=8,
|
||||
StrokeStyle="1.5",
|
||||
StrokeFill = color
|
||||
//StrokeFill = color
|
||||
Bindings = { { nameof(Line.StrokeFill), nameof(this.ControlBoxStroke), this } },
|
||||
},
|
||||
new Polyline
|
||||
{
|
||||
@ -392,7 +415,8 @@ namespace CPF.Controls
|
||||
new Point(9,7),
|
||||
new Point(6,7)
|
||||
},
|
||||
StrokeFill = color,
|
||||
//StrokeFill = color,
|
||||
Bindings = { { nameof(Line.StrokeFill), nameof(this.ControlBoxStroke), this } },
|
||||
StrokeStyle="2"
|
||||
}
|
||||
}
|
||||
@ -452,7 +476,8 @@ namespace CPF.Controls
|
||||
EndPoint = new Point(14, 13),
|
||||
StrokeStyle = "2",
|
||||
IsAntiAlias=true,
|
||||
StrokeFill=color
|
||||
//StrokeFill=color
|
||||
Bindings = { { nameof(Line.StrokeFill), nameof(this.ControlBoxStroke), this } }
|
||||
},
|
||||
new Line
|
||||
{
|
||||
@ -462,7 +487,8 @@ namespace CPF.Controls
|
||||
EndPoint = new Point(1, 13),
|
||||
StrokeStyle = "2",
|
||||
IsAntiAlias=true,
|
||||
StrokeFill=color
|
||||
//StrokeFill=color
|
||||
Bindings = { { nameof(Line.StrokeFill), nameof(this.ControlBoxStroke), this } }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
104
CPF/CpfObject.cs
104
CPF/CpfObject.cs
@ -13,6 +13,7 @@ using CPF.Animation;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CPF
|
||||
{
|
||||
@ -193,6 +194,10 @@ namespace CPF
|
||||
{
|
||||
if (value.Command != null)
|
||||
{
|
||||
if (value.Command.AsyncAction != null)
|
||||
{
|
||||
Commands.Add(propertyName, value.Command.AsyncAction);
|
||||
}
|
||||
if (value.Command.Action != null)
|
||||
{
|
||||
Commands.Add(propertyName, value.Command.Action);
|
||||
@ -1786,10 +1791,6 @@ namespace CPF
|
||||
/// <param name="eventName"></param>
|
||||
public void RaiseEvent<TEventArgs>(in TEventArgs eventArgs, string eventName)
|
||||
{
|
||||
//if (eventArgs is RoutedEventArgs routed)
|
||||
//{
|
||||
// routed.Sender = this;
|
||||
//}
|
||||
OnRaiseEvent(eventArgs, eventName);
|
||||
|
||||
if (observers != null && eventArgs is EventArgs args)
|
||||
@ -1817,10 +1818,6 @@ namespace CPF
|
||||
v = item.Target.Target;
|
||||
objs.Add(v);
|
||||
}
|
||||
//else if (item.Relation != null && this is UIElement)
|
||||
//{
|
||||
// objs.AddRange(item.Relation.Query(this as UIElement));
|
||||
//}
|
||||
else
|
||||
{
|
||||
v = CommandContext;
|
||||
@ -1856,14 +1853,6 @@ namespace CPF
|
||||
}
|
||||
}
|
||||
}
|
||||
//v.GetType().GetMethod(item.MethodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).FastInvoke(v, ps);
|
||||
|
||||
//var m = obj.GetType().GetMethod(item.MethodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
//if (m == null)
|
||||
//{
|
||||
// throw new Exception("未找到该方法 " + item.MethodName);
|
||||
//}
|
||||
//m.Invoke(obj, ps);
|
||||
obj.Invoke(item.MethodName, ps);
|
||||
}
|
||||
}
|
||||
@ -1882,6 +1871,89 @@ namespace CPF
|
||||
}
|
||||
}
|
||||
|
||||
public async Task AsyncRaiseEvent<TEventArgs>(TEventArgs eventArgs, string eventName)
|
||||
{
|
||||
OnRaiseEvent(eventArgs, eventName);
|
||||
|
||||
if (observers != null && eventArgs is EventArgs args)
|
||||
{
|
||||
EventObserver<EventArgs, CpfObject> eventObserver = new EventObserver<EventArgs, CpfObject>(eventName, args, this);
|
||||
foreach (var observer in observers)
|
||||
{
|
||||
observer.OnNext(eventObserver);
|
||||
}
|
||||
}
|
||||
|
||||
if (commands != null)
|
||||
{
|
||||
List<Command> list;
|
||||
if (commands.commands.TryGetValue(eventName, out list))
|
||||
{
|
||||
foreach (var item in list)
|
||||
{
|
||||
if (item.AsyncAction == null)
|
||||
{
|
||||
var objs = new List<object>();
|
||||
object v = null;
|
||||
if (item.Target != null)
|
||||
{
|
||||
v = item.Target.Target;
|
||||
objs.Add(v);
|
||||
}
|
||||
else
|
||||
{
|
||||
v = CommandContext;
|
||||
if (v != null)
|
||||
{
|
||||
objs.Add(v);
|
||||
}
|
||||
}
|
||||
foreach (var obj in objs)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
object[] ps = new object[item.Params == null ? 0 : item.Params.Length];
|
||||
if (item.Params != null && item.Params.Length > 0)
|
||||
{
|
||||
//ps = item.Params;
|
||||
item.Params.CopyTo(ps, 0);
|
||||
for (int i = 0; i < ps.Length; i++)
|
||||
{
|
||||
var p = ps[i];
|
||||
if (p is CommandParameter)
|
||||
{
|
||||
if ((CommandParameter)p == CommandParameter.EventArgs)
|
||||
{
|
||||
ps[i] = eventArgs;
|
||||
}
|
||||
else if ((CommandParameter)p == CommandParameter.EventSender)
|
||||
{
|
||||
ps[i] = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
await obj.AsyncInvoke(item.MethodName, ps);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//item.Action(this, eventArgs);
|
||||
await item.AsyncAction(this, eventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var handler = Events[eventName];
|
||||
if (handler != null)
|
||||
{
|
||||
await handler.AsyncInvoke(this, eventArgs);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnRaiseEvent<TEventArgs>(in TEventArgs eventArgs, string eventName)
|
||||
{
|
||||
|
||||
|
9
CPF/Input/AsyncEventHandler.cs
Normal file
9
CPF/Input/AsyncEventHandler.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CPF.Input
|
||||
{
|
||||
public delegate Task AsyncEventHandler<TEventArgs>(object sender, TEventArgs e);
|
||||
}
|
@ -13,6 +13,7 @@ using CPF.Threading;
|
||||
using CPF.Controls;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace CPF
|
||||
{
|
||||
@ -652,6 +653,18 @@ namespace CPF
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
public static bool Or<T>(this T obj, params T[] ps)
|
||||
{
|
||||
foreach (var item in ps)
|
||||
{
|
||||
if (obj.Equals(item))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class Enumerable : IList
|
||||
|
@ -6,6 +6,7 @@ using System.Reflection;
|
||||
using System.Linq.Expressions;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection.Emit;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CPF.Reflection
|
||||
{
|
||||
@ -69,6 +70,7 @@ namespace CPF.Reflection
|
||||
}
|
||||
}
|
||||
static ConcurrentDictionary<Type, ConcurrentDictionary<string, InvokeHandler>> methods = new ConcurrentDictionary<Type, ConcurrentDictionary<string, InvokeHandler>>();
|
||||
static ConcurrentDictionary<Type, ConcurrentDictionary<string, AsyncInvokeHandler>> asyncMethods = new ConcurrentDictionary<Type, ConcurrentDictionary<string, AsyncInvokeHandler>>();
|
||||
static KeyValuePair<Type, ConcurrentDictionary<string, InvokeHandler>>[] saveMethods;
|
||||
|
||||
static ConcurrentDictionary<Type, ConcurrentDictionary<string, SetHandler<object>>> setValues = new ConcurrentDictionary<Type, ConcurrentDictionary<string, SetHandler<object>>>();
|
||||
@ -106,6 +108,28 @@ namespace CPF.Reflection
|
||||
return fun(instance, parameters);
|
||||
}
|
||||
|
||||
public static async Task AsyncInvoke(this object instance, string methodName, params object[] parameters)
|
||||
{
|
||||
var type = instance.GetType();
|
||||
|
||||
if (!asyncMethods.TryGetValue(type, out var list))
|
||||
{
|
||||
list = new ConcurrentDictionary<string, AsyncInvokeHandler>();
|
||||
asyncMethods.TryAdd(type, list);
|
||||
}
|
||||
if (!list.TryGetValue(methodName, out var fun))
|
||||
{
|
||||
var minfo = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (minfo == null)
|
||||
{
|
||||
throw new Exception(type + "未找到方法:" + methodName);
|
||||
}
|
||||
fun = AsyncMethodCache.CreateInvokeDelegate(minfo);
|
||||
list.TryAdd(methodName, fun);
|
||||
}
|
||||
await fun(instance, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 反射快速调用
|
||||
/// </summary>
|
||||
@ -115,10 +139,15 @@ namespace CPF.Reflection
|
||||
/// <returns></returns>
|
||||
public static object FastInvoke(this MethodInfo methodInfo, object instance, params object[] parameters)
|
||||
{
|
||||
//return FastReflectionCaches.MethodInvokerCache.Get(methodInfo).Invoke(instance, parameters);
|
||||
return methodCache.Get(methodInfo).Invoke(instance, parameters);
|
||||
}
|
||||
public static async Task FastAsyncInvoke(this MethodInfo methodInfo, object instance, params object[] parameters)
|
||||
{
|
||||
await asyncMethodCache.Get(methodInfo).Invoke(instance, parameters);
|
||||
}
|
||||
|
||||
static MethodCache methodCache = new MethodCache();
|
||||
static AsyncMethodCache asyncMethodCache = new AsyncMethodCache();
|
||||
|
||||
/// <summary>
|
||||
/// 快速动态设置对象的属性值
|
||||
@ -369,7 +398,57 @@ namespace CPF.Reflection
|
||||
}
|
||||
}
|
||||
|
||||
class AsyncMethodCache : FastReflectionCache<MethodInfo, AsyncInvokeHandler>
|
||||
{
|
||||
protected override AsyncInvokeHandler Create(MethodInfo key)
|
||||
{
|
||||
return CreateInvokeDelegate(key);
|
||||
}
|
||||
|
||||
public static AsyncInvokeHandler CreateInvokeDelegate(MethodInfo methodInfo)
|
||||
{
|
||||
var instanceParameter = Expression.Parameter(typeof(object), "instance");
|
||||
var parametersParameter = Expression.Parameter(typeof(object[]), "parameters");
|
||||
|
||||
var parameterExpressions = new List<Expression>();
|
||||
var paramInfos = methodInfo.GetParameters();
|
||||
for (int i = 0; i < paramInfos.Length; i++)
|
||||
{
|
||||
BinaryExpression valueObj = Expression.ArrayIndex(
|
||||
parametersParameter, Expression.Constant(i));
|
||||
UnaryExpression valueCast = Expression.Convert(
|
||||
valueObj, paramInfos[i].ParameterType);
|
||||
|
||||
parameterExpressions.Add(valueCast);
|
||||
}
|
||||
|
||||
var instanceCast = methodInfo.IsStatic ? null :
|
||||
Expression.Convert(instanceParameter, methodInfo.ReflectedType);
|
||||
|
||||
var methodCall = Expression.Call(instanceCast, methodInfo, parameterExpressions);
|
||||
|
||||
if (methodCall.Type == typeof(void))
|
||||
{
|
||||
var lambda = Expression.Lambda<Action<object, object[]>>(
|
||||
methodCall, instanceParameter, parametersParameter);
|
||||
|
||||
Action<object, object[]> execute = lambda.Compile();
|
||||
return (instance, parameters) =>
|
||||
{
|
||||
execute(instance, parameters);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
var castMethodCall = Expression.Convert(methodCall, typeof(Task));
|
||||
var lambda = Expression.Lambda<AsyncInvokeHandler>(
|
||||
castMethodCall, instanceParameter, parametersParameter);
|
||||
|
||||
return lambda.Compile();
|
||||
}
|
||||
}
|
||||
}
|
||||
class MethodCache : FastReflectionCache<MethodInfo, InvokeHandler>
|
||||
{
|
||||
protected override InvokeHandler Create(MethodInfo key)
|
||||
@ -482,6 +561,8 @@ namespace CPF.Reflection
|
||||
//iLGenerator.Ret();
|
||||
//return (InvokeHandler)dynamicMethod.CreateDelegate(typeof(InvokeHandler));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class PropertyGetCache : FastReflectionCache<PropertyInfo, GetHandler<object>>
|
||||
@ -578,5 +659,6 @@ namespace CPF.Reflection
|
||||
public delegate void SetHandler<T>(object target, T value);
|
||||
public delegate T GetHandler<T>(object target);
|
||||
public delegate object InvokeHandler(object target, object[] paramters);
|
||||
public delegate Task AsyncInvokeHandler(object target, object[] paramters);
|
||||
public delegate void SetRefHandler<T, V>(ref T target, V value);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ using System.Text;
|
||||
using CPF.Reflection;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CPF
|
||||
{
|
||||
@ -48,6 +49,24 @@ namespace CPF
|
||||
}
|
||||
}
|
||||
|
||||
public async Task AsyncInvoke(object sender, object e)
|
||||
{
|
||||
if (delegates != null)
|
||||
{
|
||||
foreach (var item in delegates.ToArray())
|
||||
{
|
||||
if (item.reference.TryGetTarget(out var target) || item.method.IsStatic)
|
||||
{
|
||||
await item.method.FastAsyncInvoke(target, sender, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
delegates.Remove(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
delegates = null;
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29324.140
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.8.34316.72
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp1", "ConsoleApp1\ConsoleApp1.csproj", "{ABE4ED47-CB9F-4183-9CE3-65E3E521BE2A}"
|
||||
EndProject
|
||||
@ -59,12 +59,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CPF.Demo", "CPF_Demo\CPF.De
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "蓝图重制版", "蓝图重制版\蓝图重制版.csproj", "{003E155A-8C40-41AF-A796-ED17E729E013}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Toolkit", "Toolkit", "{28FB518C-2103-4772-A245-C5F1D40E1EF5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CPF.Toolkit", "CPF.Toolkit\CPF.Toolkit.csproj", "{09C160EB-D2C3-42E5-82B3-7047CF87CE6C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CPF.Toolkit.Demo", "CPF.Toolkit.Demo\CPF.Toolkit.Demo.csproj", "{AEA7FF33-1621-4A0A-9C08-6C4CB10C76FF}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决方案项", "{C2358108-0235-4151-97F6-0283CFF98093}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Directory.Build.props = Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
||||
Private\SharedVSIX\SharedVSIX.projitems*{db53e8d7-dfb6-48eb-a7b6-d1cf762acb9b}*SharedItemsImports = 4
|
||||
Private\SharedVSIX\SharedVSIX.projitems*{df526631-d060-47f2-afd4-62c6cea2fe9a}*SharedItemsImports = 4
|
||||
Private\SharedVSIX\SharedVSIX.projitems*{f34cffee-546f-490e-a76a-2792840b284d}*SharedItemsImports = 13
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
@ -224,6 +230,18 @@ Global
|
||||
{003E155A-8C40-41AF-A796-ED17E729E013}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{003E155A-8C40-41AF-A796-ED17E729E013}.类库d|Any CPU.ActiveCfg = 类库d|Any CPU
|
||||
{003E155A-8C40-41AF-A796-ED17E729E013}.类库d|Any CPU.Build.0 = 类库d|Any CPU
|
||||
{09C160EB-D2C3-42E5-82B3-7047CF87CE6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{09C160EB-D2C3-42E5-82B3-7047CF87CE6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{09C160EB-D2C3-42E5-82B3-7047CF87CE6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{09C160EB-D2C3-42E5-82B3-7047CF87CE6C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{09C160EB-D2C3-42E5-82B3-7047CF87CE6C}.类库d|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{09C160EB-D2C3-42E5-82B3-7047CF87CE6C}.类库d|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AEA7FF33-1621-4A0A-9C08-6C4CB10C76FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AEA7FF33-1621-4A0A-9C08-6C4CB10C76FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AEA7FF33-1621-4A0A-9C08-6C4CB10C76FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AEA7FF33-1621-4A0A-9C08-6C4CB10C76FF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AEA7FF33-1621-4A0A-9C08-6C4CB10C76FF}.类库d|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AEA7FF33-1621-4A0A-9C08-6C4CB10C76FF}.类库d|Any CPU.Build.0 = Debug|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -240,5 +258,15 @@ Global
|
||||
{1278A1BC-327D-4D13-AD04-C6FF2B680530} = {2B729C46-7592-425A-87E9-D769A94881F7}
|
||||
{F34CFFEE-546F-490E-A76A-2792840B284D} = {2B729C46-7592-425A-87E9-D769A94881F7}
|
||||
{DF526631-D060-47F2-AFD4-62C6CEA2FE9A} = {2B729C46-7592-425A-87E9-D769A94881F7}
|
||||
{09C160EB-D2C3-42E5-82B3-7047CF87CE6C} = {28FB518C-2103-4772-A245-C5F1D40E1EF5}
|
||||
{AEA7FF33-1621-4A0A-9C08-6C4CB10C76FF} = {28FB518C-2103-4772-A245-C5F1D40E1EF5}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {E38AA5AA-8B93-40BD-8A5E-2E0D1538EB8D}
|
||||
EndGlobalSection
|
||||
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
||||
Private\SharedVSIX\SharedVSIX.projitems*{db53e8d7-dfb6-48eb-a7b6-d1cf762acb9b}*SharedItemsImports = 4
|
||||
Private\SharedVSIX\SharedVSIX.projitems*{df526631-d060-47f2-afd4-62c6cea2fe9a}*SharedItemsImports = 4
|
||||
Private\SharedVSIX\SharedVSIX.projitems*{f34cffee-546f-490e-a76a-2792840b284d}*SharedItemsImports = 13
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
6
Directory.Build.props
Normal file
6
Directory.Build.props
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<LangVersion>preview</LangVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
Loading…
x
Reference in New Issue
Block a user