实现的目标:
1.通过Excel文件,加载IO的信息
2.通过颜色反馈IO的当前的状态
3.通过点击,能触发IO的改变
先来看看 Excel文件
再来看看界面的效果
接下来就介绍实现方式了:
创建UserControl ,把加载和点击控制的功能进行封装,数据来源就用绑定的方式
XAML界面代码:
<UserControl
x:Class="LS.AvaloniaClient.UserControls.IOControl"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<UserControl.Styles>
<Style Selector="TextBlock.TitleDefaultStyle">
<Setter Property="Margin" Value="0,0,0,0" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Microsoft YaHei UI" />
<Setter Property="FontSize" Value="22" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="#FF35414F" />
</Style>
<Style Selector="Label.ContentDefaultStyle">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Microsoft YaHei UI" />
<Setter Property="Foreground" Value="Black" />
</Style>
</UserControl.Styles>
<ScrollViewer
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<Grid x:Name="showGrid" />
</ScrollViewer>
</UserControl>
CS代码:
因Avalonia没有InputBinding的事件,也没有触发器的概念,所以点击只能用鼠标事件来触发,触发器就用绑定的方式+转换器 来切换颜色;
public partial class IOControl : UserControl
{
public IOControl()
{
InitializeComponent();
this.Loaded += IOControl_Loaded;
}
private void IOControl_Loaded(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
IOItemsProperty.Changed.AddClassHandler<Interactive>(IOItemsValueChanged);
BoolArrayProperty.Changed.AddClassHandler<Interactive>(BoolArrayValueChanged);
if (!string.IsNullOrEmpty(ExcelPath))
{
//从Excel中读取数据
dataInfo = readExcelDataByNPOI();
LoadControl();
}
}
private void LoadControl()
{
if (dataInfo != null && dataInfo.Count > 0)
{
Grid grid = this.FindControl<Grid>("showGrid");
if (grid.Children.Count > 0)
grid.Children.Clear();
if (grid.ColumnDefinitions.Count > 0)
grid.ColumnDefinitions.Clear();
if (grid.RowDefinitions.Count > 0)
grid.RowDefinitions.Clear();
int colNum = 0;
int index = 0;//用于数据累计的索引
foreach (var col in dataInfo)
{
//添加列
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(ColWidth) });
//添加行,如果未添加过的情况
if (grid.RowDefinitions.Count < 1)
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(TitleHeight) });
//列头的显示控件
TextBlock title = new TextBlock();
title.Classes.Add("TitleDefaultStyle");
title.Text = col.Key;
grid.Children.Add(title);
Grid.SetColumn(title, colNum);
Grid.SetRow(title, 0);
//循环数据,添加行
string[] ds = col.Value.ToArray();
for (int i = 0; i < ds.Length; i++)
{
//先判断是否需要新增行
if (grid.RowDefinitions.Count < i + 2)
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(ContentHeight) });
//添加边框
Border border = new Border();
border.HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Stretch;
border.VerticalAlignment = Avalonia.Layout.VerticalAlignment.Stretch;
//参数可传,有默认值
border.BorderThickness = BorderNewThickness;
border.BorderBrush = BorderNewBrush;
border.Margin = BorderMargin;
border.Background = BorderBackground;
//添加Label,用来显示文本
string contentName = "lb_" + index;
Label content = new Label();
content.Name = contentName;
content.Content = ds[i];
content.Margin = ContentMargin;
content.Tag = IOItems[index];
//点击事件绑定
if (IOItems[index].ClickCommand != null)
{
content.PointerPressed += Content_PointerPressed;
}
//此处是绑定数组,用来显示颜色
Binding binding1 = new Binding($"{BoolArrayName}[{index}]");
binding1.Source = this.DataContext;
binding1.Mode = BindingMode.TwoWay;
//转换器,bool值转换为Brush
BoolToColorConverter btc = new BoolToColorConverter();
//显示的颜色可传参,有默认值
if(IOItems[index].InBrush!=null)
{
btc.InDefaultBrush = IOItems[index].InBrush;
}
if (IOItems[index].OutBrush != null)
{
btc.OutDefaultBrush = IOItems[index].OutBrush;
}
binding1.Converter = btc;
//添加绑定关系
content.Bind(ForegroundProperty, binding1);
//添加样式
content.Classes.Add("ContentDefaultStyle");
index++;
//添加到界面Grid中
grid.Children.Add(border);
Grid.SetColumn(border, colNum);
Grid.SetRow(border, i + 1);
grid.Children.Add(content);
Grid.SetColumn(content, colNum);
Grid.SetRow(content, i + 1);
}
colNum++;
}
this.showGrid = grid;
}
}
public class BoolToColorConverter : IValueConverter
{
/// <summary>
/// In的时候默认背景色
/// </summary>
public IBrush InDefaultBrush { get; set; } = Brushes.Red;
/// <summary>
/// Out的时候默认背景色
/// </summary>
public IBrush OutDefaultBrush { get; set; } = Brushes.Gray;
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is bool boolValue)
{
return boolValue ? InDefaultBrush : OutDefaultBrush;
}
return OutDefaultBrush;
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is IBrush colorValue)
{
return colorValue == InDefaultBrush;
}
return false;
}
}
private void Content_PointerPressed(object? sender, Avalonia.Input.PointerPressedEventArgs e)
{
if(sender!=null)
{
Label label = (Label)sender;
var model = label.Tag;
if(model!=null)
{
var item = model as IOItemModel;
if(item != null && item.ClickCommand!=null)
{
item.ClickCommand.Execute(item.CommandParameter);
}
}
}
}
Dictionary<string, List<string>> dataInfo;
/// <summary>
/// 使用NPOI读取Excel文件 无需安装EXcel
/// </summary>
/// <returns></returns>
private Dictionary<string, List<string>> readExcelDataByNPOI()
{
Dictionary<string, List<string>> result = new Dictionary<string, List<string>>();
if (!File.Exists(ExcelPath))
{
//取一个默认的Excel文件
ExcelPath = AppDomain.CurrentDomain.BaseDirectory + "Assets\\Excels\\IOExcel.xlsx";
}
FileStream file = new FileStream(ExcelPath, FileMode.Open);
ISheet sheet;
IWorkbook workbook = null;
// 2007版本及以上版本
if (ExcelPath.IndexOf(".xlsx") > 0)
{
workbook = new XSSFWorkbook(file);
}
// 2003版本
else if (ExcelPath.IndexOf(".xls") > 0)
{
workbook = new HSSFWorkbook(file);
}
if (workbook != null)
{
//读取excel中第一个sheet
sheet = workbook.GetSheetAt(0);
int columnsint = sheet.GetRow(0).LastCellNum;//得到列数
for (int col = 0; col < columnsint; col++)
{
//取列头
string title = sheet.GetRow(0)?.GetCell(col)?.StringCellValue;
if (string.IsNullOrEmpty(title))
continue;
if (!result.ContainsKey(title))
result.Add(title, new List<string>());
int row = 1;
while (true)
{
string content = sheet.GetRow(row)?.GetCell(col)?.StringCellValue;
if (string.IsNullOrEmpty(content))
break;
result[title].Add(content);
row++;
}
}
}
file.Close();
file.Dispose();
return result;
}
#region 属性
private bool InitFinish = false;
/// <summary>
/// 显示模板Excel的文件路径
/// </summary>
public string ExcelPath { get; set; }
/// <summary>
/// 标题的高度
/// </summary>
public double TitleHeight { get; set; } = 35;
/// <summary>
/// 显示的一列的宽度
/// </summary>
public double ColWidth { get; set; } = 298.3;
/// <summary>
/// 单个按钮或者Label1的高度
/// </summary>
public double ContentHeight { get; set; } = 32;
/// <summary>
/// 边框的Margin
/// </summary>
public Thickness BorderMargin = new Thickness(5, 1, 5, 1);
/// <summary>
/// 边框的粗细
/// </summary>
public Thickness BorderNewThickness = new Thickness(1);
/// <summary>
/// 边框的颜色
/// </summary>
public IBrush BorderNewBrush = Brushes.Black;
/// <summary>
/// 边框的背景色
/// </summary>
public IBrush BorderBackground = Brushes.WhiteSmoke;
/// <summary>
/// 单个按钮或者Label1的间隔
/// </summary>
public Thickness ContentMargin { get; set; } = new Thickness(5, 0, 5, 0);
/// <summary>
/// 绑定的BoolArray的实例名称
/// </summary>
public string BoolArrayName { get; set; }
/// <summary>
/// 绑定的Bool数组
/// </summary>
public bool[] BoolArray
{
get { return (bool[])GetValue(BoolArrayProperty); }
set { SetValue(BoolArrayProperty, value); }
}
public static readonly AttachedProperty<bool[]> BoolArrayProperty =
AvaloniaProperty.RegisterAttached<IOControl, Interactive, bool[]>("BoolArray", default(bool[]), false);
private static void BoolArrayValueChanged(Interactive interactElem, AvaloniaPropertyChangedEventArgs args)
{
interactElem.SetValue(BoolArrayProperty, (bool[])args.NewValue);
var element = interactElem as IOControl;
if (!element.InitFinish)
{
element.LoadControl();
element.InitFinish = true;
}
}
/// <summary>
/// 按钮的细节配置,绑定的Command,显示的背景色等等
/// </summary>
public List<IOItemModel> IOItems
{
get { return (List<IOItemModel>)GetValue(IOItemsProperty); }
set { SetValue(IOItemsProperty, value); }
}
public static readonly AttachedProperty<List<IOItemModel>> IOItemsProperty =
AvaloniaProperty.RegisterAttached<IOControl, Interactive,List<IOItemModel>>("IOItems", default(List<IOItemModel>),false, BindingMode.OneTime);
private static void IOItemsValueChanged(Interactive interactElem, AvaloniaPropertyChangedEventArgs args)
{
interactElem.SetValue(IOItemsProperty, (List<IOItemModel>)args.NewValue);
}
#endregion
}
public class IOItemModel
{
public ICommand ClickCommand { get; set; } = null;
public object CommandParameter { get; set; } = null;
/// <summary>
/// In的时候默认背景色
/// </summary>
public Brush InBrush { get; set; } = null;
/// <summary>
/// Out的时候默认背景色
/// </summary>
public Brush OutBrush { get; set; } = null;
}
使用的方式,就在界面添加 控件,然后赋值相关的属性即可,数据的变化就自行处理了
<ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">
<ucLib:IOControl
x:Name="_ioCrl"
x:DataType="vm:VM_PageIO"
BoolArray="{Binding BoolArrary, Mode=TwoWay}"
BoolArrayName="BoolArrary"
ExcelPath="E:\Work\GitCode\LS.Avalonia\Code\LS.AvaloniaClient\Assets\Excels\IOExcel.xlsx"
IOItems="{Binding IOItemModels, Mode=TwoWay}" />
</ScrollViewer>