XamlParseException when using Graph# libraries - xaml

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!

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)

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 solution:
Add your library as an Assembly Asset to your .vsixmanifest file:
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
}

Related

How to use Xamarin DataTemplateSelector with DataTemplates organized in folders?

I'm trying to implement something like this MS Docs sample, with the DataTemplates as separate files:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/templates/data-templates/selector
My folder structure...
Project
|
└─ Views\
| MyView.xaml
|
└───DataTemplates\
DT1.xaml (no .cs)
DT2.xaml (no .cs)
DTSelector.cs
From MyView.xaml...
<ContentPage ...
xmlns:datatemplates="clr-namespace: Project.Views.DataTemplates"/>
<ContentPage.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<datatemplates:DT1/>
<datatemplates:DT2/>
<!-- This is the x:Key name, right? -->
<!-- Intellisense can't find these -->
</ResourceDictionary.MergedDictionaries>
<datatemplates:DTSelector x:Key="dTSelector"
DT1= "{StaticResource dT1}"
DT2= "{StaticResource dT2}"/>
</ResourceDictionary>
From a DataTemplate...
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<!-- x:Class has been removed -->
<DataTemplate x:Name="DT1" x:Key="dT1">
<Grid, etc...
DataTemplateSelector...
public class DTSelector: DataTemplateSelector
{
public DataTemplate DT1{ get; set; }
public DataTemplate DT2{ get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
switch (App.CurrentUser.SomeEnum)
{
case SomeEnum.Pref1:
return DT1;
break;
case SomeEnum.Pref2:
return DT2;
break;
default:
return DT1;
}
}
}
I have wrestled the code into the App level and got it to compile, but then DTSelector's always returns a null object, and it throws an exception. I'd prefer it at the page level, anyhow. It seems like there should be a... ResourceDictionary Source="DT1.xaml" x:Key="DT1" but that's not valid.
I assume MyView can't find the templates via xmlns because Intellisense only sees cs files... but I get a green squiggle and compilation error XLS0414: "The type 'datatemplates:DT1' not found..."
GitRepo here, for your pleasure:
https://github.com/BullCityCabinets/DataTemplateSelectorExample201014
Thanks for any help!
I found if you put the DT1.xaml and MyView.xaml in the same folder. You can reference the resource dictionary by :
<ContentPage.Resources>
<ResourceDictionary Source="DT1.xaml" />
<ResourceDictionary Source="DT2.xaml" />
<datatemplates:DTSelector x:Key="dTSelector"
DT1ref = "{StaticResource DT1key}"
DT2ref = "{StaticResource DT2key}"/>
</ContentPage.Resources>
And the folder:
Refer: merge-local-resource-dictionaries

How to bind json data to Looping Selector for windows phone 8

I'm developing windows phone 8 application . And using the Looping Selector functionality for bind list of city name.
I get city name list in json format.
Now i need to bind the result to looping selector as data source
XAML CODE
<DataTemplate x:Key="NumberTemplate">
<Grid>
<TextBlock
Text="{Binding }"
FontSize="54"
FontFamily="{StaticResource PhoneFontFamilySemiBold}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</DataTemplate>
<toolkit:LoopingSelector
x:Name="loopselector"
Grid.Column="1"
Margin="12"
Width="128"
ItemSize="128,128"
ItemTemplate="{StaticResource NumberTemplate}">
<toolkit:LoopingSelector.DataSource>
<local:NumbersDataSource Minimum="0" Maximum="50" />
</toolkit:LoopingSelector.DataSource>
</toolkit:LoopingSelector>
CS CODE
public void Citybind()
{
try
{
string city_nameurl = "http://xxxxxxx.yyyyyy";
WebClient city_namewc = new WebClient();
city_namewc.DownloadStringAsync(new Uri(city_nameurl), UriKind.Relative);
city_namewc.DownloadStringCompleted += city_namewc_DownloadStringCompleted;
}
catch (Exception ex)
{
}
}
void city_namewc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
try
{
var city_name = e.Result;
loopselector.ItemTemplate = city_name; /* Error Cannot convert string to system.windows.dataTemplat*/
}
You can use a popular Json converter library NewtonSoft.Json for this purpose. Just add it to your project from Nuget package manager in visual studio. Then in your city_namewc_DownloadStringCompleted handler, write something like this :
var city_name = e.Result;
ObservableCollection cityList = JsonConvert.DeserializeObject>(city_name);
loopselector.ItemTemplate = city_name;
loopselector.ItemSource = cityList;
This code snippet assumes that your json is just a plain list of strings. If it is different, then you need to adjust the type <> you provide to JsonConvert for deserialization. Hope this helps!

xaml converter error in reactiveui

I get the following mysterious error when trying to use ReactiveUI's MVVM framework in a Windows Store app:
Error: Converter failed to convert value of type 'ReactiveUI.RoutingState, ReactiveUI,
Version=5.4.0.0, Culture=neutral, PublicKeyToken=null' to type 'IRoutingState';
BindingExpression: Path='Router' DataItem='MVVMTestWS.AppBootstrapper'; target element
is 'ReactiveUI.Xaml.RoutedViewHost' (Name='null'); target property is 'Router'
(type 'IRoutingState').
The Xaml looks like the following:
<Page
x:Class="MVVMTestWS.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MVVMTestWS"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Xaml="using:ReactiveUI.Xaml"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Xaml:RoutedViewHost Router="{Binding Router}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" />
</Grid>
</Page>
The AppBootstrapper object looks like the following:
public class AppBootstrapper : ReactiveObject, IScreen
{
public IRoutingState Router { get; private set; }
public AppBootstrapper(IMutableDependencyResolver dependencyResolver = null, IRoutingState testRouter = null)
{
Router = testRouter ?? new RoutingState();
dependencyResolver = dependencyResolver ?? RxApp.MutableResolver;
// Bind
RegisterParts(dependencyResolver);
// TODO: This is a good place to set up any other app
// startup tasks, like setting the logging level
LogHost.Default.Level = LogLevel.Debug;
// Navigate to the opening page of the application
Router.Navigate.Execute(new HomePageVM(this));
}
The error mystifies me! Router is clearly declared IRoutingState, I've checked that it isn't null, and I've done my best to make sure there aren't two definitions of it floating around. There was some chatter on the web about WS apps having trouble binding to interfaces, but ICommand in a Button works just fine (I tested it in the same project).
This is a dirt simple WS app built for Win 8.1 using VS2013. I'm using the 5.4.0 release of ReactiveUI (if that makes a difference here). I am a newbie when it comes to writing WS apps. Any suggestions of what I've done wrong or what more I can do to help debug this would be most helpful!
Computers are weird. Just make it the concrete class RoutingState, the interface is probably going away in ReactiveUI 6 anyways

Silverlight for Windows Embedded: How to propagate custom property value from xaml to VS project embedded application

I am working on a Silverlight for Windows Embedded project. I defined a custom user control which consists of a TextBlock control and an image control. I want to specify different text in different instance of the custom control. So I did the following in Expression Blend:
In Blend code-behind (C#) UserControl1.xaml.cs I defined and registered a DependencyProperty and set DataContext of the TextBlock:
namespace WindowsEmbeddedSilverlightApplication1
{
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
ItemText.DataContext = this;
}
public String MyText
{
get { return (String)GetValue(MyTextProperty); }
set { SetValue(MyTextProperty, value); }
}
public static readonly DependencyProperty MyTextProperty =
DependencyProperty.Register("MyText", typeof(String), typeof(UserControl1), null);
}
}
In UserControl1.xaml:
<UserControl
......
x:Class="WindowsEmbeddedSilverlightApplication1.UserControl1"
d:DesignWidth="196" d:DesignHeight="85">
<Grid x:Name="LayoutRoot">
<Image x:Name="ItemImage" Margin="0,0,90,0"/>
<TextBlock x:Name="ItemText" HorizontalAlignment="Right" Width="68" Text="{Binding MyText}" TextWrapping="Wrap" Height="23" VerticalAlignment="Bottom"/>
</Grid>
</UserControl>
To use the custom user control in MainPage.xaml:
<UserControl
......
xmlns:local="clr-namespace:WindowsEmbeddedSilverlightApplication1"
x:Class="WindowsEmbeddedSilverlightApplication1.MainPage"
Width="640" Height="480">
<Grid x:Name="LayoutRoot" Background="White">
<local:UserControl1 HorizontalAlignment="Left" Margin="94,117,0,0" Width="196" Height="85" VerticalAlignment="Top" MyText="Text1"/>
<local:UserControl1 HorizontalAlignment="Left" Margin="94,217,0,0" Width="196" Height="85" VerticalAlignment="Top" MyText="Text2"/>
</Grid>
</UserControl>
So with these when I run the application in Expression Blend I am able to see the correct text displayed on the two instances of the custom user control.
Then I import the project into Visual Studio Silverlight for Windows Embedded Application. I read some posts mentioning that I have to redo the registeration. So I did the following:
In UserControl1.h:
static HRESULT Register()
{
HRESULT hr = E_FAIL;
hr = XRCustomUserControlImpl<UserControl1>::Register (__uuidof(UserControl1), L"UserControl1", L"clr-namespace:WindowsEmbeddedSilverlightApplication1");
hr = RegisterDependencyProperties();
return hr;
}
static HRESULT RegisterDependencyProperties();
HRESULT SetMyText(WCHAR* pText);
HRESULT GetMyText(BSTR* pbstrText);
public:
static DEPENDENCY_PROPERTY_ID m_dpMyTextID;
In UserControl1.cpp:
HRESULT UserControl1::RegisterDependencyProperties()
{
HRESULT hr = E_FAIL;
IXRApplication* pApplication = NULL;
XRDependencyPropertyMetaData dpm = XRDependencyPropertyMetaData();
dpm.Size = sizeof(XRDependencyPropertyMetaData);
dpm.pfnPropertyChangeNotification = NULL;
dpm.pfnTypeConverter = NULL;
dpm.pfnEnumerableCreation = NULL;
XRValue defValue;
defValue.vType = VTYPE_READONLY_STRING;
defValue.pReadOnlyStringVal = L"Default";
dpm.DefaultValue = defValue;
hr = GetXRApplicationInstance(&pApplication);
hr = pApplication->RegisterDependencyProperty(L"MyText", VTYPE_BSTR, ControlID(), &dpm, &m_dpMyTextID);
pApplication->Release();
return hr;
}
HRESULT UserControl1::SetMyText( WCHAR* pText )
{
HRESULT hr = E_FAIL;
XRValue xrValue;
xrValue.vType = VTYPE_READONLY_STRING;
xrValue.pReadOnlyStringVal = pText;
hr = SetPropertyValue(m_dpMyTextID, &xrValue);
return hr;
}
HRESULT UserControl1::GetMyText( BSTR* pbstrText )
{
HRESULT hr = E_FAIL;
XRValue xrValue;
hr = GetPropertyValue(m_dpMyTextID, &xrValue);
if (SUCCEEDED(hr))
{
*pbstrText = xrValue.bstrStringVal;
}
return hr;
}
I didn't change anything in the generated MainPage.h and MainPage.cpp code.
Compilation is successful, and execution is also ok. The custom controls are displayed, but the texts that I put in the xaml are not displayed.
Am I doing something wrong or missing something? I couldn't find much information on this topic on the Internet. Could anyone point me in the right direction. Thanks!
Problem solved.
I added a callback to XRDependencyPropertyMetaData.pfnPropertyChangeNotification:
dpm.pfnPropertyChangeNotification = NamePropertyChanged;
According to MSDN, PFN_PROPERTY_CHANGE is a callback method that XAML for Windows Embedded invokes when the value of the associated property changes. Indeed this callback is called during initialization. In the callback, I set the TextBlock text to the new value:
void UserControl1::NamePropertyChanged(__in IXRDependencyObject* pControl, __in XRValue* pOldValue, __in XRValue* pNewValue)
{
HRESULT hr;
if (pControl && pOldValue && pNewValue)
{
UserControl1 *tempObj;
pControl->QueryInterface(__uuidof(UserControl1), (void**)&tempObj);
hr = tempObj->m_pItemText->SetText(pNewValue->pReadOnlyStringVal);
}
}
So the way of binding DependencyProperty value to a control in C++ code-behind is different from C# code-behind.

Access resx in application from Silverlight class library

Resource files in Silverlight can be accessed using the code below:
ResourceManager rm = new ResourceManager("MyLibraryNamespace.MyFolder.MyResources", Assembly.GetExecutingAssembly());
However in my application this piece of code is not in the application itself, but in a Silverlight class library and the app has reference to it; changing the namespace to the "MyAppNamespace" just generates error.
How can I reach the resources in the xap file from the Silverlight class library?
There is a nice video here: http://msdn.microsoft.com/en-us/hh336287
The trick is to write a "proxy" class so that you can reference strings from XAML. From MSDN:
public class LocalizedStrings {
public LocalizedStrings() { }
private static sdkGlobalizationCS.AppResources localizedResources = new sdkGlobalizationCS.AppResources();
public sdkGlobalizationCS.AppResources LocalizedResources { get { return localizedResources; } }
}
And in XAML (after adding the class in the static resources):
<ListBoxItem Content="{Binding Path=LocalizedResources.LangRegionNameFrFR, Source={StaticResource LocalizedStrings}}" />
This is good and I was able to do the same.
In my case I have the same library shared between applications so I extract dynamically the name of the assembly:
var ast = assembly.FullName;
char[] delimit = new char[] { ',' };
string[] parts = ast.Split(delimit);
var gResources = new System.Resources.ResourceManager(parts[0]+"resource path here", assembly);
In order to achieve what I wanted I had to do the following:
var assembly = Application.Current.GetType().Assembly;
And after that I can create ResourceManager with the resources like this:
var rm = new System.Resources.ResourceManager(name, assembly);
where name is the path from my first post.