I'm setting a Button's content to an Image. It looks something like this:
<Button>
<Image Source="pack://application:,,,/NavigationImages/nav_up_left.png" />
</Button>
In my project I have a subfolder named NavigationImages and within that folder is the image file nav_up_left.png.
When I view the Designer the image appears, however during runtime I get an IOException error saying it cannot locate the resource.
The Build Action is set to Resource.
Actually, this worked fine in one project. But when I copied it over the another project it fails. This seems like an incredibly simple problem, but I find myself stumped and ready to start pulling out hair. #_#
Your thoughts and suggestions will be much appreciated!
Whelp, I figured it out...kinda.
I copied that xaml code from one project where the output type is Windows Application, to another project where the output type is Class Library.
I didn't think of it at the time, but apparently when the output type is a Class Library the pack URI needs to change.
So instead of "pack://application:,,,/NavigationImages/nav_up_left.png" I changed it to "/ProjectName;component/NavigationImages/nav_up_left.png" and now it's working just fine.
I'm not 100% clear why this is works and not the former. I've read through the MSDN documentation on pack URIs in WPF but perhaps I misinterpreted something.
I'll leave this answer unchecked in the event someone can give me a good explanation why what I previously had doesn't work in a project with output type Class Library.
I'm probably missing something really simple. #_#
I just struggled with this same problem for quite a while, and I think that part of what was going wrong in the original was the missing word "component". I, for instance, had
myBitmapImage.UriSource = new Uri(#"pack://application:,,,/MyApp;images/mona2.jpg");
but should have had
... = new Uri(#"pack://application:,,,/MyApp;component/images/mona2.jpg");
The word "component" is not part of the pathname, despite its appearance -- it's a string literal that has to be there. Why? Someone thought it'd be a good idea, I guess.
And for those struggling with another part of the thing, what about "MyApp"? That's the name of the Assembly. Right-click on your project name, select "Properties...", and under the "Application" tab you'll see the "Assembly name:" field.
If you don't feel like searching for that (or worry that it might change, breaking your code), you can do this:
String appUri = #"pack://application:,,,/" +
System.Reflection.Assembly.GetEntryAssembly().GetName().Name + ";";
String path = appUri + "component/images/mona2.jpg";
myBitmapImage.UriSource = new Uri(path);
Not very pretty code, I admit -- it can clearly be shortened -- but it'll gets you where you need to go, I hope. Remember to set the "Build" property on your image file to "Resource"!
Just to shine a light on what was happening in your situation. The second pack uri. The one that worked. Is meant for resources located in an assembly other than the host application. By the sounds of it, the host application was loading this resource from the Class Library in question?
You can see the differences in the pack uri schemes here:
MSDN Pack URI Scheme
The uri changes slightly when referencing a resource from the main assembly, and referencing one from another assembly.
Also, the pack://application:,,, includes what is referred to as the "authority", to omit it would basically make it a relative path, both are valid in most cases where the application authority is assumed.
EDIT: basically because /Subfolder/Resource.xaml(.jpg etc.) and /Assembly;component/Resource.xaml are very similar, the latter tells the parser/loader that it's looking in a referenced assembly, not in the main application's assembly. (I imagine this helps speed up the search).
One other solution to getting this right:
Once your image Build Action is set to 'Resource' and you have rebuilt, navigate to the properties of your <Image /> object. The properties window will provide a ... file resource browser, whereupon selecting your image the Source="..." attribute of your <Image /> will be correctly filled in.
Related
In short:
I'm new to VisualStudio Extensibility and my goal is to create an extension with a ToolWindow (which already works) showing different views for each context of a VisualStudio solution, i. e. a view for the solution, a view for a project etc.. The window should be opened by clicking on a context menu entry in the context menus of the Solution Explorer, Class View, Object Browser and (ideally) any other window showing contents like projects, namespaces, classes etc..
After searching I found a lot of information, but for some points I couldn't find very helpful information. How do I ...
... create a context menu item for the VisualStudio views?
... get the currently open solution as an instance in code?
... get the projects of the solution and their contens as instances in code?
... add/remove items to/from a solution/project/class/... in code?
... react to selection changes in the Solution Explorer?
What I've done, so far:
I read the docs for Starting to Develop Visual Studio Extensions and downloaded the VSSDK-Extensibility-Samples. Especially the WPF_Toolwindow example was interesting for my purposes, so I built and ran it, which was successful, so far. Another interesting sample would have been the WPFDesigner_XML, but it always throws a NullReferenceException, so I decided to stick with the former ToolWindow, which is completely fine, for now.
Furtermore, I tried to understand the example by having a close look at each file in the project, running it in the debugger and analyzing what happened. I'm confident I understood it, but am also open for corrections of my possibly misguided thoughts following.
Now, I have created a new project, based on the WPF_Toolwindow sample, renamed and adapted to my needs (basically, I created new GUIDs, renamed the namespaces and removed things I won't use). This extension still works in the debugger. I even uninstalled everything from the experimental instance and debugged the extension from scratch.
What I try to achieve:
Have the ToolWindow load a specific view/viewmodel, when the selection changes in the Solution Explorer (or any other VisualStudio view). Alternatively, there should be a context menu item for every node's context menu in the Solution Explorer tree (or any other VisualStudio view).
Get the currently open solution, the containing projects and basically everything from the Solution Explorer's content as instances processable in my viewmodel. I need to properly add/remove
classes/structs/enums to/from
a folder in a project
a namespace
properties/fields to/from a class/struct
Generate code based on information of the solution and add the file properly to a project.
Does anyone know of examples for something like this or can anyone give me some hints, where I can find further information? Any help would be appreciated. Thanks in advance.
(1) The items already have a context menu and I want to add a new command to this menu.
if you want to add a sub menu to the context menu, the following link provide a complete sample
https://github.com/visualstudioextensibility/VSX-Samples/tree/master/CommandSubmenu
(3) Yes, basically adding a file to a project without manually manipulating the project file would be nice.
You can add the file to project via Project.ProjectItems.AddFromFile, and the following provide a sample for your reference.
https://www.mztools.com/Articles/2014/MZ2014009.aspx
Update:
I select a project and a similar event is fired. Are there such events I can subscribe to?
You could use IVsMonitorSelection to implement. here is the code which retrieve related project path for your reference.
IntPtr hierarchyPointer, selectionContainerPointer;
Object selectedObject = null;
IVsMultiItemSelect multiItemSelect;
uint projectItemId;
IVsMonitorSelection monitorSelection =
(IVsMonitorSelection)Package.GetGlobalService(
typeof(SVsShellMonitorSelection));
monitorSelection.GetCurrentSelection(out hierarchyPointer,
out projectItemId,
out multiItemSelect,
out selectionContainerPointer);
IVsHierarchy selectedHierarchy = Marshal.GetTypedObjectForIUnknown(
hierarchyPointer,
typeof(IVsHierarchy)) as IVsHierarchy;
if (selectedHierarchy != null)
{
ErrorHandler.ThrowOnFailure(selectedHierarchy.GetProperty(
projectItemId,
(int)__VSHPROPID.VSHPROPID_ExtObject,
out selectedObject));
}
Project selectedProject = selectedObject as Project;
string projectPath = selectedProject.FullName;
For more information about the usage, please refer to:
https://www.mztools.com/articles/2007/mz2007024.aspx
Ok I found this wonderful idea on code project.
link
The idea is great add all your data templates to collection in your list box. Tell each one what to look for (a type) and what data template to use when it runs into that type. The problem is that the included source code is different from the on page code and I can't seen to get any combination of it to work. Even adding the missing quotation marks and changing the type to a local class instead of the non-accessible string and int32 classes.
So the question is. What am I doing wrong?
Bryan
Should be totally redundant when you have DataTemplate.DataType.
(Example)
I have implemented a converter to convert Int32 to String to be able to binding a property to a textBox.
I implement this converter in the namespace MyApp.Converters and it is called Int32ToStringConverter.
Then, in my axml I add the reference to my converter as follow:
<Window x:Class="MusicaDB.Views.PrincipalView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
**xmlns:converter="clr-namesapce:MyApp.Converters, aseembly=MyApp**">
Later, in windows.Resources I have:
<Window.Resources>
<**converter:Int32ToStringConverter** x:Key="Int32ToStringConverter" />
</Window.Resources>
I get the error that the tag Int32ToString converter does not exist in the namespace MyApp.Converters,assembly=MyApp.
I have the project in the local hard drive, in the project properties, the destination .NET is framework 4.0, not framework 4.0 client profile and I try to clear the solution and recompile but the problem persists.
Mainly, this is the two solutions that I always find, but don't resolve my problem.
Three fixes to make here:
No spaces -> xmlns:converter="clr-namesapce:MyApp.Converters,aseembly=MyApp"
No misspellings -> xmlns:converter="clr-namespace:MyApp.Converters,assembly=MyApp"
Right delimiters -> xmlns:converter="clr-namespace:MyApp.Converters;assembly=MyApp"
From the the documentation:
Note that the character separating the clr-namespace token from its value is a colon (:) whereas the character separating the assembly token from its value is an equals sign (=). The character to use between these two tokens is a semicolon. Also, do not include any whitespace anywhere in the declaration.
Another possible solution to this problem is that you're not using the same version of .Net in your project and your library.
I am exploring as to why this is happening, but if your converter is in the main assembly, removing the assembly= from your xmlns:converters tag should remove that build error.
For the record ...
I've face a similar problem and if I removed the ";assembly=X" part from the XAML it worked fine
But don't really understand the reason.
As suggested in this blog:
http://zoomicon.wordpress.com/2012/07/02/fix-the-tag-xxx-does-not-exist-in-xml-namespace-clr-namespaceyyy/#comment-7761
I see two possible causes. The first is that you misspelled "assembly" as "aseembly" in the first starred line. Changing the spelling might be enough. The second possibility is that you haven't added MyApp.dll to your project references, which appear like this
in Visual Studio.
All answers are right. And after trying all of them and you cannot configure why its happening, everything seems alright, Please restart the Visual studio.
That worked for me after wasting almost 1 hour. I found everything ok, but restarted the VS with administration.
use the assemble tag only if it is in another project.
other wise use just namespace tag alone.
For me this fixed the issue
In my situation, I had the same problem with xmlns:local="clr-namespace:<mydefaultnamespace>".
I solved this changing the order of the includes. I put it first and all was solved.
A strange behaviour, but this was my workaround that I found in my situation.
In my case, the assembly which contained the namespace was not physically there.
I checked the references of the assembly that had the build error and looked at the properties of the referenced assembly in question.
I navigated to the path and discovered the assembly was indeed missing (which I realised was my own doing), giving rise to the misleading error.
There is one very obscure case when you get this error - if you're using Microsoft.mshtml.dll and you upgrade to Windows 10 anniversary edition, or as it turns out the Creator edition too.
Even if this isn't what happens to you make sure the library containing the component that cannot be found can be fully compiled. Look in the error list (not the grid but the Output console) for any clues.
In my case I was using Microsoft.mshtml.dll as part of an HTML editor and it was unregistered somehow (in the GAC).
The following article explains with screenshots:
https://techninotes.blogspot.com/2016/08/fixing-cannot-find-wrapper-assembly-for.html#comment-form
In short I had to run a Visual Studio command prompt (as admin) run these commands:
cd C:\Windows\assembly\GAC\Microsoft.mshtml\7.0.3300.0__b03f5f7f11d50a3a
regasm Microsoft.mshtml.dll
I did say obscure :-) The important point is to read the errors that may be buried amongst all your warnings because there might be an important clue.
This can be especially confusing if an Operating system update suddenly breaks your project.
I was temporarily replacing a NuGet dll with a local one when this happened. Turned out the assembly was not the same version as the one I was replacing. I built my assembly with the correct version and it worked.
I am mucking about with WPF glyphs and documents and have run into a null reference exception in the .Net 4 framework.
I extract and save true-type fonts to disk as .ttf files, then try to create Glyphs based on the fonts. The first time I save a font to disk and instantiate a GlyphTypeface based on the font after creating a GlyphTypeface from another font in the same folder I get a null reference exception.
Say I have fonts A and B. B has not been saved to disk (A may or may not have been saved to disk; that doesn't seem to matter):
1) save B to disk in the same folder as A,
2) create GlyphTypeface using font A,
3) create GlyphTypeface using font B = exception.
Null reference exception at:
at MS.Internal.FontCache.FontFaceLayoutInfo.IntMap.TryGetValue(Int32 key, UInt16& value)
at MS.Internal.FontCache.FontFaceLayoutInfo..ctor(Font font)
at System.Windows.Media.GlyphTypeface.Initialize(Uri typefaceSource, StyleSimulations styleSimulations)
at System.Windows.Media.GlyphTypeface..ctor(Uri typefaceSource)
If I restart my app and run it again (with font B already on disk), step 3 doesn't throw an exception.
The code to save a font to disk is simply writing a section from a binary stream and letting go of the file:
if (!File.Exists(filename))
{
using (FileStream fs = File.Create(filename, length))
{
fs.Write(m_data, m_index, length);
fs.Close();
}
}
Any ideas? I don't want to have to put every font in its own folder...
Thanks for your time.
This bug has been driving me nuts but I think I have a better understanding of what is going on now.
For testing I used the following XAML:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Glyphs
FontUri="C:\Users\Public\Desktop\A.ttf"
FontRenderingEmSize="100"
Fill="Black"
UnicodeString="Test"/>
</Page>
Using the XamlPadX application which runs on the .NET 2 runtime I could reliably render the XAML no matter where I placed the font.
Using the Kaxaml application which runs on the .NET 4 runtime the XAML would often fail to render depending on where I placed the font in the file system. By moving the font file around and renaming I tried to discover a pattern in what was allowed. However, it was very hard to see a pattern.
For instance storing the font in the path below would render the glyphs:
C:\Users\Public\Desktop\A.ttf - OK
Renaming it from A.ttf to B.ttf would throw the exception:
C:\Users\Public\Desktop\B.ttf - throws exception
Changing the extension would also throw the exception:
C:\Users\Public\Desktop\A.odttf - throws exception
Renaming parts of the path would sometimes wreak havoc but I was unable to see any pattern. Initially I used the temp path and getting exceptions lead me to this question and the answer about not using that path. However, later I have actually been able to use that path as long as the name of the file is A.ttf and not B.ttf so avoiding the temp path is not a sure fix.
At some point during my tests using my own WPF application the B.ttf file name suddenly started working. However, I had to restart the Kaxaml application before it would accept the B.ttf file name. Also, at that point the A.odttf file name was still throwing exceptions.
My suggestion is to use an application like Kaxaml or to create a small WPF application to test which font file names are acceptable and then use them. However, I fear that the nature of this bug is such that a "good" font file name may turn "bad" at a later point in time. Only time will show.
I ended up using the workaround of saving each font to its own folder (using the font name for the folder name). The exception went away, so I guess we can chalk this up to a bug in .Net.
I (and a co-worker) finally found what our particular problem was: do not save the font files to %TEMP%. For some reason, having the fonts saved to some other folder makes it work (for us), and saving it to anywhere inside %TEMP% makes it break.
According to XamlToys Doesn't work on framework 4.0???, the problem is in the extension of the file for partial fonts.
When I renamed the .ofttf files I save to .ttf, it all works again. Haven't got the foggiest idea of why that is though. Seems to be new in .NET 4.0.
My workaround was to simply replace the < Glyphs > with equavalent < TextBlock >s. The couple of pixels difference in layout was not a problem in my case.
Like you noted was the case for you, in my case also it was not a problem in .Net 3.5, but appeared in .Net 4.0.
I currently am loading all images in a folder in my "MyPictures" folder on my machine which works fine...
foreach (string filename in Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)))
What I really want to be able to do, though, is load all the images in my Images folder within my solution project. Can someone please tell me the correct syntax to do this?
[Nothing in your question (as it is currently stated) is really directly related to WPF as opposed to C# (and Windows development) in general, as far as I can tell. You might get a better reply if the question was tagged to C# as opposed to just WPF.]
I don't think there is a way to reference your solution's folder as such (nor does it really make much sense, as the users of your application won't in general have the solution, only the distributables).
If you need the directory to be within your solution folder somehow, maybe you should refer to the directory your executable resides in (...\SolutionDir\bin\Debug), which you can get using
System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly()
.GetModules()[0].FullyQualifiedName);
(Of course, you could tack \..\.. to that to refer to the SolutionDir instead, but that'd be a bit ugly.)
Depending on the usage of the images, though, it'd probably be better to put them under one of the defined special directories -- Environment.SpecialFolder.CommonApplicationData sounds like the best candidate, if the images are to be shared by all users.
One way to access images stored in a folder inside the WPF project is to do the following:
If you have already added the images inside an Images folder, Add the images file names in the Resources.resx file under Properties. You can access the images in the code by the following
string imageFilename = "pack://application:,,,/APP.UI;component/Images/" + Properties.Resources.imagefilename;
var src = new BitmapImage();
src.UriSource = new Uri(imageFilename , UriKind.Absolute);