@@ -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> |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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 |
@@ -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> |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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) | |||
)] |
@@ -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> |
@@ -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); } | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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> |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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> |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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> |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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 | |||
{ | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; } | |||
} | |||
} |
@@ -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 | |||
{ | |||
} | |||
} |
@@ -0,0 +1,9 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
<PropertyGroup> | |||
<TargetFramework>net6.0-windows</TargetFramework> | |||
<Nullable>enable</Nullable> | |||
<UseWPF>true</UseWPF> | |||
</PropertyGroup> | |||
</Project> |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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 属性 | |||
} | |||
} |
@@ -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 方法 | |||
} | |||
} |
@@ -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); } | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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))); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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))); | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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); } | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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) | |||
{ | |||
} | |||
} | |||
} |
@@ -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) | |||
{ | |||
} | |||
} | |||
} |
@@ -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") | |||
{ | |||
} | |||
} | |||
} |
@@ -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) | |||
{ | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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, | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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 方法 | |||
} | |||
} |
@@ -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> |