fix: replace RowStyle IsSelected binding with SelectionChanged event

- RowStyle TwoWay binding on IsSelected is unreliable with virtualizing DataGrid
- Switched to DataGrid.SelectionChanged event handler in code-behind
- Syncs RemovedItems/AddedItems to ViewModel.IsSelected reliably
This commit is contained in:
tian 2026-06-04 21:42:07 +08:00
parent 6b8bae2afc
commit 7dec26b1ac
2 changed files with 47 additions and 37 deletions

View File

@ -42,11 +42,6 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
<Setter Property="Foreground" Value="{StaticResource NavisworksSecondaryBrush}"/>
<Setter Property="Height" Value="20"/>
</Style>
<!-- 可多选的DataGrid行样式 -->
<Style x:Key="SelectableRowStyle" TargetType="DataGridRow">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Style>
</ResourceDictionary>
</UserControl.Resources>
@ -241,13 +236,12 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
</Grid>
<!-- 路径列表 -->
<DataGrid ItemsSource="{Binding PathRoutes}"
<DataGrid x:Name="PathRoutesGrid" ItemsSource="{Binding PathRoutes}"
SelectedItem="{Binding SelectedPathRoute}"
AutoGenerateColumns="False"
CanUserAddRows="False"
CanUserDeleteRows="False"
SelectionMode="Extended"
RowStyle="{StaticResource SelectableRowStyle}"
HeadersVisibility="Column"
GridLinesVisibility="Horizontal"
Height="340"

View File

@ -17,30 +17,46 @@ namespace NavisworksTransport.UI.WPF.Views
public partial class PathEditingView : UserControl
{
/// <summary>
/// ViewModel属性用于外部访问
/// ViewModel属性,用于外部访问
/// </summary>
public PathEditingViewModel ViewModel { get; private set; }
/// <summary>
/// 时标服务实例
/// </summary>
private TimeTagService _timeTagService;
/// <summary>
/// 构造函数需要传入主ViewModel以支持统一状态栏
/// 构造函数,需要传入主ViewModel以支持统一状态栏
/// </summary>
/// <param name="mainViewModel">主ViewModel用于统一状态栏</param>
/// <param name="mainViewModel">主ViewModel,用于统一状态栏</param>
public PathEditingView(LogisticsControlViewModel mainViewModel)
{
InitializeComponent();
// 创建ViewModel传入主ViewModel引用
// 创建ViewModel,传入主ViewModel引用
ViewModel = new PathEditingViewModel(mainViewModel);
DataContext = ViewModel;
PathRoutesGrid.SelectionChanged += OnPathRoutesSelectionChanged;
LogManager.Info("PathEditingView初始化完成 - 支持统一状态栏");
}
/// <summary>
/// 同步 DataGrid 多选状态到 ViewModel 的 IsSelected
/// </summary>
private void OnPathRoutesSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (ViewModel?.PathRoutes == null) return;
foreach (PathRouteViewModel item in e.RemovedItems)
item.IsSelected = false;
foreach (PathRouteViewModel item in e.AddedItems)
item.IsSelected = true;
}
/// <summary>
/// 清理资源
/// </summary>
@ -50,7 +66,7 @@ namespace NavisworksTransport.UI.WPF.Views
{
// 清理ViewModel
ViewModel?.Cleanup();
LogManager.Info("PathEditingView资源清理完成");
}
catch (Exception ex)
@ -60,14 +76,14 @@ namespace NavisworksTransport.UI.WPF.Views
}
/// <summary>
/// 路径列表中"时标"按钮点击打开时间标签窗口
/// 路径列表中"时标"按钮点击,打开时间标签窗口
/// </summary>
private void OnTimeTagButtonClick(object sender, RoutedEventArgs e)
{
try
{
LogManager.Info("时标按钮被点击");
// 从按钮的DataContext获取当前路径ViewModel
if (!(sender is Button button) || !(button.DataContext is PathRouteViewModel routeVm))
{
@ -82,7 +98,7 @@ namespace NavisworksTransport.UI.WPF.Views
LogManager.Warning("PathRouteViewModel中的Route为空");
return;
}
// 确保服务已初始化
if (_timeTagService == null)
{
@ -91,13 +107,13 @@ namespace NavisworksTransport.UI.WPF.Views
var db = pathManager.GetPathDatabase();
if (db == null)
{
throw new InvalidOperationException("时标服务初始化失败无法获取数据库实例");
throw new InvalidOperationException("时标服务初始化失败:无法获取数据库实例");
}
_timeTagService = new TimeTagService(db);
LogManager.Info("时标服务已初始化");
}
// 创建并显示时标对话框
var dlg = new TimeTagDialog(_timeTagService, route);
DialogHelper.SetOwnerFromUserControl(dlg, this);
@ -112,17 +128,17 @@ namespace NavisworksTransport.UI.WPF.Views
MessageBox.Show($"打开时标窗口失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// 路径分析按钮点击事件,打开路径规划分析对话框(非模态)
/// 路径分析按钮点击事件,打开路径规划分析对话框(非模态)
/// </summary>
private void OnPathAnalysisButtonClick(object sender, RoutedEventArgs e)
{
try
{
LogManager.Info("路径分析按钮被点击准备打开PathAnalysisDialog窗口");
// 使用静态方法显示(单例模式,非模态)
LogManager.Info("路径分析按钮被点击,准备打开PathAnalysisDialog窗口");
// 使用静态方法显示(单例模式,非模态)
var parentWindow = Window.GetWindow(this);
PathAnalysisDialog.ShowAnalysis(parentWindow);
}
@ -134,18 +150,18 @@ namespace NavisworksTransport.UI.WPF.Views
}
/// <summary>
/// 生成导航地图按钮点击事件打开生成导航地图对话框
/// 生成导航地图按钮点击事件,打开生成导航地图对话框
/// </summary>
private void OnGenerateNavigationMapButtonClick(object sender, RoutedEventArgs e)
{
try
{
LogManager.Info("生成导航地图按钮被点击准备打开GenerateNavigationMapDialog窗口");
LogManager.Info("生成导航地图按钮被点击,准备打开GenerateNavigationMapDialog窗口");
// 检查前置条件
if (ViewModel?.SelectedPathRoute == null || ViewModel.SelectedPathRoute.Points.Count == 0)
{
LogManager.Warning("无法生成导航地图未选择路径或路径为空");
LogManager.Warning("无法生成导航地图:未选择路径或路径为空");
return;
}
@ -235,32 +251,32 @@ namespace NavisworksTransport.UI.WPF.Views
}
/// <summary>
/// 测量包围盒按钮点击事件打开元素包围盒信息窗口
/// 测量包围盒按钮点击事件,打开元素包围盒信息窗口
/// </summary>
private void OnMeasureBoundsButtonClick(object sender, RoutedEventArgs e)
{
try
{
LogManager.Info("测量包围盒按钮被点击准备打开ModelItemBoundsWindow窗口");
LogManager.Info("测量包围盒按钮被点击,准备打开ModelItemBoundsWindow窗口");
// 创建或复用窗口实例
if (_boundsWindow == null || !_boundsWindow.IsVisible)
{
_boundsWindow = new ModelItemBoundsWindow();
// 设置父窗口(非模态窗口)
// 设置父窗口(非模态窗口)
DialogHelper.SetOwnerFromUserControl(_boundsWindow, this);
// 使用 Show() 而非 ShowDialog()允许窗口一直开着
// 使用 Show() 而非 ShowDialog(),允许窗口一直开着
_boundsWindow.Show();
LogManager.Info("ModelItemBoundsWindow窗口已显示(非模态)");
LogManager.Info("ModelItemBoundsWindow窗口已显示(非模态)");
}
else
{
// 窗口已存在刷新信息并激活
// 窗口已存在,刷新信息并激活
_boundsWindow.RefreshBoundsInfo();
_boundsWindow.Activate();
LogManager.Info("ModelItemBoundsWindow窗口已存在已刷新并激活");
LogManager.Info("ModelItemBoundsWindow窗口已存在,已刷新并激活");
}
}
catch (Exception ex)
@ -271,7 +287,7 @@ namespace NavisworksTransport.UI.WPF.Views
}
/// <summary>
/// 包围盒信息窗口实例保持引用以防止被GC回收
/// 包围盒信息窗口实例(保持引用以防止被GC回收)
/// </summary>
private ModelItemBoundsWindow _boundsWindow;
}