Different XAP files in Silverlight - Sharing context - silverlight

I have a silverlight application which I recently split them into separate xap files.
The intention is this. There is xap file 1 which takes a few inputs from the user persists it to the database. And when the user clicks a button on this UI (from xap file 1), it loads xap file 2, which asks for more inputs and saves it to the database.
I was able to invoke xap file 2 from xap file 1, but the UI doesn't seem to be able to get the information from the database (the UI shows what was persisted by the previous UI), nor it is able to persist the user's input. I realize that the xap file 2 somehow needs to told somehow where and how to persist.
This is how I load the xap file 2
WebClient wc = new WebClient();
wc.OpenReadCompleted += new OpenReadCompletedEventHandler(OpenReadCompleted);
Uri uri = new Uri("xapfile2.xap", UriKind.Relative);
wc.OpenReadAsync(uri);
private void OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
Uri uri = new Uri("xapfile2.dll", UriKind.Relative);
StreamResourceInfo resource_stream = App.GetResourceStream(new StreamResourceInfo(e.Result, null), uri);
AssemblyPart part = new AssemblyPart();
Assembly assembly = part.Load(resource_stream.Stream);
UIElement control = assembly.CreateInstance("xapfile2.Window") as UIElement;
if (control != null)
{
RadWindow window = (RadWindow)control;
window.ShowDialog();
}
}
(All of this UI was working before I split them into separate xap's. We had good reasons to splitting them)
Any help would be greatly appreciated
UPDATE
I tried following the example link and was able to launch the second UI from the separate xap file with all the information from the database.
Now I seem to have hit a new problem. When I do a cancel on the second UI, do I have to unload the second xap calling removeXap from the catalog? When I do so I get Composition remains unchanged error.
1) Change in exports prevented by non-recomposable import 'xapfile2.Views.ViewModel (ContractName="MyViewModel")' on part 'xapfile2.Views.MyView'. Any ideas?.
Thanks
K

You should use a framework to bring in your XAP file. You're reinventing the wheel.
My suggestion is to use MEF, a framework created by Microsoft to do exactly what you are creating.
MEF has a concept of a deployment catalog, which downloads xap files and loads them. Then, using patterns like interfaces and contracts, you can create objects, show them on the screen and take more input.
See this example: http://codebetter.com/glennblock/2010/03/08/building-hello-mef-part-iv-deploymentcatalog/
Good Luck!

Having seperate XAP files doesn't create any boundries -- when the 2nd XAP is loaded, its types are loaded into the same AppDomain. Seems like you need some kind of common messaging bus between classes in your Xap1 and Xap2. You can use an Event Aggregator. Many frameworks have one or you can use your own -- Build it (and custom event types) in a dll referenced by both xap's.
I think I've used http://www.keith-woods.com/Blog/post/Rx-Event-Aggregator.aspx

After a lot of struggle I found out that I had redundant assemblies in the xap files. Apparently there should not be a conflict in assemblies. Setting CopyLocal = False on the assemblies required for the second xap seemed to have solved the issue.
Thanks guys for your tips
K

Related

Using itextsharp to set ocg state of existing pdf

I have spent several hours researching this and can't seem to locate the answer.
I have downloaded and referenced itextsharp in my wpf .net application. (VB)
What I am doing is needing to turn off a specific layer (ocg object) in an exisiting .pdf that was created in Autocad that is defaulted on.
I have successfully opened and displayed the .pdf but i can't seem to use the setOCGstate control correctly
pdf name is "random.pdf"
layer name that i can see once i open the .pdf is "Option 1"
where im getting stuck is i know the layer names are stored in an array inside the .pdf. i know the name of the layer i am trying to turn off, so how do i reference that layer and turn it off using the setocgstate.
example code
dim doc1 as New PdfReader("random.pdf")
PdfAction.SetOCGstate ("confused", False)
I've created an example that turns off the visibility of a specific layer. See ChangeOCG
The concept is really simple. You already have a PdfReader object and you want to apply a change to a file. As documented, you create a PdfStamper object. As you want to change an OCG layer, you use the getPdfLayers() method and you select the layer you want to change by name. (In my example, the layer I want to turn off is named "Nested layer 1"). You use the setOn() method to change its status, and you're done:
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
Map<String, PdfLayer> layers = stamper.getPdfLayers();
PdfLayer layer = layers.get("Nested layer 1");
layer.setOn(false);
stamper.close();
reader.close();
This is Java code. Please read it as if it were pseudo-code and adapt it to your language of choice.

How to enumerate images included as "Content" in the XAP?

I'm including a number of images as "Content" in my deployed XAP for Mango.
I'd like to enumerate these at runtime - is there any way to do this?
I've tried enumerating resources like:
foreach (string key in Application.Current.Resources.Keys)
{
Debug.WriteLine("Resource:" + key);
}
But the images aren't included in the list. I've also tried using embedded resources instead - but that didn't help. I can read the streams using Application.GetResourceStream(uri) but obviously I need to know the names in order to do this.
This is no API baked in to WP7 that allows you to enumerate the contents of the Xap. You need to know the name of the content items before you can retreive them.
There probably is some code floating around somewhere that is able to sniff out the Zip catalog in the XAP however I would strongly recommend that you don't bother. Instead include some sensible resource such as an Xml file or ResourceDictionary that lists them.
Having found no practical way to read the Content files from a XAP I build such a list at design time using T4.
See an example at https://github.com/mrlacey/phonegap-wp7/blob/master/WP7Gap/WP7Gap/MainPage.xaml.cs
This seems the right way to go as:
a) I'd rather build the list once at design time rather than on every phone which needs the code.
and
b) I shouldn't ever be building the XAP without being certain about what files I'm including anyway.
Plus it's a manual step to set the build action on all such files so adding a manual step to "Run Custom Tool" once for each build isn't an issue for me.
There is no way to enumerate the files set as "Content".
However, there is a way to enumerate files at runtime, if you set your files as "Embedded Resource".
Here is how you can do this:
Set the Build Action of your images as "Embedded Resource".
Use Assembly.GetCallingAssembly().GetManifestResourceNames() to
enumerate the resources names
Use
Assembly.GetCallingAssembly().GetManifestResourceStream(resName)
to get the file streams.
Here is the code:
public void Test()
{
foreach (String resName in GetResourcesNames())
{
Stream s = GetStreamFromEmbeddedResource(resName);
}
}
string[] GetResourcesNames()
{
return Assembly.GetCallingAssembly().GetManifestResourceNames();
}
Stream GetStreamFromEmbeddedResource(string resName)
{
return Assembly.GetCallingAssembly().GetManifestResourceStream(resName);
}
EDIT : As quetzalcoatl noted, the drawback of this solution is that images are embedded in the DLL, so if you a high volume of images, the app load time might take a hit.

MissingManifestResourceException for EmbeddedResouce in Silverlight

I write Silverlight games using XNA-based Silverlight engines. I have a previous game where I have files (MP3s and text files) with Build Action set to Embedded Resource, and no *.resx file to be seen in my solution.
The game runs fine; you can see the production version here.
On the other hand, my current project doesn't allow this. When I try to make files Embedded Resources, I get a MissingManifestResourceException thrown in my constructor of the main UserControl instance that starts my app. The error message is:
Could not find any resources appropriate for the specified culture or the neutral culture. Make sure "DeenGames.Colosseum.Content.Audio.2.mp3.resources" was correctly embedded or linked into assembly "DeenGames.Colosseum" at compile time, or that all the satellite assemblies required are loadable and fully signed.
I'm very, very, very perplexed. Setting any item's Build Action to Embedded Resource, whether MP3, text, or image, causes this exception.
How the heck do I fix (or debug) this? I'm 99% sure I do not need a .resx file, because my previous projects don't have one.
There's this lovely MSDN page which assures the world that:
In particular, Silverlight embedded resources must always use the
Resource build action, and not the Embedded Resource build action,
which uses a format that Silverlight cannot recognize.
But there's a well-known solution using Assembly.GetExecutingAssembly().GetManifestResourceNames(). In my case, it doesn't show me the resource if it's just a Resource; if it's an Embedded Resource, I can see the file name with dot-delimited namespace (as expected).
Download and see for yourself a very simple working example here. It has two embedded files (.2dg and .map) and compiles/runs without any exceptions OR resx file.
You can also download a broken example here. Replace FlatRedBall.dll with RadiantWrench.dll and watch the working example break. (Use ScreenController.ShowScreen and remove all FRB-referenced code.)
Embedded Resource is a WinForms technology that is depreciated in the Silverlight runtime. Instead, a build action of Resource or Content should be used instead.
When you set an item to Embedded Resource, Silverlight expects this to be a .resx file because this is what happens inside the .csproj or .vbproj file when you create a .resx and add resources to it (the file is marked as Embedded Resource for MSBuild and its resources are simply a None inside of an <ItemGroup/> that are discovered by the ResXGenerator at runtime based off the relative URI folder of "Resources"). If it isn't, it removes it or sets it as Content. You can examine Microsoft.Silverlight.Common.targets (usually in your C:\Program Files (x86)\MSBuild\Microsoft\Silverlight\v4.0 folder) to see how it changes items marked as Embedded Resource - setting to content, setting to none or setting to a .resx file.
If you're looking to just query what resources you have in the project, you could try this somewhat cumbersome approach: Enumerating embedded resources
UPDATE: In looking at your project, this is not really using an Embedded Resource the way WinForms uses this Build Action type or even .resx, per say. It uses a function from the ToolsSilverlight.dll called EmbeddedResourceFileReader.ReadFile. The code for that is:
private static string ReadFile(string fileName, Assembly currentAssembly)
{
string text = EmbeddedResourceHelper.CheckAndSanitizePath(fileName);
string result = "";
using (Stream manifestResourceStream = currentAssembly.GetManifestResourceStream(text))
{
if (manifestResourceStream == null)
{
throw new ArgumentException("Couldn't open " + fileName + ". Make sure the file exists in that directory, and has Build Action set to Embedded Resource.");
}
using (StreamReader streamReader = new StreamReader(manifestResourceStream))
{
result = streamReader.ReadToEnd();
}
}
return result;
}
Your .csproject file lists your files as:
<ItemGroup>
<EmbeddedResource Include="Content\Qadar.2dg" />
<EmbeddedResource Include="Content\Maps\main.map" />
<None Include="Properties\AppManifest.xml" />
</ItemGroup>
All this does is embed, as mentioned with the Microsoft.Silverlight.Common.targets above, your files as common Resources (at a top level, not with the list of other actual resouces) and finds a way to read them. You can decompile your DLL with ILSpy to exam that these are indeed now common Resources under the Resources folder.
So how can you do this in your new project? Replicate the exact method you did in your first one - add ToolsSilverlight.dll, list your items as Embedded Resource, and call them using EmbeddedResourceFileReader.ReadFile. You may also want to ensure your .csproj file <ItemGroup/> structure is similar to original one. Not sure if <None Include="Properties\AppManifest.xml"/> is needed by EmbeddedResourceFileReader, but it may be.

WPF - Saving font to disk, then instantiating GlyphTypeface for font throws exception. Why?

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.

looping through an image folder in a wpf application

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);

Resources