380 lines
13 KiB
C#
380 lines
13 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using Avalonia;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Controls.Primitives;
|
|
using Avalonia.Data;
|
|
using Avalonia.Input;
|
|
using Avalonia.Layout;
|
|
using Avalonia.Markup.Xaml;
|
|
using Avalonia.Media;
|
|
using Avalonia.Threading;
|
|
using DispenserCommon.Atrributes;
|
|
using DispenserCommon.Utils;
|
|
using Masuit.Tools;
|
|
using ReactiveUI;
|
|
using SQLite;
|
|
|
|
namespace DispenserUI.Views.Controls;
|
|
|
|
/// <summary>
|
|
/// 参数配置编辑器
|
|
/// </summary>
|
|
public partial class SettingEditor : UserControl
|
|
{
|
|
public event EventHandler<object> OnSaveClicked;
|
|
|
|
public static readonly StyledProperty<object> ParamProperty =
|
|
AvaloniaProperty.Register<SettingEditor, object>(nameof(Param));
|
|
|
|
public static readonly StyledProperty<string> TitleProperty =
|
|
AvaloniaProperty.Register<SettingEditor, string>(nameof(Title));
|
|
|
|
public static readonly StyledProperty<string?> PathNameProperty =
|
|
AvaloniaProperty.Register<SettingEditor, string?>(nameof(PathName));
|
|
|
|
public SettingEditor()
|
|
{
|
|
InitializeComponent();
|
|
Layout = this.FindControl<ScrollViewer>("Layout");
|
|
this.GetObservable(ParamProperty).Subscribe(ps =>
|
|
{
|
|
if (ps == null) return;
|
|
Dispatcher.UIThread.InvokeAsync(() =>
|
|
{
|
|
Param = ps;
|
|
Render();
|
|
});
|
|
});
|
|
}
|
|
|
|
public object Param
|
|
{
|
|
get => GetValue(ParamProperty);
|
|
set => SetValue(ParamProperty, value);
|
|
}
|
|
|
|
public string Title
|
|
{
|
|
get => GetValue(TitleProperty);
|
|
set => SetValue(TitleProperty, value);
|
|
}
|
|
|
|
public string? PathName
|
|
{
|
|
get => GetValue(PathNameProperty);
|
|
set => SetValue(PathNameProperty, value);
|
|
}
|
|
|
|
private void InitializeComponent()
|
|
{
|
|
AvaloniaXamlLoader.Load(this);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 渲染UI控件
|
|
/// </summary>
|
|
private void Render()
|
|
{
|
|
if (Param.IsNullOrEmpty()) return;
|
|
|
|
// 外层用一个大的 Border 来装
|
|
var itemLayout = new Border
|
|
{
|
|
Padding = new Thickness(10),
|
|
Margin = new Thickness(5),
|
|
Background = Brush.Parse("#F6F8FA"),
|
|
BoxShadow = BoxShadows.Parse("0 0 16 0 LightGray"),
|
|
CornerRadius = new CornerRadius(10)
|
|
};
|
|
|
|
var stackPanel = new StackPanel();
|
|
|
|
var titleBorder = new Border
|
|
{
|
|
Height = 40,
|
|
Padding = new Thickness(20, 0, 20, 0),
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
HorizontalAlignment = HorizontalAlignment.Stretch,
|
|
BorderBrush = new SolidColorBrush(Colors.Gray),
|
|
BorderThickness = new Thickness(0, 0, 0, 1)
|
|
};
|
|
|
|
var titleGrid = new Grid
|
|
{
|
|
RowDefinitions = RowDefinitions.Parse("*")
|
|
};
|
|
|
|
|
|
var titleText = new TextBlock
|
|
{
|
|
Text = GetTitle(),
|
|
FontSize = 16,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
HorizontalAlignment = HorizontalAlignment.Left
|
|
};
|
|
|
|
var saveBtn = new Button
|
|
{
|
|
Content = "保存",
|
|
HorizontalAlignment = HorizontalAlignment.Right,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
VerticalContentAlignment = VerticalAlignment.Center,
|
|
HorizontalContentAlignment = HorizontalAlignment.Center,
|
|
Command = ReactiveCommand.Create(() =>
|
|
{
|
|
OnSaveClicked?.Invoke(this, Param);
|
|
ToastUtil.Success("保存成功");
|
|
}),
|
|
Foreground = Brushes.White,
|
|
Background = Brushes.DodgerBlue,
|
|
Width = 80,
|
|
Margin = new Thickness(0, 0, 10, 0)
|
|
};
|
|
|
|
Grid.SetRow(titleText, 0);
|
|
Grid.SetRow(saveBtn, 0);
|
|
|
|
titleGrid.Children.Add(titleText);
|
|
titleGrid.Children.Add(saveBtn);
|
|
titleBorder.Child = titleGrid;
|
|
|
|
var scrollViewer = new ScrollViewer
|
|
{
|
|
MaxHeight = 500,
|
|
VerticalScrollBarVisibility = ScrollBarVisibility.Auto
|
|
};
|
|
|
|
var contentWrapper = new WrapPanel
|
|
{
|
|
Orientation = Orientation.Horizontal
|
|
};
|
|
|
|
contentWrapper.Children.AddRange(GetParamItems());
|
|
scrollViewer.Content = contentWrapper;
|
|
|
|
stackPanel.Children.Add(titleBorder);
|
|
stackPanel.Children.Add(scrollViewer);
|
|
|
|
itemLayout.Child = stackPanel;
|
|
|
|
Layout.Content = itemLayout;
|
|
}
|
|
|
|
|
|
private string GetTitle()
|
|
{
|
|
var type = Param.GetType();
|
|
|
|
var descriptionAttribute = type.GetCustomAttribute<DescriptionAttribute>();
|
|
var tableAttribute = type.GetCustomAttribute<TableAttribute>();
|
|
return Title ?? descriptionAttribute?.Description ?? tableAttribute?.Name ?? type.Name;
|
|
}
|
|
|
|
private List<StackPanel> GetParamItems()
|
|
{
|
|
var context = DataContext;
|
|
if (context.IsNullOrEmpty()) return [];
|
|
|
|
var type = Param.GetType();
|
|
var contextProperties = context!
|
|
.GetType()
|
|
.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
|
|
|
|
// 从context 中找到对应的属性
|
|
var contextName = PathName ?? contextProperties.FirstOrDefault(p => p.PropertyType == type)?.Name;
|
|
|
|
var properties = type
|
|
.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
|
|
List<StackPanel> panels = [];
|
|
foreach (var property in properties)
|
|
{
|
|
// 如果标记为忽略的直接跳过
|
|
var ignore = property.GetCustomAttributes<IgnoreAttribute>();
|
|
if (ignore.Any()) continue;
|
|
|
|
var hide = property.GetCustomAttributes<Hide>();
|
|
if (hide.Any()) continue;
|
|
|
|
var descriptionAttribute = property.GetCustomAttribute<DescriptionAttribute>();
|
|
var columnAttribute = property.GetCustomAttribute<ColumnAttribute>();
|
|
var title = descriptionAttribute?.Description ?? columnAttribute?.Name ?? property.Name;
|
|
|
|
var item = new StackPanel
|
|
{
|
|
Orientation = Orientation.Horizontal,
|
|
MinWidth = 400,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
Margin = new Thickness(20, 5, 20, 5)
|
|
};
|
|
|
|
var titleBlock = new TextBlock
|
|
{
|
|
Text = title,
|
|
FontSize = 14,
|
|
Width = 190,
|
|
Margin = new Thickness(0, 0, 10, 0),
|
|
TextWrapping = TextWrapping.Wrap,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
HorizontalAlignment = HorizontalAlignment.Left
|
|
};
|
|
|
|
item.Children.Add(titleBlock);
|
|
item.Children.Add(GetValueControl(property, contextName));
|
|
|
|
panels.Add(item);
|
|
}
|
|
|
|
return panels;
|
|
}
|
|
|
|
// 根据类型不同,返回不同的控件
|
|
private Control GetValueControl(PropertyInfo property, string? contextName)
|
|
{
|
|
var type = property.PropertyType.Name;
|
|
if (type.ToLower().Contains("enum"))
|
|
{
|
|
type = "Enum";
|
|
}
|
|
|
|
var pro = property.GetCustomAttribute<Property>();
|
|
|
|
switch (type)
|
|
{
|
|
case "String":
|
|
var textBox = new TextBox
|
|
{
|
|
Width = 200,
|
|
Height = 40,
|
|
IsReadOnly = pro?.IsReadOnly ?? false,
|
|
TextWrapping = TextWrapping.Wrap,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
HorizontalAlignment = HorizontalAlignment.Left,
|
|
VerticalContentAlignment = VerticalAlignment.Center
|
|
};
|
|
textBox.Bind(TextBox.TextProperty, new Binding(contextName + "." + property.Name)
|
|
{
|
|
Mode = BindingMode.TwoWay
|
|
});
|
|
|
|
if (pro != null && pro.Width != 0)
|
|
{
|
|
textBox.Width = pro.Width;
|
|
}
|
|
|
|
if (pro != null && pro.Height != 0)
|
|
{
|
|
textBox.Height = pro.Height;
|
|
textBox.VerticalContentAlignment = VerticalAlignment.Top;
|
|
}
|
|
|
|
if (pro is { IsPassword: true })
|
|
{
|
|
textBox.PasswordChar = '*';
|
|
}
|
|
|
|
return textBox;
|
|
case "Boolean":
|
|
var toggleSwitch = new ToggleSwitch
|
|
{
|
|
Width = 50,
|
|
Height = 40,
|
|
OnContent = "",
|
|
OffContent = "",
|
|
IsEnabled = !(pro?.IsReadOnly ?? false),
|
|
Cursor = new Cursor(StandardCursorType.Hand),
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
HorizontalAlignment = HorizontalAlignment.Left,
|
|
VerticalContentAlignment = VerticalAlignment.Center
|
|
};
|
|
toggleSwitch.Bind(ToggleButton.IsCheckedProperty, new Binding(contextName + "." + property.Name)
|
|
{
|
|
Mode = BindingMode.TwoWay
|
|
});
|
|
return toggleSwitch;
|
|
case "Enum":
|
|
var comboBox = new ComboBox
|
|
{
|
|
Width = 200,
|
|
Height = 40,
|
|
IsEnabled = !(pro?.IsReadOnly ?? false),
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
HorizontalAlignment = HorizontalAlignment.Left,
|
|
VerticalContentAlignment = VerticalAlignment.Center
|
|
};
|
|
|
|
var fields = property.PropertyType.GetFields();
|
|
var items = fields.Select(p =>
|
|
{
|
|
var description = p.GetCustomAttribute<DescriptionAttribute>();
|
|
return description?.Description ?? p.Name;
|
|
}).Where(p => p != "value__").ToList();
|
|
comboBox.ItemsSource = items;
|
|
|
|
comboBox.Bind(SelectingItemsControl.SelectedIndexProperty,
|
|
new Binding(contextName + "." + property.Name)
|
|
{
|
|
Mode = BindingMode.TwoWay
|
|
});
|
|
return comboBox;
|
|
case "Int32":
|
|
case "Int64":
|
|
var numericUpDown = new NumericUpDown
|
|
{
|
|
Width = 200,
|
|
Height = 40,
|
|
ShowButtonSpinner = false,
|
|
FormatString = "F0",
|
|
IsReadOnly = pro?.IsReadOnly ?? false,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
HorizontalAlignment = HorizontalAlignment.Left,
|
|
VerticalContentAlignment = VerticalAlignment.Center
|
|
};
|
|
numericUpDown.Bind(NumericUpDown.ValueProperty, new Binding(contextName + "." + property.Name)
|
|
{
|
|
Mode = BindingMode.TwoWay
|
|
});
|
|
return numericUpDown;
|
|
case "Float":
|
|
case "Double":
|
|
case "Decimal":
|
|
var format = pro?.Format ?? "0.###";
|
|
var @decimal = new NumericUpDown
|
|
{
|
|
Width = 200,
|
|
Height = 40,
|
|
ShowButtonSpinner = false,
|
|
FormatString = format,
|
|
IsReadOnly = pro?.IsReadOnly ?? false,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
HorizontalAlignment = HorizontalAlignment.Left,
|
|
VerticalContentAlignment = VerticalAlignment.Center
|
|
};
|
|
@decimal.Bind(NumericUpDown.ValueProperty, new Binding(contextName + "." + property.Name)
|
|
{
|
|
Mode = BindingMode.TwoWay
|
|
});
|
|
return @decimal;
|
|
default:
|
|
var defalutText = new TextBox
|
|
{
|
|
Width = 200,
|
|
Height = 40,
|
|
IsReadOnly = pro?.IsReadOnly ?? false,
|
|
TextWrapping = TextWrapping.Wrap,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
HorizontalAlignment = HorizontalAlignment.Left,
|
|
VerticalContentAlignment = VerticalAlignment.Center
|
|
};
|
|
defalutText.Bind(TextBox.TextProperty, new Binding(contextName + "." + property.Name)
|
|
{
|
|
Mode = BindingMode.TwoWay
|
|
});
|
|
return defalutText;
|
|
}
|
|
}
|
|
} |