Create simple calculator with Dynamic AX 2012 - axapta

I'm new with Dynamic AX and I want to create a simple calculator with input values and display the result in the form:

Your question is very broad to be answered precisely because there are a lot of strategies to tackle the task, but judging from the screenshot you have provided you have a class which should contain all calculation logic and a form to provide UI to the user with two input fields and one output field which should display operation result.
So the easiest solution would be:
Implement the Kalkulator class which exposes two parm methods to
set up the operands and four methods which execute the
operation and return the result: add, subtract, multiply and divide.
Create a private instance of the Kalkulator class in your form,
initialize it, set up operands when user clicks one of the buttons,
call appropriate method to run the operation and output the result
on the form field.
So supposing that operands are integer values (for demonstrative purpose) your TRN_Kalkulator may look something like this:
class TRN_Kalkulator
{
private int value1;
private int value2;
public int parmValue1(int _value = value1)
{
value1 = _value;
return value1;
}
public int parmValue2(int _value = value2)
{
value2 = _value;
return value2;
}
public int Sum()
{
return value1 + value2;
}
public int Diff()
{
return value1 - value2;
}
public int Mult()
{
return value1 * value2;
}
public int Div()
{
return value2 == 0 ? 0 : value1 / value2;
}
}
In the class declaration on the form you have to declare a private instance of TRN_Kalkulator which will be initialized by overriding the init() method:
TRN_Kalkulator calculator;
//...
public void init()
{
super();
calculator = new TRN_Kalkulator();
}
Finally when one of the buttons is clicked you parse user input by reading the values of the form fields, set up the operands, run the operation and output the result. All of this is done by overriding click() method on each of the buttons:
// read text values of the textboxes and parse them to integer
int a = str2Int(TxtOperand1.text());
int b = str2Int(TxtOperand2.text());
// set up calculator operands
calculator.parmValue1(a);
calculator.parmValue2(b);
// call the operation depending on which button was clicked
int result = calculator.Sum();
// set result textbox text
TxtResult.text(int2Str(result));
Notice that there are a lot of ways to improve this code (like for example using some display and edit methods on the form) and you definitely should do it, but this implementation suits your current setup and should point you in the right direction.

Related

How to get string[] array from database with EF core [duplicate]

How can I store an array of doubles to database using Entity Framework Code-First with no impact on the existing code and architecture design?
I've looked at Data Annotation and Fluent API, I've also considered converting the double array to a string of bytes and store that byte to the database in it own column.
I cannot access the public double[] Data { get; set; } property with Fluent API, the error message I then get is:
The type double[] must be a non-nullable value type in order to use
it as parameter 'T'.
The class where Data is stored is successfully stored in the database, and the relationships to this class. I'm only missing the Data column.
You can do a thing like this :
[NotMapped]
public double[] Data
{
get
{
string[] tab = this.InternalData.Split(',');
return new double[] { double.Parse(tab[0]), double.Parse(tab[1]) };
}
set
{
this.InternalData = string.Format("{0},{1}", value[0], value[1]);
}
}
[EditorBrowsable(EditorBrowsableState.Never)]
public string InternalData { get; set; }
Thank you all for your inputs, due to your help I was able to track down the best way to solve this. Which is:
public string InternalData { get; set; }
public double[] Data
{
get
{
return Array.ConvertAll(InternalData.Split(';'), Double.Parse);
}
set
{
_data = value;
InternalData = String.Join(";", _data.Select(p => p.ToString()).ToArray());
}
}
Thanks to these stackoverflow posts:
String to Doubles array and
Array of Doubles to a String
I know it is a bit expensive, but you could do this
class Primitive
{
public int PrimitiveId { get; set; }
public double Data { get; set; }
[Required]
public Reference ReferenceClass { get; set; }
}
// This is the class that requires an array of doubles
class Reference
{
// Other EF stuff
// EF-acceptable reference to an 'array' of doubles
public virtual List<Primitive> Data { get; set; }
}
This will now map a single entity (here 'Reference') to a 'list' of your Primitive class. This is basically to allow the SQL database to be happy, and allow you to use your list of data appropriately.
This may not suit your needs, but will be a way to make EF happy.
It would be far easier if you use List<double> rather then double[]. You already have a table that stores your Data values. You probably have foreign key from some table to the table where your double values are stored. Create another model that reflects the table where doubles are stored and add foreign key mappings in the mappings class. That way you will not need to add some complex background logic which retrieves or stores values in a class property.
In my opinion almost all other answers work on the opposite of how it should be.
Entity EF should manage the string and the array must be generated from it. So the array must be whole read and written only when the string is accessed by EF.
A solution involving logic on Data[] is wrong because, as I wrote in a comment, you would run into paradoxical conditions. In all other conditions the variable must remain a pure array.
By putting the "get" and "set" logic in Data[], as I've seen so far, this happens:
1 - Every time an index access is made to the array, the array is automatically recreated from the string. This is a useless work, think of an iteration in a loop...
2 - when you go to set a single element it is not stored because it passes through "get" and not "set".
If you try to declare Data=new []{0,0,0} then set Data[1]=2 , going to re-read Data[1] the result is 0.
My solution is to completely turn the logic around.
public string Data_string
{
get => string.Join(';', Data??Array.Empty());
set => Data= value == null ? Array.Empty<double>() : Array.ConvertAll(value.Split(';',StringSplitOptions.RemoveEmptyEntries), double.Parse);
}
[NotMapped]
public double[] Data {get;set;}
Obviously this only applies to storing and retrieving data on databases, access to Data_string is exclusive to EF.
Once the string is read from the DB it is associated to Data_string which, through set, creates the Data array.
At this point you can work on Data without affecting the string in any way, like a normal array.
When you will ask EF to save in the DB, through the get in the Data_string property, the string will be completely reconstructed based on the Data elements and then stored as a string.
Practically the string is modified only twice, at the moment of reading from the DB and at the moment of saving.
In my opinion this solution is much more efficient than operating continuously on the string.
Nathan White has the best answer (got my vote).
Here is a small improvement over Joffrey Kern's answer to allow lists of any length (untested):
[NotMapped]
public IEnumerable<double> Data
{
get
{
var tab = InternalData.Split(',');
return tab.Select(double.Parse).AsEnumerable();
}
set { InternalData = string.Join(",", value); }
}
[EditorBrowsable(EditorBrowsableState.Never)]
public string InternalData { get; set; }
Don't use double[] use List insted.
Like this.
public class MyModel{
...
public List<MyClass> Data { get; set; }
...
}
public class MyClass{
public int Id { get; set; }
public double Value { get; set; }
}
All that solution that I see there are bad, because:
If you create table, you don't want to store data like this: "99.5,89.65,78.5,15.5" that's not valid! Firstly its a string that means if you can type letter into it and at the moment when your ASP.NET server call double.Parse it will result in FormatException and that you really don't want!
It's slower, because your server must parse the string. Why parse the string instead getting almost ready data from SQL Server to use?
i know this post is Ancient, but in case someone still needs to do something like this, PLEASE DO NOT USE THE ABOVE SOLUTIONS,
as the above solutions are EXTREMELY inefficient (Performance and Disk Space wise).., the best way is to store the array as a Byte array
public byte[] ArrayData;
[NotMapped]
public double[] Array {
get {
var OutputArray = new double[ArrayData.Length / 8];
for (int i = 0;i < ArrayData.Length / 8;i++)
OutputArray[i] = BitConverter.ToDouble(ArrayData, i * 8);
return OutputArray;
}
set {
var OutputData = new byte[value.Length * 8];
for (int i = 0;i < value.Length;i++) {
var BinaryValue = BitConverter.GetBytes(value[i]);
OutputData[(i*8)] = BinaryValue[0];
OutputData[(i*8)+1] = BinaryValue[1];
OutputData[(i*8)+2] = BinaryValue[2];
OutputData[(i*8)+3] = BinaryValue[3];
OutputData[(i*8)+4] = BinaryValue[4];
OutputData[(i*8)+5] = BinaryValue[5];
OutputData[(i*8)+6] = BinaryValue[6];
OutputData[(i*8)+7] = BinaryValue[7];
}
ArrayData = OutputData;
}
}
`
And if you need more performance, you can go for Unsafe code and use pointers .. instead of BitConverter ..
This is way better than saving double values (that can get huge) as string, then spliting the string array !! and then parsing the strings to double !!!
These getter/setters work on the whole array, but if you need to get just one item from the array, you can make a function that gets a single item from the array with a complexity of O(1) :
for Get :
public double Array_GetValue(int Index) {
return BitConverter.ToDouble(ArrayData, Index * 8);
}
for Set :
public void Array_SetValue(int Index, double Value) {
var BinaryValue = BitConverter.GetBytes(Value);
ArrayData[(Index*8)] = BinaryValue[0];
ArrayData[(Index*8)+1] = BinaryValue[1];
ArrayData[(Index*8)+2] = BinaryValue[2];
ArrayData[(Index*8)+3] = BinaryValue[3];
ArrayData[(Index*8)+4] = BinaryValue[4];
ArrayData[(Index*8)+5] = BinaryValue[5];
ArrayData[(Index*8)+6] = BinaryValue[6];
ArrayData[(Index*8)+7] = BinaryValue[7];
}
If your collection can be null or empty, and you want this to be preserved, do this:
[NotMapped]
public double[] Data
{
get => InternalData != null ? Array.ConvertAll(Data.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries), double.Parse) : null;
set => InternalData = value != null ? string.Join(";", value) : null;
}
Also, specify [Column(TypeName = "varchar")] on the string property for a more efficient storage data type.
A perfect enhancement to #Jonas's answer will be to add the necessary annotations. So, a cleaner version would be
[EditorBrowsable(EditorBrowsableState.Never)]
[JsonIgnore]
public string InternalData { get; set; }
[NotMapped]
public double[] Data
{
get => Array.ConvertAll(InternalData.Split(';'), double.Parse);
set
{
InternalData = string.Join(";", value.Select(p => p.ToString(CultureInfo.InvariantCulture)).ToArray());
}
}
The [JsonIgnore] Annotation will ignore the InternalData field from JSON serialization and Swagger UI.
[EditorBrowsable(EditorBrowsableState.Never)] will hide the public method from the IDE IntelliSense

Bind repeater list with enum

I have a requirement where when a user clicks on image a list should be shown with checkboxes and all the categories that is present in DB and user should be able to select the checkboxes. How can this be achieved using asp:repeater control? the caegory is a enum type and can have n number of values. In repeater i have added a checkbox and a label; the label should display the category text.
To start with, you should add the [Description] attribute to each value in your Enum. This allows you to set proper descriptive text for each value. This attribute is in System.ComponentModel, here's an example: -
public enum CalendarShowAsEnum
{
[Description("None")]
None = 10,
[Description("Busy")]
Busy = 20,
[Description("Out Of Office")]
OutOfOffice = 30,
[Description("On Holiday")]
OnHoliday = 40
}
You then need 2 functions: -
One function that takes an Enum type and a ListBox/DropDown as parameters, and adds an entry for each Enum into the list
A helper function that converts the enum into the descriptive title you gave them (example above)
The List function might look as follows (all this is taken from a project I worked on): -
public static void BindNamedEnumList(ListControl list,
Type enumerationType)
{
list.Items.Clear();
Array array = Enum.GetValues(enumerationType);
ListItem item;
string name;
var enumerator = array.GetEnumerator();
if (enumerator != null)
{
while (enumerator.MoveNext())
{
Enum value = enumerator.Current as Enum;
name = EnumHelper.GetEnumName(value);
item = new ListItem(name);
item.Value = Convert.ToInt32(value).ToString();
list.Items.Add(item);
}
}
}
This function takes a Type and a ListControl (which ListBox and DropDownList both inherit from). The Type is the .GetType() of the enum you want to add to the list. Note that it doesn't select any values and that it does depend on each enum value having a defined integer value. The latter part will help you with selecting individual items.
Note the loop calls EnumHelper.GetEnumName(value) - this is the helper function that uses the Description attribute I mentioned at the start. This function looks like: -
public static string GetEnumName(object value)
{
string retVal = string.Empty;
try
{
FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
retVal = ((attributes.Length != 0) ? attributes[0].Description : value.ToString());
}
catch (System.NullReferenceException)
{
}
finally
{
if (string.IsNullOrEmpty(retVal))
{
retVal = "Unknown";
}
}
return retVal;
}
It uses reflection, so you'll need to add an Imports for System.Reflection
To use the list function to bind a set of Enum values to the list, simply call
{HelperClass}.BindNamedEnumList(myListBox, typeof({MyEnumType})

Implement "Navigation bar" for custom editor

When registering a custom language service extension, Visual Studio creates a new options entry for the language within the Text Editor node (in the Visual Studio options dialog). Beneath that node two default nodes are created named General and Tabs, whereby the General tab contains statement completion and display settings...
In the Dispay group there are three options; one of them is the Navigation Bar checkbox (which shows/hides the editor´s navigation bar). For my custom language service, this option is disabled. Of course, it´s not implemented yet.
I would like to know, what I have to do, to provide a navigation bar for my custom editor... I guess that there is a certain interface I have to implement in the editor´s factory, or the language service package must export a certain MEF component, or, or, ...
Jon Senchyna´s answer guided me into the right direction. The OnSynchronizeDropdowns method gets never called (the SDK documentation is just wrong in that case). What did the final trick was to override at least GetComboAttributes, GetEntryAttributes and GetEntryText to get text-only items for both combo boxes...
[ComVisible(true)]
public sealed class CustomTypeAndMemberDropdownBars : TypeAndMemberDropdownBars
{
private readonly IList<string> declarations;
private readonly IList<string> members;
public CustomTypeAndMemberDropdownBars(
LanguageService languageService,
IVsTextView view)
: base(languageService)
{
// TODO: initialize declarations and members from the given text view...
this.declarations = ...
this.members = ...
}
private enum ComboIndex
{
Types = 0,
Members = 1
}
public override int GetComboAttributes(
int combo,
out uint entries,
out uint entryType,
out IntPtr imageList)
{
entries = 0;
imageList = IntPtr.Zero;
entryType = (uint)DROPDOWNENTRYTYPE.ENTRY_TEXT;
var comboType = (ComboIndex)combo;
switch (comboType)
{
case ComboIndex.Types:
entries = (uint)this.declarations.Count();
break;
case ComboIndex.Members:
entries = (uint)this.members.Count();
break;
}
return VSConstants.S_OK;
}
public override int GetEntryAttributes(
int combo,
int entry,
out uint fontAttrs)
{
fontAttrs = (uint)DROPDOWNFONTATTR.FONTATTR_PLAIN;
return VSConstants.S_OK;
}
public override int GetEntryText(
int combo,
int entry,
out string text)
{
text = null;
var comboType = (ComboIndex)combo;
switch (comboType)
{
case ComboIndex.Types:
text = this.declarations[entry];
break;
case ComboIndex.Members:
text = this.members[entry];
break;
}
return VSConstants.S_OK;
}
public override bool OnSynchronizeDropdowns(
LanguageService languageService,
IVsTextView textView,
int line,
int col,
ArrayList dropDownTypes,
ArrayList dropDownMembers,
ref int selectedType,
ref int selectedMember)
{
return false;
}
}
I believe the following steps should be what you need:
In your Package class, set the ShowDropDownOptions property to true in the ProvideLanguageService attribute
Create a class that implements TypeAndMemberDropdownBars
In your LanguageService class, implement the CreateDropDownHelper function and have it return an instance of your TypeAndMemberDropdownBars

Calculated value passed as parameter to data model not showing on tableview

I have a form that has 4 TextFields which I'm trying to track with an ObservableList that has 5 columns. The TableView has an extra column to hold a calculated value (the 5th column in my ObservableList).
The data is dumping fine from the 4 TextFields, but the calculated column comes out blank. I assume this is a problem with my getters and setters, because the value is calculated before I pass it to my data model, AND I just tested the data model, and it is GETTING the value (passed as a parameter).
To not put extraneous code here, I think these are the relevant parts:
// This is (part of) my data model
public static class ItemSale {
private ItemSale (Double barC, String itemm, Double pricee,
Integer quant, Double totsP) {
this.barCode = new SimpleDoubleProperty(barC);
this.item = new SimpleStringProperty(itemm);
this.price = new SimpleDoubleProperty(pricee);
this.quantity = new SimpleIntegerProperty(quant);
this.rowPrice = new SimpleDoubleProperty(totsP);
System.out.println(totsP); // this (also) prints the correct value to the screen
// price * quantity = rowPrice, the calculated value that doesn't show up later
// getter & setter for quantity (works, is a textfield in my form)
public SimpleIntegerProperty getQuantity() {
return quantity;
}
public void setQuantity(Integer quant) {
quantity.set(quant);
}
// getter & setter for rowPrice (doesn't work, is calculated, see below)
public SimpleDoubleProperty getRowPrice(Double totsP) {
return rowPrice;
}
public void setRowPrice(Double totsP) {
rowPrice.set(totsP);
}
// in the Add button action handler, I have this:
Double rowPP;
rowPP = qua * pr; //qua = variable for quantity, pr = variable for price
System.out.println(rowPP); //prints to screen fine
data.add(new ItemSale(
bcode,
item.getText(),
pr,
qua,
rowPP
));
Ooops...got it figured out. I was researching another problem and found the answer on JavaFx - How to display SimpleStringProperty value in TableView and, in going through my code, I noticed I had the getter with parameters. Removed the parameters and BOOM! it worked.

flex: referencing class variables

I have a bunch of variables in a class. There are situations when I want to set then to null/ "temp" etc as per a well defined logic. The challenge is to list out the variables at multiple places- tedious and error-prone.
classname.speed=NaN
classname.speedtype="not_set"
classname.distance=NaN
classname.distancetype="not_set"
Ideally, would prefer a way to refer to these variables programatically and set something like
"for all class variables- if variable ends in type, set as "not_set"; for other variables set as NaN
How can I achieve this? Any pointers will help
The simplest approach would be just write function to clear them all.
If you want something more automatic, it will requre efforts - look at introspection api. Basically, you call describeType on your class and it returns XML description. All variables will be listed there, along with other info. Then you can parse returned XML and set all variables to needed value, accessing them dynamically with square bracket syntax:
var myClass:MyClass = new MyClass();
myClass["varName"] = "new value";
It can be achieved through Inheritance i.e. implementing interface or extending class
which contains common fields
public class MyClass
{
public a:String = null;
public b:String = null;
public function MyClass()
{
}
}
which contains common var and Child Class could be
public class MyClassChild extends MyClass
{
public var c:String = null;
public function MyClassChild()
{
super();
this.a ="";
this.b ="";
}
}
and you can cast or use for each loop to set values
var temp:MyClassChild = new MyClassChild ();
MyClass(temp).a = "Hello World";
Hopes that helps

Resources