Genexus Extensions SDK - Where can I find the avaliable Menu Context strings? - sdk

Im trying to use the Genexus Extensions SDK to place buttons on the IDE, in this case, i want to place it in the "context" menu, avaliable only in objects of type "Webpanel/Webcomponent" and "Transaction", Just like WorkWithPlus does here:
So far, digging up into the avaliable documentation, i've noticed that you need tu put the context type string into the xml tag and the GUID of the package that you're aiming to add the menu item, such as below in GeneXusPackage.package:
The Context ID above will add the item into the "Folder View" Context.
My questions:
Where can I find a list with all the possible ID Context strings?
What is that package attribute for, where can i get it's possible values?
I am using the SDK for Genexus 16 U11

I'm sorry to say that there is no extensive list of all the menus available. I'd never thought of it until now, and I see how it could be useful, so we'll definitely consider making it part of the SDK so that any package implementor may use it for reference.
In the meantime, in order to add a new command in the context menu you mentioned, you have to add it to the command group that is listed as part of that menu. That group is KBObjectGrp which is provided by the core shell package whose id is 98121D96-A7D8-468b-9310-B1F468F812AE.
First define your command in your .package file inside a Commands section:
<Commands>
<CommandDefinition id='MyCommand' context='selection'/>
</Commands>
Then add it to the KBObjectGrp mentioned earlier.
<Groups>
<Group refid='KBObjectGrp' package='98121D96-A7D8-468b-9310-B1F468F812AE'>
<Command refid='MyCommand' />
</Group>
</Groups>
Then in order to make your command available only to the objects you said before, you have to code a query handler for the command, that will rule when the command is enabled, disabled, or not visible at all. You can do that in the Initialize method of your package class.
public override void Initialize(IGxServiceProvider services)
{
base.Initialize(services);
CommandKey myCmdKey = new CommandKey(Id, "MyCommand");
AddCommand(myCmdKey, ExecMyCommand, QueryMyCommand);
}
private bool QueryMyCommand(CommandData data, ref CommandStatus status)
{
var selection = KBObjectSelectionHelper.TryGetKBObjectsFrom(data.Context).ToList();
status.Visible(selection.Count > 0 && selection.All(obj => obj.Type == ObjClass.Transaction || obj.Type == ObjClass.WebPanel));
return true;
}
private bool ExecMyCommand(CommandData data)
{
// Your command here
return true;
}
I'm using some helper classes here in order to get the objects from the selection, and then a class named ObjClass which exposes the guid of the most common object types. If you feel something isn't clear enough, don't hesitate to reach out.

Decompiling the Genexus dll and looking for the resource called package, you can infer what the names are.
It's cumbersome but it works

Related

How to start another Activity with android-annotation?

I'm just trying to use android-annotation. When I start another Activity, an empty activity showed up.
I check this to find that the #EActivity generate the subclass of XXActivity named XXActivity_. So I try to code
mIntent = new Intent(this, XXActivity_.class);
But eclipse shows error that XXActivity_ cannot be resolved to a type. I don't know when the XX_ is generated.
I have add the jar, declare the XX_ in the AndroidManifest.xml. How to make eclipse generate the XX_ class?
you could start activity using annotations like this
first you should write your activities on the manifest file with '_' after that you have two activities you want to go from one to another you could use this :
CarDetailActivity_.intent(CarSaleListActivity.this).start();
with this you will go the CarDetailActivity on the other hand if you want to pass message to the other activity you will use this
CarDetailActivity_.intent(CarSaleListActivity.this).myMessage("arrived with android annotations").start();
and in this case you should define this on the CarDetailActivity
#Extra
String myMessage;
and you could use this message on CarDetailActivity like this on
#AfterViews
public void showMessage(){
Toast.makeText(this,myMessage,Toast.LENGTH_SHORT).show();
}
Note : CarDetailActivity should be #EActivity to make this work
Blockquote

Object Id set as null when saving - AjaxDependencySelection

So I decided to use AjaxDependencySelection Plugin for Grails, and it has proven to be very useful. However, I am trying to implement autoComplete boxes, and it does not seem to be saving the object id when using an Autocompleted selection. Here is my implementation in my gsp
<g:selectPrimary id="template" name="template"
domain='dms.nexusglobal.Template'
searchField='templateName'
collectField='id'
domain2='dms.nexusglobal.Tag'
bindid="template.id"
searchField2='tagName'
collectField2='id'
hidden="hiddenNew"
noSelection="['': 'Please choose Template']"
setId="tag"
value="${documentPartInstance?.template}"/>
<g:selectSecondary id="tag" name="tag"
domain2='dms.nexusglobal.Subtag'
bindid="tag.id"
searchField2='subtagName'
collectField2='id'
autocomp="1"
noSelection="['': 'Please choose Tag']"
setId="subtag"
value="${documentPartInstance?.tag}"/>
<g:autoCompleteSecondary id="subtag" name="subtagId"
domain='dms.nexusglobal.Subtag'
primarybind='tag.id'
hidden='tag'
hidden2='hidden5'
searchField='subtagName'
collectField='id'
value='${documentPartInstance?.subtag}'/>
<input type=hidden id="hidden5" name="subtagId" value="${documentPartInstance?.subtag}"/>
However, everytime I save it, I am presented with this error Column 'subtag_id' cannot be null . Here is my domain class definition for Subtag
class Subtag {
static scaffold = true
String subtagName
static belongsTo = [tag : Tag]
public Subtag()
{
}
public Subtag(String s)
{
subtagName = s
}
static constraints = {
}
String toString(){
subtagName
}
}
Tag hasMany subtags as well
It seems to be creating new Subtag instances when using the autoselect box (as an error shows up saying Could not find matching constructor for:packagename.Subtag(java.lang.String) Although this is a feature I am looking to implement in my application at later stages (being able to create new Subtags on the fly when creating a document Part), right now, all I would like to be able to do is just choose from my already existing subtags.
When I add in a string constructor, it comes back with the error that Column subtag_id cannot be null
I have developed it so will try help you through your issue.
The problem is that you are trying to push a value from selectSecondary and update the elementId of g:autocomplete which is actually a seperate entity.
I will update the plugin with a new method, need to test it out first.. Also take a look at g:selectAutoComplete. Although this method would only work if your secondary was the primary task... so no good in that case either..
hang on and look out for 0.37 release
Released 0.37 documentation on how to do such a thing here: https://github.com/vahidhedayati/ajaxdependancyselection/wiki/from-selection-to-autocomplete---how-to

Conditional imports / code for Dart packages

Is there any way to conditionally import libraries / code based on environment flags or target platforms in Dart? I'm trying to switch out between dart:io's ZLibDecoder / ZLibEncoder classes and zlib.js based on the target platform.
There is an article that describes how to create a unified interface, but I'm unable to visualize that technique not creating duplicate code and redundant tests to test that duplicate code. game_loop employs this technique, but uses separate classes (GameLoopHtml and GameLoopIsolate) that don't seem to share anything.
My code looks a bit like this:
class Parser {
Layer parse(String data) {
List<int> rawBytes = /* ... */;
/* stuff you don't care about */
return new Layer(_inflateBytes(rawBytes));
}
String _inflateBytes(List<int> bytes) {
// Uses ZLibEncoder on dartvm, zlib.js in browser
}
}
I'd like to avoid duplicating code by having two separate classes -- ParserHtml and ParserServer -- that implement everything identically except for _inflateBytes.
EDIT: concrete example here: https://github.com/radicaled/citadel/blob/master/lib/tilemap/parser.dart. It's a TMX (Tile Map XML) parser.
You could use mirrors (reflection) to solve this problem. The pub package path is using reflection to access dart:io on the standalone VM or dart:html in the browser.
The source is located here. The good thing is, that they use #MirrorsUsed, so only the required classes are included for the mirrors api. In my opinion the code is documented very good, it should be easy to adopt the solution for your code.
Start at the getters _io and _html (stating at line 72), they show that you can load a library without that they are available on your type of the VM. Loading just returns false if the library it isn't available.
/// If we're running in the server-side Dart VM, this will return a
/// [LibraryMirror] that gives access to the `dart:io` library.
///
/// If `dart:io` is not available, this returns null.
LibraryMirror get _io => currentMirrorSystem().libraries[Uri.parse('dart:io')];
// TODO(nweiz): when issue 6490 or 6943 are fixed, make this work under dart2js.
/// If we're running in Dartium, this will return a [LibraryMirror] that gives
/// access to the `dart:html` library.
///
/// If `dart:html` is not available, this returns null.
LibraryMirror get _html =>
currentMirrorSystem().libraries[Uri.parse('dart:html')];
Later you can use mirrors to invoke methods or getters. See the getter current (starting at line 86) for an example implementation.
/// Gets the path to the current working directory.
///
/// In the browser, this means the current URL. When using dart2js, this
/// currently returns `.` due to technical constraints. In the future, it will
/// return the current URL.
String get current {
if (_io != null) {
return _io.classes[#Directory].getField(#current).reflectee.path;
} else if (_html != null) {
return _html.getField(#window).reflectee.location.href;
} else {
return '.';
}
}
As you see in the comments, this only works in the Dart VM at the moment. After issue 6490 is solved, it should work in Dart2Js, too. This may means that this solution isn't applicable for you at the moment, but would be a solution later.
The issue 6943 could also be helpful, but describes another solution that is not implemented yet.
Conditional imports are possible based on the presence of dart:html or dart:io, see for example the import statements of resource_loader.dart in package:resource.
I'm not yet sure how to do an import conditional on being on the Flutter platform.

Autofac error: The instance registration can support SingleInstance() sharing only

When I try to register my class with autofac I get the following error: "The instance registration 'GetAllDivisionsCommand' can support SingleInstance() sharing only".
I don't understand why I'm getting this error, but assume it's something to do with the class having static member variables used for caching as that's the only thing that's different about this class. I haven't had any trouble registering any other classes as either SingleInstance or InstancePerDependency.
Essentially, the class is used to retrieve a rarely changing list of divisions from the database, and caches the result. Each time the command is run, it first checks for changes on the database and then re-runs the query if changes are detected; if not, it returns the cached list.
So I am trying to register GetAllDivisionsCommand with Autofac as an IGetAllDivisionsCommand. IGetAllDivisionsCommand itself implements IInjectableCommand, which is just a marker interface, and ICachedListCommand. The concrete command class inherits from the abstract base class CachedListCommand which is where the static member variables live.
Does anyone know what would cause this error message? SingleInstance won't work for me as I can't keep reusing the same session.
Code:
Type commandType = typeof(IInjectedCommand);
Type aCommandType = typeof(GetAllDivisions);
var commands =
from t in aCommandType.Assembly.GetExportedTypes()
where t.Namespace == aCommandType.Namespace
&& t.IsClass
&& !t.IsAbstract
&& (commandType.IsAssignableFrom(t))
let iface = t.GetInterfaces().FirstOrDefault(x => "I" + t.Name == x.Name)
select new { Command = t, Interface = iface };
foreach (var cmd in commands)
{
builder.RegisterInstance(cmd.Command).As(cmd.Interface).InstancePerLifetimeScope();
}
RegisterInstace as the name implies is for registering instances not types.
What you need is RegisterType:
foreach (var cmd in commands)
{
builder.RegisterType(cmd.Command).As(cmd.Interface).InstancePerLifetimeScope();
}
And by the way with the Autofac scanning feature your registration code is roughly equivalent:
builder
.RegisterAssemblyTypes(aCommandType.Assembly)
.AssignableTo<IInjectedCommand>()
.InNamespace(aCommandType.Namespace)
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
In my case, I did want RegisterInstance because I actually have an instance in hand that I wanted to register.
I had
builder.RegisterInstance(myInstance).InstancePerDependency();
The documentation for InstancePerDependency reads:
Configure the component so that every dependent component or call to
Resolve() gets a new, unique instance (default.)
On closer inspection, it makes sense that registering an instance with "instance per dependency" is not possible, since it is not possible for Autofac to give back a new instance each time Resolve is called if there is in fact 1 instance registered.
So, in my case, the solution was this.
builder.RegisterInstance(myInstance).SingleInstance();
The Autofac exception could possibly have been worded more clearly to explain this problem.

How to return ArrayList type from DomainService Class to CLient Side?

Background: 3-4 weeks experience in Silverlight3/C#/.Net and about 3days worth with the RIA Services concept. (most of my previous questions up to date should explain why)
I am doing a test implementation of Microsoft's RIA services with Silverlight3. This is part of a proof of concept i have to do for a client. So its very basic.
I have figured out how build the Silverlight3 project using RIA services etc. So passing and returning strings and int's is no problem at the moment.
But i require to return an ArrayList from my Domain Service Class to my SL3 client. But it seems passing back an ArrayList as is, is not permitted. And my limited knowledge of C# does not aid in doing quick type casting/convertions/etc. This server-side function gets an ArrayList which must be returned to the SL3 client, so i have to do something with it to send it client side.
Question:
Does anyone know what should be done to an ArrayList (in c#) to allow a DomainService class function to return it to a calling client/SL3 function?
[NOTE: the majority of my attempts all end in the error: "Service operation named 'myFunctionName' does not conform to the required signature. Both return and parameter types must be an entity type or one of the predefined serializable types."]
Please feel free to request any information you feel would be appropriate.
Thank you in advance.
My apologies for not posting the solution i found. Bosses threw more work at me than i could handle. :)
Please note my solution may not be the best but since my knowledge in SL and RIA services are so new, i guess it may be excused. Initially i wanted to pass back rather complicated arrays from the code provided by our client, but effort and time restraints allowed me to only get it right to convert and return a List.
Hope this helps in some way.
Client Side : Silverlight Code in the MainPage.xaml.cs i have a call to retrieve a list of data from the server side, to display in a dropDown list.
// Function called on load of the SL interface
// 'slayer' is an object of the Domain Service Class server-side
// 'this.gidSessionNumber' is just a number used in the demo to represent a session
public void loadPaymentTypeComboBox()
{
InvokeOperation<IEnumerable<string>> comboList = sLayer.getPaymentTypeCombo(this.gidSessionNumber);
comboList.Completed += new EventHandler(popPaymentCombo_complete);
}//function loadAllComboBoxes
// Event handler assigned
public void popPaymentCombo_complete(object sender, EventArgs e)
{
InvokeOperation<IEnumerable<string>> obj = (InvokeOperation<IEnumerable<string>>)sender;
string[] list = obj.Value.ToArray();
// 'paymentTypeDropdown' is the name of the specific comboBox in the xaml file
paymentTypeDropdown.IsEnabled = true;
// Assign the returned arrayList as itemSource to the comboBox
paymentTypeDropdown.ItemsSource = list;
}
In the Domain Service Class i have the associated function:
[ServiceOperation]
public List<string> getPaymentTypeCombo(string gidNumber)
{
// Build objects from libraries provided by our client
SDT.Life.LifeCO.clsSystemCreator.CreateSysObjects(gidNumber);
this.lobjSys = SDT.Life.LifeCO.clsSystemCreator.GetSysObject(gidNumber);
// Rtrieve the ArrayList from the client's code
clsTextList comboList= this.lobjSys.lstPaymentType_PaymentQueue;
// Get the length of the returned list
int cnt= (int)comboList.Count();
// Create the List<string> which will be populated and returned
List<string> theList= new List<string>();
// Copy each element from the clsTextList to the List<string>
for (int i = 0; i < cnt;i++)
{
string status= comboList.Item(i).Description;
theList.Add(status);
}
// return the newly populated List<string>
return theList;
}//end function getPaymentTypeCombo
Not sure that you can return an ArrayList. I guess you should think about returning an IEnumerable instead which will make the service recognize the method as a Read method.
If you have a List or ObservableCollection and wish to bind it to an ItemControl like ComboBox, you can set the ItemsSource on your ItemControl. Use the DisplayPath property on the ItemControl to set the property you wish to display or use a DataTemplate.
<ComboBox>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text={"Binding Path=Property1"}/>
<TextBlock Text={"Binding Path=Property2"}/>
<TextBlock Text={"Binding Path=Property3"}/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>

Resources