382 lines
14 KiB
C#
382 lines
14 KiB
C#
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Input;
|
|
using System.Diagnostics;
|
|
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel.Params;
|
|
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel;
|
|
using MECF.Framework.UI.Client.RecipeEditorLib.DGExtension.CustomColumn;
|
|
using MECF.Framework.Common.Account.Permissions;
|
|
using OpenSEMI.ClientBase;
|
|
using DataGridRowEventArgs = ExtendedGrid.Microsoft.Windows.Controls.DataGridRowEventArgs;
|
|
using DataGridCellEditEndingEventArgs = ExtendedGrid.Microsoft.Windows.Controls.DataGridCellEditEndingEventArgs;
|
|
using DataGridBeginningEditEventArgs = ExtendedGrid.Microsoft.Windows.Controls.DataGridBeginningEditEventArgs;
|
|
using ExDataGridRow = ExtendedGrid.Microsoft.Windows.Controls.DataGridRow;
|
|
|
|
namespace MECF.Framework.UI.Client.RecipeEditorLib.DGExtension
|
|
{
|
|
/// <summary>
|
|
/// Interaction logic for DataGridRecipe.xaml
|
|
/// </summary>
|
|
public partial class DataGridRecipe : UserControl
|
|
{
|
|
enum Scroll
|
|
{
|
|
VerticalOffset,
|
|
HorizontalOffset
|
|
}
|
|
|
|
#region Constructors
|
|
|
|
ScrollViewer scroll;
|
|
public DataGridRecipe()
|
|
{
|
|
InitializeComponent();
|
|
}
|
|
|
|
private void dgCustom_ScrollChanged(object sender, ScrollChangedEventArgs e)
|
|
{
|
|
|
|
if (scroll==null)
|
|
scroll = (ScrollViewer)e.OriginalSource;
|
|
|
|
if (ScrollViewerOffset == null)
|
|
ScrollViewerOffset=new double[2];
|
|
|
|
var _verticalOffset = scroll.VerticalOffset < scroll.ScrollableHeight ? scroll.VerticalOffset :
|
|
ScrollViewerOffset[(int)Scroll.VerticalOffset] <= scroll.ScrollableHeight? scroll.VerticalOffset : ScrollViewerOffset[(int)Scroll.VerticalOffset];
|
|
|
|
var _horizontalOffset= scroll.HorizontalOffset < scroll.ScrollableWidth ? scroll.HorizontalOffset :
|
|
ScrollViewerOffset[(int)Scroll.HorizontalOffset] <= scroll.ScrollableWidth ? scroll.HorizontalOffset: ScrollViewerOffset[(int)Scroll.HorizontalOffset];
|
|
|
|
ScrollViewerOffset = new double[] { _verticalOffset, _horizontalOffset };
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
|
|
#endregion
|
|
|
|
#region Dependency Properties
|
|
|
|
public static readonly DependencyProperty AllowDragToFillProperty = DependencyProperty.Register(
|
|
nameof(AllowDragToFill), typeof(bool), typeof(DataGridRecipe), new PropertyMetadata(true));
|
|
|
|
public bool AllowDragToFill
|
|
{
|
|
get => (bool)GetValue(AllowDragToFillProperty);
|
|
set => SetValue(AllowDragToFillProperty, value);
|
|
}
|
|
|
|
|
|
public double[] ScrollViewerOffset
|
|
{
|
|
get { return (double[])GetValue(ScrollViewerOffsetProperty); }
|
|
set { SetValue(ScrollViewerOffsetProperty, value); }
|
|
}
|
|
|
|
// Using a DependencyProperty as the backing store for ScrollViewerOffset. This enables animation, styling, binding, etc...
|
|
public static readonly DependencyProperty ScrollViewerOffsetProperty =
|
|
DependencyProperty.Register("ScrollViewerOffset", typeof(double[]), typeof(DataGridRecipe), new PropertyMetadata(new double[2], ScrollViewerOffsetPropertyChangedCallback));
|
|
|
|
#region RecipeData
|
|
|
|
|
|
public static readonly DependencyProperty RecipeProperty = DependencyProperty.Register(
|
|
nameof(Recipe), typeof(RecipeData), typeof(DataGridRecipe), new PropertyMetadata(default(RecipeData), RecipePropertyChangedCallback));
|
|
|
|
public ExtendedGrid.Microsoft.Windows.Controls.DataGridHeadersVisibility ComperHeadersVisibility
|
|
{
|
|
get { return (ExtendedGrid.Microsoft.Windows.Controls.DataGridHeadersVisibility)GetValue(ComperHeadersVisibilityProperty); }
|
|
set { SetValue(ComperHeadersVisibilityProperty, value); }
|
|
}
|
|
|
|
// Using a DependencyProperty as the backing store for ComperHeadersVisibility. This enables animation, styling, binding, etc...
|
|
public static readonly DependencyProperty ComperHeadersVisibilityProperty =
|
|
DependencyProperty.Register("ComperHeadersVisibility", typeof(ExtendedGrid.Microsoft.Windows.Controls.DataGridHeadersVisibility), typeof(DataGridRecipe), new PropertyMetadata(ExtendedGrid.Microsoft.Windows.Controls.DataGridHeadersVisibility.Column));
|
|
|
|
|
|
private static void ScrollViewerOffsetPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
if (d is DataGridRecipe self)
|
|
{
|
|
if (self.scroll != null)
|
|
{
|
|
if (e.NewValue != null)
|
|
{
|
|
var _scOffset = (double[])e.NewValue;
|
|
|
|
self.scroll.ScrollToVerticalOffset(_scOffset[(int)Scroll.VerticalOffset] <= self.scroll.ScrollableHeight ? _scOffset[(int)Scroll.VerticalOffset] : self.scroll.ScrollableHeight);
|
|
self.scroll.ScrollToHorizontalOffset(_scOffset[(int)Scroll.HorizontalOffset] <= self.scroll.ScrollableWidth ? _scOffset[(int)Scroll.HorizontalOffset] : self.scroll.ScrollableWidth);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
private static void RecipePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
if (d is DataGridRecipe dg)
|
|
{
|
|
if (e.NewValue is RecipeData recipe)
|
|
{
|
|
dg.dgCustom.ItemsSource = recipe.Steps;
|
|
recipe.PropertyChanged += (sender, e) =>
|
|
{
|
|
// 同步白名单编辑模式
|
|
if (e.PropertyName == nameof(RecipeData.IsAccessibleWhitelistEditMode))
|
|
{
|
|
dg.dgCustom.IsAccessibleWhitelistEditMode = recipe.IsAccessibleWhitelistEditMode;
|
|
}
|
|
|
|
};
|
|
|
|
// 创建DataGrid列
|
|
dg.ClearColumns();
|
|
|
|
if (recipe.Columns != null)
|
|
{
|
|
foreach (var col in recipe.Columns)
|
|
dg.AddColumn(col);
|
|
}
|
|
}
|
|
else
|
|
dg.dgCustom.ItemsSource = null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置或返回编辑器正在编辑的Recipe。
|
|
/// </summary>
|
|
public RecipeData Recipe
|
|
{
|
|
get => (RecipeData)GetValue(RecipeProperty);
|
|
set => SetValue(RecipeProperty, value);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region FrozenColumnCount
|
|
|
|
public static readonly DependencyProperty FrozenColumnCountProperty = DependencyProperty.Register(
|
|
nameof(FrozenColumnCount), typeof(int), typeof(DataGridRecipe), new PropertyMetadata(default(int), FrozenColumnCountPropertyChangedCallback));
|
|
|
|
private static void FrozenColumnCountPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
if (d is DataGridRecipe dg)
|
|
{
|
|
if (e.NewValue is int count)
|
|
dg.dgCustom.FrozenColumnCount = count;
|
|
else
|
|
dg.dgCustom.FrozenColumnCount = 0;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置或返回编辑器冻结的列数。
|
|
/// </summary>
|
|
public int FrozenColumnCount
|
|
{
|
|
get => (int)GetValue(FrozenColumnCountProperty);
|
|
set => SetValue(FrozenColumnCountProperty, value);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
private void RowOnSelected(object sender, RoutedEventArgs e)
|
|
{
|
|
if (!(e.Source is ExDataGridRow dgr))
|
|
return;
|
|
|
|
if (!(dgr.DataContext is RecipeStep recipeStep))
|
|
return;
|
|
|
|
var param = recipeStep.FindParamByControlName(RecipeControlNames.STEP_NO);
|
|
if (param is StepParam sp)
|
|
{
|
|
sp.IsChecked = true;
|
|
}
|
|
}
|
|
|
|
private void RowOnUnselected(object sender, RoutedEventArgs e)
|
|
{
|
|
if (!(e.Source is ExDataGridRow dgr))
|
|
return;
|
|
|
|
if (!(dgr.DataContext is RecipeStep recipeStep))
|
|
return;
|
|
|
|
var param = recipeStep.FindParamByControlName(RecipeControlNames.STEP_NO);
|
|
if (param is StepParam sp)
|
|
{
|
|
sp.IsChecked = false;
|
|
}
|
|
}
|
|
|
|
private void ClearColumns()
|
|
{
|
|
dgCustom.Columns.Clear();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 生成编辑器的列。
|
|
/// </summary>
|
|
private void AddColumn(EditorDataGridTemplateColumnBase col)
|
|
{
|
|
// 设置ColumnHeaderTemplate和DataGridCellTemplate
|
|
if (string.IsNullOrEmpty(col.StringCellTemplate) == false)
|
|
col.CellTemplate = (DataTemplate)FindResource(col.StringCellTemplate);
|
|
|
|
if (string.IsNullOrEmpty(col.StringCellEditingTemplate) == false)
|
|
col.CellEditingTemplate = (DataTemplate)FindResource(col.StringCellEditingTemplate);
|
|
|
|
if (string.IsNullOrEmpty(col.StringHeaderTemplate) == false)
|
|
col.HeaderTemplate = (DataTemplate)FindResource(col.StringHeaderTemplate);
|
|
|
|
// 通过Columns重建XDataGrid列
|
|
dgCustom.Columns.Add(col);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 滚动到并高亮指定的参数单元格。
|
|
/// </summary>
|
|
/// <param name="param"></param>
|
|
public void FocusToParam(IParam param)
|
|
{
|
|
if (param == null)
|
|
return;
|
|
|
|
Recipe.Steps.ResetHighlight();
|
|
|
|
var row = param.RowOwner;
|
|
var col = param.ColumnOwner;
|
|
|
|
if (row != null && col != null)
|
|
{
|
|
dgCustom.ScrollIntoView(param.Parent, col);
|
|
param.Highlight();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Events
|
|
|
|
private void DgCustom_OnBeginningEdit(object sender, DataGridBeginningEditEventArgs e)
|
|
{
|
|
Debug.Assert(e.Row.Item is RecipeStep, "The content of row is not RecipeStep.");
|
|
if (e.Row.Item is RecipeStep step)
|
|
{
|
|
var param = step[e.Column.DisplayIndex];
|
|
|
|
if (param is IValueParam && param.Permission != MenuPermissionEnum.MP_READ_WRITE || param.IsHideValue)
|
|
{
|
|
e.Cancel = true;
|
|
|
|
// 如果单元格为只读权限、或设置了隐藏参数值,则提示不能编辑
|
|
var reason = "";
|
|
if (param.ColumnPermission != MenuPermissionEnum.MP_READ_WRITE)
|
|
reason = "Recipe Row Access Denied!\r\n\r\nPlease check the RecipeRow Access Permission.";
|
|
else if (param.StepPermission != MenuPermissionEnum.MP_READ_WRITE)
|
|
reason = "Recipe Step Access Denied!\r\n\r\nPlease check the RecipeCol Access Permission.";
|
|
else if (param.IsHideValue)
|
|
reason = "Hidden Cell is denied editing.";
|
|
else
|
|
reason = "Cell Access Denied!\r\n\r\nPlease check the RecipeRow/RecipeCol Access Permission.";
|
|
|
|
|
|
DialogBox.ShowError(reason);
|
|
}
|
|
}
|
|
else
|
|
e.Cancel = true;
|
|
}
|
|
|
|
private void DataGridCell_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
|
|
{
|
|
|
|
// 仅在编辑AccessPermissionWhitelist编辑模式下有效。
|
|
if (!Recipe.IsAccessibleWhitelistEditMode)
|
|
return;
|
|
|
|
if (sender is Border bdr && bdr.DataContext is Param param)
|
|
{
|
|
if (param.IsHighlighted)
|
|
param.ResetHighlight();
|
|
else
|
|
param.Highlight();
|
|
}
|
|
}
|
|
|
|
private void DgCustom_OnLoadingRow(object sender, DataGridRowEventArgs e)
|
|
{
|
|
e.Row.Selected += RowOnSelected;
|
|
e.Row.Unselected += RowOnUnselected;
|
|
|
|
if (sender is XDataGrid dg && e.Row.DataContext is RecipeStep step)
|
|
{
|
|
for (var i = 0; i < step.Count; i++)
|
|
{
|
|
step[i].RowOwner = e.Row;
|
|
step[i].ColumnOwner = dg.Columns[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DgCustom_OnUnloadingRow(object sender, DataGridRowEventArgs e)
|
|
{
|
|
e.Row.Selected -= RowOnSelected;
|
|
e.Row.Unselected -= RowOnUnselected;
|
|
}
|
|
|
|
|
|
private void DgCustom_OnCellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
|
|
{
|
|
if (e.Row.Item is RecipeStep step)
|
|
{
|
|
step.CalculateGasFlow();
|
|
step.Parent.Validate();
|
|
}
|
|
}
|
|
|
|
private void Expander_OnExpanded(object sender, RoutedEventArgs e)
|
|
{
|
|
if (sender is Expander expander && expander.DataContext is ExpanderColumn col)
|
|
{
|
|
foreach (var subCol in col.ChildColumns)
|
|
{
|
|
subCol.UpdateVisibility();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Expander_OnCollapsed(object sender, RoutedEventArgs e)
|
|
{
|
|
if (sender is Expander expander && expander.DataContext is ExpanderColumn col)
|
|
{
|
|
foreach (var subCol in col.ChildColumns)
|
|
{
|
|
subCol.Visibility = Visibility.Collapsed;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 滚动DataGrid视图到指定的配方步骤。
|
|
/// </summary>
|
|
/// <param name="step"></param>
|
|
public void ScrollToRecipeStep(RecipeStep step)
|
|
{
|
|
dgCustom.ScrollIntoView(step);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|