Control Identification Issue - winforms

I have a bit of a strange situation. Our application under test contains the version number in the title bar of the main window. Eg: Photoshop 6.1.06
During development cycles the version changes frequently.
At runtime I can inject code into the UI map to update the search properties dynamically pulled from the ApplicationUnderTest.Exe path using something like this:
var versionInfo = FileVersionInfo.GetVersionInfo(Constants.ApplicationUndertestPath);
string version = versionInfo.FileVersion;
_map.MainWin.SearchProperties[DXTestControl.PropertyNames.Name] =
string.Format("Photoshop : {0}", version);
So far so good, but the problem comes with control identification using the UIMap and Coded UI Recorder.
Here I tried to change the search property of the main window from instead of Equal operator to a Contains.
Something like this:
this.SearchProperties.Add(new
PropertyExpression(DXTestControl.PropertyNames.Name, "Photoshop :",
PropertyExpressionOperator.Contains));
However the newly identified controls are not added to the same MainWin tree structure, Instead it creates a lookup based on the exact version and adds another MainWin.version number instance to the UIMap.
If I set the exact version in my MainWin using an Equal operator - then everything works fine and new controls are appended to the MainWindow ui map branch structure, but this means maintaining the UIMap with each build.
How can I get around this?

Related

WinAppDriver - How do I get the list of properties available on an element

I am using Appium with WinAppDriver to control a WinForms / WPF application.
I am looking for a programmatic way to get the list of properties available on an element that has been retrieved.
My current thinking is to ask for the className and use this to look up a static dictionary of properties I have pre-configured.
var element = driver.FindElementByXPath(xPath);
var properties = element.getProperties(); // Is there something I can call here?
This is not the greatest solution but I figured I would mention it just in case someone else might find it useful:
It is possible to get the xml of the pagesource and look at the properties there. This can be accomplished by calling driver.PageSource which will return an xml string.
Hope someone finds this useful.
You can use element.GetAttribute("Value") to get the value. You can also use other attributes like LegacyState, Value.Value, IsEnabled, IsOffscreen, ControlType etc. You can catch hold of the list of attributes in Inspect.exe (UI access)that comes with windows tools

how to get rid of namespace errors caused by including custom control in wpf application?

I am working on a wpf-project that used a ScrollViewer to show a range of items.
In order to create a more advanced look and feel for the application, I replaced the Scrollviewer with a Carousel-control.
The code for the Carousel-control I downloaded from here:
https://www.codeproject.com/Articles/181835/WPF-Carousel-Control
Conceptually, the carousel control (as part of my wider application) consists of a large black box (which one does not need to touch) plus just a few lines of code for plugging in the carousel control. The black box is the Carousel project, highlighted in the following screenshot:
In order to plug the carousel-control in the application, just a couple of lines had to be commented out and a couple of other lines had to be added. The comments in the following two screenshots mark off the lines of code that had to be commented out and the lines of code that had to be added (in order for the scrollviewer-control to be replaced by the carousel-control):
... and (at the end of the file):
Furthermore, at the beginning of the xaml-file that contains the carousel, the following line was included:
xmlns:Carousel="clr-namespace:Carousel;assembly=Carousel"
as can be seen in the following screenshot:
As you can see, at the moment, the code for the scrollviewer is commented out. Hence, the application is using the Carousel at the moment.
This carousel works fine. However, the error list shows a bunch of errors, mostly of the following type:
the name "XYZ" does not exist in the namespace "bla".
The following screenshot shows some of the error messages:
As already mentioned, the carousel-control works despite those error messages. However, I still need to get rid of the error messages before leaving this project.
Regarding the error messages, the following points might be of interest:
No error messages are shown, when the scrollviewer-control is used.
As you can see from screenshot 5, most error messages refer to line 1 of the file CarouselControl.xaml. This file is located inside the "black box":
The beginning of file CarouselControl.xaml contains the following lines of code:
As you can see from screenshot 5, most of the error messages say that some name or property does not exist in namespace xyz, whereby namespace xyz is one of the namespaces listed at the beginning of file CarouselControl.xaml (see screenshot 7).
********************************UPDATE*****************************************
(Right-click on) Solution -> Properties -> Configuration Properties, I noticed that it was apparently not possible to change the configuration of the Carousel-project to anything other than platform x86:
No matter which platform I selected (from the drop down menu at the top of the screenshot), the platform for the Carousel-project stubbornly remained at value "x86".
Might this have something to do with the error messages?
I'm not sure how useful this may be, but I believe I have found the code that was the source of my problem:
var variables = values[0] as ObservableCollection<variable>;
var identifier = values[1] as string;
var variable = variables.SingleOrDefault(x => x.identifier == identifier);
if (variable == null) return "";
This is code of my converter to access a variable in a collection and return its value as a string, it was used on a TextBox control.
Looking back over my branches, it seems that I made this change:
var variable = variables?.SingleOrDefault(x => x.identifier == identifier);
Resharper suggested adding a Null-conditional Operator at this point, which solved my issue. It would seem that the designer was returning errors due to the LINQ expression, since the collection at this point was uninitialized.
I would look through your code to see if you have a similar instance of uninitialized collections.

How to handle Solutions, Projects and their contents in a VisualStudio extension

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

HTML Bridge not working with cross-domain Silverlight XAP

I've got a complex Silverlight app that uses the HTML bridge functionality quite extensively (in both directions). The app runs fine when the hosting page is from the same domain as the XAP source. Unfortunately, I can't get the HTML bridge functionality to work when the hosting page is on a different domain.
Now, I know the various tricks normally required to get this to work, i.e., everything that's documented here: http://msdn.microsoft.com/en-us/library/cc645023(VS.95).aspx. I've even put together my own simplified cross-domain repro that I was hoping would highlight the problem, but unfortunately, my "repro" works, i.e., both JS->SL and SL->JS functionality work just fine in it, even if the XAP is hosted on a different domain.
Here's what I've tried so far to narrow down the problem:
On my production solution (where I'm having the problem):
Confirmed that "EnableHtmlAccess" is set to true in the <object> tag.
Confirmed that "ExternalCallersFromCrossDomain" is set to "ScriptableOnly" in the AppManifest.xml file.
On my repro solution (where I can't get it to have the problem):
Added multiple libraries with multiple registered scriptable objects.
Added events to the registered objects.
On both:
Tried it with a static <object> tag and with a dynamically created <object> tag (via Silverlight.js).
Tried it with and without specifying handlers for onSourceDownloadProgressChanged, onSourceDownloadComplete, onError, and onLoad.
Tried it with and without a splashscreen.
I'm kinda running out of ideas. Anyone have any suggestions for other troubleshooting steps?
Well, so far I haven't been able to track down the precise difference between the working and the non-working versions. But I came up with a workaround that's sufficient for my needs. As it turns out, only the JS->SL functionality was broken; any calls from SL->JS still worked. So what I did was to register the scriptable SL objects from within Silverlight. In my controlling JavaScript class, I created a function with a unique name, and registered it with the window object:
var mLoadingController;
var mAppId = 'alantaClient_' + Alanta.makeId();
var mSetLoadingControllerId = mAppId + '_SetLoadingController';
window[mSetLoadingControllerId] = function (value) {
mLoadingController = value;
onLoad();
};
And then I pass in the name of the function as a part of the Silverlight app's InitParams:
var initParams = 'setLoadingControllerId=' + mSetLoadingControllerId;
Silverlight.createObject(mSource, mAppHost, mAppId, params, events, initParams);
And then I call that registration function from within Silverlight, like so:
// Do everything necessary to make the LoadingController scriptable.
HtmlPage.RegisterScriptableObject("LoadingController", LoadingController.Instance);
string setLoadingControllerId;
if (e.InitParams.TryGetValue(LoaderConstants.SetLoadingControllerIdReference, out setLoadingControllerId))
{
HtmlPage.Window.Invoke(setLoadingControllerId, LoadingController.Instance);
}
And then I can call it from JS, like so:
mLoadingController.GoToRoom();
Kinda hacky, but it works. Close enough for now.

Dynamic Hyperlink in Livecycle Form

I am trying to figure out how to make a hyperlink in a Livecycle Form which points to a URL which will change on different days that the form is rendered. For example on one day I might want the hyperlink to point to:
mywebsite/mypage?option=XXX
and on another day I want it to point to:
mywebsite/mypage?option=YYY
The XXX and YYY can be passed into the form's data pretty easily as XML, but I just don't know how to make it so that the hyperlink is changed to correspond to this.
Any suggestions?
This can be accomplished with JavaScript in LiveCycle Designer. The following script, placed on the Form's docReady event will let you dynamically change the URL of a text object.
form1::docReady - (JavaScript, client)
// If this code is running on the server, you don't want it to run any code
// that might force a relayout, or you could get stuck in an infinite loop
if (xfa.host.name != "XFAPresentationAgent") {
// You would load the URL that you want into this variable, based on
// whatever XML data is being passed into your form
var sURL = "www.stackoverflow.com"; // mywebsite/mypage?option=xxx
// URLs are encoded in XHTML. In order to change the URL, you need
// to create the right XHTML string and push it into the Text object's
// <value> node. This is a super simple XHTML shell for this purpose.
// You could add all sorts of markup to make your hyperlink look pretty
var sRichText = "<body><p>Foo</p></body>";
// Assuming you have a text object called "Text1" on the form, this
// call will push the rich text into the node. Note that this call
// will force a re-layout of the form
this.resolveNode("Text1").value.exData.loadXML(sRichText, false, true);
}
There are a couple of caveats: URLs in Acrobat are only supported in Acrobat 9.0 and later. So if someone using an older version of Acrobat opens your form, the URLs won't work.
Also, as you can see from the "if (xfa.host.name !=...)" line, this code won't run properly if the form is being generated on the server, because forcing a re-layout of a form during docReady can cause problems on certain older versions of the LiveCycle server. If you do need to run this script on the server, you should probably pick a different event then form::docReady.
I a number of complaints from users in WorkSpace that clicking links opened them in the same tab so they lost their WorkSpace form, and there's no option to change that in Designer 11. I think the solution I came up with for that would work for you too.
I made buttons with no border and no background, and in their click event have this line (in Javascript, run at client)
app.launchURL("http:/stackoverflow.com/", true);
It would be easy to add some logic to choose the right URL based on the day and it doesn't cause any form re-rendering.
In some spots where the hyperlink is in line with other text, I leave the text of the link blue and underlined but with no hyperlink, and just place the button (no background, no border, no caption) over it. Does require positioned and not flowed subforms for that to work, so depending on your layout it could get a little clunky.
Wow, just realized I am super late to the party. Well, for anyone using ES4 facing a similar problem . . .
Ended up using a 3rd party component to manipulate the PDF's hyperlinks...wish there was a better solution as this one costs about $1000.

Resources