Can i recreate a CompositionContainer? - wpf

i have a wpf application with login window before displaying the mainwindow.
i use mef to load all modules/parts. before the mainwindow start i check the user login data against the parts which i display then. the parts a Shared and NonShared.
[ImportMany]
private IEnumerable<Lazy<IComponent, IComponentMetadata>> _components;
[ImportMany("Resourcen", typeof(ResourceDictionary))]
private IEnumerable<ResourceDictionary> _importResourcen;
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
catalog.Catalogs.Add(new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory));
_mefcontainer = new CompositionContainer(catalog);
_mefcontainer.ComposeParts(somepartwithaSharedExport, this);
this all works fine. but now i tried the "relogin".
_mefcontainer.Dispose();
_mefcontainer = null;
//here the stuff that works from above
first i thought it works, but it seems that the parts i create the first time still exist in memory and i have no chance to "kill" them. so i got OutOfMemory Exception when i relogin enough times.
that why i use this approach now
System.Diagnostics.Process.Start(Application.ResourceAssembly.Location);
App.ShutDown();
i dont feel happy with this.
is there a way to cleanup the Compositioncontainer and create a new one?

You could try to call _mefcontainer.RemovePart(somepartwithaSharedExport). More details here: http://mef.codeplex.com/wikipage?title=Parts%20Lifetime

For the non-shared part you can call CompositionContainer.ReleaseExport:
_mefcontainer.ReleaseExport(nonSharedExport);
For more info have a try the sample code from this answer.
As far as I know, the shared parts cannot be released without disposing the container. If you go with that path, then you will also have to make sure that no references to these objects are kept to allow for the GC to collect them. The documentation reference from mrtig's answer provides a lot of useful details concerning the lifetime of parts and you should probably study it along with the answer by weshaggard to a similar question. It also explains what happens to disposable parts.

Related

DllHost.exe memory leak when getting PrintTicket

I have a x86 application working on windows10 (64 bit environment).
One pf the app's features is to generate a lot of reports, so there is a lot of printing involved.
However, I noticed that every time I try to use call DefaultPrintTicket on the print queue the dllhost process (COM Surrogate) grows in memory.
I managed to isolate the code responsible and moved it to a test WPF app. When a button is clicked this code is being fired:
var localPrintServer = new LocalPrintServer();
var oneNotePrintQueue = localPrintServer.GetPrintQueues().FirstOrDefault(p => p.Description.Contains(OneNote));
var printTicket = oneNotePrintQueue?.DefaultPrintTicket;
The printing queue is irrelevant as I tried them all and the problem remains.
I am aware that this might be a duplicate to: PrintTicket DllHost.exe Memory Climbs
However, the solution provided there does not work as PrintTicked is not an IDisposable object.
I also tried some tweaks in the registry (i.e. finding AppId AA0B85DA-FDDF-4272-8D1D-FF9B966D75B0 and removing "AccessPermission", "LaunchPermission" and "RunAs") with no result.
I cannot rebuild the app as AnyCpu and I would like to avoid creating a separate 64bit process just for printing as it would be difficult to send a report generated in one app to another.
Any suggestions are greatly appreciated.
It seems that the topic is difficult.
Just want to share the solution I went with in case anyone else has the same problem.
In the end I created a separate x64 app which handles the printing.
Initially I wanted to go with a WCF service. However, I ran into problems with serializing of FixedDocuments and PrintQueue. Hence the separate app.
The solution if far from perfect and in my opinion is not nice at all. However, it solved the memory leak issue.

How do I implement IActivationForViewFetcher for a child UserControl?

I've just added ReactiveUI to an existing code base. Of course, for the first control I tried it with I hit a snag. I'm using it with a UserControl embedded in a TabControl. The code looks something like this:
public partial class TabPageControl : UserControl, IViewFor<TestViewModel>
{
public TabPageControl()
{
InitializeComponent();
ViewModel = new TestViewModel();
this.WhenActivated(dispose =>
{
dispose(this.Bind( ... ));
dispose(this.BindCommand( ... ));
});
}
}
When I run the app, I get the following error message:
Don't know how to detect when TabPageControl
is activated/deactivated, you may need to implement
IActivationForViewFetcher
So, how do I implement IActivationForViewFetcher? I'm not sure what I'm supposed to do with GetAffinityForView. I'm assuming in GetActivationForView I need to check to see if the UserControl is the currently visible inside the TabControl?
Although I would like to understand how to implement the methods for IActivationForViewFetcher (especially the part where I identify that a control is in the VisualTree) - the real cause of my problem was that my main assembly didn't have the appropriate references (the controls are in a class assembly).
I'm assuming (because I've skimmed the ReactiveUI source) ReactiveUI.Winforms.Registrations needs to be instantiated by the main assembly - which includes registering ActivationForViewFetcher.
Incidentally, the class library is written in C# and the main assembly is VB.NET. So I'm not sure whether this contributed to the problem.
At least it's working now!
I don't if this will ever help anybody, since this thread is so old.
What solved my issue was having ReactiveUI.WPF,ReactiveUI.WinForms, CefSharp.WPF and CefSharp.WinForms NuGet references on all the projects/plugins that were running on the App.
My suspicion is that when ReactiveUI/CefSharp is initialized and it doesn't contain all the info/files it needs, it will not possible to add them later on runtime. But this is just guessing based on my experience.
I know it's an old thread, but just to save other developers time when facing this problem.
My solution was to add the following code in the entrypoint of the project that makes use of ReactiveUi and ReactiveUi.Wpf.
var reactiveUiWpfName = typeof(ReactiveUI.Wpf.Registrations).Assembly.FullName;
Assembly.Load(reactiveUiWpfName);
Of course, it was just required because I couldn't reference ReactiveUi or ReactiveUi.Wpf in my application startup project due to the project specifications, otherwise this error wouldn't appear anyway.
(Please, observe that, in your case you should use ReactiveUi.Winforms in the places I've used ReactiveUi.Wpf)

Insert values in database at some intervals from a visual c++ program/project

I want to create a visual c++ program that automatically inserts some random values and the current system datetime in the database at particular intervals. I would be using the srand() function for this. I am not sure how to do this. I was able to achieve this using the winForm projects and scheduling it to run every 30 mins using Task Scheduler but the issue is that every time an empty form pops up and until and unless i close it the values are not entered. What i need is that all these happen on their own and the window should not pop up as its empty. Is winform the right way to achieve this and if not then what kinf of project should i choose. Maybe timers, threads...Please shed some light as i am relatively new to this.
Regards
PS: Here's the code
String^ constring = L"datasource=localhost;port=3306;username=root;password=root";
MySqlConnection^ conDataBase = gcnew MySqlConnection(constring);
MySqlCommand^ cmdDataBase = gcnew MySqlCommand("INSERT INTO `data`.`test` (`datetime`,`temp`,`pressure`) VALUES ('"+dt+"','"+rand_temp+"','"+rand_pressure+"');",conDataBase); MySqlDataReader^ myReader;
try{
conDataBase->Open();
myReader = cmdDataBase->ExecuteReader();
//MessageBox::Show("Data Inserted");
while(myReader->Read()){
}
}catch(Exception^ex){
MessageBox::Show(ex->Message);
}
Application::Exit();
The above code is inside my formload method
Use a console application project instead of a winforms project
You should put the code in the "Main" method and not in the constructor of your Form. You do not Need a Form at all...
Also I do not recommend using a console application, because this will popup a Console-Window...
please share your code for deeper insight.
the program is writing to the DB the values, but the DB won't be updated(A.K.A committed) until you'll close the connection/do manual commit. again share your code please. i would advise not to use winforms if you don't need a form. you can use a variety of different ways to achieve DB update. for example, you can use sleep so the thread will work once in a while(depends on how much u gave him on the sleep method).
in anyway, give us more information so we can help you
edited
after the cmdDataBase->ExecuteReader(); use the MySQLConnection.commit() in order to commit the transaction. take all your code to the main function rather then in the creation of the form. it doesn't seems you need a form at all, right?
use the Sleep method to wait for some time if you need(read here) for more information or search google.
anything more?

How to get all the AutomationIDs of a WPF application in a file?

In automation of a WPF application (using UI Automation; VSTS 2010), we were adding all the Automation IDs in a Resource File manually and then access it one by one. Considering the application can expand any time, manually adding these IDs can become tedious.
So, is there any tool available which can create this for us? i.e. Get all the ids in a hierarchical format and store it in a file (xml or csv), and then we could parse it whenever required.
I was hoping for a tool like UISpy, which not only can spy all the elements but also export the same.
Do such tools exist? Or is there any alternate approach?
Any valuable feedback is highly appreciated.
Thanks!
I do like this:
public static class AutomationIds
{
public static readonly string MyDataGridId= Create();
private static string Create([CallerMemberName] string name = null)
{
return name;
}
}
<DataGrid AutomationProperties.AutomationId="{x:Static local:AutomationIds.MyDataGridId}"
... />
Then in tests
var dataGrid = window.Get<ListView>(AutomationIds.MyDataGridId);
Assign the automation IDs directly in XAML, then parse XAML files since they are XML after all...
Let's see...
First, I think that your data is not hierarchical - just because a control can be dynamically assigned to be a child of another.
If we change the problem to a subset: "how can we get a hierarchical view of the controls at a time t?" then we can answer this with MS UIA, and say, using a simple RawViewWalker (just a simple breadth-first search on the walker, starting from your main window will do - of course while the application is running so that UIA can reach and query it).
But this subset will not satisfy your initial question, because you'll probably see a portion of your whole ui collection (since some will be hidden / not activated yet at time t).
So it becomes very hard to use a UIA based tool (such as uispy) because then you'll have to set the application view to different states to reach all the controls in your application at different times t1, t2...
I would suggest parsing all your xmls at the same time and build a complete tree of the application's "static" control map, which I believe would be closest to what you're asking for.
Given that this is an old question, I doubt it matters anymore, but just wanted to make the distinctions here.

"The calling thread must be STA, because many UI components require this." Error in WPF?

I am creating a xps document as below.
Assembly assembly = Assembly.GetExecutingAssembly();
//read embedded xpsDocument file
Stream helpStream = assembly.GetManifestResourceStream(resourceNameOfContext);
if (helpStream != null)
{
Package package = Package.Open(helpStream);
string inMemoryPackageName = "memorystream://" + topicName + ".xps";
Uri packageUri = new Uri(inMemoryPackageName);
//Add package to PackageStore
PackageStore.AddPackage(packageUri, package);
docXps = new XpsDocument(package, CompressionOption.Maximum, inMemoryPackageName);
}
return docXps;
When i am trying to get docXps.GetFixedDocumentSequence();
I am getting the above error. Can anyone help?
Thanks,
Your problem has nothing to do with the code surrounding the creation or use of the XPS document. It has everything to do with what thread you are running under.
You will receive the The calling thread must be STA, because many UI components require this error whenever any of the following are attempted on a MTA thread:
You construct any object derived from FrameworkElement (including Controls and Panels)
You construct any object derived from BitmapEffect
You construct any object derived from TextComposition
You construct any object derived from HwndSource
You access the current InputManager
You access the primary KeyboardDevice, StylusDevice, or TabletDevice
You attempt to change the focus on a FrameworkContentElement
You provide mouse, keyboard or IME input to any control that accepts text input
You make WPF content visible or update its layout
You manipulate the visual tree in such a way as to cause a re-evaluation for rendering
Several other changes, mostly having to do with display and input
For example, I received this error last year when I tried to deserialize some XAML that contained <Button> and other WPF objects from within a WCF service. The problem was simple to solve: I just switch to a STA thread to do the processing.
Obviously most work with XPS documents will trigger one or more of the above conditions. In your case I suspect that GetFixedDocumentSequence ends up using TextComposition or one of its subclasses.
No doubt the my solution of switching to a STA thread will also work for you, but first you need to figure out how your code that works with XpsDocuments is getting executed run from a MTA thread. Normally any code from from the GUI (eg a button press) is automatically run in a STA thread.
Is it possible that your code that manipulates XPS Documents may be being executed without a GUI? From a user-created thread? From a WCF service or a web service? From an ASPX page? Track that down and you'll probably find your solution.
If that doesn't work, let us know the details of the path through which GetFixedDocumentSequence is called, so we can diagnose it. The directly surrounding code isn't nearly as important as the call stack and how it is originally being invoked. If it is hard to explain you probably should add a call stack to prevent misunderstandings and help us diagnose the problem further, or tell you how to start a STA thread in your particular situation.
Is your code trying to access the xps doc from a background thread? If this is the case, you'll want to use the dispatcher. Info on that here.
If this doesn't help, could you post the code where you're actually calling GetFixedDocumentSequence()?

Resources