feat: inline editing with click-to-edit, TextBox overlay, Focus+SelectAll
- Grid overlay: TextBox covers TextBlock when editing (no more dual display) - EditValue property: auto-initialized to DisplayName on edit start - Click on already-selected node enters inline edit (PreviewMouseLeftButtonDown) - Right-click auto-selects node before context menu - TextBox IsVisibleChanged: Focus + SelectAll on Loaded priority - XAML Visibility moved to Style setter (fix DataTrigger precedence) - Light yellow background (#FFFFFDE6)
This commit is contained in:
parent
ad398652a7
commit
d358c31a7d
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Windows.Input;
|
||||||
using Autodesk.Navisworks.Api;
|
using Autodesk.Navisworks.Api;
|
||||||
|
|
||||||
namespace NavisworksTransport.UI.WPF.ViewModels
|
namespace NavisworksTransport.UI.WPF.ViewModels
|
||||||
@ -56,9 +57,25 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
public bool IsEditing
|
public bool IsEditing
|
||||||
{
|
{
|
||||||
get => _isEditing;
|
get => _isEditing;
|
||||||
set { _isEditing = value; OnPropertyChanged(nameof(IsEditing)); }
|
set
|
||||||
|
{
|
||||||
|
if (_isEditing == value) return;
|
||||||
|
_isEditing = value;
|
||||||
|
OnPropertyChanged(nameof(IsEditing));
|
||||||
|
// 进入编辑时初始化 EditValue 为当前显示名
|
||||||
|
if (value)
|
||||||
|
EditValue = DisplayName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>编辑框的临时文本(进入编辑时初始化为 DisplayName)</summary>
|
||||||
|
public string EditValue
|
||||||
|
{
|
||||||
|
get => _editValue;
|
||||||
|
set { _editValue = value; OnPropertyChanged(nameof(EditValue)); }
|
||||||
|
}
|
||||||
|
private string _editValue;
|
||||||
|
|
||||||
/// <summary>是否孤儿节点(模型结构变化后无法定位)</summary>
|
/// <summary>是否孤儿节点(模型结构变化后无法定位)</summary>
|
||||||
public bool IsOrphan
|
public bool IsOrphan
|
||||||
{
|
{
|
||||||
@ -92,8 +109,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
|
|
||||||
public AliasNodeViewModel()
|
public AliasNodeViewModel()
|
||||||
{
|
{
|
||||||
|
StartEditCommand = new RelayCommand(() => IsEditing = true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>启动内联编辑的命令</summary>
|
||||||
|
public ICommand StartEditCommand { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 刷新显示文本(别名变更新调用)
|
/// 刷新显示文本(别名变更新调用)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -2,7 +2,8 @@
|
|||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:vm="clr-namespace:NavisworksTransport.UI.WPF.ViewModels"
|
xmlns:vm="clr-namespace:NavisworksTransport.UI.WPF.ViewModels"
|
||||||
xmlns:converters="clr-namespace:NavisworksTransport.UI.WPF.Converters">
|
xmlns:converters="clr-namespace:NavisworksTransport.UI.WPF.Converters"
|
||||||
|
PreviewKeyDown="UserControl_PreviewKeyDown">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
@ -16,16 +17,16 @@
|
|||||||
<!-- 别名树 TreeView 的模板 -->
|
<!-- 别名树 TreeView 的模板 -->
|
||||||
<HierarchicalDataTemplate DataType="{x:Type vm:AliasNodeViewModel}"
|
<HierarchicalDataTemplate DataType="{x:Type vm:AliasNodeViewModel}"
|
||||||
ItemsSource="{Binding Children}">
|
ItemsSource="{Binding Children}">
|
||||||
<StackPanel Orientation="Horizontal" Margin="0,1"
|
<Grid VerticalAlignment="Center">
|
||||||
VerticalAlignment="Center">
|
<!-- 显示模式 -->
|
||||||
<!-- 节点名:别名用暗红色,原名用黑色 -->
|
<TextBlock Text="{Binding DisplayName}"
|
||||||
<TextBlock Text="{Binding DisplayName}" VerticalAlignment="Center"
|
|
||||||
FontSize="12" TextTrimming="CharacterEllipsis" MaxWidth="200"
|
FontSize="12" TextTrimming="CharacterEllipsis" MaxWidth="200"
|
||||||
FontWeight="SemiBold">
|
FontWeight="SemiBold">
|
||||||
<TextBlock.Style>
|
<TextBlock.Style>
|
||||||
<Style TargetType="TextBlock">
|
<Style TargetType="TextBlock">
|
||||||
<Setter Property="Foreground" Value="#FF1A1A1A"/>
|
<Setter Property="Foreground" Value="#FF1A1A1A"/>
|
||||||
<Setter Property="FontStyle" Value="Normal"/>
|
<Setter Property="FontStyle" Value="Normal"/>
|
||||||
|
<Setter Property="Visibility" Value="Visible"/>
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
<DataTrigger Binding="{Binding HasAlias}" Value="True">
|
<DataTrigger Binding="{Binding HasAlias}" Value="True">
|
||||||
<Setter Property="Foreground" Value="#FFC62828"/>
|
<Setter Property="Foreground" Value="#FFC62828"/>
|
||||||
@ -37,21 +38,25 @@
|
|||||||
<Setter Property="TextDecorations" Value="Strikethrough"/>
|
<Setter Property="TextDecorations" Value="Strikethrough"/>
|
||||||
<Setter Property="Foreground" Value="#FFAAAAAA"/>
|
<Setter Property="Foreground" Value="#FFAAAAAA"/>
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding IsEditing}" Value="True">
|
||||||
|
<Setter Property="Visibility" Value="Collapsed"/>
|
||||||
|
</DataTrigger>
|
||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
</TextBlock.Style>
|
</TextBlock.Style>
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
|
|
||||||
<!-- 编辑文本框(IsEditing=true 时显示) -->
|
<!-- 编辑模式 -->
|
||||||
<TextBox Text="{Binding Alias, UpdateSourceTrigger=PropertyChanged}"
|
<TextBox Text="{Binding EditValue, UpdateSourceTrigger=PropertyChanged}"
|
||||||
Width="150" VerticalAlignment="Center"
|
FontSize="12"
|
||||||
Visibility="Collapsed" FontSize="12"
|
|
||||||
KeyDown="OnAliasTextBoxKeyDown"
|
KeyDown="OnAliasTextBoxKeyDown"
|
||||||
LostFocus="OnAliasTextBoxLostFocus"
|
LostFocus="OnAliasTextBoxLostFocus"
|
||||||
Background="#FFFFF8DC"
|
IsVisibleChanged="OnEditTextBoxVisibleChanged"
|
||||||
|
Background="#FFFFFDE6"
|
||||||
BorderBrush="#FF1565C0" BorderThickness="1">
|
BorderBrush="#FF1565C0" BorderThickness="1">
|
||||||
<TextBox.Style>
|
<TextBox.Style>
|
||||||
<Style TargetType="TextBox">
|
<Style TargetType="TextBox">
|
||||||
|
<Setter Property="Visibility" Value="Collapsed"/>
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
<DataTrigger Binding="{Binding IsEditing}" Value="True">
|
<DataTrigger Binding="{Binding IsEditing}" Value="True">
|
||||||
<Setter Property="Visibility" Value="Visible"/>
|
<Setter Property="Visibility" Value="Visible"/>
|
||||||
@ -60,19 +65,7 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</TextBox.Style>
|
</TextBox.Style>
|
||||||
</TextBox>
|
</TextBox>
|
||||||
|
</Grid>
|
||||||
<!-- 铅笔编辑按钮(鼠标悬停显示) -->
|
|
||||||
<Button Style="{StaticResource AliasToolbarButtonStyle}"
|
|
||||||
ToolTip="编辑别名"
|
|
||||||
Tag="{Binding}"
|
|
||||||
Click="OnEditClick"
|
|
||||||
Width="18" Height="18"
|
|
||||||
Margin="2,0,0,0">
|
|
||||||
<Path Data="{StaticResource EditIconGeometry}"
|
|
||||||
Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"
|
|
||||||
Width="14" Height="14" Stretch="Uniform"/>
|
|
||||||
</Button>
|
|
||||||
</StackPanel>
|
|
||||||
</HierarchicalDataTemplate>
|
</HierarchicalDataTemplate>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
@ -98,14 +91,6 @@
|
|||||||
|
|
||||||
<!-- 图标工具栏 -->
|
<!-- 图标工具栏 -->
|
||||||
<StackPanel Orientation="Horizontal" DockPanel.Dock="Right">
|
<StackPanel Orientation="Horizontal" DockPanel.Dock="Right">
|
||||||
<Button x:Name="BtnSave" Style="{StaticResource AliasToolbarButtonStyle}"
|
|
||||||
ToolTip="保存别名 (Ctrl+S)"
|
|
||||||
IsEnabled="False"
|
|
||||||
Click="OnSaveCurrentClick">
|
|
||||||
<Path Data="{StaticResource SaveIconGeometry}"
|
|
||||||
Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"
|
|
||||||
Width="16" Height="16" Stretch="Uniform"/>
|
|
||||||
</Button>
|
|
||||||
<Separator Style="{StaticResource AliasToolbarSeparatorStyle}"/>
|
<Separator Style="{StaticResource AliasToolbarSeparatorStyle}"/>
|
||||||
<Button x:Name="BtnAutoGen" Style="{StaticResource AliasToolbarButtonStyle}"
|
<Button x:Name="BtnAutoGen" Style="{StaticResource AliasToolbarButtonStyle}"
|
||||||
ToolTip="自动生成别名"
|
ToolTip="自动生成别名"
|
||||||
@ -165,7 +150,9 @@
|
|||||||
BorderThickness="0"
|
BorderThickness="0"
|
||||||
ItemContainerStyle="{StaticResource AliasTreeViewItemStyle}"
|
ItemContainerStyle="{StaticResource AliasTreeViewItemStyle}"
|
||||||
TreeViewItem.Expanded="OnTreeViewItemExpanded"
|
TreeViewItem.Expanded="OnTreeViewItemExpanded"
|
||||||
TreeViewItem.Selected="OnTreeViewItemSelected">
|
TreeViewItem.Selected="OnTreeViewItemSelected"
|
||||||
|
TreeViewItem.PreviewMouseRightButtonDown="OnTreeViewItemRightClick"
|
||||||
|
TreeViewItem.PreviewMouseLeftButtonDown="OnTreeViewItemLeftClick">
|
||||||
<TreeView.Resources>
|
<TreeView.Resources>
|
||||||
<!-- 无焦点时也显示蓝色选中态(浅灰蓝底色 + 白字,匹配选择树) -->
|
<!-- 无焦点时也显示蓝色选中态(浅灰蓝底色 + 白字,匹配选择树) -->
|
||||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
|
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
|
||||||
|
|||||||
@ -125,12 +125,8 @@ namespace NavisworksTransport.UI.WPF.Views
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 别名树选中 → 同步到 Navisworks 选择
|
/// 别名树选中 → 同步到 Navisworks 选择
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnTreeViewSelected(object sender, RoutedEventArgs e)
|
private void OnTreeViewSelected(AliasNodeViewModel node)
|
||||||
{
|
{
|
||||||
if (!(e.OriginalSource is TreeViewItem tvi) || !(tvi.DataContext is AliasNodeViewModel node))
|
|
||||||
return;
|
|
||||||
if (node.IsOrphan) return;
|
|
||||||
|
|
||||||
LogManager.Info($"[别名树] 树点击: NodeKey={node.NodeKey}, OriginalName={node.OriginalName}, ModelItem={node.ModelItem?.DisplayName ?? "null"}");
|
LogManager.Info($"[别名树] 树点击: NodeKey={node.NodeKey}, OriginalName={node.OriginalName}, ModelItem={node.ModelItem?.DisplayName ?? "null"}");
|
||||||
|
|
||||||
_isInternalSelection = true;
|
_isInternalSelection = true;
|
||||||
@ -154,6 +150,18 @@ namespace NavisworksTransport.UI.WPF.Views
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void StartInlineEdit(AliasNodeViewModel node, TreeViewItem tvi)
|
||||||
|
{
|
||||||
|
// 直接用,不需要 tvi
|
||||||
|
StartInlineEdit(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartInlineEdit(AliasNodeViewModel node)
|
||||||
|
{
|
||||||
|
ClearAllEditing();
|
||||||
|
node.IsEditing = true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Navisworks 选择变化 → 同步到别名树高亮
|
/// Navisworks 选择变化 → 同步到别名树高亮
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -172,7 +180,6 @@ namespace NavisworksTransport.UI.WPF.Views
|
|||||||
var item = selected.First();
|
var item = selected.First();
|
||||||
_currentSelectionItem = item;
|
_currentSelectionItem = item;
|
||||||
TbCurrentNode.Text = $"当前: {item.DisplayName}";
|
TbCurrentNode.Text = $"当前: {item.DisplayName}";
|
||||||
BtnSave.IsEnabled = true;
|
|
||||||
|
|
||||||
LogManager.Info($"[别名树] NW选中: DisplayName={item.DisplayName}, ClassName={item.ClassName}");
|
LogManager.Info($"[别名树] NW选中: DisplayName={item.DisplayName}, ClassName={item.ClassName}");
|
||||||
|
|
||||||
@ -184,7 +191,6 @@ namespace NavisworksTransport.UI.WPF.Views
|
|||||||
{
|
{
|
||||||
_currentSelectionItem = null;
|
_currentSelectionItem = null;
|
||||||
TbCurrentNode.Text = selected.Count > 1 ? $"当前: ({selected.Count} 个选中)" : "当前: 无";
|
TbCurrentNode.Text = selected.Count > 1 ? $"当前: ({selected.Count} 个选中)" : "当前: 无";
|
||||||
BtnSave.IsEnabled = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -510,7 +516,9 @@ namespace NavisworksTransport.UI.WPF.Views
|
|||||||
{
|
{
|
||||||
if (currentContainer is TreeViewItem t)
|
if (currentContainer is TreeViewItem t)
|
||||||
{
|
{
|
||||||
|
_isProgrammaticSelect = true;
|
||||||
t.IsSelected = true;
|
t.IsSelected = true;
|
||||||
|
_isProgrammaticSelect = false;
|
||||||
t.BringIntoView();
|
t.BringIntoView();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -562,7 +570,9 @@ namespace NavisworksTransport.UI.WPF.Views
|
|||||||
var childTvi = parentTvi.ItemContainerGenerator.ContainerFromItem(current) as TreeViewItem;
|
var childTvi = parentTvi.ItemContainerGenerator.ContainerFromItem(current) as TreeViewItem;
|
||||||
if (childTvi != null)
|
if (childTvi != null)
|
||||||
{
|
{
|
||||||
|
_isProgrammaticSelect = true;
|
||||||
childTvi.IsSelected = true;
|
childTvi.IsSelected = true;
|
||||||
|
_isProgrammaticSelect = false;
|
||||||
childTvi.BringIntoView();
|
childTvi.BringIntoView();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -613,25 +623,20 @@ namespace NavisworksTransport.UI.WPF.Views
|
|||||||
// 事件处理:工具栏
|
// 事件处理:工具栏
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
private void OnSaveCurrentClick(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (_currentSelectionItem == null || _dataStore == null) return;
|
|
||||||
string input = TxtAliasInput.Text?.Trim();
|
|
||||||
if (string.IsNullOrEmpty(input)) return;
|
|
||||||
|
|
||||||
var identity = AliasNodeIdentity.FromModelItem(_currentSelectionItem);
|
|
||||||
LogManager.Info($"[别名树] 保存别名: {input}, NodeKey={identity.ToKey()}");
|
|
||||||
_dataStore.SetAlias(identity, input);
|
|
||||||
TxtAliasInput.Clear();
|
|
||||||
|
|
||||||
// 刷新树中对应节点
|
|
||||||
RefreshNodeDisplay(identity.ToKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnAliasInputKeyDown(object sender, KeyEventArgs e)
|
private void OnAliasInputKeyDown(object sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.Key == Key.Enter && BtnSave.IsEnabled)
|
if (e.Key == Key.Enter)
|
||||||
OnSaveCurrentClick(null, null);
|
{
|
||||||
|
if (_currentSelectionItem == null || _dataStore == null) return;
|
||||||
|
string input = TxtAliasInput.Text?.Trim();
|
||||||
|
if (string.IsNullOrEmpty(input)) return;
|
||||||
|
|
||||||
|
var identity = AliasNodeIdentity.FromModelItem(_currentSelectionItem);
|
||||||
|
LogManager.Info($"[别名树] 保存别名: {input}, NodeKey={identity.ToKey()}");
|
||||||
|
_dataStore.SetAlias(identity, input);
|
||||||
|
TxtAliasInput.Clear();
|
||||||
|
RefreshNodeDisplay(identity.ToKey());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAutoGenClick(object sender, RoutedEventArgs e)
|
private void OnAutoGenClick(object sender, RoutedEventArgs e)
|
||||||
@ -715,6 +720,18 @@ namespace NavisworksTransport.UI.WPF.Views
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnEditTextBoxVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is TextBox tb && tb.IsVisible)
|
||||||
|
{
|
||||||
|
Dispatcher.BeginInvoke(new Action(() =>
|
||||||
|
{
|
||||||
|
tb.Focus();
|
||||||
|
tb.SelectAll();
|
||||||
|
}), System.Windows.Threading.DispatcherPriority.Loaded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnAliasTextBoxLostFocus(object sender, RoutedEventArgs e)
|
private void OnAliasTextBoxLostFocus(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
CommitEdit(sender as TextBox);
|
CommitEdit(sender as TextBox);
|
||||||
@ -768,8 +785,38 @@ namespace NavisworksTransport.UI.WPF.Views
|
|||||||
private void OnCtxEditClick(object sender, RoutedEventArgs e)
|
private void OnCtxEditClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var node = GetSelectedNode();
|
var node = GetSelectedNode();
|
||||||
|
LogManager.Info($"[别名树] OnCtxEditClick: node={node?.OriginalName ?? "null"}");
|
||||||
if (node == null) return;
|
if (node == null) return;
|
||||||
OnEditClick(new Button { Tag = node }, null);
|
|
||||||
|
// 从可视化树中查找 TreeViewItem,不依赖 ContainerFromItem
|
||||||
|
var tvi = FindTreeViewItemByDataContext(AliasTreeView, node);
|
||||||
|
LogManager.Info($"[别名树] OnCtxEditClick: tvi found={tvi != null}");
|
||||||
|
if (tvi != null)
|
||||||
|
StartInlineEdit(node, tvi);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TreeViewItem FindTreeViewItemByDataContext(ItemsControl parent, object dataContext)
|
||||||
|
{
|
||||||
|
// 先检查直接子项
|
||||||
|
for (int i = 0; i < parent.Items.Count; i++)
|
||||||
|
{
|
||||||
|
var item = parent.Items[i];
|
||||||
|
if (item == dataContext)
|
||||||
|
{
|
||||||
|
return parent.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
|
||||||
|
}
|
||||||
|
if (item is AliasNodeViewModel vm)
|
||||||
|
{
|
||||||
|
// 递归搜索子项(先获取容器,再搜它的子项)
|
||||||
|
var tvi = parent.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
|
||||||
|
if (tvi != null && tvi.Items.Count > 0)
|
||||||
|
{
|
||||||
|
var found = FindTreeViewItemByDataContext(tvi, dataContext);
|
||||||
|
if (found != null) return found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCtxBatchEditClick(object sender, RoutedEventArgs e)
|
private void OnCtxBatchEditClick(object sender, RoutedEventArgs e)
|
||||||
@ -906,9 +953,86 @@ namespace NavisworksTransport.UI.WPF.Views
|
|||||||
LazyLoadChildren(node, aliasMap);
|
LazyLoadChildren(node, aliasMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool _isProgrammaticSelect;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 树节点被选中时:如果 500ms 内再次选中同一节点 → 进入内联编辑
|
||||||
|
/// </summary>
|
||||||
|
/// <summary>
|
||||||
|
/// 右键前先选中节点,确保右键菜单操作的是正确节点
|
||||||
|
/// </summary>
|
||||||
|
private void OnTreeViewItemRightClick(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
var tvi = FindAncestor(e.OriginalSource as DependencyObject);
|
||||||
|
if (tvi != null)
|
||||||
|
{
|
||||||
|
tvi.IsSelected = true;
|
||||||
|
tvi.Focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TreeViewItem FindAncestor(DependencyObject current)
|
||||||
|
{
|
||||||
|
while (current != null)
|
||||||
|
{
|
||||||
|
if (current is TreeViewItem tvi) return tvi;
|
||||||
|
current = VisualTreeHelper.GetParent(current);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 左键点击已选中节点 → 进入内联编辑
|
||||||
|
/// </summary>
|
||||||
|
private void OnTreeViewItemLeftClick(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
var tvi = FindAncestor(e.OriginalSource as DependencyObject);
|
||||||
|
if (tvi != null && tvi.IsSelected && tvi.DataContext is AliasNodeViewModel node && !node.IsOrphan)
|
||||||
|
{
|
||||||
|
StartInlineEdit(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnTreeViewItemSelected(object sender, RoutedEventArgs e)
|
private void OnTreeViewItemSelected(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
OnTreeViewSelected(sender, e);
|
if (e.OriginalSource is TreeViewItem tvi && tvi.DataContext is AliasNodeViewModel node && !node.IsOrphan)
|
||||||
|
{
|
||||||
|
if (!_isProgrammaticSelect)
|
||||||
|
OnTreeViewSelected(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 选中状态下点击 → 进入内联编辑(模仿 DataGrid 行为)
|
||||||
|
/// </summary>
|
||||||
|
/// <summary>
|
||||||
|
/// F2 键 → 进入内联编辑
|
||||||
|
/// </summary>
|
||||||
|
private void UserControl_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Key == Key.F2)
|
||||||
|
{
|
||||||
|
EnterEditSelectedNode();
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 双击 → 进入内联编辑
|
||||||
|
/// </summary>
|
||||||
|
private void OnTreeViewDoubleClick(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
EnterEditSelectedNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnterEditSelectedNode()
|
||||||
|
{
|
||||||
|
var node = GetSelectedNode();
|
||||||
|
if (node != null)
|
||||||
|
{
|
||||||
|
var tvi = AliasTreeView.ItemContainerGenerator.ContainerFromItem(node) as TreeViewItem;
|
||||||
|
if (tvi != null) StartInlineEdit(node, tvi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user