264 lines
8.9 KiB
C#
264 lines
8.9 KiB
C#
using Prism.Ioc;
|
|
using System;
|
|
using System.Globalization;
|
|
using System.Windows.Media;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Data;
|
|
using System.Windows.Input;
|
|
using XP.Common.Logging.Interfaces;
|
|
using XplorePlane.Services;
|
|
using XplorePlane.ViewModels.Cnc;
|
|
|
|
namespace XplorePlane.Views.Cnc
|
|
{
|
|
/// <summary>
|
|
/// CNC editor main page view.
|
|
/// </summary>
|
|
public partial class CncPageView : UserControl
|
|
{
|
|
private static readonly Brush SelectedNodeBackground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#E7F0F7"));
|
|
private static readonly Brush SelectedNodeBorder = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#9CB9D1"));
|
|
private static readonly Brush HoverNodeBackground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#F6FAFC"));
|
|
private static readonly Brush HoverNodeBorder = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#D7E4EE"));
|
|
private static readonly Brush TransparentBrush = Brushes.Transparent;
|
|
private CncInspectionModulePipelineViewModel _inspectionModulePipelineViewModel;
|
|
|
|
public CncPageView()
|
|
{
|
|
InitializeComponent();
|
|
Loaded += OnLoaded;
|
|
}
|
|
|
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
|
{
|
|
CncEditorViewModel editorViewModel = DataContext as CncEditorViewModel;
|
|
if (editorViewModel == null)
|
|
{
|
|
try
|
|
{
|
|
editorViewModel = ContainerLocator.Current?.Resolve<CncEditorViewModel>();
|
|
DataContext = editorViewModel;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// keep existing DataContext if resolution fails
|
|
}
|
|
}
|
|
|
|
if (editorViewModel == null || _inspectionModulePipelineViewModel != null)
|
|
return;
|
|
|
|
try
|
|
{
|
|
var imageProcessingService = ContainerLocator.Current.Resolve<IImageProcessingService>();
|
|
var persistenceService = ContainerLocator.Current.Resolve<IPipelinePersistenceService>();
|
|
var logger = ContainerLocator.Current.Resolve<ILoggerService>();
|
|
|
|
_inspectionModulePipelineViewModel = new CncInspectionModulePipelineViewModel(
|
|
editorViewModel,
|
|
imageProcessingService,
|
|
persistenceService,
|
|
logger);
|
|
|
|
InspectionModulePipelineEditor.DataContext = _inspectionModulePipelineViewModel;
|
|
InspectionModulePipelineEmptyState.DataContext = _inspectionModulePipelineViewModel;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// keep page usable even if pipeline editor host setup fails
|
|
}
|
|
|
|
CncTreeView.ContextMenuOpening -= CncTreeView_ContextMenuOpening;
|
|
CncTreeView.ContextMenuOpening += CncTreeView_ContextMenuOpening;
|
|
CncTreeView.LayoutUpdated -= CncTreeView_LayoutUpdated;
|
|
CncTreeView.LayoutUpdated += CncTreeView_LayoutUpdated;
|
|
UpdateNodeVisualState();
|
|
}
|
|
|
|
private void CncTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
|
{
|
|
if (DataContext is CncEditorViewModel viewModel)
|
|
{
|
|
viewModel.SelectedNode = e.NewValue as CncNodeViewModel;
|
|
}
|
|
|
|
UpdateNodeVisualState();
|
|
}
|
|
|
|
private void CncTreeView_PreviewKeyDown(object sender, KeyEventArgs e)
|
|
{
|
|
if (e.Key != Key.Delete || DataContext is not CncEditorViewModel viewModel)
|
|
return;
|
|
|
|
if (!viewModel.DeleteNodeCommand.CanExecute())
|
|
return;
|
|
|
|
viewModel.DeleteNodeCommand.Execute();
|
|
e.Handled = true;
|
|
}
|
|
|
|
private void CncTreeView_ContextMenuOpening(object sender, ContextMenuEventArgs e)
|
|
{
|
|
if (DataContext is not CncEditorViewModel viewModel)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var position = Mouse.GetPosition(CncTreeView);
|
|
var hit = VisualTreeHelper.HitTest(CncTreeView, position);
|
|
var treeViewItem = FindAncestor<TreeViewItem>(hit?.VisualHit);
|
|
if (treeViewItem?.DataContext is not CncNodeViewModel nodeVm)
|
|
{
|
|
CncTreeView.ContextMenu = null;
|
|
return;
|
|
}
|
|
|
|
viewModel.SelectedNode = nodeVm;
|
|
UpdateNodeVisualState();
|
|
|
|
CncTreeView.ContextMenu = new ContextMenu
|
|
{
|
|
Items =
|
|
{
|
|
new MenuItem
|
|
{
|
|
Header = "在上方插入位置",
|
|
Command = viewModel.PrepareInsertAboveCommand,
|
|
CommandParameter = nodeVm
|
|
},
|
|
new MenuItem
|
|
{
|
|
Header = "在下方插入位置",
|
|
Command = viewModel.PrepareInsertBelowCommand,
|
|
CommandParameter = nodeVm
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
private void CncTreeView_LayoutUpdated(object sender, EventArgs e)
|
|
{
|
|
HideInlineDeleteButtons();
|
|
UpdateNodeVisualState();
|
|
}
|
|
|
|
private void HideInlineDeleteButtons()
|
|
{
|
|
foreach (var button in FindVisualDescendants<Button>(CncTreeView))
|
|
{
|
|
if (button.ToolTip is string)
|
|
{
|
|
button.Visibility = Visibility.Collapsed;
|
|
button.IsHitTestVisible = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UpdateNodeVisualState()
|
|
{
|
|
foreach (var item in FindVisualDescendants<TreeViewItem>(CncTreeView))
|
|
{
|
|
if (item.DataContext is not CncNodeViewModel)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var card = FindNodeCard(item);
|
|
if (card == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (item.IsSelected)
|
|
{
|
|
card.Background = SelectedNodeBackground;
|
|
card.BorderBrush = SelectedNodeBorder;
|
|
}
|
|
else if (card.IsMouseOver)
|
|
{
|
|
card.Background = HoverNodeBackground;
|
|
card.BorderBrush = HoverNodeBorder;
|
|
}
|
|
else
|
|
{
|
|
card.Background = TransparentBrush;
|
|
card.BorderBrush = TransparentBrush;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static Border FindNodeCard(DependencyObject root)
|
|
{
|
|
foreach (var border in FindVisualDescendants<Border>(root))
|
|
{
|
|
if (border.DataContext is CncNodeViewModel && border.CornerRadius.TopLeft == 4 && border.BorderThickness.Left == 1)
|
|
{
|
|
return border;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static T FindAncestor<T>(DependencyObject dependencyObject) where T : DependencyObject
|
|
{
|
|
var current = dependencyObject;
|
|
while (current != null)
|
|
{
|
|
if (current is T match)
|
|
{
|
|
return match;
|
|
}
|
|
|
|
current = VisualTreeHelper.GetParent(current);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static System.Collections.Generic.IEnumerable<T> FindVisualDescendants<T>(DependencyObject root) where T : DependencyObject
|
|
{
|
|
if (root == null)
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
int childCount = VisualTreeHelper.GetChildrenCount(root);
|
|
for (int i = 0; i < childCount; i++)
|
|
{
|
|
var child = VisualTreeHelper.GetChild(root, i);
|
|
if (child is T typed)
|
|
{
|
|
yield return typed;
|
|
}
|
|
|
|
foreach (var descendant in FindVisualDescendants<T>(child))
|
|
{
|
|
yield return descendant;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public class NullToVisibilityConverter : IValueConverter
|
|
{
|
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
{
|
|
var invert = string.Equals(parameter as string, "Invert", StringComparison.OrdinalIgnoreCase);
|
|
var isVisible = value != null;
|
|
if (invert)
|
|
{
|
|
isVisible = !isVisible;
|
|
}
|
|
|
|
return isVisible ? Visibility.Visible : Visibility.Collapsed;
|
|
}
|
|
|
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
}
|
|
}
|