I have an application that contains a plugin system. The plugins define their menu and toolbar entries of the main application.
I thought on creating on the plugins a UserControl just to hold plugins menu and toolbar entries (and be able to define them using xaml) to put them on the main application. When I try to attach them to the main Window I get an exception saying
Element already has a logical parent. It must be detached from the old
parent before it is attached to a new one
I've tried to remove first the element in this way:
public System.Windows.Controls.MenuItem Menu
{
get
{
((StackPanel)(_controlItems.Content)).Children.Remove(_controlItems.ItemMenu);
return _controlItems.ItemMenu;
}
}
But I get the same exception. Any thoughts?
Related
I am working on an application that is monitoring a given application for automation events. Currently, I am working specifically with structure change events on a WPF application that I developed.
public void MonitorStructureChangedEvents(AutomationElement element)
{
Automation.AddStructureChangedEventHandler(element, TreeScope.Subtree, OnStructureChanged);
}
where in this case, element is the root AutomationElement of the Application (its main window). The WPF application in question is just a Window with a grid view and various controls (text boxes, checkboxes, buttons, etc). It is a test app I have developed specifically for testing UIAutomation events.
I am using a Unit Test project to test these events, and I am launching the application in the ClassInitialize decorated method. I do not register for StructureChanged events until the application is launched and I have located it via WMI in my TestMethod. The application is spawned as a new process.
However, upon registering for structure changed events, I receive structure changed events for all the elements in the main window of my application, even though the WPF application is effectively idling. I have buttons in the main window that add and remove controls to test StructureChanged events, and it does work, however I am unsure why when I initially register, all of the elements fire a structure changed event.
Edit: After further testing, I notice that these events are fired as soon as I either click on the application window, or hover over a button. It then fires a structure changed event for every element in the app one time. After it is done, it no longer fires a structure changed event if I hover over a button, or click on the application (even after clicking on another application or the desktop)
Edit2: After further testing, I believe I figured out the cause of the issue, but no solution yet. When I try to TreeWalker.RawViewWalker.GetFirstChild(rootApplicationElement) I receive a null. It appears that the AutomationElement that I am acquiring has no children cached. Once I add the StructureChanged event handler on the element, the TreeWalker method works, and I get a valid element. It seems when I activate the window after this, that's when it realizes that it now has all these new child elements. Is there a way to cache all the descendants of the rootApplicationElement so that before I add the event handler, I can walk the entire subtree?
I was able to solve the problem by using the following method
CacheRequest request = new CacheRequest();
request.TreeScope = TreeScope.Element | TreeScope.Descendants;
using (request.Activate())
{
rootApplicationElement = AutomationElement.RootElement.FindAll(TreeScope.Children,
new PropertyCondition(AutomationElementIdentifiers.ProcessIdProperty, ApplicationInstance.ProcessId))[0];
}
I do not advise that people acquire a root element in this fashion, since if an application has more than one window you will get more than one result, but this was tailored to a specific testing need.
I'm currently working on a "Settings" screen for a project and want to implement a view similar to that found in Visual Studio, where there is a TreeView with a list of options and clicking on one of these options will load a UserControl in an adjacent panel in the same form. I am using a SplitContainer to group these two controls.
I thought that the Load event for the User Control would be triggered when it was displayed in the panel, but this is not the case. I also tried to trigger the Enter event but it still did not work so I tried to call a function when the form was initialized using the following method.
ViewSecurity newViewSecurity = new ViewSecurity(Globals._connectionString);
// This creates a new instance of the ViewSecurity form from within the TreeView.
And this is the code in the initializing function for the User Control
public ViewSecurity(string _cString)
{
InitializeComponent();
connectionString = _cString;
MessageBox.Show("Test");
populateData();
}
This method does not work either - the MessageBox does not show up and the function populateData() isn't called either. Any advice on how I could achieve what I am trying to do?
Thanks in advance!
My problem is this, my main window's title is dynamic (it contains the version of the application), so when I recorded my coded ui tests, several objects were created for that window under the UIMap node in the UI Control Map named "MainWindow", "MainWindow1", "MainWindow2" etc... The only difference between them is the title.
So I changed the search property of the first "MainWindow" to "Contains" and just the name of the application in order to make it ignore the version part. But now my question is, how do I remove all the other main window objects and reference all of the UI actions and other controls (which are under the redundant window objects in the tree) to the "MainWindow" object?
I can't find any clean way to do this. Thanks a lot.
Install Feature Pack 2 for Visual Studio, this will give you a graphical editor for the UIMap.
I also recommend using this extension: http://uimaptoolbox.codeplex.com/
You can edit the UIMap as xml (Right click the UIMap -> Open with -> xml (Text) Editor)
There, under <UIMap> find the <Decendents> tag of MainWindow1 and MainWindow2.
copy all the <UIObject ..> nodes and move them to MainWindow under <Descendants>.
Then delete MainWindow1 and MainWindow2 <TopLevelWindow> nodes.
Hope this helps
Im developing an application in C# under WPF.I want to change the status of the check box and also i need to change the text block's value of already opened window from the currently working windows operation and to update that opened window with these changes(Refresh the already opened window with some updates).
In order to control UI elements from code behind you need to assign a name to each UI element you would like to control.
As for check box decleared as
<CheckBox Name="chkA"> Checkbox A </CheckBox>
you can change its' checked state from code-behind via
chkA.IsChecked = true;
As for the diffenet window update - your Windows in WPF are just classes, part of which usually lives in *.xaml file, and another in the corresponding *.cs file.
If you declare a public method that refreshed the windows content's as you want in your second windows' class, and, when you will be creating your second window, you somehow save the reference to its' instance available in a first class (or some other logic in your application), you will be able to simply call that method from windows' 1 code to refresh the second widows appearance, as declared in a method called.
Basically, from Windows1 you call:
MySecondWindow secW = new MySecondWindow();
secW.Show();
....
secW.RefreshWithMyChages();
RefreshWithMyChages() is just a public method in your second windows' class codebehind.
All of this hold true if:
both of your windows are in the same project
you are not willing to use MVVM or other UI-patterns.
I am having an interesting issue with a COM component written to function as a toolbar in IE. Basically if you open up several tabs at once in IE the individual instances of the COM objects get all twisted around. Bear with me here.
Say I open up five browser tabs all at once by right clicking several different links and opening them in new tabs. Now a function of my toolbar involves selecting text in the web page and then clicking a button to copy that text into the Toolbar. So let's do that in tab 3. We select text and click the button and nothing is there. However, if we select text in tab 2, then go back to tab 3 and click the button we get the text selected in tab 2. So...the toolbar in tab 3 getting stuff from tab 2. Not good.
I have traced this problem back to static references inside our COM object, the toolbar.
[ComVisible(true), Guid("2CC75392-1182-470D-BECC-EFA33E629AB8")]
[CLSCompliant(false)]
public sealed class Toolbar : ADXIEToolbar
{
public static Toolbar Instance;
public Toolbar()
{
Instance = this;
InitializeComponent();
}
...other code...
}
Note only one toolbar instance exists per each IE tab.
This reference doesn't get assigned properly, almost like it isn't thread safe (it isn't) but instead not domain safe or something. It will sometimes reference another instance down the line. Same with other static fields and even thread-safe singletons. I don't get it.
Also note that if I pass a reference to this toolbar (inside InitializeComponent) to a control I have the same issue.
this.publicationDateCb.Toolbar = this;
This reference will sometimes point to a different tab.
If I use a purely subscription based model with absolutely zero static references with the toolbar as the referee then things seem to work fine. This basically means I would have to re-design the program to where no classes interacted with each other directly - they fire events that the toolbar subscribes to, calling methods in other classes. Ouch.
So should I go with that model (which may be ideal but I am pretty far along here) or is there a simple fix I am missing here?
Other notes:
All IE tabs are running in seperate processes.
The BHO/Toolbar is running in the same process as the IE tab.
I am using Add-In-Express for Internet Explorer to handle the IE integration.
The project is written for .NET 3.5; the loader uses .NET 2.0
If you want to share your selected text within all your toolbars you can look at: http://www.add-in-express.com/creating-addins-blog/2009/06/19/internet-explorer-plugin-settings-synchronize/
Problem solved but static references are gone. I did a few things:
First off, I changed the target .NET version to 4.0. Apparently BHOs written in 4.0 work better - I can't find a link to substantiate this claim but I have read it somewhere.
More importantly I did away with static references within the assembly altogether. I got rid of the singletons and instead created a property for each former singleton class in my Toolbar class, which will always be unique. I then passed a reference to the Toolbar whenever a class needed to reference a former singleton.
So...constructors look like this now:
internal class RegistryData
{
public RegistryData(Toolbar toolbar)
{
ToolbarRef = toolbar;
}
...
}
And let's say RegistryData needs to call Messaging.
private void RegistryUpdated(int keyId)
{
ToolbarRef.Messaging.SendMessage(keyId);
}
Huge pain, right? Hours of work. But problem solved. I would not be shocked if this issue were related exclusively to Add-In-Express.