I am building a simple journal form based on the form pattern DetailsTransaction. In this pattern it has the standard two view layout, the header/*journalTable grid and a lines/*journalTrans grid.
However, when I click the New button two create a new header/journal, it automatically invokes the taskSwitchToDetailsView task and switches to the lines. I wish to block this from happening, but I am unsure on how to do it. Is there a way to block this task from being invoked?
Have you experimented with the viewEditModeHelper() and other form event handlers?
I don't have an environment in front of me now, but here's a little snip that might give you an idea where to look. I know it's not exactly what you're looking for but the same style is what I would think.
[FormEventHandler(formStr(LogisticsPostalAddress), FormEventType::Initialized)]
public static void MyForm_OnInitialized(xFormRun sender, FormEventArgs e)
{
// Subscribe event handlers
FormRun formRun = sender as FormRun;
formRun.viewEditModeHelper().EditModeSwitched += eventhandler(MyEventHandler.ViewEditModeSwitched);
}
There is a lot of complexity around the OOTB journals, and if I needed a robust journal implementation I would have created classes that derived from JournalFormController and JournalFormTable/JournalFormTrans which provide number sequence generation, blocking/locking, validation, and much more very useful and powerful functionality to a journal form + table structure.
However, I don't need any of that. So to solve my specific problem I added this to the create method of the *journalTable datasource's create method (which the super call changes the context of the form to the lines by calling task(#taskSwitchToDetailsView). To counter this, I simply call task(#taskSwitchToGridView) immediately after the super.
[DataSource]
class CustomJournalTable
{
public void create(boolean _append = false)
{
#Task
super(_append);
element.task(#taskSwitchToGridView);
}
}
Related
I'm trying to create an EventHandler for the mouse dragged event. I'll use this same handler to do the same thing with several ImageViews. Now this is what I did.
static EventHandler<MouseEvent> dragHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
e.getSource().toFront();
e.getSource().setTranslateX(e.getSceneX() );
e.getSource().setTranslateY(e.getSceneY() );
}
};
But apparently I can't use toFront or setTranslate methods or anything that I used for ImageViews because e.getSource returns an Object and these are ImageView methods that are not available to Object type. And apparently I can't simply cast that into an ImageView either by doing
(ImageView)( e.getSource() ).toFront();
I could simply use inner classes and lambda expressions but I thought there must be a more efficient way than just copy pasting the same lines like 15 times for each ImageView. So please enlighten me if there is.
Thanks in advance.
Casting would work, but the precedence of casting is below that of dereferencing (.), so your code example tries to downcast the result of (e.getSource()).toFront(), which doesn't work (as that has no type, since toFront() is void).
So
((ImageView) e.getSource() ).toFront();
would work.
However, it's usually better to register a different handler for each image view. There's no need to repeat code: just use any standard programming technique to avoid doing so. E.g. you can write a method:
private void registerEventHandler(ImageView imageView) {
imageView.setOnMouseDragged(e -> {
imageView.toFront();
imageView.setTranslateX(e.getSceneX() );
imageView.setTranslateY(e.getSceneY() );
});
// register other event handlers, as needed.
}
and then call the method for each image view (in a loop, if you have them in some suitable data structure).
Alternatively, you could create a method that creates the image views and registers any necessary handlers.
As well as being arguably cleaner code, these techniques also avoid the downcast, which in general is a good thing.
We are evaluating Grid Gain 6.5.5 at the moment as a potential solution for distribution of compute jobs over a grid.
The problem we are facing at the moment is a lack of a suitable asynchronous notification mechanism that will notify the sender asynchronously upon job completion (or future completion).
The prototype architecture is relatively simple and the core issue is presented in the pseudo code below (the full code cannot be published due to an NDA). *** Important - the code represents only the "problem", the possible solution in question is described in the text at the bottom together with the question.
//will be used as an entry point to the grid for each client that will submit jobs to the grid
public class GridClient{
//client node for submission that will be reused
private static Grid gNode = GridGain.start("config xml file goes here");
//provides the functionality of submitting multiple jobs to the grid for calculation
public int sendJobs2Grid(GridJob[] jobs){
Collection<GridCallable<GridJobOutput>> calls = new ArrayList<>();
for (final GridJob job : jobs) {
calls.add(new GridCallable<GridJobOutput>() {
#Override public GridJobOutput call() throws Exception {
GridJobOutput result = job.process();
return result;
}
});
}
GridFuture<Collection<GridJobOutput>> fut = this.gNode.compute().call(calls);
fut.listenAsync(new GridInClosure<GridFuture<Collection<GridJobOutput>>>(){
#Override public void apply(GridFuture<Collection<GridJobOutput>> jobsOutputCollection) {
Collection<GridJobOutput> jobsOutput;
try {
jobsOutput = jobsOutputCollection.get();
for(GridJobOutput currResult: jobsOutput){
//do something with the current job output BUT CANNOT call jobFinished(GridJobOutput out) method
//of sendJobs2Grid class here
}
} catch (GridException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
return calls.size();
}
//This function should be invoked asynchronously when the GridFuture is
//will invoke some processing/aggregation of the result for each submitted job
public void jobFinished(GridJobOutput out) {}
}
}
//represents a job type that is to be submitted to the grid
public class GridJob{
public GridJobOutput process(){}
}
Description:
The idea is that a GridClient instance will be used to in order to submit a list/array of jobs to the grid, notify the sender how many jobs were submitted and when the jobs are finished (asynchronously) is will perform some processing of the results. For the results processing part the "GridClient.jobFinished(GridJobOutput out)" method should be invoked.
Now getting to question at hand, we are aware of the GridInClosure interface that can be used with "GridFuture.listenAsync(GridInClosure> lsnr)"
in order to register a future listener.
The problem (if my understanding is correct) is that it is a good and pretty straightforward solution in case the result of the future is to be "processed" by code that is within the scope of the given GridInClosure. In our case we need to use the "GridClient.jobFinished(GridJobOutput out)" which is out of the scope.
Due to the fact that GridInClosure has a single argument R and it has to be of the same type as of GridFuture result it seems impossible to use this approach in a straightforward manner.
If I got it right till now then in order to use "GridFuture.listenAsync(..)" aproach the following has to be done:
GridClient will have to implement an interface granting access to the "jobFinished(..)" method let's name it GridJobFinishedListener.
GridJob will have to be "wrapped" in new class in order to have an additional property of GridJobFinishedListener type.
GridJobOutput will have to be "wrapped" in new class in order to have an addtional property of GridJobFinishedListener type.
When the GridJob will be done in addition to the "standard" result GridJobOutput will contain the corresponding GridJobFinishedListener reference.
Given the above modifications now GridInClosure can be used now and in the apply(GridJobOutput) method it will be possible to call the GridClient.jobFinished(GridJobOutput out) method through the GridJobFinishedListener interface.
So if till now I got it all right it seems a bit clumsy work around so I hope I have missed something and there is a much better way to handle this relatively simple case of asynchronous call back.
Looking forward to any helpful feedback, thanks a lot in advance.
Your code looks correct and I don't see any problems in calling jobFinished method from the future listener closure. You declared it as an anonymous class which always has a reference to the external class (GridClient in your case), therefore you have access to all variables and methods of GridClient instance.
Sometimes, when I need to do more complicated stuff than change one value in datasource, I would like some method on caller. For example I have a form A with overview. Form A has method setName() (I define). I open a related detail (form B). I change something and I want to call setName on caller.
Nowdays I am doing it in following way
element.args().caller().setName();
but I am looking for more idiomatic way. So what is proper way of calling method on caller in AX 2012 R3?
It sounds like you need to change your development methodology if you referencing that many caller-form methods. You would mostly do that for calling doRefresh or calling updateDesign, which are both typically created methods on forms. Beyond updating the design and refeshing, you should use a class form handler.
If you must do a caller-callback, you can validate by doing:
if (formHasMethod(element.args().caller(), identifierstr(updateDesign)))
{
element.args().caller().updateDesign();
}
You can pass your class as the caller. Here is a simple sample set of code:
\Forms\Form1\Designs\Design\[Group:Group]\Button:Button\Methods\clicked:
void clicked()
{
FormRun formRun;
Args args = new Args(formstr(Form2));
TestClass testLocal = new TestClass();
testLocal.parmTestVar('ZZZ');
args.caller(testLocal);
formRun = classfactory.formRunClass(args);
formRun.init();
formRun.run();
formRun.wait(true);
}
\Forms\Form2\Methods\init:
public void init()
{
TestClass testClass;
super();
testClass = element.args().caller() as testClass;
info(strFmt("%1", testClass.parmTestVar()));
}
Look at \Forms\SalesTable and \Classes\SalesTableForm or \Classes\SysCompare\startCompareOfContextProvider and the init method
identifierStr is not depreciated. It's a normal intrinsic function, but you will get a best practice warning if you use the identifierStr function. This is because no existence checking is carried out for identifierStr. Try to use a more specific intrinsic function if one is available. See http://msdn.microsoft.com/en-us/library/aa626893.aspx
You could take a look at Calling methods on a caller form, but identifierStr is deprecated in AX 2012. As far as I know there is no way to check for form methods at compile time.
But I would suggest avoiding methods on forms. Place them in a form handler class instead, you can then use the methodStr function to check for a method.
I'm building some web user controls and just wondering what is the right / best practice approach to implement properties. In this example he control is a "score card" control which has to display a score ( and it also has to do other stuff) ....to make things easier I made these code samples very simple but in reality my control does other stuff as well with the score besides displaying it in a label :-)
Choice #1
private int _score;
public int Score
{
get { return _score; }
set { _score = value; Refresh(); }
}
public void Refresh()
{
lblScore.Text = Score;
}
Choice #2:
public int Score {get;set;}
protected void PageLoad(object sender, EventArgs e)
{
Refresh();
}
private void Refresh()
{
lblScore.Text = Score;
}
Choice #3:
public int Score
{
get { lblScore.Text; }
set { lblScore.Text = value; }
}
So , of course, the question is what is the best practice way of implementing the Score property of the control ....:-)
MadSeb
Choice 1
Choice 2 is out of this because you should not link initialization and functionality to specific page events in a UserControl. That is a source for nasty errors related to Page-Lifecycle. You might want to make modifications after Page_Load(f.e. in a Button's Click-Event in the page) but it's too late for the implicit Refresh.
Choice 3 is out because for simply setting the Text of a Label you don't want somebody to remember that he has to call Refresh after he has set the Score. But that depends on how expensive "my control does other stuff as well with the score besides displaying it in a label" is. If you often change the Score but not necessarily need to refresh immediately, i would do the Refresh after all initialization has done.
In my opinion a UserControl should encapsulate complexity as long as it keeps enough flexibility and control to be reusable. Don't do too much "magic" things in the background that might cause errors in different conditions that you won't find quickly. That is particularly so in a Setter what normally only should set the corresponding variable.
There are two different use cases for an UserControl:
Reusability.
If your control contains only few controls but you want to reuse it many times, i would let the controller get/set properties and don't do complex things in it that depend on specific conditions. That would reduce reusability. You might want to provide clear methods and events that the controller could handle.
Container.
If your control behaves similar to a page and has a lot of controls and functionality, it should do most of all by itself. You only want to provide a few methods and events(that don't have to be handled necessarily). The most important method in this case would be e.g. a public void BindData() that does all initialization after the controller has set the necessary variables. That is the replacement for your Choice 2.
Note: if your score is stored in lblScore.Text as string anyway, i would prefer using the Text property of the label instead of creating another int-variable(cast it to an int in the getter). That has the advantages that you don't need to store your variable in ViewState manually, because it's already stored. On this way you don't need to set it on every postback.
I'm working on a CRUD site with a lot of very similar forms for adding new data. In other words:
AddMovie.aspx, AddGame.aspx, AddBeer.aspx, AddAdd.aspx
I keep thinking to myself, "Self, it would be really nice to have a single Add.aspx instead of re-writing so many similar pages - plus all those OOP nerds would think I'm cool since I'm re-using instead of copy/pasting!"
So assuming I'm on the right track, if I were to go with the single Add.aspx page, how could I represent all sets of fields for each object? I thought about a bunch of panels or divs that I could hide/show, but not sure I really like that solution. Is there a better way to do it or should I just give up and go back to the multiple bad ol' AddObject.aspx pages?
Also, this is a plain ol' (3.5) web forms app. No ASP.NET MVC goodness for this one, sadly. It seems like there should be such a trivial solution and that I'm just over-thinking things, but I can't come up with one and so I turn to Stack Overflow. :)
Maybe you should look at ASP.NET dynamic data or the subsonic project. Both allow to build CRUD-type website very fast because they support "scaffolding" (the edit pages are generated automatically based on your database model).
A better way would perhaps be to have a single page called Add.aspx and then based on the querystring you send it (i.e. Add.asps?type=game) you could customize the form and the logic for the particular type of object your are trying to work with.
Another option is to subclass Page, and then make your pages inherit from it, so you've got one place with all common functionality.
For example:
public abstract class BasePage<T> : System.Web.UI.Page
{
protected T GetObjectById(int objectId)
{
// return new T();
}
protected void SaveObject(T obj)
{
// Save object to DB here
}
protected void DeleteObjectById(int objectId)
{
// Delete object
}
protected abstract void PopulateUI(T obj);
protected override void OnLoad(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
int objectId = Convert.ToInt32(Request.QueryString.Get("id"));
T obj = GetObjectById(objectId);
PopulateUI(obj);
}
}
}
Your pages would then inherit from this:
public class AddGame : BasePage<Game>
{
protected override void PopulateUI(Game game)
{
// Populate the UI with game information
GameNameTextBox.Text = game.Name;
PublisherNameTextBox.Text = game.Publisher.Name;
// etc
}
}
This should make creating the pages much quicker and easier, and gives you a bit more control over how data is retrieved and saved.