MSAGL:WpfGraphControl点击图形后如何获取节点/边对象?
WPF+MVVM中MSAGL控件点击获取节点/边的问题
我使用WPF和MVVM模式开发应用,需要在点击图形后获取节点、边等对象进行不同处理。但点击图形时,将sender转换为GraphViewer类型得到null值,实际sender是Microsoft.Msagl.WpfGraphControl.AutomaticGraphLayoutControl类型,该类没有直接获取目标对象的能力,其内部的_graphViewer属性(GraphViewer类型)为私有。
现有代码
View XAML
<Window x:Class="myApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:myApp" xmlns:wpfgraphcontrol="http://mlsagl" mc:Ignorable="d" Title="Main Window" SizeToContent="WidthAndHeight" MinHeight="800" MinWidth="800" x:Name="mainWindow"> <Grid> <wpfgraphcontrol:AutomaticGraphLayoutControl Graph="{Binding CurrentGraph.GraphObject, UpdateSourceTrigger=PropertyChanged}" MouseDown="graphDisplay_MouseDown"> </wpfgraphcontrol:AutomaticGraphLayoutControl> </Grid> </Window>
View 代码后台
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = new ApplicationViewModel(new DefaultDialogService(), new MSAGLFileService()); } private void graphDisplay_MouseDown(object sender, MouseButtonEventArgs e) { var graphViewer = sender as GraphViewer; if (graphViewer != null) { if(graphViewer.ObjectUnderMouseCursor as IViewerNode != null) MessageBox.Show("You click on node"); else if(graphViewer.ObjectUnderMouseCursor as IViewerEdge != null) MessageBox.Show("You click on edge"); else MessageBox.Show("You click not on edge or not on node"); } else MessageBox.Show("sender is null"); } }
ApplicationViewModel
public class ApplicationViewModel { private GraphModel currentGraph; public GraphModel CurrentGraph { get { return currentGraph; } set { currentGraph = value; OnPropertyChanged(nameof(CurrentGraph)); } } public ApplicationViewModel(IDialogService dialogService, IFileService fileService) { currentGraph = new GraphModel(); } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
GraphModel
public class GraphModel : INotifyPropertyChanged { private string name { get; set; } private Graph graphObject { get; set; } private bool isInitialized { get; set; } public string Name { get{ return name; } set { name = value; OnPropertyChanged(nameof(Name)); } } public Graph GraphObject { get{ return graphObject; } set{ graphObject = value; OnPropertyChanged(nameof(GraphObject));} } public bool IsInitialized { get{ return isInitialized; } set{ isInitialized = value; OnPropertyChanged(nameof(IsInitialized));} } public GraphModel() { IsInitialized = false; Name = " - "; GraphObject = new Graph(Name); } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
解决方法
由于AutomaticGraphLayoutControl的_graphViewer是私有成员,我们可以通过反射获取该实例,进而访问ObjectUnderMouseCursor属性判断点击对象类型。修改graphDisplay_MouseDown方法如下:
private void graphDisplay_MouseDown(object sender, MouseButtonEventArgs e) { var layoutControl = sender as AutomaticGraphLayoutControl; if (layoutControl == null) return; // 通过反射获取私有成员 _graphViewer var graphViewerField = typeof(AutomaticGraphLayoutControl).GetField("_graphViewer", BindingFlags.NonPublic | BindingFlags.Instance); var graphViewer = graphViewerField?.GetValue(layoutControl) as GraphViewer; if (graphViewer != null) { if(graphViewer.ObjectUnderMouseCursor is IViewerNode) MessageBox.Show("点击了节点"); else if(graphViewer.ObjectUnderMouseCursor is IViewerEdge) MessageBox.Show("点击了边"); else MessageBox.Show("未点击节点或边"); } else MessageBox.Show("无法获取GraphViewer实例"); }
补充说明
- 反射访问私有成员存在版本兼容性风险:如果MSAGL控件后续版本修改了
_graphViewer的名称或访问级别,这段代码可能失效,建议后续关注控件是否提供公开API来获取GraphViewer实例。 - 原
GraphModel类需显式实现INotifyPropertyChanged接口,确保属性变更通知正常触发。
内容的提问来源于stack exchange,提问作者TA1989
相关产品推荐
相关产品推荐

