I`m creating apllication on WPF with using MVVM and I need to get an object (node, edge) after mouse click on a graph, to process them with different ways.
But when I click on a graph, I get an object sender equals null after casting it to GraphViewer type. Object sender is retrieving by type Microsoft.Msagl.WpfGraphControl.AutomaticGraphLayoutControl and I do not know how to get this object, because this type do not have this capability. Yes this type (Microsoft.Msagl.WpfGraphControl.AutomaticGraphLayoutControl) have property _graphViewer with type GraphViewer but it is private.
So here is my code.
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 codebehind:
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 = "")
{
if (PropertyChanged != null)
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
GraphModel:
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{i sInitialized = value; OnPropertyChanged(nameof(IsInitialized));}
}
public GraphModel()
{
IsInitialized = false;
Name = " - ";
GraphObject = new Graph(Name);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
2
Try subscribing the the GViewer’s click event like this:
gViewer.Click += GraphObject_Click;
Then you create the method and you will be able to see what was clicked from the EventArgs
:
private void GraphObject_Click(object? sender, EventArgs e)
{
GViewer viewer = sender as GViewer;
MouseEventArgs mouseEvent = (MouseEventArgs)e;
if (viewer.SelectedObject is Node node)
{
Console.WriteLine($"Just clicked a node {node}")
}
}
You can do the same to see whether the clicked object was an Edge
. The viewer has more useful attributes like SelectedObject
or ObjectUnderMouseCursor
.
EDIT:
I didn’t read your problem well and I assumed you were using a GViewer like this:
<WindowsFormsHost x:Name="windowsFormsHost"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<gv:GViewer x:Name="gViewer" />
</WindowsFormsHost>
The Gviewer approach seems easier. Sorry for not answering your question.