using CommunityToolkit.Mvvm.ComponentModel; using OpenTap.Addin; using OpenTapEditor.Util; using SeqEditor.Util; using System.Collections.ObjectModel; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using UILib; namespace OpenTapEditor { /// /// VariableTree.xaml 的交互逻辑 /// [ObservableObject] public partial class VariableReadOnlyTree : UserControl { [ObservableProperty] private bool initEdit = false; public EditBox EditingCell { get; private set; } = null; public VariableReadOnlyTree() { this.Loaded += VariableReadOnlyTree_Loaded; InitializeComponent(); BindingOperations.SetBinding(fileGlobalView, TreeListView.ItemsSourceProperty, new Binding(nameof(Datasource)) { Source = this, Mode = BindingMode.TwoWay, }); } private void VariableReadOnlyTree_Loaded(object sender, RoutedEventArgs e) { InitEdit = true; } public static DependencyProperty DatasourceProperty = DependencyProperty.Register( "Datasource", typeof(ObservableCollection), typeof(VariableReadOnlyTree), new PropertyMetadata(null) ); public event EventHandler ItemDoubleClicked; public string Prefix { get; set; } public ObservableCollection Datasource { get => (ObservableCollection)GetValue(DatasourceProperty); set { SetValue(DatasourceProperty, value); } } private void OnPreviewMouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) { DependencyObject source = e.OriginalSource as DependencyObject; while (source != null && source.GetType() != typeof(TreeListViewItem)) { source = System.Windows.Media.VisualTreeHelper.GetParent(source); } if (source != null) { TreeListViewItem item = source as TreeListViewItem; item.Focus(); var variable = item.DataContext; CreateContextMenu(item, variable); } else { CreateContextMenu(null, null); } } public List RefreshMenuItems(TreeListViewItem parentItem, TestVariable parent) { var allSteps = StepTypeLoader.Steps; var StepMenuItems = new List(allSteps.Count); foreach (TestVariableType type in Enum.GetValues(typeof(TestVariableType))) { TestVariableMenuItem menuItem = new TestVariableMenuItem(); menuItem.Header = type.ToString(); menuItem.SourceItem = parentItem; menuItem.Click += MenuItem_Click; menuItem.TargetIsArray = false; menuItem.TargetType = type; menuItem.Parent = parent; StepMenuItems.Add(menuItem); } var arrItem = new MenuItem(); arrItem.Header = "Array Of..."; foreach (TestVariableType type in Enum.GetValues(typeof(TestVariableType))) { TestVariableMenuItem menuItem = new TestVariableMenuItem(); menuItem.Header = type.ToString(); menuItem.SourceItem = parentItem; menuItem.Click += MenuItem_Click; menuItem.TargetIsArray = true; menuItem.TargetType = type; menuItem.Parent = parent; arrItem.Items.Add(menuItem); } StepMenuItems.Add(arrItem); return StepMenuItems; } /// /// 显示菜单 /// /// private void CreateContextMenu(TreeListViewItem item, object obj) { var v = obj as TestVariable; ContextMenu contextMenu = new ContextMenu(); contextMenu.Closed += ContextMenu_Closed; var parent = item?.parent?.DataContext as TestVariable; TestVariableMenuItem menuItem = new TestVariableMenuItem(); if (v == null) { menuItem.SetValue(TestVariableMenuItem.HeaderProperty, new DynamicResourceExtension("插入").ProvideValue(null)); foreach (var i in RefreshMenuItems(item, null)) { menuItem.Items.Add(i); } contextMenu.Items.Add(menuItem); } else if (v.IsArray) { menuItem.SetValue(TestVariableMenuItem.HeaderProperty, new DynamicResourceExtension("插入元素").ProvideValue(null)); menuItem.Variable = v; menuItem.Parent = v; menuItem.Click += MenuItem_Click; contextMenu.Items.Add(menuItem); } else if (v.Type == TestVariableType.Container) { menuItem.SetValue(TestVariableMenuItem.HeaderProperty, new DynamicResourceExtension("插入").ProvideValue(null)); foreach (var i in RefreshMenuItems(item, v)) { menuItem.Items.Add(i); } contextMenu.Items.Add(menuItem); } if (v != null) { menuItem = new TestVariableMenuItem(); menuItem.SetValue(TestVariableMenuItem.HeaderProperty, new DynamicResourceExtension("删除").ProvideValue(null)); menuItem.Click += Delete_Click; menuItem.Variable = v; menuItem.Tag = item; contextMenu.Items.Add(menuItem); menuItem = new TestVariableMenuItem(); menuItem.SetValue(TestVariableMenuItem.HeaderProperty, new DynamicResourceExtension("复制名称").ProvideValue(null)); menuItem.Click += CopyName_Click; menuItem.Tag = item; contextMenu.Items.Add(menuItem); } this.fileGlobalView.ContextMenu = contextMenu; } private void ContextMenu_Closed(object sender, RoutedEventArgs e) { this.fileGlobalView.ContextMenu = null; } private void MenuItem_Click(object sender, RoutedEventArgs e) { TestVariableMenuItem item = sender as TestVariableMenuItem; var v = item.Parent; TreeListViewItem parentItem = item.SourceItem; TestVariable newOne = null; if (v == null) { newOne = new TestVariable { IsArray = item.TargetIsArray, Type = item.TargetType, Value = item.TargetIsArray ? null : TestVariable.DefaultValue(item.TargetType) }; Datasource.Add(newOne); goto End; } if (v.IsArray) { newOne = new TestVariable { Name = $"[{v.Children.Count}]", IsArray = false, Type = v.Type, Value = TestVariable.DefaultValue(v.Type) }; v.Children.Add(newOne); for (int i = 0; i < v.Children.Count; i++) { v.Children[i].Name = $"[{i}]"; } goto End; } if (v.Type == TestVariableType.Container) { newOne = new TestVariable { IsArray = item.TargetIsArray, Type = item.TargetType, Value = item.TargetIsArray ? null : TestVariable.DefaultValue(item.TargetType) }; v.Children.Add(newOne); goto End; } End: parentItem.IsExpanded = true; DispatcherHelper.WaitForPriority(); var scroll = fileGlobalView.Template.FindName("scroll", fileGlobalView) as ScrollViewer; var tvi = parentItem.ItemContainerGenerator.ContainerFromIndex(parentItem.Items.Count - 1) as TreeListViewItem; if (!DispatcherHelper.IsElementVisibleInScrollViewer(scroll, tvi)) { Point offset = tvi.TransformToAncestor(scroll).Transform(new Point(0, 0)); scroll.ScrollToVerticalOffset(offset.Y); } var eb = DispatcherHelper.FindVisualChild(tvi); eb?.TryEdit(null); tvi.IsSelected = true; EditingCell = eb; } private void Delete_Click(object sender, RoutedEventArgs e) { var tv = ((TestVariableMenuItem)sender).Variable; var item = ((TestVariableMenuItem)sender).Tag as TreeListViewItem; if (item.parent == null) { Datasource.Remove(tv); } else { var parentData = item.parent.DataContext as TestVariable; parentData.Children.Remove(tv); if (parentData.IsArray) { for (int i = 0; i < parentData.Children.Count; i++) { parentData.Children[i].Name = $"[{i}]"; } } } } private void Button_Click(object sender, RoutedEventArgs e) { var tv = ((Button)sender).Tag as TestVariable; MessageBox.Show(tv.Name); } private void CopyName_Click(object sender, RoutedEventArgs e) { var item = ((TestVariableMenuItem)sender).Tag as TreeListViewItem; var tv = item?.DataContext as TestVariable; string name = ""; while (tv != null) { if (tv.IsArray) { name = tv.Name + name; } else { name = tv.Name + (string.IsNullOrEmpty(name) ? "" : $".{name}"); } item = item.parent; tv = item?.DataContext as TestVariable; } Clipboard.SetText(string.IsNullOrEmpty(Prefix) ? name : $"{Prefix}.{name}"); } private void GridViewRowPresenter_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e) { if (e.ClickCount >= 2) { var item = ((GridViewRowPresenter)sender).Tag as TreeListViewItem; var tv = item.DataContext as TestVariable; string name = ""; while (tv != null) { if (tv.IsArray) { name = tv.Name + name; } else { name = tv.Name + (string.IsNullOrEmpty(name) ? "" : $".{name}"); } item = item.parent; tv = item?.DataContext as TestVariable; } string las = string.IsNullOrEmpty(Prefix) ? name : $"{Prefix}.{name}"; ItemDoubleClicked?.Invoke(this, las); e.Handled = true; } } private bool VariableNamePreSubmit(object sender, object value, object source) { EditBox eb = (EditBox)sender; TreeListViewItem item = (TreeListViewItem)eb.Tag; var parentItem = item.parent; if (parentItem == null) { return false; } if (string.IsNullOrEmpty(value?.ToString())) { MessageBox.Show(LangUtil.Get("参数名称不能为空")); EditingCell = eb; return false; } TestVariable parent = (TestVariable)parentItem.DataContext; var target = parent.Children.FirstOrDefault(c => c.Name == value.ToString()); if (target != null && target != source) { MessageBox.Show(LangUtil.Format("参数名称重复", value)); EditingCell = eb; return false; } EditingCell = null; return true; } private bool VariableNamePreEditing(EditBox eb) { EditingCell = eb; return true; } } }