Question

I'm trying to use the Graph# libraries in my VSPackage project, but unfortunately there are some obstacles to conquer. Here is what I did:

I copied all the following DLL's to a folder /Libraries in the project root:

  • GraphSharp.dll
  • GraphSharp.Controls.dll
  • QuickGraph.dll
  • WPFExtensions.dll

The Build Action of all is 'Content' and the option Copy to Output is set to 'Do not copy'.

I added those references to my project. (Add Reference... -> Browse -> select them from the /Library folder)

After that, I created the following files. You can see that the ViewModel is set to be the DataContext of the UserControl and that it defines a "MethodGraph" to which the UI binds.

XAML file

<UserControl x:Class="Biocoder.InteractiveExploration.View.ExplorationControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:graphsharp="clr-namespace:GraphSharp.Controls;assembly=GraphSharp.Controls"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>

    <ListView Grid.Row="0" ItemsSource="{Binding SelectedMethods}">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Method" DisplayMemberBinding="{Binding Name}"/>
                <GridViewColumn Header="ReturnType" DisplayMemberBinding="{Binding ReflectionInfo.ReturnType}"/>
                <GridViewColumn Header="Incoming Calls"/>
                <GridViewColumn Header="Outgoing Calls"/>
            </GridView>
        </ListView.View>
    </ListView>

    <graphsharp:GraphLayout Graph="{Binding MethodGraph}"/>

</Grid>

</UserControl>

Code-behind

public partial class ExplorationControl : UserControl
{
    public ExplorationControl()
    {
        InitializeComponent();

        // set the datacontext
        DataContext = InteractiveExplorationPackage.ExplorationToolViewModel;
    }
}

ViewModel

public class ExplorationToolViewModel : ViewModelBase
{
    private IBidirectionalGraph<object, IEdge<object>> _methodGraph;

    public IBidirectionalGraph<object, IEdge<object>> MethodGraph
    {
        get { return _methodGraph; }
        set
        {
            if (value != _methodGraph)
            {
                _methodGraph = value;
                NotifyPropertyChanged("MethodGraph");
            }
        }
    }

    public ExplorationToolViewModel()
    {
        InitializeViewModel();
    }

    private void InitializeViewModel()
    {
        SelectedMethods = new ObservableCollection<Method>();
        CreateGraph();
    }

    private void CreateGraph()
    {
        var g = new BidirectionalGraph<object, IEdge<object>>();

        // add vertices
        string[] vertices = new string[5];
        for (int i = 0; i < 5; i++)
        {
            vertices[i] = i.ToString();
            g.AddVertex(vertices[i]);
        }

        // add edges
        g.AddEdge(new Edge<object>(vertices[0], vertices[1]));
        g.AddEdge(new Edge<object>(vertices[1], vertices[2]));
        g.AddEdge(new Edge<object>(vertices[2], vertices[3]));
        g.AddEdge(new Edge<object>(vertices[3], vertices[1]));
        g.AddEdge(new Edge<object>(vertices[1], vertices[4]));

        MethodGraph = g;
    }
}

Fortunately, I can compile the whole project but at runtime the following error in the XAML occurs on the tag (right above the needed tag):

Could not load file or assembly 'GraphSharp.Controls, PublicKeyToken=null' or one of its dependencies. The system cannot find the file.

But I referenced the assemblies, they are listed in the references list. What's the problem? Could it be that assemblies have to be referenced another way round than usual when writing a Visual Studio Package (plugin)?

EDIT: I just tried to get it work in another project, so I just set up a normal WPF Application and did all the above. In this solution everything works properly! That's so strange!

Hope you can help me :-) Best regards!

Was it helpful?

Solution 3

I managed to get everything working now. Thanks for your help anyway!

The problem with VSPackages at runtime is basically that they load third party assemblies from another location on the computer called the Private Assembly folder. (C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies) So all you have to do is to copy the referenced assemblies into this folder (requires admin rights). In order to be able to use the assemblies when developing just add those references to your project as you do normally and the compiler will use them the usual way. The only difference is at runtime since Visual Studio loads those references from the Private Assemblies folder.

More information about this can be found here: Managed VSPackage File Location Keys

OTHER TIPS

Are you able to use nuget in your project? If so, instead copying the dll-s and references manually you should try run install-package graphsharp command.

I think that's some kind of DLL strong name problem.

Have you tried this one? http://shfb.codeplex.com/workitem/32819

It says:

I had such an issue and it is discussed somewhere in the discussions. What you need to do is to open the project properties > Paths and there delete all paths (just leave them empty)

Other solution:

  1. Add your library as an Assembly Asset to your .vsixmanifest file:
  2. Add this code to your package initialization code.
protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress<ServiceProgressData> progress)
{
    AppDomain.CurrentDomain.AssemblyResolve += LoadFromSameFolder;

    static Assembly? LoadFromSameFolder(object sender, ResolveEventArgs args)
    {
        var executingAssemblyPath = Assembly.GetExecutingAssembly().Location;
        var folderPath = Path.GetDirectoryName(executingAssemblyPath) ?? string.Empty;
        var assemblyPath = Path.Combine(folderPath, $"{new AssemblyName(args.Name).Name}.dll");

        return File.Exists(assemblyPath)
            ? Assembly.LoadFrom(assemblyPath)
            : null;
    }

    // your code
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top