添加 MX-PD-盘古 项目文件

将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
This commit is contained in:
Shi.Ji
2026-05-18 11:43:09 +08:00
parent 03632a379d
commit e31d3560bb
739 changed files with 99783 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
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.Input;
namespace MainShell.Resources.CustomControl
{
public partial class AxisMoveControl : UserControl
{
public static readonly DependencyProperty IsAllShowProperty =
DependencyProperty.Register(nameof(IsAllShow), typeof(bool), typeof(AxisMoveControl), new PropertyMetadata(true));
public static readonly DependencyProperty IsReadOnlyProperty =
DependencyProperty.Register(nameof(IsReadOnly), typeof(bool), typeof(AxisMoveControl), new PropertyMetadata(false));
public static readonly DependencyProperty LableContent1Property =
DependencyProperty.Register(nameof(LableContent1), typeof(string), typeof(AxisMoveControl), new PropertyMetadata());
public static readonly DependencyProperty Value1Property =
DependencyProperty.Register(nameof(Value1), typeof(double), typeof(AxisMoveControl), new PropertyMetadata(0.0));
public static readonly DependencyProperty Min1Property =
DependencyProperty.Register(nameof(Min1), typeof(double), typeof(AxisMoveControl), new PropertyMetadata(-1000.0));
public static readonly DependencyProperty Max1Property =
DependencyProperty.Register(nameof(Max1), typeof(double), typeof(AxisMoveControl), new PropertyMetadata(1000.0));
public static readonly DependencyProperty LableContent2Property =
DependencyProperty.Register(nameof(LableContent2), typeof(string), typeof(AxisMoveControl), new PropertyMetadata());
public static readonly DependencyProperty Value2Property =
DependencyProperty.Register(nameof(Value2), typeof(double), typeof(AxisMoveControl), new PropertyMetadata(0.0));
public static readonly DependencyProperty Min2Property =
DependencyProperty.Register(nameof(Min2), typeof(double), typeof(AxisMoveControl), new PropertyMetadata(-1000.0));
public static readonly DependencyProperty Max2Property =
DependencyProperty.Register(nameof(Max2), typeof(double), typeof(AxisMoveControl), new PropertyMetadata(1000.0));
public static readonly DependencyProperty LableWidthProperty =
DependencyProperty.Register(nameof(LableWidth), typeof(int), typeof(AxisMoveControl), new PropertyMetadata(80));
public static readonly DependencyProperty NumberBoxWidthProperty =
DependencyProperty.Register(nameof(NumberBoxWidth), typeof(int), typeof(AxisMoveControl), new PropertyMetadata(80));
public bool IsAllShow { get => (bool)GetValue(IsAllShowProperty); set => SetValue(IsAllShowProperty, value); }
public bool IsReadOnly { get => (bool)GetValue(IsReadOnlyProperty); set => SetValue(IsReadOnlyProperty, value); }
public string LableContent1 { get => (string)GetValue(LableContent1Property); set => SetValue(LableContent1Property, value); }
public int LableWidth { get => (int)GetValue(LableWidthProperty); set => SetValue(LableWidthProperty, value); }
public int NumberBoxWidth { get => (int)GetValue(NumberBoxWidthProperty); set => SetValue(NumberBoxWidthProperty, value); }
public double Value1 { get => (double)GetValue(Value1Property); set => SetValue(Value1Property, value); }
public double Min1 { get => (double)GetValue(Min1Property); set => SetValue(Min1Property, value); }
public double Max1 { get => (double)GetValue(Max1Property); set => SetValue(Max1Property, value); }
public string LableContent2 { get => (string)GetValue(LableContent2Property); set => SetValue(LableContent2Property, value); }
public double Value2 { get => (double)GetValue(Value2Property); set => SetValue(Value2Property, value); }
public double Min2 { get => (double)GetValue(Min2Property); set => SetValue(Min2Property, value); }
public double Max2 { get => (double)GetValue(Max2Property); set => SetValue(Max2Property, value); }
public ICommand MoveCommand
{
get => (ICommand)GetValue(MoveCommandProperty);
set => SetValue(MoveCommandProperty, value);
}
public static readonly DependencyProperty MoveCommandProperty =
DependencyProperty.Register(nameof(MoveCommand), typeof(ICommand), typeof(AxisMoveControl), new PropertyMetadata(null));
public ICommand ReadCommand
{
get => (ICommand)GetValue(ReadCommandProperty);
set => SetValue(ReadCommandProperty, value);
}
public static readonly DependencyProperty ReadCommandProperty =
DependencyProperty.Register(nameof(ReadCommand), typeof(ICommand), typeof(AxisMoveControl), new PropertyMetadata(null));
}
}

View File

@@ -0,0 +1,58 @@
<UserControl x:Class="MainShell.Resources.CustomControl.AxisMoveControl"
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:local="clr-namespace:MainShell.Resources.CustomControl"
xmlns:mw="http://www.maxwell-gp.com/"
mc:Ignorable="d" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Content="{Binding LableContent1, RelativeSource={RelativeSource AncestorType=UserControl}}"
Width="{Binding LableWidth, RelativeSource={RelativeSource AncestorType=UserControl}}"
Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<mw:NumberBox Value="{Binding Value1, RelativeSource={RelativeSource AncestorType=UserControl}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Minimum="{Binding Min1, RelativeSource={RelativeSource AncestorType=UserControl}}"
Maximum="{Binding Max1, RelativeSource={RelativeSource AncestorType=UserControl}}"
Width="{Binding NumberBoxWidth, RelativeSource={RelativeSource AncestorType=UserControl}}"
IsReadOnly="{Binding IsReadOnly, RelativeSource={RelativeSource AncestorType=UserControl}}"
mw:NumericKeypadAttach.IsEnabled="True"
Grid.Column="1" HorizontalAlignment="Left"
Margin="2" Height="35" />
<Label Visibility="{Binding IsAllShow,Converter={StaticResource BoolToVisibleConverter},
RelativeSource={RelativeSource AncestorType=UserControl}}"
Content="{Binding LableContent2,RelativeSource={RelativeSource AncestorType=UserControl}}"
Width="{Binding LableWidth, RelativeSource={RelativeSource AncestorType=UserControl}}"
Grid.Column="2"
HorizontalAlignment="Right" VerticalAlignment="Center"/>
<mw:NumberBox Visibility="{Binding IsAllShow,
Converter={StaticResource BoolToVisibleConverter},RelativeSource={RelativeSource AncestorType=UserControl}}" Value="{Binding Value2,RelativeSource={RelativeSource AncestorType=UserControl}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Minimum="{Binding Min2, RelativeSource={RelativeSource AncestorType=UserControl}}"
Maximum="{Binding Max2, RelativeSource={RelativeSource AncestorType=UserControl}}"
Width="{Binding NumberBoxWidth, RelativeSource={RelativeSource AncestorType=UserControl}}"
IsReadOnly="{Binding IsReadOnly, RelativeSource={RelativeSource AncestorType=UserControl}}"
mw:NumericKeypadAttach.IsEnabled="True"
Grid.Column="3" HorizontalAlignment="Left"
Margin="2" Height="35" />
<UniformGrid Columns="2" Grid.Column="4">
<Button Grid.Column="1"
Style="{StaticResource TeachButtonStyle}"
Content="{DynamicResource PositionTeach}"
Command="{Binding ReadCommand,RelativeSource={RelativeSource AncestorType=UserControl}}"
Width="90" Height="35" HorizontalAlignment="Left" Margin="2" />
<Button Grid.Column="2"
Style="{StaticResource AxisMoveButtonStyle}"
Content="{DynamicResource MoveToPosition}"
Command="{Binding MoveCommand,RelativeSource={RelativeSource AncestorType=UserControl}}"
Width="90" Height="35" HorizontalAlignment="Left" Margin="2" />
</UniformGrid>
</Grid>
</UserControl>

View File

@@ -0,0 +1,29 @@
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 MainShell.Resources.CustomControl
{
/// <summary>
/// AxisMoveControl.xaml 的交互逻辑
/// </summary>
public partial class AxisMoveControl : UserControl
{
public AxisMoveControl()
{
InitializeComponent();
//DefaultStyleKeyProperty.OverrideMetadata(typeof(AxisMoveControl), new FrameworkPropertyMetadata(typeof(AxisMoveControl)));
}
}
}

View File

@@ -0,0 +1,595 @@
using MainShell.Common;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.ComponentModel;
namespace MainShell.Resources.CustomControl
{
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>оƬMapͼ<70>ؼ<EFBFBD><D8BC><EFBFBD>֧<EFBFBD><D6A7>5-10<31><30><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ķ<EFBFBD>̬״̬<D7B4><CCAC><EFBFBD>£<EFBFBD>֧<EFBFBD><D6A7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ק<EFBFBD><D7A7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
public class DieMapControl : FrameworkElement
{
private int _rows;
private int _columns;
private DieState[,] _dieStates;
private Point[,] _dieCoordinates;
private double _minX, _maxX, _minY, _maxY;
private Dictionary<DieState, Brush> _stateBrushes;
// <20><>Ⱦ<EFBFBD><C8BE><EFBFBD><EFBFBD>
private DrawingVisual _visual;
private VisualCollection _visuals;
private DispatcherTimer _renderTimer;
private bool _needsRedraw = false;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
private MatrixTransform _transform = new MatrixTransform();
private Point _lastMousePosition;
private Point _mouseDownPosition;
private bool _isDragging;
private bool _isViewChangedByUser;
private Popup _infoPopup;
private TextBlock _infoText;
public static readonly DependencyProperty BackgroundProperty =
DependencyProperty.Register("Background", typeof(Brush), typeof(DieMapControl), new FrameworkPropertyMetadata(Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsRender));
public Brush Background
{
get { return (Brush)GetValue(BackgroundProperty); }
set { SetValue(BackgroundProperty, value); }
}
public static readonly DependencyProperty MapModelProperty =
DependencyProperty.Register("MapModel", typeof(DieMapModel), typeof(DieMapControl), new PropertyMetadata(null, OnMapModelChanged));
public DieMapModel MapModel
{
get { return (DieMapModel)GetValue(MapModelProperty); }
set { SetValue(MapModelProperty, value); }
}
public static readonly DependencyProperty DieClickedCommandProperty =
DependencyProperty.Register("DieClickedCommand", typeof(ICommand), typeof(DieMapControl), new PropertyMetadata(null));
public ICommand DieClickedCommand
{
get { return (ICommand)GetValue(DieClickedCommandProperty); }
set { SetValue(DieClickedCommandProperty, value); }
}
public event EventHandler<DieClickedEventArgs> DieClicked;
public class DieClickedEventArgs : EventArgs
{
public int Row { get; }
public int Col { get; }
public DieState State { get; }
public DieClickedEventArgs(int row, int col, DieState state)
{
Row = row;
Col = col;
State = state;
}
}
private static void OnMapModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (DieMapControl)d;
if (e.OldValue is DieMapModel oldModel)
{
oldModel.MapInitialized -= control.OnMapInitialized;
oldModel.DieStateChanged -= control.OnDieStateChanged;
oldModel.DieStatesChanged -= control.OnDieStatesChanged;
}
if (e.NewValue is DieMapModel newModel)
{
newModel.MapInitialized += control.OnMapInitialized;
newModel.DieStateChanged += control.OnDieStateChanged;
newModel.DieStatesChanged += control.OnDieStatesChanged;
control.InitializeFromModel(newModel);
}
}
private void OnMapInitialized(object sender, EventArgs e)
{
InitializeFromModel(MapModel);
}
private void OnDieStateChanged(object sender, (int Row, int Col, DieState State) e)
{
_needsRedraw = true;
}
private void OnDieStatesChanged(object sender, IEnumerable<(int Row, int Col, DieState State)> e)
{
_needsRedraw = true;
}
public static readonly DependencyProperty DieSizeProperty =
DependencyProperty.Register("DieSize", typeof(double), typeof(DieMapControl), new FrameworkPropertyMetadata(4.0, FrameworkPropertyMetadataOptions.AffectsRender, OnSizeChanged));
public double DieSize
{
get { return (double)GetValue(DieSizeProperty); }
set { SetValue(DieSizeProperty, value); }
}
public static readonly DependencyProperty SpacingProperty =
DependencyProperty.Register("Spacing", typeof(double), typeof(DieMapControl), new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.AffectsRender, OnSizeChanged));
public double Spacing
{
get { return (double)GetValue(SpacingProperty); }
set { SetValue(SpacingProperty, value); }
}
private static void OnSizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (DieMapControl)d;
control.RedrawAll();
}
public DieMapControl()
{
_visuals = new VisualCollection(this);
_visual = new DrawingVisual();
_visuals.Add(_visual);
// <20><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>ˢ<EFBFBD>ֵ䣬<D6B5><E4A3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
_stateBrushes = new Dictionary<DieState, Brush>
{
{ DieState.Available, CreateFrozenBrush(Color.FromRgb(211, 211, 211)) }, // dz<><C7B3>ɫ
{ DieState.Used, CreateFrozenBrush(Color.FromRgb(50, 205, 50)) }, // <20><>ɫ
{ DieState.Error, CreateFrozenBrush(Color.FromRgb(255, 0, 0)) }, // <20><>ɫ
{ DieState.NotExist, Brushes.Transparent }, // ͸<><CDB8>
{ DieState.Current, CreateFrozenBrush(Color.FromRgb(0, 191, 255)) }, // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> - <20><>ǰλ<C7B0><CEBB>
{ DieState.Target, CreateFrozenBrush(Color.FromRgb(255, 165, 0)) } // <20><>ɫ - Ŀ<><C4BF>λ<EFBFBD><CEBB>
};
// <20><>ʼ<EFBFBD><CABC>Popup
_infoPopup = new Popup
{
Placement = PlacementMode.Mouse,
StaysOpen = false,
AllowsTransparency = true
};
Border popupBorder = new Border
{
Background = new SolidColorBrush(Color.FromArgb(220, 30, 30, 30)),
BorderBrush = Brushes.Gray,
BorderThickness = new Thickness(1),
CornerRadius = new CornerRadius(4),
Padding = new Thickness(8)
};
_infoText = new TextBlock
{
Foreground = Brushes.White,
FontSize = 12
};
popupBorder.Child = _infoText;
_infoPopup.Child = popupBorder;
// <20><><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>
this.MouseWheel += OnMouseWheel;
this.MouseDown += OnMouseDown;
this.MouseUp += OnMouseUp;
this.MouseMove += OnMouseMove;
this.MouseLeave += OnMouseLeave;
// <20>ü<EFBFBD><C3BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߽<EFBFBD><DFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
this.ClipToBounds = true;
// <20><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>1<EFBFBD><31>3<EFBFBD><33> (Լ333ms)
_renderTimer = new DispatcherTimer(DispatcherPriority.Render);
_renderTimer.Interval = TimeSpan.FromMilliseconds(333);
_renderTimer.Tick += RenderTimer_Tick;
_renderTimer.Start();
}
private void RenderTimer_Tick(object sender, EventArgs e)
{
if (_needsRedraw)
{
RedrawAll();
_needsRedraw = false;
}
}
private SolidColorBrush CreateFrozenBrush(Color color)
{
var brush = new SolidColorBrush(color);
brush.Freeze();
return brush;
}
protected override int VisualChildrenCount => _visuals.Count;
protected override Visual GetVisualChild(int index)
{
if (index < 0 || index >= _visuals.Count)
throw new ArgumentOutOfRangeException();
return _visuals[index];
}
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
if (Background != null)
{
drawingContext.DrawRectangle(Background, null, new Rect(0, 0, ActualWidth, ActualHeight));
}
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
if (!_isViewChangedByUser && _rows > 0)
{
FitToScreen();
}
}
private void InitializeFromModel(DieMapModel model)
{
if (model == null) return;
_rows = model.Rows;
_columns = model.Columns;
_dieStates = model.States;
_dieCoordinates = model.Coordinates;
if (_dieCoordinates != null)
{
CalculateBounds();
}
// <20><><EFBFBD>ñ任
_transform.Matrix = Matrix.Identity;
// <20>ӳ<EFBFBD>ִ<EFBFBD><D6B4>FitToScreen<65><6E>ȷ<EFBFBD><C8B7><EFBFBD>ؼ<EFBFBD><D8BC>Ѿ<EFBFBD><D1BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Dispatcher.BeginInvoke(new Action(() =>
{
if (ActualWidth > 0 && ActualHeight > 0)
{
FitToScreen();
}
else
{
RedrawAll();
}
}), DispatcherPriority.Loaded);
}
private void CalculateBounds()
{
_minX = double.MaxValue;
_maxX = double.MinValue;
_minY = double.MaxValue;
_maxY = double.MinValue;
for (int r = 0; r < _rows; r++)
{
for (int c = 0; c < _columns; c++)
{
var pt = _dieCoordinates[r, c];
if (pt.X < _minX) _minX = pt.X;
if (pt.X > _maxX) _maxX = pt.X;
if (pt.Y < _minY) _minY = pt.Y;
if (pt.Y > _maxY) _maxY = pt.Y;
}
}
}
private void RedrawAll()
{
if (_rows == 0 || _columns == 0 || _dieStates == null) return;
using (DrawingContext dc = _visual.RenderOpen())
{
// Ӧ<>õ<EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD>ź<EFBFBD>ƽ<EFBFBD>Ʊ任
dc.PushTransform(_transform);
double size = DieSize;
double spacing = Spacing;
double physicalWidth = _maxX - _minX;
double physicalHeight = _maxY - _minY;
if (physicalWidth == 0) physicalWidth = 1;
if (physicalHeight == 0) physicalHeight = 1;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><D0A1>δ<EFBFBD><CEB4><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0>
double baseWidth = _columns * (size + spacing);
double baseHeight = _rows * (size + spacing);
for (int r = 0; r < _rows; r++)
{
for (int c = 0; c < _columns; c++)
{
DieState state = _dieStates[r, c];
if (state == DieState.NotExist) continue;
Brush brush = _stateBrushes.ContainsKey(state) ? _stateBrushes[state] : Brushes.Transparent;
if (brush == Brushes.Transparent) continue;
double x, y;
if (_dieCoordinates != null)
{
var pt = _dieCoordinates[r, c];
x = ((pt.X - _minX) / physicalWidth) * baseWidth;
y = (1.0 - (pt.Y - _minY) / physicalHeight) * baseHeight;
}
else
{
x = c * (size + spacing);
y = r * (size + spacing);
}
dc.DrawRectangle(brush, null, new Rect(x, y, size, size));
}
}
dc.Pop();
}
_needsRedraw = false;
}
#region <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƽ<EFBFBD><EFBFBD>)
private void OnMouseWheel(object sender, MouseWheelEventArgs e)
{
Point mousePos = e.GetPosition(this);
double scaleFactor = e.Delta > 0 ? 1.1 : 1 / 1.1;
Matrix matrix = _transform.Matrix;
matrix.ScaleAt(scaleFactor, scaleFactor, mousePos.X, mousePos.Y);
_transform.Matrix = matrix;
_isViewChangedByUser = true;
RedrawAll();
e.Handled = true;
}
private void OnMouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Middle)
{
FitToScreen();
}
else if (e.ChangedButton == MouseButton.Left)
{
_mouseDownPosition = e.GetPosition(this);
_lastMousePosition = _mouseDownPosition;
_isDragging = true;
this.CaptureMouse();
_infoPopup.IsOpen = false;
}
}
private void OnMouseUp(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
_isDragging = false;
this.ReleaseMouseCapture();
Point currentPosition = e.GetPosition(this);
if ((currentPosition - _mouseDownPosition).Length < 5)
{
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
{
ShowDieInfo(currentPosition);
}
else
{
HandleDieClick(currentPosition);
}
}
}
}
private void HandleDieClick(Point mousePos)
{
if (_rows == 0 || _columns == 0 || _dieStates == null) return;
if (!_transform.Matrix.HasInverse) return;
Matrix inverse = _transform.Matrix;
inverse.Invert();
Point canvasPos = inverse.Transform(mousePos);
double size = DieSize;
double spacing = Spacing;
double physicalWidth = _maxX - _minX;
double physicalHeight = _maxY - _minY;
if (physicalWidth == 0) physicalWidth = 1;
if (physicalHeight == 0) physicalHeight = 1;
double baseWidth = _columns * (size + spacing);
double baseHeight = _rows * (size + spacing);
int clickedRow = -1;
int clickedCol = -1;
for (int r = 0; r < _rows; r++)
{
for (int c = 0; c < _columns; c++)
{
DieState state = _dieStates[r, c];
if (state == DieState.NotExist) continue;
double x, y;
if (_dieCoordinates != null)
{
var pt = _dieCoordinates[r, c];
x = ((pt.X - _minX) / physicalWidth) * baseWidth;
y = (1.0 - (pt.Y - _minY) / physicalHeight) * baseHeight;
}
else
{
x = c * (size + spacing);
y = r * (size + spacing);
}
if (canvasPos.X >= x && canvasPos.X <= x + size &&
canvasPos.Y >= y && canvasPos.Y <= y + size)
{
clickedRow = r;
clickedCol = c;
break;
}
}
if (clickedRow != -1) break;
}
if (clickedRow != -1)
{
var dieInfo = (Row: clickedRow, Col: clickedCol, State: _dieStates[clickedRow, clickedCol]);
// <20><><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>
DieClicked?.Invoke(this, new DieClickedEventArgs(clickedRow, clickedCol, _dieStates[clickedRow, clickedCol]));
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (DieClickedCommand != null && DieClickedCommand.CanExecute(dieInfo))
{
DieClickedCommand.Execute(dieInfo);
}
}
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (_isDragging)
{
Point currentPosition = e.GetPosition(this);
Vector delta = currentPosition - _lastMousePosition;
Matrix matrix = _transform.Matrix;
matrix.Translate(delta.X, delta.Y);
_transform.Matrix = matrix;
_isViewChangedByUser = true;
_lastMousePosition = currentPosition;
RedrawAll();
}
}
private void OnMouseLeave(object sender, MouseEventArgs e)
{
if (_isDragging)
{
_isDragging = false;
this.ReleaseMouseCapture();
}
}
private void FitToScreen()
{
if (_rows == 0 || _columns == 0) return;
double size = DieSize;
double spacing = Spacing;
double baseWidth = _columns * (size + spacing);
double baseHeight = _rows * (size + spacing);
if (baseWidth == 0 || baseHeight == 0 || ActualWidth == 0 || ActualHeight == 0) return;
double scaleX = ActualWidth / baseWidth;
double scaleY = ActualHeight / baseHeight;
double scale = Math.Min(scaleX, scaleY) * 0.9; // 90% to leave some margin
if (scale <= 0) scale = 1;
_transform.Matrix = new Matrix(scale, 0, 0, scale,
(ActualWidth - baseWidth * scale) / 2,
(ActualHeight - baseHeight * scale) / 2);
_isViewChangedByUser = false;
RedrawAll();
}
private void ShowDieInfo(Point mousePos)
{
if (_rows == 0 || _columns == 0 || _dieStates == null) return;
if (!_transform.Matrix.HasInverse) return;
Matrix inverse = _transform.Matrix;
inverse.Invert();
Point canvasPos = inverse.Transform(mousePos);
double size = DieSize;
double spacing = Spacing;
double physicalWidth = _maxX - _minX;
double physicalHeight = _maxY - _minY;
if (physicalWidth == 0) physicalWidth = 1;
if (physicalHeight == 0) physicalHeight = 1;
double baseWidth = _columns * (size + spacing);
double baseHeight = _rows * (size + spacing);
int clickedRow = -1;
int clickedCol = -1;
for (int r = 0; r < _rows; r++)
{
for (int c = 0; c < _columns; c++)
{
DieState state = _dieStates[r, c];
if (state == DieState.NotExist) continue;
double x, y;
if (_dieCoordinates != null)
{
var pt = _dieCoordinates[r, c];
x = ((pt.X - _minX) / physicalWidth) * baseWidth;
y = (1.0 - (pt.Y - _minY) / physicalHeight) * baseHeight;
}
else
{
x = c * (size + spacing);
y = r * (size + spacing);
}
if (canvasPos.X >= x && canvasPos.X <= x + size &&
canvasPos.Y >= y && canvasPos.Y <= y + size)
{
clickedRow = r;
clickedCol = c;
break;
}
}
if (clickedRow != -1) break;
}
if (clickedRow != -1)
{
DieState state = _dieStates[clickedRow, clickedCol];
string info = $"<22><> (Row): {clickedRow}\n<><6E> (Col): {clickedCol}\n״̬: {MainShell.Converter.EnumHelper.GetEnumDescription(state)}";
if (_dieCoordinates != null)
{
var pt = _dieCoordinates[clickedRow, clickedCol];
info += $"\nX: {pt.X:F3}\nY: {pt.Y:F3}";
}
_infoText.Text = info;
_infoPopup.IsOpen = true;
}
else
{
_infoPopup.IsOpen = false;
}
}
#endregion
}
}

View File

@@ -0,0 +1,85 @@
using MainShell.Common;
using System;
using System.Collections.Generic;
using System.Windows;
namespace MainShell.Resources.CustomControl
{
/// <summary>
/// 芯片Map的数据模型用于MVVM绑定
/// </summary>
public class DieMapModel
{
public int Rows { get; private set; }
public int Columns { get; private set; }
public Point[,] Coordinates { get; private set; }
public DieState[,] States { get; private set; }
public event EventHandler MapInitialized;
public event EventHandler<(int Row, int Col, DieState State)> DieStateChanged;
public event EventHandler<IEnumerable<(int Row, int Col, DieState State)>> DieStatesChanged;
/// <summary>
/// 初始化Map图大小和坐标
/// </summary>
public void Initialize(int rows, int columns, Point[,] coordinates = null)
{
Rows = rows;
Columns = columns;
Coordinates = coordinates;
States = new DieState[rows, columns];
// 默认全部设置为NotExist或者根据需要设置
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < columns; c++)
{
States[r, c] = DieState.Available;
}
}
MapInitialized?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// 更新单个芯片状态
/// </summary>
public void SetDieState(int row, int col, DieState state)
{
if (States != null && row >= 0 && row < Rows && col >= 0 && col < Columns)
{
if (States[row, col] != state)
{
States[row, col] = state;
DieStateChanged?.Invoke(this, (row, col, state));
}
}
}
/// <summary>
/// 批量更新芯片状态
/// </summary>
public void SetDieStates(IEnumerable<(int row, int col, DieState state)> updates)
{
if (States == null) return;
bool changed = false;
foreach (var update in updates)
{
if (update.row >= 0 && update.row < Rows && update.col >= 0 && update.col < Columns)
{
if (States[update.row, update.col] != update.state)
{
States[update.row, update.col] = update.state;
changed = true;
}
}
}
if (changed)
{
DieStatesChanged?.Invoke(this, updates);
}
}
}
}

View File

@@ -0,0 +1,38 @@
<UserControl x:Class="MainShell.Resources.CustomControl.DieMapPanelControl"
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:local="clr-namespace:MainShell.Resources.CustomControl"
x:Name="Root"
mc:Ignorable="d"
d:DesignHeight="220"
d:DesignWidth="260">
<Border BorderBrush="#C7C7C7"
BorderThickness="1"
Background="#F3F4F6">
<Grid>
<local:DieMapControl Background="{Binding MapBackground, ElementName=Root}"
MapModel="{Binding MapModel, ElementName=Root}"
Margin="{Binding MapMargin, ElementName=Root}"
DieSize="{Binding DieSize, ElementName=Root}"
Spacing="{Binding Spacing, ElementName=Root}"
DieClickedCommand="{Binding DieClickedCommand, ElementName=Root}"/>
<Button Width="24"
Height="24"
Margin="0,6,6,0"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Click="OpenPreviewWindow"
ToolTip="放大查看"
FontSize="12"
FontWeight="Bold"
Content="⛶"/>
<TextBlock Text="{Binding Caption, ElementName=Root}"
Foreground="{Binding CaptionForeground, ElementName=Root}"
VerticalAlignment="Bottom"
HorizontalAlignment="Center"
Margin="{Binding CaptionMargin, ElementName=Root}"/>
</Grid>
</Border>
</UserControl>

View File

@@ -0,0 +1,211 @@
using MainShell.Common;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
namespace MainShell.Resources.CustomControl
{
public partial class DieMapPanelControl : UserControl
{
private DieMapPreviewWindow _previewWindow;
public static readonly DependencyProperty CaptionProperty =
DependencyProperty.Register("Caption", typeof(string), typeof(DieMapPanelControl), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty MapModelProperty =
DependencyProperty.Register("MapModel", typeof(DieMapModel), typeof(DieMapPanelControl), new PropertyMetadata(null));
public static readonly DependencyProperty DieSizeProperty =
DependencyProperty.Register("DieSize", typeof(double), typeof(DieMapPanelControl), new PropertyMetadata(8.0));
public static readonly DependencyProperty SpacingProperty =
DependencyProperty.Register("Spacing", typeof(double), typeof(DieMapPanelControl), new PropertyMetadata(1.0));
public static readonly DependencyProperty MapBackgroundProperty =
DependencyProperty.Register("MapBackground", typeof(Brush), typeof(DieMapPanelControl), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(229, 231, 235))));
public static readonly DependencyProperty CaptionForegroundProperty =
DependencyProperty.Register("CaptionForeground", typeof(Brush), typeof(DieMapPanelControl), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(107, 114, 128))));
public static readonly DependencyProperty MapMarginProperty =
DependencyProperty.Register("MapMargin", typeof(Thickness), typeof(DieMapPanelControl), new PropertyMetadata(new Thickness(8)));
public static readonly DependencyProperty CaptionMarginProperty =
DependencyProperty.Register("CaptionMargin", typeof(Thickness), typeof(DieMapPanelControl), new PropertyMetadata(new Thickness(0, 0, 0, 14)));
public static readonly DependencyProperty DieClickedCommandProperty =
DependencyProperty.Register("DieClickedCommand", typeof(ICommand), typeof(DieMapPanelControl), new PropertyMetadata(null));
public string Caption
{
get
{
return (string)GetValue(CaptionProperty);
}
set
{
SetValue(CaptionProperty, value);
}
}
public DieMapModel MapModel
{
get
{
return (DieMapModel)GetValue(MapModelProperty);
}
set
{
SetValue(MapModelProperty, value);
}
}
public double DieSize
{
get
{
return (double)GetValue(DieSizeProperty);
}
set
{
SetValue(DieSizeProperty, value);
}
}
public double Spacing
{
get
{
return (double)GetValue(SpacingProperty);
}
set
{
SetValue(SpacingProperty, value);
}
}
public Brush MapBackground
{
get
{
return (Brush)GetValue(MapBackgroundProperty);
}
set
{
SetValue(MapBackgroundProperty, value);
}
}
public Brush CaptionForeground
{
get
{
return (Brush)GetValue(CaptionForegroundProperty);
}
set
{
SetValue(CaptionForegroundProperty, value);
}
}
public Thickness MapMargin
{
get
{
return (Thickness)GetValue(MapMarginProperty);
}
set
{
SetValue(MapMarginProperty, value);
}
}
public Thickness CaptionMargin
{
get
{
return (Thickness)GetValue(CaptionMarginProperty);
}
set
{
SetValue(CaptionMarginProperty, value);
}
}
public ICommand DieClickedCommand
{
get
{
return (ICommand)GetValue(DieClickedCommandProperty);
}
set
{
SetValue(DieClickedCommandProperty, value);
}
}
public DieMapPanelControl()
{
InitializeComponent();
}
private void OpenPreviewWindow(object sender, RoutedEventArgs e)
{
if (_previewWindow == null)
{
_previewWindow = CreatePreviewWindow();
_previewWindow.Closed += OnPreviewWindowClosed;
_previewWindow.Show();
return;
}
if (_previewWindow.WindowState == WindowState.Minimized)
{
_previewWindow.WindowState = WindowState.Normal;
}
_previewWindow.Activate();
}
private DieMapPreviewWindow CreatePreviewWindow()
{
DieMapPreviewWindow previewWindow = new DieMapPreviewWindow();
Window owner = Window.GetWindow(this);
if (owner != null && !ReferenceEquals(owner, previewWindow))
{
previewWindow.Owner = owner;
}
BindingOperations.SetBinding(previewWindow, DieMapPreviewWindow.CaptionProperty, CreateBinding(nameof(Caption)));
BindingOperations.SetBinding(previewWindow, DieMapPreviewWindow.MapModelProperty, CreateBinding(nameof(MapModel)));
BindingOperations.SetBinding(previewWindow, DieMapPreviewWindow.MapBackgroundProperty, CreateBinding(nameof(MapBackground)));
BindingOperations.SetBinding(previewWindow, DieMapPreviewWindow.DieSizeProperty, CreateBinding(nameof(DieSize)));
BindingOperations.SetBinding(previewWindow, DieMapPreviewWindow.SpacingProperty, CreateBinding(nameof(Spacing)));
BindingOperations.SetBinding(previewWindow, DieMapPreviewWindow.DieClickedCommandProperty, CreateBinding(nameof(DieClickedCommand)));
return previewWindow;
}
private Binding CreateBinding(string propertyName)
{
return new Binding(propertyName)
{
Source = this,
Mode = BindingMode.OneWay
};
}
private void OnPreviewWindowClosed(object sender, EventArgs e)
{
if (_previewWindow == null)
{
return;
}
_previewWindow.Closed -= OnPreviewWindowClosed;
_previewWindow = null;
}
}
}

View File

@@ -0,0 +1,37 @@
<Window x:Class="MainShell.Resources.CustomControl.DieMapPreviewWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MainShell.Resources.CustomControl"
x:Name="Root"
Title="{Binding Caption, ElementName=Root}"
Width="900"
Height="700"
MinWidth="640"
MinHeight="480"
WindowStartupLocation="CenterOwner"
Background="#F3F4F6"
mc:Ignorable="d"
d:DesignWidth="900"
d:DesignHeight="700">
<Grid Margin="12">
<Border BorderBrush="#C7C7C7"
BorderThickness="1"
Background="#F3F4F6">
<Grid>
<local:DieMapControl Background="{Binding MapBackground, ElementName=Root}"
MapModel="{Binding MapModel, ElementName=Root}"
Margin="12,12,12,36"
DieSize="{Binding DieSize, ElementName=Root}"
Spacing="{Binding Spacing, ElementName=Root}"
DieClickedCommand="{Binding DieClickedCommand, ElementName=Root}"/>
<TextBlock Text="{Binding Caption, ElementName=Root}"
Foreground="#6B7280"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Margin="0,0,0,12"/>
</Grid>
</Border>
</Grid>
</Window>

View File

@@ -0,0 +1,104 @@
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
namespace MainShell.Resources.CustomControl
{
public partial class DieMapPreviewWindow : Window
{
public static readonly DependencyProperty CaptionProperty =
DependencyProperty.Register("Caption", typeof(string), typeof(DieMapPreviewWindow), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty MapModelProperty =
DependencyProperty.Register("MapModel", typeof(DieMapModel), typeof(DieMapPreviewWindow), new PropertyMetadata(null));
public static readonly DependencyProperty DieSizeProperty =
DependencyProperty.Register("DieSize", typeof(double), typeof(DieMapPreviewWindow), new PropertyMetadata(8.0));
public static readonly DependencyProperty SpacingProperty =
DependencyProperty.Register("Spacing", typeof(double), typeof(DieMapPreviewWindow), new PropertyMetadata(1.0));
public static readonly DependencyProperty MapBackgroundProperty =
DependencyProperty.Register("MapBackground", typeof(Brush), typeof(DieMapPreviewWindow), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(229, 231, 235))));
public static readonly DependencyProperty DieClickedCommandProperty =
DependencyProperty.Register("DieClickedCommand", typeof(ICommand), typeof(DieMapPreviewWindow), new PropertyMetadata(null));
public string Caption
{
get
{
return (string)GetValue(CaptionProperty);
}
set
{
SetValue(CaptionProperty, value);
}
}
public DieMapModel MapModel
{
get
{
return (DieMapModel)GetValue(MapModelProperty);
}
set
{
SetValue(MapModelProperty, value);
}
}
public double DieSize
{
get
{
return (double)GetValue(DieSizeProperty);
}
set
{
SetValue(DieSizeProperty, value);
}
}
public double Spacing
{
get
{
return (double)GetValue(SpacingProperty);
}
set
{
SetValue(SpacingProperty, value);
}
}
public Brush MapBackground
{
get
{
return (Brush)GetValue(MapBackgroundProperty);
}
set
{
SetValue(MapBackgroundProperty, value);
}
}
public ICommand DieClickedCommand
{
get
{
return (ICommand)GetValue(DieClickedCommandProperty);
}
set
{
SetValue(DieClickedCommandProperty, value);
}
}
public DieMapPreviewWindow()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,28 @@
<UserControl x:Class="MainShell.Resources.CustomControl.FlowStageDisplayControl"
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:local="clr-namespace:MainShell.Resources.CustomControl"
mc:Ignorable="d"
d:DesignHeight="80" d:DesignWidth="500">
<Grid>
<Border Height="2" Margin="86,0,86,30" Background="#D1D5DB" VerticalAlignment="Bottom"/>
<ItemsControl ItemsSource="{Binding FlowNodes, RelativeSource={RelativeSource AncestorType={x:Type local:FlowStageDisplayControl}}}"
Margin="40,14,40,16" VerticalAlignment="Center">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel HorizontalAlignment="Center">
<Ellipse Width="12" Height="12" Fill="{Binding Brush}"/>
<TextBlock Text="{Binding DisplayName}" HorizontalAlignment="Center" Margin="0,4,0,0"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>

View File

@@ -0,0 +1,23 @@
using System.Collections;
using System.Windows;
using System.Windows.Controls;
namespace MainShell.Resources.CustomControl
{
public partial class FlowStageDisplayControl : UserControl
{
public static readonly DependencyProperty FlowNodesProperty =
DependencyProperty.Register("FlowNodes", typeof(IEnumerable), typeof(FlowStageDisplayControl), new PropertyMetadata(null));
public IEnumerable FlowNodes
{
get { return (IEnumerable)GetValue(FlowNodesProperty); }
set { SetValue(FlowNodesProperty, value); }
}
public FlowStageDisplayControl()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,53 @@
<UserControl x:Class="MainShell.Resources.CustomControl.HeaderDeviceStatusView"
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"
mc:Ignorable="d"
d:DesignHeight="40" d:DesignWidth="290"
Visibility="{Binding IsVisible, Converter={StaticResource BoolToVisibleConverter}}">
<Border Width="282"
Height="38"
Background="{Binding BadgeBackgroundBrush}"
BorderBrush="{Binding BadgeBorderBrush}"
BorderThickness="1"
CornerRadius="6"
Padding="14,0,16,0">
<Border.Effect>
<DropShadowEffect BlurRadius="8" ShadowDepth="1" Opacity="0.16"/>
</Border.Effect>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="{Binding LabelText}"
Margin="0,0,10,0"
VerticalAlignment="Center"
Foreground="{Binding LabelForegroundBrush}"
FontSize="12"
FontWeight="SemiBold"/>
<Ellipse Grid.Column="1"
Width="10"
Height="10"
Margin="0,0,10,0"
VerticalAlignment="Center"
Fill="{Binding IndicatorBrush}">
<Ellipse.Effect>
<DropShadowEffect BlurRadius="6" ShadowDepth="0" Color="#FFFFFFFF" Opacity="0.32"/>
</Ellipse.Effect>
</Ellipse>
<TextBlock Grid.Column="2"
Text="{Binding StatusText}"
VerticalAlignment="Center"
Foreground="{Binding StatusForegroundBrush}"
FontSize="15"
FontWeight="Bold"/>
</Grid>
</Border>
</UserControl>

View File

@@ -0,0 +1,12 @@
using System.Windows.Controls;
namespace MainShell.Resources.CustomControl
{
public partial class HeaderDeviceStatusView : UserControl
{
public HeaderDeviceStatusView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,33 @@
<UserControl x:Class="MainShell.Resources.CustomControl.LightControl"
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:local="clr-namespace:MainShell.Resources.CustomControl"
xmlns:mw="http://www.maxwell-gp.com/"
mc:Ignorable="d"
>
<Grid Margin="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="120"/>
</Grid.ColumnDefinitions>
<Border BorderThickness="1" Grid.ColumnSpan="3" BorderBrush="{StaticResource BackgroundDeepBrush}"/>
<TextBlock Grid.Column="0" FontWeight="Black" Style="{StaticResource TextBlockStyle}"
Text="{Binding Header, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
<Slider Grid.Column="1"
VerticalAlignment="Center"
Minimum="{Binding Min, RelativeSource={RelativeSource AncestorType=UserControl}}"
Maximum="{Binding Max, RelativeSource={RelativeSource AncestorType=UserControl}}"
TickFrequency="{Binding Tick, RelativeSource={RelativeSource AncestorType=UserControl}}"
IsSnapToTickEnabled="True"
Value="{Binding Value, RelativeSource={RelativeSource AncestorType=UserControl}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<mw:IntNumberBox Grid.Column="2" HorizontalContentAlignment="Right" Margin="6,0,0,0"
Minimum="{Binding Min, RelativeSource={RelativeSource AncestorType=UserControl}}"
Maximum="{Binding Max, RelativeSource={RelativeSource AncestorType=UserControl}}"
Value="{Binding Value, RelativeSource={RelativeSource AncestorType=UserControl}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
</UserControl>

View File

@@ -0,0 +1,57 @@
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 MainShell.Resources.CustomControl
{
/// <summary>
/// LightControl.xaml 的交互逻辑
/// </summary>
public partial class LightControl : UserControl
{
public LightControl()
{
InitializeComponent();
}
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register(nameof(Header), typeof(string), typeof(LightControl), new FrameworkPropertyMetadata("通道",FrameworkPropertyMetadataOptions.AffectsRender));
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(nameof(Value), typeof(int), typeof(LightControl), new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public static readonly DependencyProperty EnabledProperty =
DependencyProperty.Register(nameof(Enabled), typeof(bool), typeof(LightControl), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public static readonly DependencyProperty MinProperty =
DependencyProperty.Register(nameof(Min), typeof(int), typeof(LightControl), new PropertyMetadata(0));
public static readonly DependencyProperty MaxProperty =
DependencyProperty.Register(nameof(Max), typeof(int), typeof(LightControl), new PropertyMetadata(255));
public static readonly DependencyProperty TickProperty =
DependencyProperty.Register(nameof(Tick), typeof(double), typeof(LightControl), new PropertyMetadata(1d));
public string Header { get => (string)GetValue(HeaderProperty); set => SetValue(HeaderProperty, value); }
public int Value { get => (int)GetValue(ValueProperty); set => SetValue(ValueProperty, value); }
public bool Enabled { get => (bool)GetValue(EnabledProperty); set => SetValue(EnabledProperty, value); }
public int Min { get => (int)GetValue(MinProperty); set => SetValue(MinProperty, value); }
public int Max { get => (int)GetValue(MaxProperty); set => SetValue(MaxProperty, value); }
public double Tick { get => (double)GetValue(TickProperty); set => SetValue(TickProperty, value); }
}
}

View File

@@ -0,0 +1,67 @@
using MwFramework.Controls.Components;
using Stylet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace MainShell.Resources.CustomControl
{
public class LoadingService : PropertyChangedBase
{
public static LoadingService Instance { get; } = new LoadingService();
private bool _isBusy;
private string _message;
private double _progressValue;
private bool _canCancel;
private bool _isIndeterminate = true;
private CancellationTokenSource _cts;
public bool IsBusy { get => _isBusy; set => SetAndNotify(ref _isBusy, value); }
public string Message { get => _message; set => SetAndNotify(ref _message, value); }
public double ProgressValue { get => _progressValue; set => SetAndNotify(ref _progressValue, value); }
public bool CanCancel { get => _canCancel; set => SetAndNotify(ref _canCancel, value); }
public bool IsIndeterminate { get => _isIndeterminate; set => SetAndNotify(ref _isIndeterminate, value); }
// 暴露给外部算法使用的 Token
public CancellationToken Token => _cts?.Token ?? CancellationToken.None;
// 取消命令
public ICommand CancelCommand { get; }
private LoadingService()
{
CancelCommand = new DelegateCommand(() => {
_cts?.Cancel();
Message = "正在取消...";
});
}
public void Show(string message, bool isIndeterminate, bool canCancel)
{
_cts = new CancellationTokenSource();
Message = message;
IsIndeterminate = isIndeterminate;
CanCancel = canCancel;
ProgressValue = 0;
IsBusy = true;
}
public void Hide()
{
IsBusy = false;
_cts?.Dispose();
_cts = null;
}
public void Report(double value) => Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
ProgressValue = value;
}));
}
}

View File

@@ -0,0 +1,49 @@
<UserControl x:Class="MainShell.Resources.CustomControl.LoadingWaitView"
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:local="clr-namespace:MainShell.Resources.CustomControl"
DataContext="{x:Static local:LoadingService.Instance}"
Visibility="{Binding IsBusy, Converter={StaticResource BoolToVisibleConverter}}"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Border Background="#44000000" />
<Border Background="White" CornerRadius="8" Padding="30"
VerticalAlignment="Center" HorizontalAlignment="Center" Width="350">
<Border.Effect>
<DropShadowEffect BlurRadius="15" Opacity="0.2"/>
</Border.Effect>
<StackPanel>
<TextBlock Text="{Binding Message}" FontSize="14" Margin="0,0,0,15" TextAlignment="Center" FontWeight="Bold"/>
<ProgressBar Height="12"
Value="{Binding ProgressValue}"
IsIndeterminate="{Binding IsIndeterminate}"
Maximum="100"/>
<TextBlock HorizontalAlignment="Right" Margin="0,5,0,0" FontSize="12" Foreground="Gray">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="{Binding ProgressValue, StringFormat={}{0:F0}%}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsIndeterminate}" Value="True">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<Button Content="取消操作"
Command="{Binding CancelCommand}"
Style="{StaticResource StopButtonStyle}"
Visibility="{Binding CanCancel, Converter={StaticResource BoolToVisibleConverter}}"
HorizontalAlignment="Center"
Padding="20,5"
Margin="0,10,0,0"
Cursor="Hand"/>
</StackPanel>
</Border>
</Grid>
</UserControl>

View File

@@ -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 MainShell.Resources.CustomControl
{
/// <summary>
/// LoadingWaitView.xaml 的交互逻辑
/// </summary>
public partial class LoadingWaitView : UserControl
{
public LoadingWaitView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,93 @@
<UserControl x:Class="MainShell.Resources.CustomControl.MagazineMapControl"
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:local="clr-namespace:MainShell.Resources.CustomControl"
mc:Ignorable="d"
d:DesignHeight="520" d:DesignWidth="280">
<Border Background="#07152F" BorderBrush="#2B3E63" BorderThickness="1" CornerRadius="4" Padding="10">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding MapViewModel.Title, RelativeSource={RelativeSource AncestorType={x:Type local:MagazineMapControl}}}" Foreground="#9FB7E8" FontWeight="Bold" FontStyle="Italic"/>
<TextBlock Grid.Column="1" Text="{Binding MapViewModel.TotalSlots, RelativeSource={RelativeSource AncestorType={x:Type local:MagazineMapControl}}, StringFormat={}{0} SLOTS}" Foreground="#00E5A1" FontWeight="Bold"/>
</Grid>
<Border Grid.Row="1" Margin="0,10,0,10" BorderBrush="#1B2C4F" BorderThickness="1" Padding="6">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding MapViewModel.Slots, RelativeSource={RelativeSource AncestorType={x:Type local:MagazineMapControl}}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Margin="0,1" Padding="6,3" CornerRadius="1" Background="#0D1C3D">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding SlotName}" Foreground="#86A8DA" FontWeight="SemiBold"/>
<TextBlock Grid.Column="1" Text="{Binding StatusText}" Foreground="#506C9A" FontWeight="Bold"/>
</Grid>
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="#0D1C3D"/>
<Style.Triggers>
<DataTrigger Binding="{Binding SlotStatus}" Value="Present">
<Setter Property="Background" Value="#00A77A"/>
</DataTrigger>
<DataTrigger Binding="{Binding SlotStatus}" Value="Processing">
<Setter Property="Background" Value="#F59E0B"/>
</DataTrigger>
<DataTrigger Binding="{Binding SlotStatus}" Value="Completed">
<Setter Property="Background" Value="#2563EB"/>
</DataTrigger>
<DataTrigger Binding="{Binding SlotStatus}" Value="Target">
<Setter Property="Background" Value="#F59E0B"/>
</DataTrigger>
<DataTrigger Binding="{Binding SlotStatus}" Value="Alarm">
<Setter Property="Background" Value="#E53935"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Border>
<UniformGrid Grid.Row="2" Columns="2" Rows="3" Margin="0,2,0,0">
<StackPanel Orientation="Horizontal" Margin="0,2">
<Ellipse Width="10" Height="10" Fill="#00A77A" Margin="0,0,6,0"/>
<TextBlock Text="在位" Foreground="#C7D7F1"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,2">
<Ellipse Width="10" Height="10" Fill="#23385E" Margin="0,0,6,0"/>
<TextBlock Text="空层" Foreground="#C7D7F1"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,2">
<Ellipse Width="10" Height="10" Fill="#F59E0B" Margin="0,0,6,0"/>
<TextBlock Text="加工中" Foreground="#C7D7F1"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,2">
<Ellipse Width="10" Height="10" Fill="#2563EB" Margin="0,0,6,0"/>
<TextBlock Text="加工完成" Foreground="#C7D7F1"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,2">
<Ellipse Width="10" Height="10" Fill="#E53935" Margin="0,0,6,0"/>
<TextBlock Text="异常" Foreground="#C7D7F1"/>
</StackPanel>
</UniformGrid>
</Grid>
</Border>
</UserControl>

View File

@@ -0,0 +1,22 @@
using System.Windows;
using System.Windows.Controls;
namespace MainShell.Resources.CustomControl
{
public partial class MagazineMapControl : UserControl
{
public static readonly DependencyProperty MapViewModelProperty =
DependencyProperty.Register(nameof(MapViewModel), typeof(MagazineMapViewModel), typeof(MagazineMapControl), new PropertyMetadata(null));
public MagazineMapViewModel MapViewModel
{
get { return (MagazineMapViewModel)GetValue(MapViewModelProperty); }
set { SetValue(MapViewModelProperty, value); }
}
public MagazineMapControl()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,127 @@
using Stylet;
using System.Collections.ObjectModel;
namespace MainShell.Resources.CustomControl
{
public class MagazineMapViewModel : PropertyChangedBase
{
private string _title = "MAGAZINE MAP";
public string Title
{
get { return _title; }
set { SetAndNotify(ref _title, value); }
}
private int _totalSlots;
public int TotalSlots
{
get { return _totalSlots; }
set { SetAndNotify(ref _totalSlots, value); }
}
public ObservableCollection<MagazineSlotState> Slots { get; } = new ObservableCollection<MagazineSlotState>();
public static MagazineMapViewModel CreateDefault(int slotCount)
{
var vm = new MagazineMapViewModel { TotalSlots = slotCount };
for (var i = slotCount; i >= 1; i--)
{
var status = MagazineSlotStatus.Empty;
if (i <= 11 || i == 18)
{
status = MagazineSlotStatus.Present;
}
if (i == 10 || i == 9)
{
status = MagazineSlotStatus.Processing;
}
if (i == 8 || i == 7)
{
status = MagazineSlotStatus.Completed;
}
vm.Slots.Add(new MagazineSlotState
{
SlotName = $"L{i:D2}",
SlotStatus = status
});
}
return vm;
}
}
public enum MagazineSlotStatus
{
Empty,
Present,
Processing,
Completed,
Target,
Alarm
}
public class MagazineSlotState : PropertyChangedBase
{
private string _slotName;
public string SlotName
{
get { return _slotName; }
set { SetAndNotify(ref _slotName, value); }
}
private bool _isPresent;
public bool IsPresent
{
get { return _isPresent; }
set
{
if (SetAndNotify(ref _isPresent, value))
{
SlotStatus = value ? MagazineSlotStatus.Present : MagazineSlotStatus.Empty;
OnPropertyChanged(nameof(StatusText));
}
}
}
private MagazineSlotStatus _slotStatus = MagazineSlotStatus.Empty;
public MagazineSlotStatus SlotStatus
{
get { return _slotStatus; }
set
{
if (SetAndNotify(ref _slotStatus, value))
{
_isPresent = value == MagazineSlotStatus.Present;
OnPropertyChanged(nameof(IsPresent));
OnPropertyChanged(nameof(StatusText));
}
}
}
public string StatusText
{
get
{
switch (SlotStatus)
{
case MagazineSlotStatus.Present:
return "PRES";
case MagazineSlotStatus.Processing:
return "PROC";
case MagazineSlotStatus.Completed:
return "DONE";
case MagazineSlotStatus.Target:
return "PROC";
case MagazineSlotStatus.Alarm:
return "ALM";
default:
return "---";
}
}
}
}
}

View File

@@ -0,0 +1,311 @@
<UserControl x:Class="MainShell.Resources.CustomControl.PaginationControl"
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:local="clr-namespace:MainShell.Resources.CustomControl"
xmlns:mw="http://www.maxwell-gp.com/"
mc:Ignorable="d"
>
<UserControl.Resources>
<SolidColorBrush x:Key="PaginationPanelBackgroundBrush" Color="#F7F8FB"/>
<SolidColorBrush x:Key="PaginationPanelBorderBrush" Color="#D7DEE8"/>
<SolidColorBrush x:Key="PaginationTextBrush" Color="#2F3A4C"/>
<SolidColorBrush x:Key="PaginationMutedTextBrush" Color="#90A0B5"/>
<SolidColorBrush x:Key="PaginationAccentBrush" Color="#3D7DFF"/>
<LinearGradientBrush x:Key="PaginationPrimaryButtonBrush" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#4B668D" Offset="0"/>
<GradientStop Color="#2E4566" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="PaginationPrimaryButtonHoverBrush" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#57749C" Offset="0"/>
<GradientStop Color="#344D71" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="PaginationPrimaryButtonPressedBrush" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#2C4261" Offset="0"/>
<GradientStop Color="#21344F" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="PaginationButtonBackgroundBrush" Color="#F8FAFD"/>
<SolidColorBrush x:Key="PaginationButtonHoverBrush" Color="#EEF3FA"/>
<SolidColorBrush x:Key="PaginationComboBoxHoverBrush" Color="#F3F7FC"/>
<SolidColorBrush x:Key="PaginationComboBoxDropDownBrush" Color="#7C8DA5"/>
<SolidColorBrush x:Key="PaginationComboBoxPopupBorderBrush" Color="#CDD7E3"/>
<Style x:Key="PaginationTextStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource PaginationTextBrush}"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<Style x:Key="PaginationButtonStyle" TargetType="Button">
<Setter Property="Width" Value="32"/>
<Setter Property="Height" Value="24"/>
<Setter Property="Margin" Value="1,0"/>
<Setter Property="Padding" Value="8,0"/>
<Setter Property="Foreground" Value="{StaticResource PaginationTextBrush}"/>
<Setter Property="Background" Value="{StaticResource PaginationButtonBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource PaginationPanelBorderBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="ButtonBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="3">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="ButtonBorder" Property="Background" Value="{StaticResource PaginationButtonHoverBrush}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="ButtonBorder" Property="Background" Value="{StaticResource PaginationPanelBorderBrush}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="ButtonBorder" Property="Opacity" Value="0.5"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="PaginationPrimaryButtonStyle" TargetType="Button" BasedOn="{StaticResource PaginationButtonStyle}">
<Setter Property="Width" Value="36"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="{StaticResource PaginationPrimaryButtonBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource PaginationPrimaryButtonBrush}"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource PaginationPrimaryButtonHoverBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource PaginationPrimaryButtonHoverBrush}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="{StaticResource PaginationPrimaryButtonPressedBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource PaginationPrimaryButtonPressedBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="PaginationComboBoxToggleButtonStyle" TargetType="ToggleButton">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border x:Name="ToggleBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="3">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="22"/>
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0"
Margin="8,0,0,0"
VerticalAlignment="Center"
HorizontalAlignment="Left"/>
<Border Grid.Column="1"
BorderBrush="{StaticResource PaginationPanelBorderBrush}"
BorderThickness="1,0,0,0"
Background="Transparent">
<Path x:Name="Arrow"
Width="8"
Height="5"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Fill="{StaticResource PaginationComboBoxDropDownBrush}"
Data="M 0 0 L 4 4 L 8 0 Z"/>
</Border>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="ToggleBorder" Property="Background" Value="{StaticResource PaginationComboBoxHoverBrush}"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="ToggleBorder" Property="Background" Value="{StaticResource PaginationComboBoxHoverBrush}"/>
<Setter TargetName="Arrow" Property="Fill" Value="{StaticResource PaginationAccentBrush}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="ToggleBorder" Property="Opacity" Value="0.6"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="PaginationComboBoxItemStyle" TargetType="ComboBoxItem">
<Setter Property="Foreground" Value="{StaticResource PaginationTextBrush}"/>
<Setter Property="Padding" Value="8,4"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border x:Name="ItemBorder"
Background="Transparent"
CornerRadius="2">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="Center"
Margin="2,0"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="ItemBorder" Property="Background" Value="{StaticResource PaginationButtonHoverBrush}"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="ItemBorder" Property="Background" Value="{StaticResource PaginationComboBoxHoverBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="PaginationComboBoxStyle" TargetType="ComboBox">
<Setter Property="Height" Value="24"/>
<Setter Property="Width" Value="64"/>
<Setter Property="Margin" Value="4,0,0,0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Foreground" Value="{StaticResource PaginationTextBrush}"/>
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="{StaticResource PaginationPanelBorderBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="ItemContainerStyle" Value="{StaticResource PaginationComboBoxItemStyle}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton x:Name="ToggleButton"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Focusable="False"
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press"
Style="{StaticResource PaginationComboBoxToggleButtonStyle}">
<TextBlock Text="{Binding SelectionBoxItem, RelativeSource={RelativeSource TemplatedParent}}"
Foreground="{TemplateBinding Foreground}"
FontSize="12"
VerticalAlignment="Center"/>
</ToggleButton>
<Popup x:Name="Popup"
AllowsTransparency="True"
Focusable="False"
IsOpen="{TemplateBinding IsDropDownOpen}"
Placement="Bottom"
PopupAnimation="Slide">
<Border Margin="0,2,0,0"
MinWidth="{Binding ActualWidth, RelativeSource={RelativeSource TemplatedParent}}"
Background="White"
BorderBrush="{StaticResource PaginationComboBoxPopupBorderBrush}"
BorderThickness="1"
CornerRadius="3">
<ScrollViewer CanContentScroll="True"
MaxHeight="180"
Padding="2">
<ItemsPresenter KeyboardNavigation.DirectionalNavigation="Contained"/>
</ScrollViewer>
</Border>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="PaginationJumpBoxStyle" TargetType="mw:IntNumberBox">
<Setter Property="Width" Value="42"/>
<Setter Property="Height" Value="24"/>
<Setter Property="Margin" Value="4,0,0,0"/>
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="{StaticResource PaginationPanelBorderBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{StaticResource PaginationTextBrush}"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
</UserControl.Resources>
<ScrollViewer HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Disabled"
Style="{StaticResource ProcessScrollViewerStyle}"
Padding="0"
Background="Transparent">
<Border Background="{StaticResource PaginationPanelBackgroundBrush}"
BorderBrush="{StaticResource PaginationPanelBorderBrush}"
BorderThickness="1"
CornerRadius="2"
Padding="6,3"
MinWidth="470">
<Grid VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="12"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="14"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="每页:" Style="{StaticResource PaginationTextStyle}" FontSize="12"/>
<ComboBox Style="{StaticResource PaginationComboBoxStyle}"
ItemsSource="{Binding PageSizeOptions}"
SelectedItem="{Binding PageSize}"/>
</StackPanel>
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center">
<Button Content="首页" Command="{Binding MoveFirstCommand}" Width="36" Style="{StaticResource PaginationButtonStyle}"/>
<Button Content="&lt;" Command="{Binding MoveBackCommand}" Style="{StaticResource PaginationButtonStyle}"/>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="10,0">
<TextBlock Text="{Binding CurrentPage}"
Foreground="{StaticResource PaginationAccentBrush}"
FontSize="17"
FontWeight="Normal"
VerticalAlignment="Center"/>
<TextBlock Text=" / "
Style="{StaticResource PaginationTextStyle}"
FontSize="15"
Margin="3,0"/>
<TextBlock Text="{Binding TotalPages}"
Style="{StaticResource PaginationTextStyle}"
FontSize="15"
FontWeight="Normal"/>
<TextBlock Text="{Binding TotalItems, StringFormat='(共{0}项)'}"
Foreground="{StaticResource PaginationMutedTextBrush}"
FontSize="10"
Margin="4,4,0,0"
VerticalAlignment="Center"/>
</StackPanel>
<Button Content=">" Command="{Binding MoveNextCommand}" Style="{StaticResource PaginationButtonStyle}"/>
<Button Content="尾页" Command="{Binding MoveLastCommand}" Width="36" Style="{StaticResource PaginationButtonStyle}"/>
</StackPanel>
<Border Grid.Column="4"
Width="1"
Height="16"
Background="{StaticResource PaginationPanelBorderBrush}"
VerticalAlignment="Center"/>
<StackPanel Grid.Column="6" Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="跳转:" Style="{StaticResource PaginationTextStyle}" FontSize="12"/>
<mw:IntNumberBox Style="{StaticResource PaginationJumpBoxStyle}"
mw:NumericKeypadAttach.IsEnabled="True"
Value="{Binding JumpPage, UpdateSourceTrigger=PropertyChanged}"/>
<Button Content="Go" Command="{Binding JumpToPageCommand}" Margin="6,0,0,0" Style="{StaticResource PaginationPrimaryButtonStyle}"/>
</StackPanel>
</Grid>
</Border>
</ScrollViewer>
</UserControl>

View File

@@ -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 MainShell.Resources.CustomControl
{
/// <summary>
/// PaginationControl.xaml 的交互逻辑
/// </summary>
public partial class PaginationControl : UserControl
{
public PaginationControl()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,102 @@
using MaxwellFramework.Core.Common.Command;
using MwFramework.Controls.Components;
using Stylet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using DelegateCommand = MwFramework.Controls.Components.DelegateCommand;
namespace MainShell.Resources.CustomControl
{
public class PaginationViewModel : PropertyChangedBase
{
private int _currentPage = 1;
private int _pageSize = 20;
private int _totalItems;
private int _jumpPage = 1; // 新增跳转页字段
public List<int> PageSizeOptions { get; } = new List<int> { 20, 50, 100, 200 };
public int CurrentPage
{
get => _currentPage;
set
{
int validated = Math.Max(1, Math.Min(value, TotalPages == 0 ? 1 : TotalPages));
if (SetAndNotify(ref _currentPage, validated))
{
JumpPage = validated; // 页面变更时同步更新跳转输入框数值
PageChanged?.Invoke(this, EventArgs.Empty);
// 关键:通知命令状态刷新
(MoveFirstCommand as DelegateCommand)?.RaiseCanExecuteChanged();
(MoveBackCommand as DelegateCommand)?.RaiseCanExecuteChanged();
(MoveNextCommand as DelegateCommand)?.RaiseCanExecuteChanged();
(MoveLastCommand as DelegateCommand)?.RaiseCanExecuteChanged();
}
}
}
// 新增跳转页属性
public int JumpPage
{
get => _jumpPage;
set
{
if (SetAndNotify(ref _jumpPage, value))
{
// 输入变化时刷新跳转按钮状态
(JumpToPageCommand as DelegateCommand)?.RaiseCanExecuteChanged();
}
}
}
public int PageSize
{
get => _pageSize;
set
{
if (SetAndNotify(ref _pageSize, value))
{
OnPropertyChanged(nameof(TotalPages));
CurrentPage = 1; // 内部会触发 PageChanged
PageChanged?.Invoke(this, EventArgs.Empty);
(JumpToPageCommand as DelegateCommand)?.RaiseCanExecuteChanged();
}
}
}
public int TotalItems
{
get => _totalItems;
set
{
if (SetAndNotify(ref _totalItems, value))
{
OnPropertyChanged(nameof(TotalPages));
// 刷新命令状态,防止数据更新后按钮不可用
(MoveNextCommand as DelegateCommand)?.RaiseCanExecuteChanged();
(MoveLastCommand as DelegateCommand)?.RaiseCanExecuteChanged();
(JumpToPageCommand as DelegateCommand)?.RaiseCanExecuteChanged();
}
}
}
public int TotalPages => (int)Math.Ceiling((double)_totalItems / Math.Max(1, _pageSize));
// 优化后的命令,增加了 CanExecute 判断
public ICommand MoveFirstCommand => new DelegateCommand(() => CurrentPage = 1, () => CurrentPage > 1);
public ICommand MoveBackCommand => new DelegateCommand(() => CurrentPage--, () => CurrentPage > 1);
public ICommand MoveNextCommand => new DelegateCommand(() => CurrentPage++, () => CurrentPage < TotalPages);
public ICommand MoveLastCommand => new DelegateCommand(() => CurrentPage = TotalPages, () => CurrentPage < TotalPages);
// 新增跳转命令
public ICommand JumpToPageCommand => new DelegateCommand(
() => CurrentPage = JumpPage,
() => JumpPage >= 1 && JumpPage <= TotalPages);
public event EventHandler PageChanged;
}
}

View File

@@ -0,0 +1,70 @@
<UserControl x:Class="MainShell.Resources.CustomControl.RegionEditorView"
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:local="clr-namespace:MainShell.Resources.CustomControl"
xmlns:mw="http://www.maxwell-gp.com/"
x:Name="Root"
mc:Ignorable="d"
d:DesignHeight="150" d:DesignWidth="550">
<GroupBox Header="{Binding Title, ElementName=Root}" BorderBrush="#DDD" Margin="5">
<Grid Margin="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="10"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Orientation="Horizontal">
<TextBlock Text="起始" VerticalAlignment="Center" FontWeight="Bold" Foreground="#4A90E2"/>
</StackPanel>
<UniformGrid Grid.Row="0" Grid.Column="1" Columns="2">
<StackPanel Margin="2,0">
<TextBlock Text="行 (R)" FontSize="10" Foreground="Gray"/>
<mw:IntNumberBox mw:NumericKeypadAttach.IsEnabled="True" Value="{Binding StartRow, UpdateSourceTrigger=PropertyChanged}" Padding="3"/>
</StackPanel>
<StackPanel Margin="2,0">
<TextBlock Text="列 (C)" FontSize="10" Foreground="Gray"/>
<mw:IntNumberBox mw:NumericKeypadAttach.IsEnabled="True" Value="{Binding StartCol, UpdateSourceTrigger=PropertyChanged}" Padding="3"/>
</StackPanel>
</UniformGrid>
<TextBlock Grid.Row="0" Grid.Column="2" Text="至" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,5"/>
<StackPanel Grid.Row="0" Grid.Column="3" Orientation="Horizontal">
<TextBlock Text="结束" VerticalAlignment="Center" FontWeight="Bold" Foreground="#E24A4A"/>
</StackPanel>
<UniformGrid Grid.Row="0" Grid.Column="4" Columns="2">
<StackPanel Margin="2,0">
<TextBlock Text="行 (R)" FontSize="10" Foreground="Gray"/>
<mw:IntNumberBox mw:NumericKeypadAttach.IsEnabled="True" Value="{Binding EndRow, UpdateSourceTrigger=PropertyChanged}" Padding="3"/>
</StackPanel>
<StackPanel Margin="2,0">
<TextBlock Text="列 (C)" FontSize="10" Foreground="Gray"/>
<mw:IntNumberBox mw:NumericKeypadAttach.IsEnabled="True" Value="{Binding EndCol, UpdateSourceTrigger=PropertyChanged}" Padding="3"/>
</StackPanel>
</UniformGrid>
<Border Visibility="Collapsed" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="5" Background="#F9F9F9" CornerRadius="4" Padding="8">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="当前选区规模:" Foreground="#666"/>
<TextBlock Text="{Binding RowCount}" FontWeight="Bold"/>
<TextBlock Text=" 行 × "/>
<TextBlock Text="{Binding ColCount}" FontWeight="Bold"/>
<TextBlock Text=" 列"/>
<TextBlock Text="{Binding TotalItems, StringFormat=' (共 {0} 点)'}" Margin="10,0,0,0" FontStyle="Italic"/>
</StackPanel>
</Border>
</Grid>
</GroupBox>
</UserControl>

View File

@@ -0,0 +1,37 @@
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 MainShell.Resources.CustomControl
{
/// <summary>
/// RegionEditorView.xaml 的交互逻辑
/// </summary>
public partial class RegionEditorView : UserControl
{
public RegionEditorView()
{
InitializeComponent();
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(RegionEditorView), new PropertyMetadata("区域坐标设置"));
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
}
}