You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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实例");
}

补充说明

  1. 反射访问私有成员存在版本兼容性风险:如果MSAGL控件后续版本修改了_graphViewer的名称或访问级别,这段代码可能失效,建议后续关注控件是否提供公开API来获取GraphViewer实例。
  2. 原GraphModel类需显式实现INotifyPropertyChanged接口,确保属性变更通知正常触发。

内容的提问来源于stack exchange,提问作者TA1989

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 20:54:54