Ver a proveniência

初始化

master
pry há 1 ano
ascendente
cometimento
76ea0622b1
100 ficheiros alterados com 11691 adições e 0 eliminações
  1. +17
    -0
      BPA.Model/BPA.Model.csproj
  2. +61
    -0
      BPA.Model/RawMaterInfo.cs
  3. +51
    -0
      BPA.Model/ViewItem.cs
  4. +37
    -0
      BPA.SingleDevice.sln
  5. +16
    -0
      BPA.SingleDevice/App.xaml
  6. +31
    -0
      BPA.SingleDevice/App.xaml.cs
  7. +10
    -0
      BPA.SingleDevice/AssemblyInfo.cs
  8. +14
    -0
      BPA.SingleDevice/BPA.SingleDevice.csproj
  9. +46
    -0
      BPA.SingleDevice/Controls/ControlDisplay.cs
  10. +29
    -0
      BPA.SingleDevice/Converter/GetIconConverter.cs
  11. +32
    -0
      BPA.SingleDevice/Converter/IsSelectedToIconConverter.cs
  12. +48
    -0
      BPA.SingleDevice/Themes/Generic.xaml
  13. +13
    -0
      BPA.SingleDevice/Themes/ThemesColor.xaml
  14. +20
    -0
      BPA.SingleDevice/View/DeviceManagementView.xaml
  15. +28
    -0
      BPA.SingleDevice/View/DeviceManagementView.xaml.cs
  16. +83
    -0
      BPA.SingleDevice/View/MainView.xaml
  17. +34
    -0
      BPA.SingleDevice/View/MainView.xaml.cs
  18. +118
    -0
      BPA.SingleDevice/View/RawMaterialManagementView.xaml
  19. +28
    -0
      BPA.SingleDevice/View/RawMaterialManagementView.xaml.cs
  20. +24
    -0
      BPA.SingleDevice/View/RecipeManagementView.xaml
  21. +28
    -0
      BPA.SingleDevice/View/RecipeManagementView.xaml.cs
  22. +12
    -0
      BPA.SingleDevice/ViewModel/DeviceManagementViewModel.cs
  23. +48
    -0
      BPA.SingleDevice/ViewModel/MainViewModel.cs
  24. +30
    -0
      BPA.SingleDevice/ViewModel/RawMaterialManagementViewModel.cs
  25. +12
    -0
      BPA.SingleDevice/ViewModel/RecipeManagementViewModel.cs
  26. +9
    -0
      BPA.UIControl/BPA.UIControl.csproj
  27. +67
    -0
      BPA.UIControl/BPACommand.cs
  28. +24
    -0
      BPA.UIControl/BPAVirtualizingStackPanel.cs
  29. +174
    -0
      BPA.UIControl/BPAWindow.cs
  30. +144
    -0
      BPA.UIControl/Badge.cs
  31. +63
    -0
      BPA.UIControl/Card.cs
  32. +248
    -0
      BPA.UIControl/Clock.cs
  33. +55
    -0
      BPA.UIControl/Commons/ColumnDefinitionCollectionTypeConverter.cs
  34. +22
    -0
      BPA.UIControl/Commons/ElementObservableCollection.cs
  35. +51
    -0
      BPA.UIControl/Commons/EnumDescriptionConverter.cs
  36. +255
    -0
      BPA.UIControl/Commons/FrameworkElementExtension.cs
  37. +25
    -0
      BPA.UIControl/Commons/KnownBoxes/BooleanBoxes.cs
  38. +58
    -0
      BPA.UIControl/Commons/ObjectExtension.cs
  39. +50
    -0
      BPA.UIControl/Commons/PageSizeCollectionConverter.cs
  40. +52
    -0
      BPA.UIControl/Commons/RowDefinitionCollectionTypeConverter.cs
  41. +106
    -0
      BPA.UIControl/Commons/ValidateArgument.cs
  42. +22
    -0
      BPA.UIControl/Commons/WindowHelper.cs
  43. +81
    -0
      BPA.UIControl/ControlMask.cs
  44. +29
    -0
      BPA.UIControl/Converters/BadgeOffsetConverter.cs
  45. +64
    -0
      BPA.UIControl/Converters/BooleanConverter.cs
  46. +18
    -0
      BPA.UIControl/Converters/BooleanToBrushConverter.cs
  47. +16
    -0
      BPA.UIControl/Converters/BooleanToInverseConverter.cs
  48. +16
    -0
      BPA.UIControl/Converters/BooleanToStringConverter.cs
  49. +17
    -0
      BPA.UIControl/Converters/BooleanToVisibilityConverter.cs
  50. +88
    -0
      BPA.UIControl/Converters/CarouselScaleConvereter.cs
  51. +39
    -0
      BPA.UIControl/Converters/CloneConverter.cs
  52. +26
    -0
      BPA.UIControl/Converters/ComboBoxPopupWidthConverter.cs
  53. +30
    -0
      BPA.UIControl/Converters/DataGridRowIndexConverter.cs
  54. +28
    -0
      BPA.UIControl/Converters/DoubleToGridLengthConverter.cs
  55. +76
    -0
      BPA.UIControl/Converters/DoubleToThicknessConverter.cs
  56. +32
    -0
      BPA.UIControl/Converters/DoublesToPointConverter.cs
  57. +33
    -0
      BPA.UIControl/Converters/DoublesToSizeConverter.cs
  58. +30
    -0
      BPA.UIControl/Converters/EnumGetDescriptionConverter.cs
  59. +49
    -0
      BPA.UIControl/Converters/EnumToBooleanConverter.cs
  60. +24
    -0
      BPA.UIControl/Converters/EnumToBooleanInverseConverter.cs
  61. +62
    -0
      BPA.UIControl/Converters/EnumToVisibilityConverter.cs
  62. +41
    -0
      BPA.UIControl/Converters/GetArcPointConverter.cs
  63. +28
    -0
      BPA.UIControl/Converters/GetCanvasCentreConverter.cs
  64. +46
    -0
      BPA.UIControl/Converters/GetDataGridColumnCheckedContentConverter.cs
  65. +34
    -0
      BPA.UIControl/Converters/GetPercentConverter.cs
  66. +24
    -0
      BPA.UIControl/Converters/GetWidthConverter.cs
  67. +25
    -0
      BPA.UIControl/Converters/HalfOfDoubleConverter.cs
  68. +83
    -0
      BPA.UIControl/Converters/InsideCornerRadiusConverter.cs
  69. +24
    -0
      BPA.UIControl/Converters/IsEqualConverter.cs
  70. +36
    -0
      BPA.UIControl/Converters/IsLargeArcConverter.cs
  71. +25
    -0
      BPA.UIControl/Converters/IsNullOrEmptyConverter.cs
  72. +41
    -0
      BPA.UIControl/Converters/ListViewGridViewConverter.cs
  73. +51
    -0
      BPA.UIControl/Converters/MathConverter.cs
  74. +78
    -0
      BPA.UIControl/Converters/MathMultipleConverter.cs
  75. +25
    -0
      BPA.UIControl/Converters/NotNullConverter.cs
  76. +25
    -0
      BPA.UIControl/Converters/NotNullOrEmptyConverter.cs
  77. +41
    -0
      BPA.UIControl/Converters/NullToVisibilityConverter.cs
  78. +37
    -0
      BPA.UIControl/Converters/VisibilityToBooleanConverter.cs
  79. +27
    -0
      BPA.UIControl/DataAnnotations/ColumnWidthAttribute.cs
  80. +138
    -0
      BPA.UIControl/DataGridDetailToggleButtonColumn.cs
  81. +188
    -0
      BPA.UIControl/DataGridSelectCheckBoxColumn.cs
  82. +359
    -0
      BPA.UIControl/DateTimePicker.cs
  83. BIN
     
  84. BIN
     
  85. BIN
     
  86. BIN
     
  87. BIN
     
  88. BIN
     
  89. BIN
     
  90. +7230
    -0
      BPA.UIControl/Demo/Rubyer.xml
  91. BIN
     
  92. +32
    -0
      BPA.UIControl/Demo/RubyerDemo.exe.config
  93. BIN
     
  94. BIN
     
  95. BIN
     
  96. BIN
     
  97. BIN
     
  98. BIN
     
  99. BIN
     
  100. BIN
     

+ 17
- 0
BPA.Model/BPA.Model.csproj Ver ficheiro

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BPA.Communication" Version="1.0.142" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\BPA.UIControl\BPA.UIControl.csproj" />
</ItemGroup>

</Project>

+ 61
- 0
BPA.Model/RawMaterInfo.cs Ver ficheiro

@@ -0,0 +1,61 @@
using BPA.Helper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BPA.Model
{
public class RawMaterInfo : NotifyBase
{
/// <summary>
/// 物料信息
/// </summary>
/// <param name="id">原料ID</param>
/// <param name="name">原料名称</param>
/// <param name="dNum">原料对应设备编号</param>
/// <param name="wNum">原料对应设备的料仓编号</param>
/// <param name="lm">最后修改时间</param>
public RawMaterInfo(string id, string name, string dNum, string wNum, string lm)
{
Id = id;
Name = name;
DeviceNum = dNum;
WarehouseNum = wNum;
LastModified = lm;
}

/// <summary>
/// 物料ID
/// </summary>
public string Id { get { return _mId; } set { _mId = value; OnPropertyChanged(); } }
private string _mId;

/// <summary>
/// 原料名称
/// </summary>
public string Name { get { return _mName; } set { _mName = value; OnPropertyChanged(); } }
private string _mName;

/// <summary>
/// 设备编号
/// </summary>
public string DeviceNum { get { return _mDeviceNum; } set { _mDeviceNum = value; OnPropertyChanged(); } }
private string _mDeviceNum;

/// <summary>
/// 设备料仓编号
/// </summary>
public string WarehouseNum { get { return _mWarehouseNum; } set { _mWarehouseNum = value; OnPropertyChanged(); } }
private string _mWarehouseNum;

/// <summary>
/// 最后修改时间
/// </summary>
public string LastModified { get { return _mLastModified; } set { _mLastModified = value; OnPropertyChanged(); } }
private string _mLastModified;


}
}

+ 51
- 0
BPA.Model/ViewItem.cs Ver ficheiro

@@ -0,0 +1,51 @@
using BPA.Helper;
using BPA.UIControl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BPA.Model
{
public class ViewItem : NotifyBase
{
public ViewItem(string name, string description, object content, IconType? iconType = null)
{
Name = name;
Description = description;
Content = content;
Icon = iconType;
}
public ViewItem()
{

}

/// <summary>
/// 名称
/// </summary>
public string Name { get { return _mName; } set { _mName = value; OnPropertyChanged(); } }
private string _mName;

/// <summary>
/// 描述
/// </summary>
public string Description { get { return _mDescription; } set { _mDescription = value; OnPropertyChanged(); } }
private string _mDescription;

/// <summary>
/// 内容
/// </summary>
public object Content { get { return _mContent; } set { _mContent = value; OnPropertyChanged(); } }
private object _mContent;

/// <summary>
/// 图标类型
/// </summary>
public IconType? Icon { get { return _mIcon; } set { _mIcon = value; OnPropertyChanged(); } }
private IconType? _mIcon;


}
}

+ 37
- 0
BPA.SingleDevice.sln Ver ficheiro

@@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.33414.496
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BPA.SingleDevice", "BPA.SingleDevice\BPA.SingleDevice.csproj", "{DA921F9F-BE4E-4553-9453-BC8B35DE0C50}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BPA.Model", "BPA.Model\BPA.Model.csproj", "{CC3E5D6F-AE46-4116-8326-EFF82685EF29}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BPA.UIControl", "BPA.UIControl\BPA.UIControl.csproj", "{19BBBC01-3914-43EA-8A71-0A5DA9D8AAE1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DA921F9F-BE4E-4553-9453-BC8B35DE0C50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DA921F9F-BE4E-4553-9453-BC8B35DE0C50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DA921F9F-BE4E-4553-9453-BC8B35DE0C50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DA921F9F-BE4E-4553-9453-BC8B35DE0C50}.Release|Any CPU.Build.0 = Release|Any CPU
{CC3E5D6F-AE46-4116-8326-EFF82685EF29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CC3E5D6F-AE46-4116-8326-EFF82685EF29}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CC3E5D6F-AE46-4116-8326-EFF82685EF29}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CC3E5D6F-AE46-4116-8326-EFF82685EF29}.Release|Any CPU.Build.0 = Release|Any CPU
{19BBBC01-3914-43EA-8A71-0A5DA9D8AAE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{19BBBC01-3914-43EA-8A71-0A5DA9D8AAE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{19BBBC01-3914-43EA-8A71-0A5DA9D8AAE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{19BBBC01-3914-43EA-8A71-0A5DA9D8AAE1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B4869FEA-BC50-4047-AF2E-70215CD6714A}
EndGlobalSection
EndGlobal

+ 16
- 0
BPA.SingleDevice/App.xaml Ver ficheiro

@@ -0,0 +1,16 @@
<Application
x:Class="BPA.SingleDevice.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BPA.SingleDevice">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/BPA.UIControl;component/Themes/Resources/I18N/zh-CN.xaml" />
<ResourceDictionary Source="/BPA.UIControl;component/Themes/Generic.xaml" />
<ResourceDictionary Source="/BPA.SingleDevice;component/Themes/ThemesColor.xaml" />
<ResourceDictionary Source="/BPA.SingleDevice;component/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

+ 31
- 0
BPA.SingleDevice/App.xaml.cs Ver ficheiro

@@ -0,0 +1,31 @@
using BPA.SingleDevice.View;
using BPA.UIControl;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;

namespace BPA.SingleDevice
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);

MainView mv = new MainView();
mv.Show();
}

protected override void OnExit(ExitEventArgs e)
{
base.OnExit(e);
}
}
}

+ 10
- 0
BPA.SingleDevice/AssemblyInfo.cs Ver ficheiro

@@ -0,0 +1,10 @@
using System.Windows;

[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

+ 14
- 0
BPA.SingleDevice/BPA.SingleDevice.csproj Ver ficheiro

@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\BPA.Model\BPA.Model.csproj" />
</ItemGroup>

</Project>

+ 46
- 0
BPA.SingleDevice/Controls/ControlDisplay.cs Ver ficheiro

@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows;

namespace BPA.SingleDevice.Controls
{
/// <summary>
/// 展示控件
/// </summary>
public class ControlDisplay : ContentControl
{
static ControlDisplay()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ControlDisplay), new FrameworkPropertyMetadata(typeof(ControlDisplay)));
}

public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(ControlDisplay), new PropertyMetadata(null));

/// <summary>
/// 标题
/// </summary>
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}


public static readonly DependencyProperty DescriptionProperty =
DependencyProperty.Register("Description", typeof(string), typeof(ControlDisplay), new PropertyMetadata(null));

/// <summary>
/// 描述
/// </summary>
public string Description
{
get { return (string)GetValue(DescriptionProperty); }
set { SetValue(DescriptionProperty, value); }
}
}
}

+ 29
- 0
BPA.SingleDevice/Converter/GetIconConverter.cs Ver ficheiro

@@ -0,0 +1,29 @@
using BPA.UIControl.Commons;
using BPA.UIControl;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;

namespace BPA.SingleDevice.Converter
{
/// <summary>
/// 根据 IconType 获取 Icon
/// </summary>
public class GetIconConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var iconType = ValidateArgument.NotNullOrEmptyCast<IconType>(value, nameof(value));
return new Icon { Type = iconType };
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

+ 32
- 0
BPA.SingleDevice/Converter/IsSelectedToIconConverter.cs Ver ficheiro

@@ -0,0 +1,32 @@
using BPA.UIControl;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows;

namespace BPA.SingleDevice.Converter
{
public class IsSelectedToIconConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((bool)value)
{
return new Icon { Type = IconType.CheckboxFill };
}
else
{
return new Icon { Type = IconType.CheckboxBlankFill };
}
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
}

+ 48
- 0
BPA.SingleDevice/Themes/Generic.xaml Ver ficheiro

@@ -0,0 +1,48 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:BPA.SingleDevice.Controls"
xmlns:ui="clr-namespace:BPA.UIControl;assembly=BPA.UIControl">
<Style TargetType="{x:Type controls:ControlDisplay}">
<Setter Property="Foreground" Value="{DynamicResource DefaultForeground}" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="Focusable" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:ControlDisplay}">
<Grid
Margin="0,5,0,0"
ui:GridHelper.RowDefinitions="Auto, Auto, *"
ui:PanelHelper.Spacing="10">
<TextBlock Style="{StaticResource Head3TextBlock}" Text="{TemplateBinding Title}" />
<TextBox
x:Name="descriptionText"
Grid.Row="1"
Height="Auto"
Margin="3"
BorderThickness="0"
IsReadOnly="True"
Text="{TemplateBinding Description}"
TextWrapping="Wrap" />
<ui:Card
Grid.Row="2"
Margin="3,5"
Padding="10">
<ContentPresenter
x:Name="contentPresenter"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Focusable="False"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ui:Card>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Description" Value="{x:Null}">
<Setter TargetName="descriptionText" Property="Visibility" Value="Collapsed" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

+ 13
- 0
BPA.SingleDevice/Themes/ThemesColor.xaml Ver ficheiro

@@ -0,0 +1,13 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Color x:Key="LightPrimaryColor">#2d2d2d</Color>
<Color x:Key="DarkPrimaryColor">#2196F3</Color>

<Color x:Key="LightLightColor">#6EC6FF</Color>
<Color x:Key="DarkLightColor">#6EC6FF</Color>

<Color x:Key="LightDarkColor">#0069C0</Color>
<Color x:Key="DarkDarkColor">#0069C0</Color>

<Color x:Key="LightAccentColor">#F50057</Color>
<Color x:Key="DarkAccentColor">#F50057</Color>
</ResourceDictionary>

+ 20
- 0
BPA.SingleDevice/View/DeviceManagementView.xaml Ver ficheiro

@@ -0,0 +1,20 @@
<UserControl
x:Class="BPA.SingleDevice.View.DeviceManagementView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BPA.SingleDevice.View"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid>
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="Transparent"
FontSize="50"
Foreground="White"
Text="设备管理" />
</Grid>
</UserControl>

+ 28
- 0
BPA.SingleDevice/View/DeviceManagementView.xaml.cs Ver ficheiro

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BPA.SingleDevice.View
{
/// <summary>
/// DeviceManagementView.xaml 的交互逻辑
/// </summary>
public partial class DeviceManagementView : UserControl
{
public DeviceManagementView()
{
InitializeComponent();
}
}
}

+ 83
- 0
BPA.SingleDevice/View/MainView.xaml Ver ficheiro

@@ -0,0 +1,83 @@
<Window
x:Class="BPA.SingleDevice.View.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converter="clr-namespace:BPA.SingleDevice.Converter"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BPA.SingleDevice.View"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="clr-namespace:BPA.UIControl;assembly=BPA.UIControl"
xmlns:vm="clr-namespace:BPA.SingleDevice.ViewModel"
Title="味魔方自动配料系统"
Width="1200"
Topmost="True"
Height="800"
Background="Transparent"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">

<Window.DataContext>
<vm:MainViewModel />
</Window.DataContext>


<Grid>

<!--#region 菜单栏设置-->
<ui:HamburgerMenu
ui:ControlHelper.CornerRadius="0"
ui:ControlHelper.FocusedBrush="{DynamicResource Dark}"
ui:ControlHelper.FocusedForegroundBrush="{StaticResource WhiteForeground}"
ui:ControlHelper.MaskOpacity="1"
ui:ControlHelper.SelectedBrush="{DynamicResource Dark}"
ui:HeaderHelper.FontSize="16"
ui:HeaderHelper.Foreground="{StaticResource WhiteForeground}"
ui:HeaderHelper.Padding="0 13"
ui:ItemsControlHelper.ItemMargin="5 2"
ui:ItemsControlHelper.ItemPadding="10 13"
Background="#2d2d2d"
BorderThickness="0"
CollapsedWidth="56"
CornerRadius="0"
ExpandedWidth="200"
FontSize="16"
Foreground="{StaticResource WhiteForeground}"
Header="主页"
IsShowLittleBar="False"
PaneBackground="#3F000000"
PaneBorderCornerRadius="0"
SelectedIndex="0"
TransitionDuration="0:0:0.5"
TransitionType="FadeLeft">
<ui:HamburgerMenuItem
Command="{Binding SelecteCommand}"
CommandParameter="RawMaterialManagementView"
Content="{Binding MainContent}"
Header="原料管理"
IconType="ReservedFill" />
<ui:HamburgerMenuItem
Command="{Binding SelecteCommand}"
CommandParameter="DeviceManagementView"
Content="{Binding MainContent}"
Header="设备管理"
IconType="ServerFill" />
<ui:HamburgerMenuItem
Command="{Binding SelecteCommand}"
CommandParameter="RecipeManagementView"
Content="{Binding MainContent}"
Header="配方管理"
IconType="NewspaperFill" />
<!--<ui:HamburgerMenuItem
Command="{Binding SelecteCommand}"
CommandParameter="{Binding Content, RelativeSource={RelativeSource Self}}"
Content="自定义"
Header="自定义">
<ui:HamburgerMenuItem.Icon>
<Image Source="..\rubyer.ico" />
</ui:HamburgerMenuItem.Icon>
</ui:HamburgerMenuItem>-->
</ui:HamburgerMenu>
<!--#endregion-->
</Grid>

</Window>

+ 34
- 0
BPA.SingleDevice/View/MainView.xaml.cs Ver ficheiro

@@ -0,0 +1,34 @@
using BPA.UIControl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace BPA.SingleDevice.View
{
/// <summary>
/// MainView.xaml 的交互逻辑
/// </summary>
public partial class MainView : Window
{
public MainView()
{
InitializeComponent();
this.Loaded += MainView_Loaded;
}

private void MainView_Loaded(object sender, RoutedEventArgs e)
{
ThemeManager.SwitchThemeMode(UIControl.Enums.ThemeMode.Dark);
}
}
}

+ 118
- 0
BPA.SingleDevice/View/RawMaterialManagementView.xaml Ver ficheiro

@@ -0,0 +1,118 @@
<UserControl
x:Class="BPA.SingleDevice.View.RawMaterialManagementView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:BPA.SingleDevice.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BPA.SingleDevice.View"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="clr-namespace:BPA.UIControl;assembly=BPA.UIControl"
xmlns:vm="clr-namespace:BPA.SingleDevice.ViewModel"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">

<UserControl.DataContext>
<vm:RawMaterialManagementViewModel />
</UserControl.DataContext>

<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition />
</Grid.RowDefinitions>

<!--#region 功能按钮-->
<StackPanel
Grid.Row="0"
Margin="10"
HorizontalAlignment="Right"
ui:PanelHelper.Spacing="15"
Orientation="Horizontal">
<Button
HorizontalAlignment="Right"
Command="{Binding AddCommand}"
Content="添加原料"
Style="{DynamicResource DarkButton}" />

<Button
HorizontalAlignment="Right"
Command="{Binding SaveCommand}"
Content="保存修改"
Style="{DynamicResource SuccessButton}" />
</StackPanel>

<!--#endregion-->

<!--#region 列表-->
<controls:ControlDisplay Grid.Row="1">
<DataGrid
Grid.Row="1"
AutoGenerateColumns="False"
BorderBrush="Gray"
BorderThickness="1"
CanUserAddRows="False"
GridLinesVisibility="All"
IsReadOnly="True"
ItemsSource="{Binding RawMaterInfos}"
RowHeight="35"
SelectionMode="Single">
<!--<DataGrid.RowHeaderTemplate>
<DataTemplate>
<Border>
<TextBlock HorizontalAlignment="Center" Text="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow}, Converter={StaticResource DataGridRowIndexConverter}}" />
</Border>
</DataTemplate>
</DataGrid.RowHeaderTemplate>-->
<DataGrid.Columns>
<DataGridTextColumn
Width="*"
Binding="{Binding Name}"
Header="原料名称" />
<DataGridTextColumn
Width="100"
Binding="{Binding DeviceNum}"
Header="设备编号" />
<DataGridTextColumn
Width="120"
Binding="{Binding WarehouseNum}"
Header="设备料仓编号" />
<DataGridTextColumn
Width="180"
Binding="{Binding LastModified}"
Header="最后修改时间" />
<DataGridTemplateColumn Width="150" Header="操作">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button
Command="{Binding DataContext.EditCommand, RelativeSource={RelativeSource AncestorType=local:RawMaterialManagementView}}"
CommandParameter="{Binding Id}"
Foreground="#2196F3"
Style="{StaticResource TextButton}">
<ui:Icon Type="Edit2Fill" />
</Button>
<Button
Command="{Binding DataContext.CopyCommand, RelativeSource={RelativeSource AncestorType=local:RawMaterialManagementView}}"
CommandParameter="{Binding Id}"
Foreground="#2196F3"
Style="{StaticResource TextButton}">
<ui:Icon Type="CopyleftFill" />
</Button>
<Button
Command="{Binding DataContext.RemoveCommand, RelativeSource={RelativeSource AncestorType=local:RawMaterialManagementView}}"
CommandParameter="{Binding Id}"
Style="{StaticResource TextErrorButton}">
<ui:Icon Type="DeleteBinFill" />
</Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</controls:ControlDisplay>
<!--#endregion-->

</Grid>
</UserControl>

+ 28
- 0
BPA.SingleDevice/View/RawMaterialManagementView.xaml.cs Ver ficheiro

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BPA.SingleDevice.View
{
/// <summary>
/// RawMaterialManagementView.xaml 的交互逻辑
/// </summary>
public partial class RawMaterialManagementView : UserControl
{
public RawMaterialManagementView()
{
InitializeComponent();
}
}
}

+ 24
- 0
BPA.SingleDevice/View/RecipeManagementView.xaml Ver ficheiro

@@ -0,0 +1,24 @@
<UserControl x:Class="BPA.SingleDevice.View.RecipeManagementView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:controls="clr-namespace:BPA.SingleDevice.Controls"
xmlns:local="clr-namespace:BPA.SingleDevice.View"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="50"
Background="Transparent"
Foreground="White"
Text="配方管理" />

<controls:ControlDisplay Width="500" Height="100" Grid.Row="1" >
<!--<DataGrid x:Name="DataGrid2" Height="180" AutoGenerateColumns="True" CanUserAddRows="False" ItemsSource="{Binding Weathers}" />-->
</controls:ControlDisplay>

</Grid>
</UserControl>

+ 28
- 0
BPA.SingleDevice/View/RecipeManagementView.xaml.cs Ver ficheiro

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BPA.SingleDevice.View
{
/// <summary>
/// RecipeManagementView.xaml 的交互逻辑
/// </summary>
public partial class RecipeManagementView : UserControl
{
public RecipeManagementView()
{
InitializeComponent();
}
}
}

+ 12
- 0
BPA.SingleDevice/ViewModel/DeviceManagementViewModel.cs Ver ficheiro

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BPA.SingleDevice.ViewModel
{
internal class DeviceManagementViewModel
{
}
}

+ 48
- 0
BPA.SingleDevice/ViewModel/MainViewModel.cs Ver ficheiro

@@ -0,0 +1,48 @@
using BPA.Helper;
using BPA.Model;
using BPA.SingleDevice.View;
using BPA.UIControl;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace BPA.SingleDevice.ViewModel
{
public class MainViewModel : NotifyBase
{
public MainViewModel()
{
//ViewItems = new ObservableCollection<ViewItem>
//{
// new ViewItem("原料管理", "总览", new RawMaterialManagementView(), IconType.Home2Line),
// new ViewItem("设备管理", "按钮", new DeviceManagementView(), IconType.CheckboxBlankFill),
// new ViewItem("配方管理", "文本框", new RecipeManagementView(), IconType.TBoxLine),
//};

SelecteCommand = new BPARelayCommand<object>(DoNavChanged);
}

public ObservableCollection<ViewItem> ViewItems { get; set; } = new ObservableCollection<ViewItem>();

public BPARelayCommand<object> SelecteCommand { get; set; }

private void DoNavChanged(object obj)
{
if (obj != null)
{
Type type = Type.GetType($"BPA.SingleDevice.View.{obj.ToString()}");
ConstructorInfo cti = type?.GetConstructor(Type.EmptyTypes);
MainContent = (FrameworkElement)cti?.Invoke(null);
}
}

public FrameworkElement MainContent { get { return _mMainContent; } set { _mMainContent = value; OnPropertyChanged(); } }
private FrameworkElement _mMainContent;

}
}

+ 30
- 0
BPA.SingleDevice/ViewModel/RawMaterialManagementViewModel.cs Ver ficheiro

@@ -0,0 +1,30 @@
using BPA.Helper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using BPA.Model;

namespace BPA.SingleDevice.ViewModel
{
public class RawMaterialManagementViewModel : NotifyBase
{
public RawMaterialManagementViewModel()
{
for (int i = 0; i < 10; i++)
{
RawMaterInfos.Add(new RawMaterInfo(i.ToString(), i.ToString(), i.ToString(), i.ToString(), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
}
}

public ObservableCollection<RawMaterInfo> RawMaterInfos { get; set; } = new ObservableCollection<RawMaterInfo>();

public BPARelayCommand AddCommand { get; set; }
public BPARelayCommand SaveCommand { get; set; }
public BPARelayCommand<object> CopyCommand { get; set; }
public BPARelayCommand<object> EditCommand { get; set; }
public BPARelayCommand<object> RemoveCommand { get; set; }
}
}

+ 12
- 0
BPA.SingleDevice/ViewModel/RecipeManagementViewModel.cs Ver ficheiro

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BPA.SingleDevice.ViewModel
{
internal class RecipeManagementViewModel
{
}
}

+ 9
- 0
BPA.UIControl/BPA.UIControl.csproj Ver ficheiro

@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
</PropertyGroup>

</Project>

+ 67
- 0
BPA.UIControl/BPACommand.cs Ver ficheiro

@@ -0,0 +1,67 @@
using System;
using System.Windows.Input;

namespace BPA.UIControl
{
/// <summary>
/// Command
/// </summary>
public class BPACommand : ICommand
{
private readonly Action<object> _execute;
private readonly Func<object, bool> _canExecute;

/// <summary>
/// Initializes a new instance of the <see cref="BPACommand"/> class.
/// </summary>
/// <param name="execute">The execute.</param>
public BPACommand(Action<object> execute)
: this(execute, null)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="BPACommand"/> class.
/// </summary>
/// <param name="execute">The execute.</param>
/// <param name="canExecute">The can execute.</param>
public BPACommand(Action<object> execute, Func<object, bool> canExecute)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute ?? (x => true);
}

/// <inheritdoc/>
public bool CanExecute(object parameter)
{
return _canExecute(parameter);
}

/// <inheritdoc/>
public void Execute(object parameter)
{
_execute(parameter);
}

/// <inheritdoc/>
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}

/// <summary>
/// Refreshes the.
/// </summary>
public void Refresh()
{
CommandManager.InvalidateRequerySuggested();
}
}
}

+ 24
- 0
BPA.UIControl/BPAVirtualizingStackPanel.cs Ver ficheiro

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace BPA.UIControl
{
/// <summary>
/// 公开 BringIntoView() 的 VirtualizingStackPanel
/// 当使用 TreeViewHelper.RightClickToSelected 需要使用该虚拟化 StackPanel 作为 ItemsPanel
/// </summary>
public class BPAVirtualizingStackPanel : VirtualizingStackPanel
{
/// <summary>
/// Publically expose BringIndexIntoView.
/// </summary>
public void BringIntoView(int index)
{
this.BringIndexIntoView(index);
}
}
}

+ 174
- 0
BPA.UIControl/BPAWindow.cs Ver ficheiro

@@ -0,0 +1,174 @@
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace BPA.UIControl
{
/// <summary>
/// rubyer 窗体
/// </summary>
public class BPAWindow : Window
{
/// <summary>
/// Initializes a new instance of the <see cref="BPAWindow"/> class.
/// </summary>
public BPAWindow()
{
DefaultStyleKey = typeof(BPAWindow);
CommandBindings.Add(new CommandBinding(SystemCommands.CloseWindowCommand, CloseWindow));
CommandBindings.Add(new CommandBinding(SystemCommands.MaximizeWindowCommand, MaximizeWindow, CanResizeWindow));
CommandBindings.Add(new CommandBinding(SystemCommands.MinimizeWindowCommand, MinimizeWindow, CanMinimizeWindow));
CommandBindings.Add(new CommandBinding(SystemCommands.RestoreWindowCommand, RestoreWindow, CanResizeWindow));
CommandBindings.Add(new CommandBinding(SystemCommands.ShowSystemMenuCommand, ShowSystemMenu));
}

/// <inheritdoc/>
protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
if (SizeToContent == SizeToContent.WidthAndHeight)
InvalidateMeasure();
}

#region Window Commands

private void CanResizeWindow(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = ResizeMode == ResizeMode.CanResize || ResizeMode == ResizeMode.CanResizeWithGrip;
}

private void CanMinimizeWindow(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = ResizeMode != ResizeMode.NoResize;
}

private void CloseWindow(object sender, ExecutedRoutedEventArgs e)
{
(sender as Window).Close();
}

private void MaximizeWindow(object sender, ExecutedRoutedEventArgs e)
{
SystemCommands.MaximizeWindow(this);
}

private void MinimizeWindow(object sender, ExecutedRoutedEventArgs e)
{
SystemCommands.MinimizeWindow(this);
}

private void RestoreWindow(object sender, ExecutedRoutedEventArgs e)
{
SystemCommands.RestoreWindow(this);
}

private void ShowSystemMenu(object sender, ExecutedRoutedEventArgs e)
{
var element = e.OriginalSource as FrameworkElement;
if (element == null)
return;

var point = WindowState == WindowState.Maximized ? new Point(0, element.ActualHeight)
: new Point(Left + BorderThickness.Left, element.ActualHeight + Top + BorderThickness.Top);
point = element.TransformToAncestor(this).Transform(point);
SystemCommands.ShowSystemMenu(this, point);
}

#endregion Window Commands

#region 属性

/// <summary>
/// 标题栏内容
/// </summary>
public static readonly DependencyProperty TitleBarContentProperty =
DependencyProperty.Register("TitleBarContent", typeof(object), typeof(BPAWindow), new PropertyMetadata(default(object)));

/// <summary>
/// 标题栏内容
/// </summary>
public object TitleBarContent
{
get { return (object)GetValue(TitleBarContentProperty); }
set { SetValue(TitleBarContentProperty, value); }
}

/// <summary>
/// 是否显示标题栏阴影
/// </summary>
public static readonly DependencyProperty TitleShadowProperty =
DependencyProperty.Register("TitleShadow", typeof(bool), typeof(BPAWindow), new PropertyMetadata(default(bool)));

/// <summary>
/// 是否显示标题栏阴影
/// </summary>
public bool TitleShadow
{
get { return (bool)GetValue(TitleShadowProperty); }
set { SetValue(TitleShadowProperty, value); }
}

/// <summary>
/// 标题栏高度
/// </summary>
public static readonly DependencyProperty TitleHeightProperty =
DependencyProperty.Register("TitleHeight", typeof(double), typeof(BPAWindow), new PropertyMetadata(default(double)));

/// <summary>
/// 标题栏高度
/// </summary>
public double TitleHeight
{
get { return (double)GetValue(TitleHeightProperty); }
set { SetValue(TitleHeightProperty, value); }
}

/// <summary>
/// 标题背景色
/// </summary>
public static readonly DependencyProperty TitleBackgroundProperty =
DependencyProperty.Register("TitleBackground", typeof(Brush), typeof(BPAWindow), new PropertyMetadata(default(Brush)));

/// <summary>
/// 标题背景色
/// </summary>
public Brush TitleBackground
{
get { return (Brush)GetValue(TitleBackgroundProperty); }
set { SetValue(TitleBackgroundProperty, value); }
}

/// <summary>
/// 标题前景色
/// </summary>
public static readonly DependencyProperty TitleForegroundProperty =
DependencyProperty.Register("TitleForeground", typeof(Brush), typeof(BPAWindow), new PropertyMetadata(default(Brush)));

/// <summary>
/// 标题前景色
/// </summary>
public Brush TitleForeground
{
get { return (Brush)GetValue(TitleForegroundProperty); }
set { SetValue(TitleForegroundProperty, value); }
}

/// <summary>
/// Window 非活动边框颜色
/// </summary>
public static readonly DependencyProperty InactiveBorderBrushProperty =
DependencyProperty.Register("InactiveBorderBrush", typeof(Brush), typeof(BPAWindow), new PropertyMetadata(default(Brush)));

/// <summary>
/// Window 非活动边框颜色
/// </summary>
public Brush InactiveBorderBrush
{
get { return (Brush)GetValue(InactiveBorderBrushProperty); }
set { SetValue(InactiveBorderBrushProperty, value); }
}
#endregion 属性
}
}

+ 144
- 0
BPA.UIControl/Badge.cs Ver ficheiro

@@ -0,0 +1,144 @@
using BPA.UIControl.Commons.KnownBoxes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BPA.UIControl
{
/// <summary>
/// 标记
/// </summary>
public class Badge : ContentControl
{
static Badge()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Badge), new FrameworkPropertyMetadata(typeof(Badge)));
}

#region 属性

/// <summary>
/// 标记颜色
/// </summary>
public static readonly DependencyProperty BadgeBrushProperty =
DependencyProperty.Register("BadgeBrush", typeof(Brush), typeof(Badge), new PropertyMetadata(default(Brush)));

/// <summary>
/// 标记颜色
/// </summary>
public Brush BadgeBrush
{
get { return (Brush)GetValue(BadgeBrushProperty); }
set { SetValue(BadgeBrushProperty, value); }
}

/// <summary>
/// 显示文本
/// </summary>
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(Badge), new PropertyMetadata(default(string), OnTextChanged));

/// <summary>
/// 显示文本
/// </summary>
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}

/// <summary>
/// 标记尺寸
/// </summary>
public static readonly DependencyProperty BadgeSizeProperty =
DependencyProperty.Register("BadgeSize", typeof(double), typeof(Badge), new PropertyMetadata(default(double)));

/// <summary>
/// 标记尺寸
/// </summary>
public double BadgeSize
{
get { return (double)GetValue(BadgeSizeProperty); }
set { SetValue(BadgeSizeProperty, value); }
}

/// <summary>
/// 标记字体尺寸
/// </summary>
public static readonly DependencyProperty BadgeFontSizeProperty =
DependencyProperty.Register("BadgeFontSize", typeof(double), typeof(Badge), new PropertyMetadata(default(double)));

/// <summary>
/// 标记字体尺寸
/// </summary>
public double BadgeFontSize
{
get { return (double)GetValue(BadgeFontSizeProperty); }
set { SetValue(BadgeFontSizeProperty, value); }
}

/// <summary>
/// 是否隐藏
/// </summary>
public static readonly DependencyProperty IsHiddenProperty =
DependencyProperty.Register("IsHidden", typeof(bool), typeof(Badge), new PropertyMetadata(BooleanBoxes.FalseBox));

/// <summary>
/// 是否隐藏
/// </summary>
public bool IsHidden
{
get { return (bool)GetValue(IsHiddenProperty); }
set { SetValue(IsHiddenProperty, BooleanBoxes.Box(value)); }
}

#endregion 属性

#region 事件

/// <summary>
/// 文本改变事件
/// </summary>
public static readonly RoutedEvent TextChangedEvent =
EventManager.RegisterRoutedEvent("TextChanged", RoutingStrategy.Direct, typeof(RoutedEventArgs), typeof(Badge));

/// <summary>
/// 文本改变事件
/// </summary>处理
public event RoutedEventHandler TextChanged
{
add { AddHandler(TextChangedEvent, value); }
remove { RemoveHandler(TextChangedEvent, value); }
}

#endregion 事件

#region 方法

private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.OldValue == null)
{
return;
}

Badge badge = d as Badge;
RoutedEventArgs args = new RoutedEventArgs();
args.RoutedEvent = TextChangedEvent;
badge.RaiseEvent(args);
}

#endregion 方法
}
}

+ 63
- 0
BPA.UIControl/Card.cs Ver ficheiro

@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BPA.UIControl
{
/// <summary>
/// 卡片
/// </summary>
public class Card : ContentControl
{
/// <summary>
/// Initializes a new instance of the <see cref="Card"/> class.
/// </summary>
static Card()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Card), new FrameworkPropertyMetadata(typeof(Card)));
}

/// <summary>
/// 圆角半径
/// </summary>
public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(
"CornerRadius", typeof(CornerRadius), typeof(Card), new PropertyMetadata(default(CornerRadius)));

/// <summary>
/// 圆角半径
/// </summary>
public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}

/// <summary>
/// 边框阴影
/// </summary>
public static readonly DependencyProperty BorderEffectProperty = DependencyProperty.Register(
"BorderEffect", typeof(Effect), typeof(Card), new PropertyMetadata(default(Effect)));

/// <summary>
/// 边框阴影
/// </summary>
public Effect BorderEffect
{
get { return (Effect)GetValue(BorderEffectProperty); }
set { SetValue(BorderEffectProperty, value); }
}

}
}

+ 248
- 0
BPA.UIControl/Clock.cs Ver ficheiro

@@ -0,0 +1,248 @@
using BPA.UIControl.Commons.KnownBoxes;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace BPA.UIControl
{
/// <summary>
/// 时钟
/// </summary>
[TemplatePart(Name = HourListPartName, Type = typeof(Selector))]
[TemplatePart(Name = MinuteListPartName, Type = typeof(Selector))]
[TemplatePart(Name = ConfirmPartName, Type = typeof(Button))]
public class Clock : Control
{
/// <summary>
/// 小时列表名称
/// </summary>
public const string HourListPartName = "PART_HourList";

/// <summary>
/// 分钟列表名称
/// </summary>
public const string MinuteListPartName = "PART_MinuteList";

/// <summary>
/// 确认按钮名称
/// </summary>
public const string ConfirmPartName = "PART_ConfirmButton";

/// <summary>
/// Initializes a new instance of the <see cref="Clock"/> class.
/// </summary>
static Clock()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Clock), new FrameworkPropertyMetadata(typeof(Clock)));
}

/// <inheritdoc/>
public override void OnApplyTemplate()
{
base.OnApplyTemplate();

if (GetTemplateChild(ConfirmPartName) is Button confirmButton)
{
confirmButton.Click += ConfirmButton_Click;
}

Hours = new ObservableCollection<int>(Enumerable.Range(0, 24));
Minutes = new ObservableCollection<int>(Enumerable.Range(0, 60));

CurrentTime = new DateTime(DateTime.Now.TimeOfDay.Ticks);
Hour = CurrentTime.Value.Hour;
Minute = CurrentTime.Value.Minute;
}

#region 路由事件

/// <summary>
/// 选择时间改变事件
/// </summary>
public static readonly RoutedEvent SelectedTimeChangedEvent = EventManager.RegisterRoutedEvent(
"SelectedTimeChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<DateTime?>), typeof(Clock));

/// <summary>
/// 选择时间改变事件处理
/// </summary>
public event RoutedPropertyChangedEventHandler<DateTime?> SelectedTimeChanged
{
add { AddHandler(SelectedTimeChangedEvent, value); }
remove { RemoveHandler(SelectedTimeChangedEvent, value); }
}

/// <summary>
/// 当前事件改变事件
/// </summary>
public static readonly RoutedEvent CurrentTimeChangedEvent = EventManager.RegisterRoutedEvent(
"CurrentTimeChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<DateTime?>), typeof(Clock));

/// <summary>
/// 当前事件改变事件处理
/// </summary>
public event RoutedPropertyChangedEventHandler<DateTime?> CurrentTimeChanged
{
add { AddHandler(CurrentTimeChangedEvent, value); }
remove { RemoveHandler(CurrentTimeChangedEvent, value); }
}
#endregion

#region 依赖属性

/// <summary>
/// 时集合
/// </summary>
internal static readonly DependencyProperty HoursProperty = DependencyProperty.Register(
"Hours", typeof(ObservableCollection<int>), typeof(Clock), new PropertyMetadata(null));

/// <summary>
/// 时集合
/// </summary>
internal ObservableCollection<int> Hours
{
get { return (ObservableCollection<int>)GetValue(HoursProperty); }
set { SetValue(HoursProperty, value); }
}

/// <summary>
/// 时
/// </summary>
public static readonly DependencyProperty HourProperty = DependencyProperty.Register(
"Hour", typeof(int), typeof(Clock), new PropertyMetadata(0, OnItemSeletedChanged));

/// <summary>
/// 时
/// </summary>
public int Hour
{
get { return (int)GetValue(HourProperty); }
set { SetValue(HourProperty, value); }
}

/// <summary>
/// 分集合
/// </summary>
internal static readonly DependencyProperty MinutesProperty = DependencyProperty.Register(
"Minutes", typeof(ObservableCollection<int>), typeof(Clock), new PropertyMetadata(null));

/// <summary>
/// 分集合
/// </summary>
internal ObservableCollection<int> Minutes
{
get { return (ObservableCollection<int>)GetValue(MinutesProperty); }
set { SetValue(MinutesProperty, value); }
}

/// <summary>
/// 分
/// </summary>
public static readonly DependencyProperty MinuteProperty = DependencyProperty.Register(
"Minute", typeof(int), typeof(Clock), new PropertyMetadata(0, OnItemSeletedChanged));

/// <summary>
/// 分
/// </summary>
public int Minute
{
get { return (int)GetValue(MinuteProperty); }
set { SetValue(MinuteProperty, value); }
}

/// <summary>
/// 选中时间
/// </summary>
public static readonly DependencyProperty SelectedTimeProperty = DependencyProperty.Register(
"SelectedTime", typeof(DateTime?), typeof(Clock), new PropertyMetadata(default(DateTime), OnSelectTimeChanged));

private static void OnSelectTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var clock = (Clock)d;
if (clock.SelectedTime != null)
{
clock.Hour = clock.SelectedTime.Value.Hour;
clock.Minute = clock.SelectedTime.Value.Minute;
}
}

/// <summary>
/// 选中时间
/// </summary>
public DateTime? SelectedTime
{
get { return (DateTime?)GetValue(SelectedTimeProperty); }
set { SetValue(SelectedTimeProperty, value); }
}

/// <summary>
/// 当前时间
/// </summary>
public static readonly DependencyProperty CurrentTimeProperty =
DependencyProperty.Register("CurrentTime", typeof(DateTime?), typeof(Clock), new PropertyMetadata(default(DateTime?)));

/// <summary>
/// 当前时间
/// </summary>
public DateTime? CurrentTime
{
get { return (DateTime?)GetValue(CurrentTimeProperty); }
set { SetValue(CurrentTimeProperty, value); }
}

/// <summary>
/// 是否显示确认按钮
/// </summary>
public static readonly DependencyProperty IsShowConfirmButtonProperty =
DependencyProperty.Register("IsShowConfirmButton", typeof(bool), typeof(Clock), new PropertyMetadata(BooleanBoxes.TrueBox));

/// <summary>
/// 是否显示确认按钮
/// </summary>
public bool IsShowConfirmButton
{
get { return (bool)GetValue(IsShowConfirmButtonProperty); }
set { SetValue(IsShowConfirmButtonProperty, BooleanBoxes.Box(value)); }
}

#endregion

/// <summary>
/// 时间选择改变
/// </summary>
private static void OnItemSeletedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var clock = d as Clock;

if (!clock.IsLoaded)
{
return;
}

clock.CurrentTime = Convert.ToDateTime($"{clock.Hour}:{clock.Minute}");

if (e.NewValue != null)
{
var args = new RoutedPropertyChangedEventArgs<DateTime?>(DateTime.Now, (DateTime)clock.CurrentTime);
args.RoutedEvent = CurrentTimeChangedEvent;
clock.RaiseEvent(args);
}
}

/// <summary>
/// 确认时间
/// </summary>
private void ConfirmButton_Click(object sender, RoutedEventArgs e)
{
var oldTime = SelectedTime;
var newTime = CurrentTime;
SelectedTime = CurrentTime;

var args = new RoutedPropertyChangedEventArgs<DateTime?>(oldTime, newTime);
args.RoutedEvent = SelectedTimeChangedEvent;
RaiseEvent(args);
}
}
}

+ 55
- 0
BPA.UIControl/Commons/ColumnDefinitionCollectionTypeConverter.cs Ver ficheiro

@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows;

namespace BPA.UIControl.Commons
{
/// <summary>
/// ColumnDefinitionCollection 类型转换
/// from https://github.com/dotnet/maui
/// Microsoft.Maui.Controls.ColumnDefinitionCollectionTypeConverter.cs
/// </summary>
public class ColumnDefinitionCollectionTypeConverter : TypeConverter
{
/// <inheritdoc/>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
=> sourceType == typeof(string);

/// <inheritdoc/>
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
=> destinationType == typeof(string);

/// <inheritdoc/>
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
var strValue = value?.ToString();

if (strValue != null)
{
var lengths = strValue.Split(',');
var converter = new GridLengthConverter();
var definitions = new ColumnDefinition[lengths.Length];
for (var i = 0; i < lengths.Length; i++)
definitions[i] = new ColumnDefinition { Width = (GridLength)converter.ConvertFromInvariantString(lengths[i]) };
return definitions;
}

throw new InvalidOperationException(string.Format("Cannot convert \"{0}\" into {1}", strValue, typeof(ColumnDefinitionCollection)));
}

/// <inheritdoc/>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (!(value is ColumnDefinitionCollection cdc))
throw new NotSupportedException();
var converter = new GridLengthConverter();
return string.Join(", ", cdc.Select(cd => converter.ConvertToInvariantString(cd.Width)));
}
}
}

+ 22
- 0
BPA.UIControl/Commons/ElementObservableCollection.cs Ver ficheiro

@@ -0,0 +1,22 @@
using System.Collections.ObjectModel;
using System.Windows;

namespace BPA.UIControl.Commons
{
/// <summary>
/// 归属元素的可通知集合
/// </summary>
/// <typeparam name="T"></typeparam>
public class ElementObservableCollection<T> : ObservableCollection<T>
{
/// <summary>
/// 所有者
/// </summary>
public UIElement Owner { get; }

public ElementObservableCollection(UIElement owner)
{
Owner = owner;
}
}
}

+ 51
- 0
BPA.UIControl/Commons/EnumDescriptionConverter.cs Ver ficheiro

@@ -0,0 +1,51 @@
using System;
using System.ComponentModel;
using System.Globalization;

namespace BPA.UIControl.Commons
{
/// <summary>
/// Enum -> Description
/// </summary>
public class EnumDescriptionConverter : EnumConverter
{
/// <summary>
/// Initializes a new instance of the <see cref="EnumDescriptionConverter"/> class.
/// </summary>
/// <param name="type">The type.</param>
public EnumDescriptionConverter(Type type)
: base(type)
{
}

/// <inheritdoc/>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string))
{
return value?.GetDescription();
}

return string.Empty;
}

/// <inheritdoc/>
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string)
{
var enumValues = EnumType.GetEnumValues();
for (int i = 0; i < enumValues.Length; i++)
{
var enumValue = enumValues.GetValue(i);
if (value.Equals(enumValue.GetDescription()))
{
return enumValue;
}
}
}

return base.ConvertFrom(context, culture, value);
}
}
}

+ 255
- 0
BPA.UIControl/Commons/FrameworkElementExtension.cs Ver ficheiro

@@ -0,0 +1,255 @@
using BPA.UIControl.Commons;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;

namespace BPA.UIControl
{
/// <summary>
/// FrameworkElement 扩展
/// </summary>
public static class FrameworkElementExtension
{
/// <summary>
/// 获取 root 元素
/// </summary>
/// <param name="dependencyObject">依赖对象</param>
/// <returns>root 元素</returns>
public static DependencyObject GetRoot(this DependencyObject dependencyObject)
{
DependencyObject result = dependencyObject;
while ((dependencyObject = VisualTreeHelper.GetParent(dependencyObject)) != null)
{
result = dependencyObject;
}
return result;
}

/// <summary>
/// 查找父元素
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="element">元素</param>
/// <returns>父元素</returns>
public static T FindParent<T>(this FrameworkElement element) where T : FrameworkElement
{
T t = default;
while (element != null)
{
t = element as T;
if (t != null)
{
break;
}
element = element.Parent as FrameworkElement;
}
return t;
}

/// <summary>
/// 获取最顶层父元素
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="dependencyObject">依赖对象</param>
/// <returns>父元素</returns>
public static T GetOldestParent<T>(this DependencyObject dependencyObject) where T : DependencyObject
{
T t;
while ((t = VisualTreeHelper.GetParent(dependencyObject) as T) != null)
{
dependencyObject = t;
}
return dependencyObject.AssertCast<T>();
}

/// <summary>
/// 尝试查找资源
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="root">元素</param>
/// <param name="resourceKey">资源 key</param>
/// <returns>资源</returns>
internal static T TryFindResourceUp<T>(this FrameworkElement root, object resourceKey)
{
if (root != null && root.Resources.Contains(resourceKey))
{
object obj = root.Resources[resourceKey];
if (!(obj is T))
{
return default;
}
return (T)obj;
}
else
{
if (root.Parent is FrameworkElement)
{
return ((FrameworkElement)root.Parent).TryFindResourceUp<T>(resourceKey);
}
return default;
}
}

/// <summary>
/// 获取子元素
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="parent">父元素</param>
/// <returns>子元素</returns>
public static T TryGetChildPartFromVisualTree<T>(this FrameworkElement parent) where T : FrameworkElement
{
return parent.TryGetChildFromVisualTree<T>(null);
}

/// <summary>
/// 根据 Name 获取子元素
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="parent">父元素</param>
/// <param name="partName">名称</param>
/// <returns>子元素</returns>
public static T TryGetChildPartFromVisualTree<T>(this FrameworkElement parent, string partName) where T : FrameworkElement
{
ValidateArgument.NotNullOrEmpty(partName, "partName");
return parent.TryGetChildFromVisualTree<T>((FrameworkElement childControl) => childControl.Name == partName);
}

/// <summary>
/// 根据 AutomationId 获取子元素
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="parent">父元素</param>
/// <param name="automationId">自动 ID</param>
/// <returns>子元素</returns>
internal static T TryGetChildWithAutomationIdFromVisualTree<T>(this FrameworkElement parent, string automationId) where T : FrameworkElement
{
ValidateArgument.NotNullOrEmpty(automationId, "automationId");
return parent.TryGetChildFromVisualTree<T>((FrameworkElement childControl) => AutomationProperties.GetAutomationId(childControl) == automationId);
}

/// <summary>
/// VisualTree 获取子元素
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="parent">父元素</param>
/// <param name="evaluateChild">子元素表达式</param>
/// <returns>子元素</returns>
internal static T TryGetChildFromVisualTree<T>(this FrameworkElement parent, Func<FrameworkElement, bool> evaluateChild) where T : FrameworkElement
{
ValidateArgument.NotNull(parent, "parent");
FrameworkElement frameworkElement = null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
frameworkElement = VisualTreeHelper.GetChild(parent, i) as FrameworkElement;
if (frameworkElement != null && (frameworkElement is T && (evaluateChild == null || evaluateChild.Invoke(frameworkElement)) || (frameworkElement = frameworkElement.TryGetChildFromVisualTree<T>(evaluateChild)) != null))
{
break;
}
}

return frameworkElement as T;
}

/// <summary>
/// 获取父元素
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="child">子元素</param>
/// <returns>父元素</returns>
public static T TryGetParentFromVisualTree<T>(this FrameworkElement child) where T : FrameworkElement
{
if (child != null && !(child is T))
{
return (VisualTreeHelper.GetParent(child) as FrameworkElement).TryGetParentFromVisualTree<T>();
}

return (T)(object)child;
}

/// <summary>
/// 获取父元素
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="child">子元素</param>
/// <returns>父元素</returns>
public static T TryGetParentFromVisualTree<T>(this DependencyObject child) where T : DependencyObject
{
if (child != null && !(child is T))
{
return VisualTreeHelper.GetParent(child).TryGetParentFromVisualTree<T>();
}

return (T)(object)child;
}

/// <summary>
/// 遍历子元素
/// </summary>
/// <param name="dependencyObj">依赖对象</param>
/// <param name="childAction">变量方法</param>
internal static void ForEachVisualChild(this DependencyObject dependencyObj, Action<DependencyObject> childAction)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(dependencyObj, i);
child.ForEachVisualChild(childAction);
childAction.Invoke(child);
}
}

/// <summary>
/// 是否包含子对象
/// </summary>
/// <param name="parent">父元素</param>
/// <param name="dependencyObj">依赖对象</param>
/// <returns>结果</returns>
public static bool ContainsChild(this DependencyObject parent, DependencyObject dependencyObj)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(parent, i);
if (child == dependencyObj || child.ContainsChild(dependencyObj))
{
return true;
}
}

return false;
}

/// <summary>
/// 获取依赖属性的值
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="reference">对象</param>
/// <param name="property">属性</param>
/// <returns>属性的值</returns>
public static T GetAncestorValue<T>(this DependencyObject reference, DependencyProperty property)
{
T result = default;
while (reference != null && (result = ObjectExtension.AssertCast<T>(reference.GetValue(property))) == null)
{
DependencyObject parent = VisualTreeHelper.GetParent(reference);
if (parent == null)
{
FrameworkElement frameworkElement = reference as FrameworkElement;
if (frameworkElement != null)
{
parent = frameworkElement.Parent;
}
}

reference = parent;
}

return result;
}
}
}

+ 25
- 0
BPA.UIControl/Commons/KnownBoxes/BooleanBoxes.cs Ver ficheiro

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BPA.UIControl.Commons.KnownBoxes
{
internal static class BooleanBoxes
{
internal static object TrueBox = true;

internal static object FalseBox = false;

internal static object Box(bool value)
{
if (value)
{
return TrueBox;
}

return FalseBox;
}
}
}

+ 58
- 0
BPA.UIControl/Commons/ObjectExtension.cs Ver ficheiro

@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace BPA.UIControl.Commons
{
/// <summary>
/// Object 扩展
/// </summary>
public static class ObjectExtension
{
/// <summary>
/// 强转为某个类型
/// </summary>
/// <param name="value">The value.</param>
/// <returns>A T.</returns>
public static T AssertCast<T>(this object value)
{
return (T)((object)value);
}

/// <summary>
/// 强转为某个类型, 不为空
/// </summary>
/// <param name="value">The value.</param>
/// <returns>A T.</returns>
public static T AssertCastNotNull<T>(this object value)
{
return value.AssertCast<T>();
}

/// <summary>
/// 获取描述
/// </summary>
/// <param name="value">对象</param>
/// <returns>描述</returns>
public static string GetDescription(this object value)
{
if (value != null)
{
FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
if (fieldInfo != null)
{
var attributes = fieldInfo.GetCustomAttributes<DescriptionAttribute>(inherit: false);
return ((attributes.Count() > 0) && (!string.IsNullOrEmpty(attributes.First().Description)))
? attributes.First().Description
: value.ToString();
}
}

return string.Empty;
}
}
}

+ 50
- 0
BPA.UIControl/Commons/PageSizeCollectionConverter.cs Ver ficheiro

@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows;

namespace BPA.UIControl.Commons
{
/// <summary>
/// 每页大小集合转换器
/// </summary>
public class PageSizeCollectionConverter : TypeConverter
{
/// <inheritdoc/>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
=> sourceType == typeof(string);

/// <inheritdoc/>
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
=> true;

/// <inheritdoc/>
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
var strValue = value?.ToString();

if (strValue != null)
{
var sizes = strValue.Split(',');

return sizes.Select(x => int.Parse(x));
}

throw new InvalidOperationException(string.Format("Cannot convert \"{0}\" into {1}", strValue, typeof(IEnumerable<int>)));
}

/// <inheritdoc/>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (!(value is IEnumerable<int> sizes))
throw new NotSupportedException();

return string.Join(", ", sizes);
}
}
}

+ 52
- 0
BPA.UIControl/Commons/RowDefinitionCollectionTypeConverter.cs Ver ficheiro

@@ -0,0 +1,52 @@
using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Windows.Controls;
using System.Windows;

namespace BPA.UIControl.Commons
{
/// <summary>
/// RowDefinitionCollection 类型转换
/// from https://github.com/dotnet/maui
/// Microsoft.Maui.Controls.RowDefinitionCollectionTypeConverter.cs
/// </summary>
public class RowDefinitionCollectionTypeConverter : TypeConverter
{
/// <inheritdoc/>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
=> sourceType == typeof(string);

/// <inheritdoc/>
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
=> true;

/// <inheritdoc/>
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
var strValue = value?.ToString();

if (strValue != null)
{
var lengths = strValue.Split(',');
var converter = new GridLengthConverter();
var definitions = new RowDefinition[lengths.Length];
for (var i = 0; i < lengths.Length; i++)
definitions[i] = new RowDefinition { Height = (GridLength)converter.ConvertFromInvariantString(lengths[i]) };
return definitions;
}

throw new InvalidOperationException(string.Format("Cannot convert \"{0}\" into {1}", strValue, typeof(RowDefinitionCollection)));
}

/// <inheritdoc/>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (!(value is RowDefinitionCollection rdc))
throw new NotSupportedException();
var converter = new GridLengthConverter();
return string.Join(", ", rdc.Select(rd => converter.ConvertToInvariantString(rd.Height)));
}
}
}

+ 106
- 0
BPA.UIControl/Commons/ValidateArgument.cs Ver ficheiro

@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BPA.UIControl.Commons
{
/// <summary>
/// 参数验证
/// </summary>
public sealed class ValidateArgument
{
/// <summary>
/// 非 null
/// </summary>
/// <param name="obj">对象</param>
/// <param name="parameterName">参数名称</param>
/// <exception cref="ArgumentNullException"></exception>
public static void NotNull(object obj, string parameterName)
{
if (obj == null)
{
throw new ArgumentNullException(parameterName);
}
}

/// <summary>
/// 非 null 或空
/// </summary>
/// <param name="parameterValue">字符串值</param>
/// <param name="parameterName">参数名称</param>
/// <exception cref="ArgumentException"></exception>
public static void NotNullOrEmpty(string parameterValue, string parameterName)
{
if (string.IsNullOrEmpty(parameterValue))
{
throw new ArgumentException(parameterName);
}
}

/// <summary>
/// 非 Null 或空类型转换
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="parameterValue">参数值</param>
/// <param name="parameterName">参数名称</param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public static T NotNullOrEmptyCast<T>(object parameterValue, string parameterName)
{
ValidateArgument.NotNull(parameterValue, parameterName);
if (parameterValue is T)
{
return (T)((object)parameterValue);
}
throw new ArgumentException(parameterName);
}

/// <summary>
/// 类型转换
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="parameterValue">参数值</param>
/// <param name="parameterName">参数名称</param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public static T Cast<T>(object parameterValue, string parameterName)
{
if (parameterValue == null || parameterValue is T)
{
return (T)((object)parameterValue);
}
throw new ArgumentException(parameterName);
}

/// <summary>
/// 是否在范围内
/// </summary>
/// <param name="checkedExpression">检查表达式</param>
/// <param name="parameterName">参数名称</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static void Range(bool checkedExpression, string parameterName)
{
if (!checkedExpression)
{
throw new ArgumentOutOfRangeException(parameterName);
}
}

/// <summary>
/// 是否在范围内
/// </summary>
/// <param name="checkedExpression">检查表达式</param>
/// <param name="parameterName">参数名称</param>
/// <param name="message">错误信息</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static void Range(bool checkedExpression, string parameterName, string message)
{
if (!checkedExpression)
{
throw new ArgumentOutOfRangeException(parameterName, message);
}
}
}
}

+ 22
- 0
BPA.UIControl/Commons/WindowHelper.cs Ver ficheiro

@@ -0,0 +1,22 @@
using System.Linq;
using System.Windows;

namespace BPA.UIControl.Commons
{
/// <summary>
/// Window 帮助类
/// </summary>
public class WindowHelper
{
/// <summary>
/// 获取当前 Window, 找不到 Active Window 时返回 MainWindow
/// </summary>
/// <returns>当前 Window</returns>
public static Window GetCurrentWindow()
{
var window = Application.Current.Windows.OfType<Window>().FirstOrDefault(x => x.IsActive) ??
Application.Current.MainWindow;
return window;
}
}
}

+ 81
- 0
BPA.UIControl/ControlMask.cs Ver ficheiro

@@ -0,0 +1,81 @@
using BPA.UIControl.Commons.KnownBoxes;
using System.Windows;
using System.Windows.Controls;

namespace BPA.UIControl
{
/// <summary>
/// 控件遮罩
/// 用于提供 MouseOver 和 Pressed 等效果
/// </summary>
public class ControlMask : Control
{
/// <summary>
/// Initializes a new instance of the <see cref="ControlMask"/> class.
/// </summary>
static ControlMask()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ControlMask), new FrameworkPropertyMetadata(typeof(ControlMask)));
}

/// <summary>
/// 是否激活
/// </summary>
public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register(
"IsActive", typeof(bool), typeof(ControlMask), new PropertyMetadata(BooleanBoxes.FalseBox));

/// <summary>
/// 是否激活
/// </summary>
public bool IsActive
{
get { return (bool)GetValue(IsActiveProperty); }
set { SetValue(IsActiveProperty, BooleanBoxes.Box(value)); }
}

/// <summary>
/// 圆角半径
/// </summary>
public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(
"CornerRadius", typeof(CornerRadius), typeof(ControlMask), new PropertyMetadata(default(CornerRadius)));

/// <summary>
/// 圆角半径
/// </summary>
public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}

/// <summary>
/// 遮罩透明度
/// </summary>
public static readonly DependencyProperty MaskOpacityProperty = DependencyProperty.Register(
"MaskOpacity", typeof(double), typeof(ControlMask), new PropertyMetadata(default(double)));

/// <summary>
/// 遮罩透明度
/// </summary>
public double MaskOpacity
{
get { return (double)GetValue(MaskOpacityProperty); }
set { SetValue(MaskOpacityProperty, value); }
}

/// <summary>
/// 父元素 (用于出发 IsMouseOver)
/// </summary>
public static readonly DependencyProperty ParentElementProperty = DependencyProperty.Register(
"ParentElement", typeof(UIElement), typeof(ControlMask), new PropertyMetadata(default(UIElement)));

/// <summary>
/// 父元素 (用于出发 IsMouseOver)
/// </summary>
public UIElement ParentElement
{
get { return (UIElement)GetValue(ParentElementProperty); }
set { SetValue(ParentElementProperty, value); }
}
}
}

+ 29
- 0
BPA.UIControl/Converters/BadgeOffsetConverter.cs Ver ficheiro

@@ -0,0 +1,29 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// Badge 偏移计算转换器
/// </summary>
public class BadgeOffsetConverter : IMultiValueConverter
{
/// <inheritdoc/>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var height = (double)values[0];
var width = (double)values[1];
double verOffset = (height / 2) * -1;
double horOffset = (width - (height / 2)) * -1;
return new Thickness(0, verOffset, horOffset, 0);
}

/// <inheritdoc/>
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return null;
}
}
}

+ 64
- 0
BPA.UIControl/Converters/BooleanConverter.cs Ver ficheiro

@@ -0,0 +1,64 @@
using BPA.UIControl.Commons;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// bool 转换器
/// </summary>
/// <typeparam name="T"></typeparam>
public class BooleanConverter<T> : IValueConverter
{
/// <summary>
/// bool 转换器
/// </summary>
/// <param name="trueValue">true 对应值</param>
/// <param name="falseValue">false 对应值</param>
protected BooleanConverter(T trueValue, T falseValue)
{
TrueValue = trueValue;
FalseValue = falseValue;
}

/// <summary>
/// true 对应值
/// </summary>
public T TrueValue { get; set; }

/// <summary>
/// false 对应值
/// </summary>
public T FalseValue { get; set; }

/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return BooleanConverter<T>.ConvertBooleanToType(value, TrueValue, FalseValue);
}

/// <summary>
/// 转换 bool 为类型
/// </summary>
/// <param name="value">bool 值</param>
/// <param name="trueValue">true 时的值</param>
/// <param name="falseValue">false 时的值</param>
/// <returns>类型的值</returns>
internal static T ConvertBooleanToType(object value, T trueValue, T falseValue)
{
bool flag = ValidateArgument.NotNullOrEmptyCast<bool>(value, "value");
return flag ? trueValue : falseValue;
}

/// <inheritdoc/>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is T flag && EqualityComparer<T>.Default.Equals(flag, TrueValue);
}
}
}

+ 18
- 0
BPA.UIControl/Converters/BooleanToBrushConverter.cs Ver ficheiro

@@ -0,0 +1,18 @@
using System.Windows.Media;

namespace BPA.UIControl.Converters
{
/// <summary>
/// bool to brush
/// </summary>
public class BooleanToBrushConverter : BooleanConverter<Brush>
{
/// <summary>
/// Initializes a new instance of the <see cref="BooleanToBrushConverter"/> class.
/// </summary>
public BooleanToBrushConverter()
: base(Brushes.Green, Brushes.Red)
{
}
}
}

+ 16
- 0
BPA.UIControl/Converters/BooleanToInverseConverter.cs Ver ficheiro

@@ -0,0 +1,16 @@
namespace BPA.UIControl.Converters
{
/// <summary>
/// bool - 取反
/// </summary>
public class BooleanToInverseConverter : BooleanConverter<bool>
{
/// <summary>
/// Initializes a new instance of the <see cref="BooleanToInverseConverter"/> class.
/// </summary>
public BooleanToInverseConverter()
: base(false, true)
{
}
}
}

+ 16
- 0
BPA.UIControl/Converters/BooleanToStringConverter.cs Ver ficheiro

@@ -0,0 +1,16 @@
namespace BPA.UIControl.Converters
{
/// <summary>
/// bool to string
/// </summary>
public class BooleanToStringConverter : BooleanConverter<string>
{
/// <summary>
/// Initializes a new instance of the <see cref="BooleanToStringConverter"/> class.
/// </summary>
public BooleanToStringConverter()
: base("true", "false")
{
}
}
}

+ 17
- 0
BPA.UIControl/Converters/BooleanToVisibilityConverter.cs Ver ficheiro

@@ -0,0 +1,17 @@
using System.Windows;

namespace BPA.UIControl.Converters
{
/// <summary>
/// bool - 显示状态转换器
/// </summary>
public class BooleanToVisibilityConverter : BooleanConverter<Visibility>
{
/// <summary>
/// Initializes a new instance of the <see cref="BooleanToVisibilityConverter"/> class.
/// </summary>
public BooleanToVisibilityConverter() : base(Visibility.Visible, Visibility.Collapsed)
{
}
}
}

+ 88
- 0
BPA.UIControl/Converters/CarouselScaleConvereter.cs Ver ficheiro

@@ -0,0 +1,88 @@
using System;
using System.Diagnostics;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;

namespace BPA.UIControl.Converters
{
/// <summary>
/// 轮播图水平尺度转换
/// </summary>
public class CarouselScaleConvereter : IMultiValueConverter
{
private static double HorizontalScale(object[] values, ScaleTransform scaleTransform)
{
if (!(values[0] is FlipViewItem item) || !(values[3] is double))
{
return scaleTransform.ScaleX;
}

var scrollViewer = item.TryGetParentFromVisualTree<ScrollViewer>();
if (scrollViewer == null || scrollViewer.Name != "PART_ContentScrollViewer")
{
return scaleTransform.ScaleX;
}

var point = new Point(-(scrollViewer.ViewportWidth - item.ActualWidth) / 2, 0);
var targetPosition = item.TransformToVisual(scrollViewer).Transform(point);
var different = Math.Abs(targetPosition.X);
if (different > scrollViewer.ViewportWidth)
{
return 1D;
}

var percent = 1 - different / scrollViewer.ViewportWidth * 2;
return 1 + percent;
}

private static double VerticalScale(object[] values, ScaleTransform scaleTransform)
{
if (!(values[0] is FlipViewItem item) || !(values[4] is double))
{
return scaleTransform.ScaleX;
}

var scrollViewer = item.TryGetParentFromVisualTree<ScrollViewer>();
if (scrollViewer == null || scrollViewer.Name != "PART_ContentScrollViewer")
{
return scaleTransform.ScaleX;
}

var point = new Point(0, -(scrollViewer.ViewportHeight - item.ActualHeight) / 2);
var targetPosition = item.TransformToVisual(scrollViewer).Transform(point);
var different = Math.Abs(targetPosition.Y);
if (different > scrollViewer.ViewportHeight)
{
return 1D;
}

var percent = 1 - different / scrollViewer.ViewportHeight * 2;
return 1 + percent;
}

/// <inheritdoc/>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var scaleTransform = values[1] as ScaleTransform;
var orientation = (Orientation)values[2];

if (orientation == Orientation.Horizontal)
{
return HorizontalScale(values, scaleTransform);
}
else
{
return VerticalScale(values, scaleTransform);
}
}

/// <inheritdoc/>
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

+ 39
- 0
BPA.UIControl/Converters/CloneConverter.cs Ver ficheiro

@@ -0,0 +1,39 @@
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Markup;

namespace BPA.UIControl.Converters
{
/// <summary>
/// 克隆内容
/// </summary>
public class CloneConverter : IValueConverter
{
/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{
return value;
}

try
{
string xaml = XamlWriter.Save(value);
var cloneValue = XamlReader.Parse(xaml);
return cloneValue;
}
catch (Exception)
{
return value;
}
}

/// <inheritdoc/>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

+ 26
- 0
BPA.UIControl/Converters/ComboBoxPopupWidthConverter.cs Ver ficheiro

@@ -0,0 +1,26 @@
using System;
using System.Globalization;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// ComboBox 弹窗宽度转换
/// </summary>
public class ComboBoxPopupWidthConverter : IMultiValueConverter
{
/// <inheritdoc/>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var width = (double)values[0];
var marginLeft = (double)values[1];
return width + (marginLeft * 2);
}

/// <inheritdoc/>
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return null;
}
}
}

+ 30
- 0
BPA.UIControl/Converters/DataGridRowIndexConverter.cs Ver ficheiro

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// to data grid row index
/// </summary>
public class DataGridRowIndexConverter : IValueConverter
{
/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is DataGridRow row ? row.GetIndex() + 1 : 0;
}

/// <inheritdoc/>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
}

+ 28
- 0
BPA.UIControl/Converters/DoubleToGridLengthConverter.cs Ver ficheiro

@@ -0,0 +1,28 @@
using BPA.UIControl.Commons;
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// double -> GridLength
/// </summary>
public class DoubleToGridLengthConverter : IValueConverter
{
/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var doubleValue = ValidateArgument.NotNullOrEmptyCast<double>(value, "value");
return new GridLength(doubleValue);
}

/// <inheritdoc/>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var gridLength = ValidateArgument.NotNullOrEmptyCast<GridLength>(value, "value");
return gridLength.Value;
}
}
}

+ 76
- 0
BPA.UIControl/Converters/DoubleToThicknessConverter.cs Ver ficheiro

@@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// double => Thickness
/// </summary>
public class DoubleToThicknessConverter : IValueConverter
{
/// <summary>
/// Thickness 模式
/// </summary>
public ThicknessMode Mode { get; set; }

/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is double thickness)
{
switch (Mode)
{
case ThicknessMode.All:
default:
return new Thickness(thickness);

case ThicknessMode.LeftAndRight:
return new Thickness(thickness, 0, thickness, 0);

case ThicknessMode.Left:
return new Thickness(thickness, 0, 0, 0);

case ThicknessMode.Right:
return new Thickness(0, 0, thickness, 0);

case ThicknessMode.TopAndBottom:
return new Thickness(0, thickness, 0, thickness);

case ThicknessMode.Top:
return new Thickness(0, thickness, 0, 0);

case ThicknessMode.Bottom:
return new Thickness(0, 0, 0, thickness);
}
}

return new Thickness(0);
}

/// <inheritdoc/>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

/// <summary>
/// Thickness 模式
/// </summary>
public enum ThicknessMode
{
All = 0,
LeftAndRight,
Left,
Right,
TopAndBottom,
Top,
Bottom,
}
}

+ 32
- 0
BPA.UIControl/Converters/DoublesToPointConverter.cs Ver ficheiro

@@ -0,0 +1,32 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// 两个数 -> 点
/// </summary>
public class DoublesToPointConverter : IMultiValueConverter
{
/// <inheritdoc/>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length < 2)
{
throw new ArgumentException("参数少于 2 个");
}

double x = System.Convert.ToDouble(values[0]);
double y = System.Convert.ToDouble(values[1]);
return new Point(x, y);
}

/// <inheritdoc/>
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return null;
}
}
}

+ 33
- 0
BPA.UIControl/Converters/DoublesToSizeConverter.cs Ver ficheiro

@@ -0,0 +1,33 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// 2 double -> Size
/// </summary>
public class DoublesToSizeConverter : IMultiValueConverter
{
/// <inheritdoc/>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length < 2)
{
throw new ArgumentException("参数少于 2 个");
}

double width = System.Convert.ToDouble(values[0]);
double height = System.Convert.ToDouble(values[1]);

return new Size(width, height);
}

/// <inheritdoc/>
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return null;
}
}
}

+ 30
- 0
BPA.UIControl/Converters/EnumGetDescriptionConverter.cs Ver ficheiro

@@ -0,0 +1,30 @@
using BPA.UIControl.Commons;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// 枚举获取说明
/// </summary>
public class EnumGetDescriptionConverter : IValueConverter
{
/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var enumValue = ValidateArgument.NotNullOrEmptyCast<Enum>(value, "value");
return enumValue.GetDescription();
}

/// <inheritdoc/>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Binding.DoNothing;
}
}
}

+ 49
- 0
BPA.UIControl/Converters/EnumToBooleanConverter.cs Ver ficheiro

@@ -0,0 +1,49 @@
using BPA.UIControl.Commons;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// enum -> bool
/// </summary>
public class EnumToBooleanConverter : IValueConverter
{
/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return EnumToBooleanConverter.ConvertEnumToBool(value, parameter);
}

/// <summary>
/// Converts the enum to bool.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="parameter">The parameter.</param>
/// <returns>A bool.</returns>
internal static bool ConvertEnumToBool(object value, object parameter)
{
string text = ValidateArgument.NotNullOrEmptyCast<string>(parameter, "parameter");
ValidateArgument.NotNull(value, "value");
return text.Equals(value.ToString());
}

/// <inheritdoc/>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
bool flag = ValidateArgument.NotNullOrEmptyCast<bool>(value, "value");
string text = ValidateArgument.NotNullOrEmptyCast<string>(parameter, "paramater");
if (flag)
{
return Enum.Parse(targetType, text, false);
}

return null;
}
}
}

+ 24
- 0
BPA.UIControl/Converters/EnumToBooleanInverseConverter.cs Ver ficheiro

@@ -0,0 +1,24 @@
using System;
using System.Globalization;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// enum -> inverse bool
/// </summary>
public class EnumToBooleanInverseConverter : IValueConverter
{
/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return !EnumToBooleanConverter.ConvertEnumToBool(value, parameter);
}

/// <inheritdoc/>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

+ 62
- 0
BPA.UIControl/Converters/EnumToVisibilityConverter.cs Ver ficheiro

@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// enum => Visiblity
/// </summary>
public class EnumToVisibilityConverter : IValueConverter
{
/// <summary>
/// true 对应 Visibility
/// </summary>
public Visibility TrueVisibility { get; set; }

/// <summary>
/// false 对应 Visibility
/// </summary>
public Visibility FalseVisibility { get; set; }

/// <summary>
/// Initializes a new instance of the <see cref="EnumToVisibilityConverter"/> class.
/// </summary>
public EnumToVisibilityConverter()
{
TrueVisibility = Visibility.Visible;
FalseVisibility = Visibility.Collapsed;
}

/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return EnumToVisibilityConverter.ConvertEnumToVisibility(value, parameter, TrueVisibility, FalseVisibility);
}

/// <summary>
/// Converts the enum to visibility.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="parameter">The parameter.</param>
/// <param name="trueVisibility">The true visibility.</param>
/// <param name="falseVisibility">The false visibility.</param>
/// <returns>An object.</returns>
public static object ConvertEnumToVisibility(object value, object parameter, Visibility trueVisibility, Visibility falseVisibility)
{
bool flag = EnumToBooleanConverter.ConvertEnumToBool(value, parameter);
return BooleanConverter<Visibility>.ConvertBooleanToType(flag, trueVisibility, falseVisibility);
}

/// <inheritdoc/>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

+ 41
- 0
BPA.UIControl/Converters/GetArcPointConverter.cs Ver ficheiro

@@ -0,0 +1,41 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// 4 个 double 计算 Arc 点
/// </summary>
public class GetArcPointConverter : IMultiValueConverter
{
/// <inheritdoc/>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length < 4)
{
throw new ArgumentException("参数少于 4 个");
}

double value = System.Convert.ToDouble(values[0]);
double min = System.Convert.ToDouble(values[1]);
double max = System.Convert.ToDouble(values[2]);
double radius = System.Convert.ToDouble(values[3]) / 2;

double percent = (value - min) / (max - min) >= 1 ? 0.9999 : value / (max - min);
double angle = percent * 360;

double pointX = Math.Sin(angle * Math.PI / 180) * radius + radius;
double pointY = (Math.Cos(angle * Math.PI / 180) * radius - radius) * -1;

return new Point(pointX, pointY);
}

/// <inheritdoc/>
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return null;
}
}
}

+ 28
- 0
BPA.UIControl/Converters/GetCanvasCentreConverter.cs Ver ficheiro

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// 获取 Canvas 中心点
/// </summary>
public class GetCanvasCentreConverter : IMultiValueConverter
{
/// <inheritdoc/>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return ((double)values[0] - (double)values[1]) / 2;
}

/// <inheritdoc/>
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return null;
}
}
}

+ 46
- 0
BPA.UIControl/Converters/GetDataGridColumnCheckedContentConverter.cs Ver ficheiro

@@ -0,0 +1,46 @@
using BPA.UIControl.Commons;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// 获取 DataGridColumn 的 CheckedContent 属性
/// </summary>
public class GetDataGridColumnCheckedContentConverter : IMultiValueConverter
{
/// <inheritdoc/>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length < 2)
{
throw new ArgumentException("the values length can't be less the 2.");
}

var dataGrid = ValidateArgument.NotNullOrEmptyCast<DataGrid>(values[0], "values[0]");
var columnHeader = ValidateArgument.NotNullOrEmptyCast<DataGridColumnHeader>(values[1], "values[1]");
foreach (var column in dataGrid.Columns)
{
if (columnHeader.Column == column)
{
return ToggleButtonHelper.GetCheckedContent(column) ?? column.Header;
}
}

return null;
}

/// <inheritdoc/>
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return null;
}
}
}

+ 34
- 0
BPA.UIControl/Converters/GetPercentConverter.cs Ver ficheiro

@@ -0,0 +1,34 @@
using System;
using System.Globalization;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// 获取百分比
/// </summary>
public class GetPercentConverter : IMultiValueConverter
{
/// <inheritdoc/>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length < 3)
{
throw new ArgumentException("参数少于 3 个");
}

double value = System.Convert.ToDouble(values[0]);
double min = System.Convert.ToDouble(values[1]);
double max = System.Convert.ToDouble(values[2]);
double percent = (value - min) / (max - min);

return $"{System.Convert.ToInt32(percent * 100)}%";
}

/// <inheritdoc/>
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return null;
}
}
}

+ 24
- 0
BPA.UIControl/Converters/GetWidthConverter.cs Ver ficheiro

@@ -0,0 +1,24 @@
using System;
using System.Globalization;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// The get width converter.
/// </summary>
public class GetWidthConverter : IMultiValueConverter
{
/// <inheritdoc/>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return (double)values[0] - (double)values[1] * 2;
}

/// <inheritdoc/>
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return null;
}
}
}

+ 25
- 0
BPA.UIControl/Converters/HalfOfDoubleConverter.cs Ver ficheiro

@@ -0,0 +1,25 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// double 值一半转换器
/// </summary>
public class HalfOfDoubleConverter : IValueConverter
{
/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is double d ? d / 2 : DependencyProperty.UnsetValue;
}

/// <inheritdoc/>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
}

+ 83
- 0
BPA.UIControl/Converters/InsideCornerRadiusConverter.cs Ver ficheiro

@@ -0,0 +1,83 @@
using BPA.UIControl.Commons;
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// 内圆角半径转换
/// </summary>
public class InsideCornerRadiusConverter : IMultiValueConverter
{
/// <summary>
/// 内圆角半径类型
/// </summary>
public enum InsideCornerRadiusType
{
/// <summary>
/// 全部方向
/// </summary>
All = 0,

/// <summary>
/// 上方向
/// </summary>
Top,

/// <summary>
/// 下方向
/// </summary>
Bottom,

/// <summary>
/// 左方向
/// </summary>
Left,

/// <summary>
/// 右方向
/// </summary>
Right,
}

/// <summary>
/// 内圆角半径类型
/// </summary>
public InsideCornerRadiusType Type { get; set; }

/// <inheritdoc/>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length < 2)
{
throw new ArgumentException("values length not less then 2.");
}

var thickness = ValidateArgument.NotNullOrEmptyCast<Thickness>(values[0], "values[0]");
var cornerRadius = ValidateArgument.NotNullOrEmptyCast<CornerRadius>(values[1], "values[1]");
var insideCornerRadius = cornerRadius.TopLeft - (thickness.Left / 2);
if (insideCornerRadius < 0)
{
insideCornerRadius = 0;
}

return Type switch
{
InsideCornerRadiusType.All => new CornerRadius(insideCornerRadius),
InsideCornerRadiusType.Top => new CornerRadius(insideCornerRadius, insideCornerRadius, 0, 0),
InsideCornerRadiusType.Bottom => new CornerRadius(0, 0, insideCornerRadius, insideCornerRadius),
InsideCornerRadiusType.Left => new CornerRadius(insideCornerRadius, 0, insideCornerRadius, 0),
InsideCornerRadiusType.Right => new CornerRadius(0, insideCornerRadius, 0, insideCornerRadius),
_ => new CornerRadius(insideCornerRadius),
};
}

/// <inheritdoc/>
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

+ 24
- 0
BPA.UIControl/Converters/IsEqualConverter.cs Ver ficheiro

@@ -0,0 +1,24 @@
using System;
using System.Globalization;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// 是否相等
/// </summary>
public class IsEqualConverter : IMultiValueConverter
{
/// <inheritdoc/>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return values[0].Equals(values[1]);
}

/// <inheritdoc/>
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return null;
}
}
}

+ 36
- 0
BPA.UIControl/Converters/IsLargeArcConverter.cs Ver ficheiro

@@ -0,0 +1,36 @@
using System;
using System.Globalization;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// 是否为大弧形
/// </summary>
public class IsLargeArcConverter : IMultiValueConverter
{
/// <inheritdoc/>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length < 3)
{
throw new ArgumentException("参数少于 3 个");
}

double value = System.Convert.ToDouble(values[0]);
double min = System.Convert.ToDouble(values[1]);
double max = System.Convert.ToDouble(values[2]);

double percent = value / (max - min) > 1 ? 1 : value / (max - min);
double angle = percent * 360;

return angle > 180;
}

/// <inheritdoc/>
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return null;
}
}
}

+ 25
- 0
BPA.UIControl/Converters/IsNullOrEmptyConverter.cs Ver ficheiro

@@ -0,0 +1,25 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// 是否为 null 或空字符串
/// </summary>
public class IsNullOrEmptyConverter : IValueConverter
{
/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null || string.IsNullOrEmpty(value.ToString());
}

/// <inheritdoc/>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
}

+ 41
- 0
BPA.UIControl/Converters/ListViewGridViewConverter.cs Ver ficheiro

@@ -0,0 +1,41 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// ListView 的 GridView Style 选择转换器
/// </summary>
public class ListViewGridViewConverter : IValueConverter
{
/// <summary>
/// 默认 ListView 样式
/// </summary>
public Style DefaultStyle { get; set; }

/// <summary>
/// GridView 样式
/// </summary>
public Style ViewStyle { get; set; }

/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is ListView listView)
{
return listView.View != null ? ViewStyle : DefaultStyle;
}

return value is ViewBase ? ViewStyle : DefaultStyle;
}

/// <inheritdoc/>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Binding.DoNothing;
}
}
}

+ 51
- 0
BPA.UIControl/Converters/MathConverter.cs Ver ficheiro

@@ -0,0 +1,51 @@
using BPA.UIControl.Commons;
using System;
using System.Globalization;
using System.Windows.Data;
using static BPA.UIControl.Converters.MathMultipleConverter;

namespace BPA.UIControl.Converters
{
/// <summary>
/// 数学计算转换器
/// </summary>
public class MathConverter : IValueConverter
{
/// <summary>
/// 计算操作类型
/// </summary>
public MathOperation Operation { get; set; }

/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
ValidateArgument.NotNull(value, nameof(value));
ValidateArgument.NotNull(parameter, nameof(parameter));

if (!double.TryParse(value.ToString(), out double num1) || !double.TryParse(parameter.ToString(), out double num2))
return 0;

switch (Operation)
{
case MathOperation.Add:
default:
return num1 + num2;

case MathOperation.Divide:
return num1 / num2;

case MathOperation.Multiply:
return num1 * num2;

case MathOperation.Subtract:
return num1 - num2;
}
}

/// <inheritdoc/>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

+ 78
- 0
BPA.UIControl/Converters/MathMultipleConverter.cs Ver ficheiro

@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// 数学计算多转换器
/// </summary>
public class MathMultipleConverter : IMultiValueConverter
{
/// <summary>
/// 计算操作类型
/// </summary>
public enum MathOperation
{
/// <summary>
/// 加
/// </summary>
Add,

/// <summary>
/// 减
/// </summary>
Subtract,

/// <summary>
/// 乘
/// </summary>
Multiply,

/// <summary>
/// 除
/// </summary>
Divide
}

/// <summary>
/// 计算操作类型
/// </summary>
public MathOperation Operation { get; set; }

/// <inheritdoc/>
public object Convert(object[] value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || value.Length < 2 || value[0] == null || value[1] == null) return Binding.DoNothing;

if (!double.TryParse(value[0].ToString(), out double value1) || !double.TryParse(value[1].ToString(), out double value2))
return 0;

switch (Operation)
{
case MathOperation.Add:
default:
return value1 + value2;

case MathOperation.Divide:
return value1 / value2;

case MathOperation.Multiply:
return value1 * value2;

case MathOperation.Subtract:
return value1 - value2;
}
}

/// <inheritdoc/>
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

+ 25
- 0
BPA.UIControl/Converters/NotNullConverter.cs Ver ficheiro

@@ -0,0 +1,25 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// 是否不为 null 转换器
/// </summary>
public class NotNullConverter : IValueConverter
{
/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value != null;
}

/// <inheritdoc/>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
}

+ 25
- 0
BPA.UIControl/Converters/NotNullOrEmptyConverter.cs Ver ficheiro

@@ -0,0 +1,25 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// string 不为 null 或者 empty
/// </summary>
public class NotNullOrEmptyConverter : IValueConverter
{
/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value != null && !string.IsNullOrEmpty(value.ToString());
}

/// <inheritdoc/>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
}

+ 41
- 0
BPA.UIControl/Converters/NullToVisibilityConverter.cs Ver ficheiro

@@ -0,0 +1,41 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// null -> Visiblity
/// </summary>
public class NullToVisibilityConverter : IValueConverter
{
/// <summary>
/// null 对应 Visibility
/// </summary>
public Visibility NullVisibility { get; set; }

/// <summary>
/// 非 null 对应 Visibility
/// </summary>
public Visibility NotNullVisibility { get; set; }

public NullToVisibilityConverter()
{
NullVisibility = Visibility.Collapsed;
NotNullVisibility = Visibility.Visible;
}

/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is null ? NullVisibility : NotNullVisibility;
}

/// <inheritdoc/>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

+ 37
- 0
BPA.UIControl/Converters/VisibilityToBooleanConverter.cs Ver ficheiro

@@ -0,0 +1,37 @@
using BPA.UIControl.Commons;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;

namespace BPA.UIControl.Converters
{
/// <summary>
/// Visibility -> bool
/// </summary>
public class VisibilityToBooleanConverter : IValueConverter
{
/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ConvertVisibilityToBool(value);
}

internal static bool ConvertVisibilityToBool(object value)
{
Visibility visibility = ValidateArgument.NotNullOrEmptyCast<Visibility>(value, "value");
return visibility == Visibility.Visible;
}

/// <inheritdoc/>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
bool flag = ValidateArgument.NotNullOrEmptyCast<bool>(value, "value");
return flag ? Visibility.Visible : Visibility.Collapsed;
}
}
}

+ 27
- 0
BPA.UIControl/DataAnnotations/ColumnWidthAttribute.cs Ver ficheiro

@@ -0,0 +1,27 @@
using System;
using System.Windows.Controls;

namespace BPA.UIControl.DataAnnotations
{
/// <summary>
/// DataGrid 列宽
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class ColumnWidthAttribute : Attribute
{
/// <summary>
/// 列宽
/// </summary>
public DataGridLength Width { get; }

/// <summary>
/// DataGrid 列宽
/// </summary>
/// <param name="width">列宽</param>
public ColumnWidthAttribute(string width)
{
var converter = new DataGridLengthConverter();
Width = (DataGridLength)converter.ConvertFromString(width);
}
}
}

+ 138
- 0
BPA.UIControl/DataGridDetailToggleButtonColumn.cs Ver ficheiro

@@ -0,0 +1,138 @@
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;

namespace BPA.UIControl
{
/// <summary>
/// DataGrid 详细内容展开列
/// </summary>
public class DataGridDetailToggleButtonColumn : DataGridBoundColumn
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridDetailToggleButtonColumn"/> class.
/// </summary>
static DataGridDetailToggleButtonColumn()
{
var elementStyle = (Style)Application.Current.FindResource("RubyerDataGridDetailToggleButtonColumn");
DataGridBoundColumn.ElementStyleProperty.OverrideMetadata(typeof(DataGridDetailToggleButtonColumn), new FrameworkPropertyMetadata(elementStyle));
DataGridBoundColumn.EditingElementStyleProperty.OverrideMetadata(typeof(DataGridDetailToggleButtonColumn), new FrameworkPropertyMetadata(elementStyle));
}

/// <inheritdoc/>
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
return GenerateToggleButton(isEditing: false, cell);
}

/// <inheritdoc/>
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
{
return GenerateToggleButton(isEditing: true, cell);
}

/// <summary>
/// Applies the binding.
/// </summary>
/// <param name="target">The target.</param>
/// <param name="property">The property.</param>
internal void ApplyBinding(DependencyObject target, DependencyProperty property)
{
BindingBase binding = Binding;
if (binding != null)
{
BindingOperations.SetBinding(target, property, binding);
}
else
{
BindingOperations.ClearBinding(target, property);
}
}

/// <summary>
/// Applies the style.
/// </summary>
/// <param name="isEditing">If true, is editing.</param>
/// <param name="defaultToElementStyle">If true, default to element style.</param>
/// <param name="element">The element.</param>
internal void ApplyStyle(bool isEditing, bool defaultToElementStyle, FrameworkElement element)
{
Style style = PickStyle(isEditing, defaultToElementStyle);
if (style != null)
{
element.Style = style;
}
}

/// <summary>
/// Picks the style.
/// </summary>
/// <param name="isEditing">If true, is editing.</param>
/// <param name="defaultToElementStyle">If true, default to element style.</param>
/// <returns>A Style.</returns>
private Style PickStyle(bool isEditing, bool defaultToElementStyle)
{
Style style = (isEditing ? EditingElementStyle : ElementStyle);
if (isEditing && defaultToElementStyle && style == null)
{
style = ElementStyle;
}

return style;
}

/// <summary>
/// Generates the toggle button.
/// </summary>
/// <param name="isEditing">If true, is editing.</param>
/// <param name="cell">The cell.</param>
/// <returns>A ToggleButton.</returns>
private ToggleButton GenerateToggleButton(bool isEditing, DataGridCell cell)
{
ToggleButton toggleButton = (cell != null) ? (cell.Content as ToggleButton) : null;
toggleButton ??= new ToggleButton();
toggleButton.IsThreeState = false;
ApplyStyle(isEditing, defaultToElementStyle: true, toggleButton);
ApplyBinding(toggleButton, ToggleButton.IsCheckedProperty);
return toggleButton;
}

/// <inheritdoc/>
protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
{
if (editingElement is ToggleButton toggleButton)
{
toggleButton.Focus();
bool? isChecked = toggleButton.IsChecked;
if (IsMouseLeftButtonDown(editingEventArgs))
{
toggleButton.IsChecked = !isChecked.GetValueOrDefault();
var dataGridCell = editingElement.GetVisualAncestry().OfType<DataGridCell>().FirstOrDefault();
dataGridCell.IsEditing = false;
}

return isChecked;
}

return false;
}

/// <summary>
/// Are the mouse left button down.
/// </summary>
/// <param name="e">The e.</param>
/// <returns>A bool.</returns>
private static bool IsMouseLeftButtonDown(RoutedEventArgs e)
{
if (e is MouseButtonEventArgs mouseButtonEventArgs && mouseButtonEventArgs.ChangedButton == MouseButton.Left)
{
return mouseButtonEventArgs.ButtonState == MouseButtonState.Pressed;
}

return false;
}
}
}

+ 188
- 0
BPA.UIControl/DataGridSelectCheckBoxColumn.cs Ver ficheiro

@@ -0,0 +1,188 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;

namespace BPA.UIControl
{
/// <summary>
/// DataGrid 选择列
/// </summary>
public class DataGridSelectCheckBoxColumn : DataGridCheckBoxColumn
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridSelectCheckBoxColumn"/> class.
/// </summary>
static DataGridSelectCheckBoxColumn()
{
}

/// <summary>
/// Initializes a new instance of the <see cref="DataGridSelectCheckBoxColumn"/> class.
/// </summary>
public DataGridSelectCheckBoxColumn()
{
var headStyle = (Style)Application.Current.FindResource("DataGridSelectCheckBoxColumnHeader");
HeaderStyle = headStyle;
CanUserSort = false;
}

/// <inheritdoc/>
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
return GenerateCheckBox(false, cell);
}

/// <inheritdoc/>
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
{
return GenerateCheckBox(true, cell);
}

private CheckBox GenerateCheckBox(bool isEditing, DataGridCell cell)
{
CheckBox checkBox = (cell != null) ? (cell.Content as CheckBox) : null;
if (checkBox == null)
{
checkBox = new CheckBox();

if (!isEditing)
{
checkBox.Loaded += CheckBox_Checked;
checkBox.Checked += CheckBox_Checked;
checkBox.Unchecked += CheckBox_Checked;
}
}

checkBox.IsThreeState = IsThreeState;
ApplyStyle(isEditing, defaultToElementStyle: true, checkBox);
ApplyBinding(checkBox, ToggleButton.IsCheckedProperty);
return checkBox;
}

private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
if (sender is CheckBox checkBox)
{
var dataGrid = checkBox.TryGetParentFromVisualTree<DataGrid>();
var columnHeader = GetHeader(this, dataGrid);
var headerCheckBox = columnHeader.TryGetChildFromVisualTree<CheckBox>(x => x is CheckBox);
if (headerCheckBox is null)
{
return;
}

var allValues = new List<bool?>();
foreach (var item in dataGrid.Items)
{
var row = dataGrid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
var cellsPresenter = row.TryGetChildFromVisualTree<DataGridCellsPresenter>(x => x is DataGridCellsPresenter);
if (cellsPresenter is null)
{
continue;
}

var cell = cellsPresenter.ItemContainerGenerator.ContainerFromIndex(DisplayIndex) as DataGridCell;
var currentCheckBox = cell.TryGetChildFromVisualTree<CheckBox>(x => x is CheckBox);
allValues.Add(currentCheckBox.IsChecked);
}

if (allValues.All(x => x == true))
{
headerCheckBox.IsChecked = true;
}
else if (allValues.All(x => x == false))
{
headerCheckBox.IsChecked = false;
}
else
{
headerCheckBox.IsChecked = null;
}
}
}

/// <inheritdoc/>
protected override bool CommitCellEdit(FrameworkElement editingElement)
{
return base.CommitCellEdit(editingElement);
}

private DataGridColumnHeader GetHeader(DataGridColumn column, DependencyObject reference)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(reference); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(reference, i);
if ((child is DataGridColumnHeader colHeader) && (colHeader.Column == column))
{
return colHeader;
}

colHeader = GetHeader(column, child);
if (colHeader != null)
{
return colHeader;
}
}

return null;
}

/// <summary>
/// Applies the binding.
/// </summary>
/// <param name="target">The target.</param>
/// <param name="property">The property.</param>
internal void ApplyBinding(DependencyObject target, DependencyProperty property)
{
BindingBase binding = Binding;
if (binding != null)
{
BindingOperations.SetBinding(target, property, binding);
}
else
{
BindingOperations.ClearBinding(target, property);
}
}

/// <summary>
/// Applies the style.
/// </summary>
/// <param name="isEditing">If true, is editing.</param>
/// <param name="defaultToElementStyle">If true, default to element style.</param>
/// <param name="element">The element.</param>
internal void ApplyStyle(bool isEditing, bool defaultToElementStyle, FrameworkElement element)
{
Style style = PickStyle(isEditing, defaultToElementStyle);
if (style != null)
{
element.Style = style;
}
}

/// <summary>
/// Picks the style.
/// </summary>
/// <param name="isEditing">If true, is editing.</param>
/// <param name="defaultToElementStyle">If true, default to element style.</param>
/// <returns>A Style.</returns>
private Style PickStyle(bool isEditing, bool defaultToElementStyle)
{
Style style = (isEditing ? EditingElementStyle : ElementStyle);
if (isEditing && defaultToElementStyle && style == null)
{
style = ElementStyle;
}

return style;
}
}
}

+ 359
- 0
BPA.UIControl/DateTimePicker.cs Ver ficheiro

@@ -0,0 +1,359 @@
using BPA.UIControl.Commons.KnownBoxes;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;

namespace BPA.UIControl
{
/// <summary>
/// 日期时间选择器
/// </summary>
[TemplatePart(Name = TextBoxPartName, Type = typeof(TextBox))]
[TemplatePart(Name = CurrentTextBoxPartName, Type = typeof(TextBox))]
[TemplatePart(Name = PopupPartName, Type = typeof(Popup))]
[TemplatePart(Name = ButtonPartName, Type = typeof(Button))]
[TemplatePart(Name = ClockPartName, Type = typeof(Clock))]
[TemplatePart(Name = CalendarPartName, Type = typeof(Calendar))]
[TemplatePart(Name = ConfirmButtonPartName, Type = typeof(Button))]
public class DateTimePicker : Control
{
const string TextBoxPartName = "PART_TextBox";
const string PopupPartName = "PART_Popup";
const string ButtonPartName = "PART_Button";
const string ClockPartName = "PART_Clock";
const string CalendarPartName = "PART_Calendar";
const string ConfirmButtonPartName = "PART_ConfirmButton";
const string CurrentTextBoxPartName = "PART_CurrentTextBox";

private TextBox _textBox;
private Popup _popup;
private Clock _clock;
private Calendar _calendar;
private Button _confirmButton;

private bool isInternalSetting = true;
private DateTime currentDateTime;

/// <summary>
/// Initializes a new instance of the <see cref="DateTimePicker"/> class.
/// </summary>
static DateTimePicker()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DateTimePicker), new FrameworkPropertyMetadata(typeof(DateTimePicker)));
}

/// <inheritdoc/>
public override void OnApplyTemplate()
{
base.OnApplyTemplate();

Clock clock = GetTemplateChild(ClockPartName) as Clock;
clock.CurrentTimeChanged += Clock_SelectedTimeChanged;
this._clock = clock;

Calendar calendar = GetTemplateChild(CalendarPartName) as Calendar;
calendar.SelectedDatesChanged += Calendar_SelectedDatesChanged;
this._calendar = calendar;

TextBox textBox = GetTemplateChild(TextBoxPartName) as TextBox;
Binding binding1 = new Binding("Text");
binding1.Source = this;
binding1.Mode = BindingMode.TwoWay;
textBox.SetBinding(TextBox.TextProperty, binding1);
_textBox = textBox;

Popup popup = GetTemplateChild(PopupPartName) as Popup;
popup.Closed += Popup_Closed;
popup.Opened += Popup_Opened;
if (IsDropDownOpen)
{
_popup.IsOpen = true;
}
_popup = popup;

Button button = GetTemplateChild(ButtonPartName) as Button;
button.Click += Button_Click;

Button confirmButton = GetTemplateChild(ConfirmButtonPartName) as Button;
confirmButton.Click += ConfirmButton_Click;
_confirmButton = confirmButton;

currentDateTime = SelectedDateTime == null ? DateTime.Now : SelectedDateTime.Value;
}

#region 路由事件

/// <summary>
/// 选择时间改变事件
/// </summary>
public static readonly RoutedEvent SelectedTimeChangedEvent =
EventManager.RegisterRoutedEvent("SelectedTimeChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<DateTime?>), typeof(DateTimePicker));

/// <summary>
/// 选择时间改变事件处理
/// </summary>
public event RoutedPropertyChangedEventHandler<DateTime?> SelectedTimeChanged
{
add { AddHandler(SelectedTimeChangedEvent, value); }
remove { RemoveHandler(SelectedTimeChangedEvent, value); }
}

#endregion 路由事件

#region 依赖属性

/// <summary>
/// 选择的日期时间
/// </summary>
public static readonly DependencyProperty SelectedDateTimeProperty = DependencyProperty.Register(
"SelectedDateTime", typeof(DateTime?), typeof(DateTimePicker), new FrameworkPropertyMetadata(default(DateTime?), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedTimeChanged));

/// <summary>
/// 选择的日期时间
/// </summary>
public DateTime? SelectedDateTime
{
get { return (DateTime?)GetValue(SelectedDateTimeProperty); }
set { SetValue(SelectedDateTimeProperty, value); }
}

/// <summary>
/// 是否下拉打开
/// </summary>
public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register(
"IsDropDownOpen", typeof(bool), typeof(DateTimePicker), new PropertyMetadata(BooleanBoxes.FalseBox, OnIsDropDownOpenChanged));

/// <summary>
/// 是否下拉打开
/// </summary>
public bool IsDropDownOpen
{
get { return (bool)GetValue(IsDropDownOpenProperty); }
set { SetValue(IsDropDownOpenProperty, BooleanBoxes.Box(value)); }
}

/// <summary>
/// Ons the is drop down open changed.
/// </summary>
/// <param name="d">The d.</param>
/// <param name="e">The e.</param>
private static void OnIsDropDownOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DateTimePicker tp = d as DateTimePicker;
bool newValue = (bool)e.NewValue;
if (tp._popup != null && tp._popup.IsOpen != newValue)
{
tp._popup.IsOpen = newValue;
if (newValue)
{
tp.Dispatcher.BeginInvoke(DispatcherPriority.Input, (Action)delegate ()
{
tp._clock.Focus();
});
}
}
}

/// <summary>
/// 显示文本
/// </summary>
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text", typeof(string), typeof(DateTimePicker), new PropertyMetadata(null, OnTextChanged));

/// <summary>
/// 显示文本
/// </summary>
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}

/// <summary>
/// 时间文本改变
/// </summary>
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DateTimePicker dateTimePicker = (DateTimePicker)d;

var oldDateTime = dateTimePicker.SelectedDateTime?.ToString(dateTimePicker.SelectedDateTimeFormat);
if (oldDateTime != dateTimePicker.Text)
{
if (DateTime.TryParse(dateTimePicker.Text, out DateTime result))
{
dateTimePicker.SelectedDateTime = result;
dateTimePicker.currentDateTime = result;
}
else if (string.IsNullOrEmpty(dateTimePicker.Text))
{
dateTimePicker.SelectedDateTime = null;
}
else
{
dateTimePicker.Text = oldDateTime;
}
}
}

/// <summary>
/// 选择时间格式化
/// </summary>
public static readonly DependencyProperty SelectedDateTimeFormatProperty = DependencyProperty.Register(
"SelectedDateTimeFormat", typeof(string), typeof(DateTimePicker), new PropertyMetadata(default(string), OnSelectedDateTimeFormatChanged));

private static void OnSelectedDateTimeFormatChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is DateTimePicker picker)
{
picker.Text = picker.SelectedDateTime?.ToString(picker.SelectedDateTimeFormat);
}
}

/// <summary>
/// 选择时间格式化
/// </summary>
public string SelectedDateTimeFormat
{
get { return (string)GetValue(SelectedDateTimeFormatProperty); }
set { SetValue(SelectedDateTimeFormatProperty, value); }
}

#endregion 依赖属性

#region 方法

/// <summary>
/// 文本鼠标点下
/// </summary>
private void TextBox_MouseDown(object sender, MouseButtonEventArgs e)
{
TextBox textBox = sender as TextBox;
textBox.Focus();
}

/// <summary>
/// 选择时间改变
/// </summary>
private static void OnSelectedTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is DateTimePicker dateTimePicker)
{
dateTimePicker.Text = dateTimePicker.SelectedDateTime?.ToString(dateTimePicker.SelectedDateTimeFormat);

var args = new RoutedPropertyChangedEventArgs<DateTime?>((DateTime?)e.OldValue, (DateTime?)e.NewValue);
args.RoutedEvent = DateTimePicker.SelectedTimeChangedEvent;
dateTimePicker.RaiseEvent(args);

dateTimePicker.currentDateTime = dateTimePicker.SelectedDateTime == null ? DateTime.Now : dateTimePicker.SelectedDateTime.Value;

dateTimePicker._textBox?.Focus();
dateTimePicker._textBox?.SelectAll();
}
}

/// <summary>
/// 时钟的时间改变
/// </summary>
private void Clock_SelectedTimeChanged(object sender, RoutedPropertyChangedEventArgs<DateTime?> e)
{
if (isInternalSetting)
{
return;
}

if (SelectedDateTime != null)
{
DateTime dateTime = (DateTime)SelectedDateTime;
DateTime newDate = (DateTime)e.NewValue;
currentDateTime = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, newDate.Hour, newDate.Minute, newDate.Second);
}
else
{
currentDateTime = e.NewValue.Value;
}

}

/// <summary>
/// 日期改变
/// </summary>
private void Calendar_SelectedDatesChanged(object sender, SelectionChangedEventArgs e)
{
if (isInternalSetting)
{
return;
}

if (SelectedDateTime != null)
{
DateTime dateTime = (DateTime)SelectedDateTime;
DateTime newTime = (DateTime)_calendar.SelectedDate;
currentDateTime = new DateTime(newTime.Year, newTime.Month, newTime.Day, dateTime.Hour, dateTime.Minute, dateTime.Second);
}
else
{
var time = _clock.CurrentTime == null ? TimeSpan.Zero : _clock.CurrentTime.Value.TimeOfDay;
currentDateTime = (DateTime)_calendar.SelectedDate + time;
}

Mouse.Capture(null);
}

/// <summary>
/// 点击时间按钮
/// </summary>
private void Button_Click(object sender, RoutedEventArgs e)
{
Text = _textBox.Text;
IsDropDownOpen = !IsDropDownOpen;
}

/// <summary>
/// popup 打开后
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Popup_Opened(object sender, EventArgs e)
{
isInternalSetting = true;
_calendar.SelectedDate = currentDateTime.Date;
_calendar.DisplayDate = currentDateTime.Date;
_clock.SelectedTime = currentDateTime;
isInternalSetting = false;
}

/// <summary>
/// popup 关闭
/// </summary>
private void Popup_Closed(object sender, EventArgs e)
{
if (_confirmButton.IsKeyboardFocusWithin)
{
_textBox.Focus();
}
else
{
IsDropDownOpen = false;
}
}

/// <summary>
/// 确定
/// </summary>
private void ConfirmButton_Click(object sender, RoutedEventArgs e)
{
SelectedDateTime = currentDateTime;
IsDropDownOpen = false;

var args = new RoutedPropertyChangedEventArgs<DateTime?>(SelectedDateTime, SelectedDateTime);
args.RoutedEvent = DateTimePicker.SelectedTimeChangedEvent;
RaiseEvent(args);
}

#endregion 方法
}
}








+ 7230
- 0
BPA.UIControl/Demo/Rubyer.xml
A apresentação das diferenças no ficheiro foi suprimida por ser demasiado grande
Ver ficheiro



+ 32
- 0
BPA.UIControl/Demo/RubyerDemo.exe.config Ver ficheiro

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Bcl.AsyncInterfaces" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.ComponentModel.Annotations" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.1.0" newVersion="4.2.1.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>









Alguns ficheiros não foram mostrados porque foram alterados demasiados ficheiros neste diff

Carregando…
Cancelar
Guardar