I wanted to manually define a wintree object as described for some other controls in below link
https://www.evoketechnologies.com/blog/windows-automation-testing-coded-ui/
First I defined a wintree object in UIMap file as below
public WinTree WinTreeObject()
{
var winTreeProps = new WinTree(WinWindow) { TechnologyName = "MSAA" };
winTreeProps.SearchProperties.Add("ControlName", "tv");
winTreeProps.WindowTitles.Add("ProMANAGE ( admin # Demo )");
return winTreeProps;
}
I call like this in the code (it threews exception VS warns if I do not use parantheses for WinTreeObject)
WinTree uITVTree1 = this.WinTreeObject();
Microsoft.VisualStudio.TestTools.UITest.Extension.FailedToPerformActionOnBlockedControlException: Another control is blocking the control. Please make the blocked control visible and retry the action. Additional Details:
TechnologyName: 'MSAA'
ControlType: 'Tree'
---> System.Runtime.InteropServices.COMException: HRESULT .. 0xF004F003
And here is how it is defined in designer file when I took a record
public WinTree UITVTree
{
get
{
if ((this.mUITVTree == null))
{
this.mUITVTree = new WinTree(this);
#region Search Criteria
this.mUITVTree.WindowTitles.Add("ProMANAGE © ( admin # Demo )");
#endregion
}
return this.mUITVTree;
}
}
You can always define a Wintree object using Coded UI.
One way is as follows:
Private WinTree ProductivityTree
{
get
{
WinTree wintreeObj= new WinTree(parentobj);
WintreeObj.searchproperties.add(Wintree.PropertyNames.Name,"treeTest");
return wintreeObj;
}
}
The error you are getting (i.e. blocked control) comes when there are more controls below the hierarchy and you are trying to access one above.
You can check the hierarchy with the help of test builder.
Related
I have a completely custom screen with its own BLC and DACs, and I want to open it as a popup from a button placed on the Bills and Adjustments screen. I have coded it as follows:
public class APInvoiceEntryExt : PXGraphExtension<APInvoiceEntry>
{
public PXAction<APInvoice> LaunchOpenSource;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Open Source")]
protected void launchOpenSource()
{
APInvoice apinvoice = (APInvoice)Base.Document.Current;
if (apinvoice != null)
{
//var url = "http://localhost/AcumaticaDB2562/?ScreenId=AC302000&OpenSourceName=Bills+and+Adjustments&DataID=" + apinvoice.RefNbr;
OpenSourceDataMaint graph = PXGraph.CreateInstance<OpenSourceDataMaint>();
graph.OpenSourceDataHeader.Current = graph.OpenSourceDataHeader.Search<xTACOpenSourceHeader.openSourceName, xTACOpenSourceHeader.dataID>("Bills and Adjustments", apinvoice.RefNbr);
if (graph.OpenSourceDataHeader.Current != null)
{
throw new PXRedirectRequiredException(graph, "Open Source")
{
Mode = PXBaseRedirectException.WindowMode.NewWindow
};
}
}
}
}
I've included all the relevant DACs and BLC for my custom screen in the Class Library project I'm using to customize the 'Bills and Adjustments' screen where I'm adding the button.
The problem I'm having is that I get the following error message when launching the button:
I've set all the relevant permissions for the screen that uses the OpenSourceDataMaint BLC to 'Delete' in 'Access Right By Role', 'Access Rights By User', and 'Access Rights By Screen'. Nothing makes any difference.
Looks like DataSource is trying to find a node in SiteMap with GraphType equal to full name off your OpenSourceDataMaint class and fails:
public class PXBaseDataSource : DataSourceControl, IAttributeAccessor, INamingContainer, ICompositeControlDesignerAccessor, ICommandSource, IPXCallbackHandler, IPXScriptControl, IPXCallbackUpdatable, IPostBackDataHandler
{
...
private static string getFormUrl(Type graphType)
{
PXSiteMapNode node = getSiteMapNode(graphType);
if (node == null)
{
throw new PXException(string.Format(ErrorMessages.GetLocal(ErrorMessages.NotEnoughRightsToAccessObject), graphType.Name));
}
String url = node.Url;
//if (url.Contains("unum=")) url = PXUrl.IgnoreQueryParameter(url, "unum");
return PXUrl.TrimUrl(url);
}
...
}
Could you please check if TypeName is properly defined for PXDataSource inside your custom Aspx page? Also could you please check if your custom Aspx page also exists in Cst_Published folder and if values set for PXDataSource.TypeName property are identical inside Pages and Cst_Published folders?
One more thing to check, does the Site Map screen show the right GraphName for your custom screen? - would be beneficial if you can provide a screenshot for verification.
If possible, please provide your customization package, that can be published locally (even with compiled assembly) - this would greatly speed up the investigation process.
The solution, for me, was to put the code (shown below) in a customization window instead of a class library project in Visual Studio. Since the code needs to have a reference to another published customization, putting it inside an Acumatica code window takes care of this. There is no reference to the published custom screen customization in my class library project, and this obviously causes issues - and I'm not sure how to handle that.
public class APInvoiceEntryExt:PXGraphExtension<APInvoiceEntry>
{
public PXAction<APInvoice> LaunchOpenSource;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Open Source")]
protected void launchOpenSource()
{
APInvoice apinvoice = (APInvoice)Base.Document.Current;
if (apinvoice != null)
{
AssistantController.OpenSourceDataMaint graph = PXGraph.CreateInstance<AssistantController.OpenSourceDataMaint>();
graph.OpenSourceDataHeader.Current = graph.OpenSourceDataHeader.Search<AssistantController.xTACOpenSourceHeader.openSourceName
,AssistantController.xTACOpenSourceHeader.dataID>("Bills and Adjustments", apinvoice.RefNbr);
throw new PXRedirectRequiredException(graph, "Open Source")
{
Mode = PXBaseRedirectException.WindowMode.NewWindow
};
}
}
}
I've got a customization to the Invoice & Memo screen where I execute some custom code (web service calls) when the Release action is activated. This works fine - I knew how to replace the PXAction code and proceeded from there. Now I want to use the Release AR Documents processing screen to do the same thing, but I'm having trouble understanding where / what to override, or where to place my code.
I see the ARDocumentRelease graph constructor with the SetProcessDelegate in the source code, but I'm not sure how to proceed - whether this is where I need to be looking or not. I need to execute my code for each line being released, using the RefNbr in my code.
Since it's an static method, you can't override it. Also, you can't do like it's done in the T300, because you are in processing graph and you can't override the release button with your own. I was able to achieve it by passing callback for each AR document that have been processed.
You can call the Initialize method of the ARDocumentRelease graph to override the logic like you said. After you just have to call ReleaseDoc that uses a callback parameter instead of using the default one.
Here's the code that I came with:
public class ARDocumentRelease_Extension : PXGraphExtension<ARDocumentRelease>
{
public override void Initialize()
{
ARSetup setup = Base.arsetup.Current;
Base.ARDocumentList.SetProcessDelegate(
delegate (List<BalancedARDocument> list)
{
List<ARRegister> newlist = new List<ARRegister>(list.Count);
foreach (BalancedARDocument doc in list)
{
newlist.Add(doc);
}
AddAdditionalLogicToRelease(newlist);
}
);
Base.ARDocumentList.SetProcessCaption("Release");
Base.ARDocumentList.SetProcessAllCaption("Release All");
}
public delegate void PostPorcessing(ARRegister ardoc, bool isAborted);
private void AddAdditionalLogicToRelease(List<ARRegister> newlist)
{
ARDocumentRelease.ReleaseDoc(newlist, true, null, delegate(ARRegister ardoc, bool isAborted) {
//Add your logic to handle each document
//Test to check if it was not aborted
});
}
}
Please note that you must always call static methods from within long running process and create necessary objects there.
Processing delegate logic is implemented as long running process which creates worker thread to execute the processing logic.
You have AddAdditionalLogicToRelease() method which requires object instance in order to call and will fail during thread context switches and hence the issue. So, you must have create object instance inside the thread context and then call instance method.
In general, method that gets called from long running processes are declared static and required objects/graphs are created inside this static method to do some work. See below example how to properly override ARDocumentRelease graph for this purpose:
public class ARDocumentRelease_Extension : PXGraphExtension<ARDocumentRelease>
{
public override void Initialize()
{
Base.ARDocumentList.SetProcessDelegate(
delegate (List<BalancedARDocument> list)
{
List<ARRegister> newlist = new List<ARRegister>(list.Count);
foreach (BalancedARDocument doc in list)
{
newlist.Add(doc);
}
// use override that allows to specify onsuccess routine
ARDocumentRelease.ReleaseDoc(newlist, true, null, (ardoc, isAborted) =>
{
//Custom code here, such as create your GL
});
}
);
}
}
I think it's the function
public static void ReleaseDoc(List<ARRegister> list, bool isMassProcess, List<Batch> externalPostList, ARMassProcessDelegate onsuccess)
under ARDocumentRelease businesss logic.
I want to disable Orchard Content Part buttons (Save and Publish Now) in the EDITOR template (when Content Item is created) based on some conditions. Can I do that ? How do I access the buttons in the EDITOR view.
Here are come examples,
To build a content fully from a Controller example, taken from the Blog Module
public ActionResult Create() {
if (!Services.Authorizer.Authorize(Permissions.ManageBlogs, T("Not allowed to create blogs")))
return new HttpUnauthorizedResult();
BlogPart blog = Services.ContentManager.New<BlogPart>("Blog");
if (blog == null)
return HttpNotFound();
dynamic model = Services.ContentManager.BuildEditor(blog);
// Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation.
return View((object)model);
}
[HttpPost, ActionName("Create")]
public ActionResult CreatePOST() {
if (!Services.Authorizer.Authorize(Permissions.ManageBlogs, T("Couldn't create blog")))
return new HttpUnauthorizedResult();
var blog = Services.ContentManager.New<BlogPart>("Blog");
_contentManager.Create(blog, VersionOptions.Draft);
dynamic model = _contentManager.UpdateEditor(blog, this);
if (!ModelState.IsValid) {
_transactionManager.Cancel();
// Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation.
return View((object)model);
}
_contentManager.Publish(blog.ContentItem);
return Redirect(Url.BlogForAdmin(blog));
}
BuidEditor does the work for you.
And you should use a alternative version of this template, but remove the edit link and publish link.
Note, you need a route for you custom create action, and a menu link on the dashboard may come in handy.
I need a custom binding and I know when and where but I don't know how I can do it. This is the relation of the view in my custom binding. Think about the *Views like controls.
I have the connections from ViewModel->ContainerView->FirstView but I can't connect it with the TableView. To connect the ContainerView to FirstView I did a custom binding (in one direction for now). And in the setvalue method I call the firstview's method SetBinding (where I want to do the binding)
I tried a few option but nothing happens, the last one looks like this:
public GolferList CurrentGolferList { get; set; }
public void SetBinding(GolferList golferList){
this.CurrentGolferList = golferList;
TableSource = new TableSourcePlayers(TableViewPlayers);
var bindingDescription = new[]{
new MvxBindingDescription {TargetName = "ItemsSource",SourcePropertyPath = "CurrentGolferList"} ,
};
Binder.Bind(this,TableSource, bindingDescription);
TableViewPlayers.Source = TableSource;
TableViewPlayers.ReloadData();
}
I would be grateful if you could tell me another way to handle it.
Update:
I followed Stuart's link and now it works fine, thanks a lot Stuart!
Actually, in my scheme the TableView is a MvxSimpleBindableTableViewSource and I want to bind the data there. So in order to make it work, I used the code below (SetBinding needs some external refactor):
private List<IMvxUpdateableBinding> bindings;
private string BindingText = "{'ItemsSource':{'Path':'CurrentGolfers'}}";
public object DataContext {
get { return dataContext; }
set { dataContext = value;
if (bindings == null)
bindings = this.GetService<IMvxBinder>().Bind(dataContext, TableSource, BindingText).ToList();
else
bindings.ForEach(b => b.DataContext = dataContext);
}
}
public void SetBinding(GolferList golferList){
this.DataContext = PlayViewModel;
tableView.Source = TableSource;
tableView.ReloadData();
}
Note that BindingText points to the table, not to the view itself.
Update 2
Now in V3 it's a bit different. First, the view must implement IMvxBindable and this members:
public object DataContext
{
get { return BindingContext.DataContext; }
set { BindingContext.DataContext = value; }
}
public IMvxBindingContext BindingContext { get; set; }
(Don't forget dispose calling BindingContext.ClearAllBindings() and also call to CreateBindingContext() in the viewload )
And then you'll be able to bind in your class. In my case:
var set = this.CreateBindingSet<FirstPlayViewController, PlayViewModel>();
set.Bind(source).To(vm => vm.CurrentGolfers).Apply(); //I love the new fluent api :)
I think what you want to do is actual a data-bound View, rather than a custom binding.
This is covered in this question - Custom bindable control in a MvvmCross Touch project
Basically what you need to do is to add a collection of 'Bindings' and the 'DataContext' property to your FirstView.
If you do that then you should be able to databind (to DataContext) within FirstView just like you do within any normal MvvmCross view.
Note - this will be much easier to do in v3 as we've added a 'BindingContext' object to assist with exactly this type of operation
I've got the following problem:
I created a WebPart with a ToolPart,
this toolpart has multiple controls (textbox, dropdownlist, ...)
when I fill in everything and apply, it all goes ok,
even when i press ok. But when i go back to
edit -> modify webpart, all my data i've entered is gone.
How can i solve this?
Thanks
You'll need to save the values from the Toolpart in the webpart's properties. For example, lets say I want to save a string for "Title"... in the webpart define a property:
private const string DEFAULT_WPPColumnTitle = "Title";
private string _WPPColumnTitle = DEFAULT_WPPColumnTitle;
[Browsable(false)]
[WebPartStorage(Storage.Shared)]
public string WPPColumnTitle
{
get { return this._WPPColumnTitle; }
set { this._WPPColumnTitle = value; }
}
I always use the prefix "WPP" to keep all the web part properties together.
Then, in the Toolpart's ApplyChanges override, save the control's value (_ddlColumnsTitle) to the webpart (WPPColumnTitle):
/// <summary>
/// Called by the tool pane to apply property changes to
/// the selected Web Part.
/// </summary>
public override void ApplyChanges()
{
// get our webpart and set it's properties
MyCustomWebPart et = (MyCustomWebPart)ParentToolPane.SelectedWebPart;
et.WPPColumnTitle = _ddlColumnsTitle.SelectedValue;
}
Lastly, if the user edited the properties already, we want the Toolpart to be pre-populated with the user's configuration. In the CreateChildControls() method of your Toolpart, initialize the controls:
protected override void CreateChildControls()
{
try
{
MyCustomWebPart et = (MyCustomWebPart)ParentToolPane.SelectedWebPart;
// ... code to create _ddlColumnsTitle and add it to the Controls
// default our dropdown to the user's selection
ListItem currentItem = _ddlColumnsTitle.Items.FindByValue(et.WPPColumnTitle);
if (null != currentItem)
{
_ddlColumnsTitle.SelectedValue = currentItem.Value;
}
}
catch (Exception ex)
{
_errorMessage = "Error adding edit controls. " + ex.ToString();
}
}
Open up the debugger and double check that the values are getting applied to your propertries on Apply (i.e. WPPColumnTitle is set).
If so then problem is that SharePoint is not serializing/deserializing the value from the property (WPPColumnTitle) to the database and back - verify by writing out this property on the web part - as soon as you leave the page and come back it will be empty.
If so then check things like this on class
[XmlRoot(Namespace = "YourNamespace")]
and this (not strictly necessary) on properties
[XmlElement(ElementName = "ColumnTitle")]
I've also seen problems if you name your web part class "WebPart" so call it MyWebPart
I've solved it with adding a property in my webpart "IsNeverSet" (bool)
and when i go to the "CreateControls()" of my toolpart, I get this property
and if it's false, I load all the properties from my webpart and fill them in the toolpart.
So I found it with the help of Kit Menke