Flex and OOP customs for simple getters and setters - apache-flex

I am having a little play with Flex and I'm curious as to a few things.
Firstly for my instance variables I can define something like
private var _count:int = 0;
It then seems that If I have a getter and setter for count e.g
public function get count():int
{
return _count;
}
public function set count(value:int):void
{
_count = count;
}
I can from within another function call something like
count++;
which in turn sets _count to increase by one.
I.E I can seemingly access count through count or _count because I have a getter and setter..
That is correct understanding?
For something like the above is good OOP practice to have the getter and setter or simply call _count++;
Thanks

I will point out that your set count method changes the variable _points. If that is a typo, then:
Yes; that is a correct understanding. It sounds like your tests already proved that.
The private var _count will not be accessible by other classes with a reference to an instance of your class; but the public 'count' will be.
Getter and Setters are useful for performing other functionality within the class. In the context of a Flex UI Component, you may dispatch an event, or invalidate the component through one of the Flex component invalidation methods.
Separating out the get and set methods also allow you to create properties that are read only, or properties that are write only, just by leaving out the respective get or set method.
IF that is not a typo; then I have no idea why count++ would change the _count variable at all; and something else is going on with the count that you haven't shown us.

Related

Data binding across multiple objects in Flex 3

I am new to Flex (got assigned to maintain an old project at work) and am having some trouble getting data binding to work correctly. I have a popup form class, AddOffer.mxml which uses a model AddOfferModel.as. On my popup form, I have the following component:
<mx:FormItem label="{getResource('addOffer.form.OFFER_DATE')}:"
labelWidth="90">
<views:OfferWindowDatesFragment
id="offerWindowField"
start="{model.offerStartDate}"
stop="{model.offerStopDate}" />
</mx:FormItem>
My AddForm.mxml file also has some embedded actionscript where I define my 'model' variable:
[Bindable]
public var model:AddOfferModel;
The model variables I am trying to bind to are standard getters/setters and look like this inside AddOfferModel.as:
[Bindable]
public function set offerStartDate(val:EditableInstant):void
{
_offerStartDate = val;
}
public function get offerStartDate():EditableInstant
{
return _offerStartDate;
}
private var _offerStartDate:EditableInstant;
[Bindable]
public function set offerStopDate(val:EditableInstant):void
{
_offerStopDate = val;
}
public function get offerStopDate():EditableInstant
{
return _offerStopDate;
}
private var _offerStopDate:EditableInstant;
Inside the OfferWindowDatesFragment component class, the start and stop variables look like this:
[Bindable]
public function set start(val:EditableInstant):void
{
_start = val;
}
public function get start():EditableInstant
{
return _start;
}
private var _start:EditableInstant;
[Bindable]
public function set stop(val:EditableInstant):void
{
_stop = val;
}
public function get stop():EditableInstant
{
return _stop;
}
private var _stop:EditableInstant;
Basically, I just want to bind the start and stop variables in my OfferWindowDatesFragment class to the offerStartDate and offerStopDate variables in the AddOfferModel.as file. Whenever I access the start/stop variables in functions inside the OfferWindowDatesFragment class, they are null.
I have an event listener function that gets triggered in OfferWindowDatesFragment anytime a user selects a new date, it looks like this:
private function changeOfferDate():void
{
start.currentValue = offerDateEditor.start;
stop.currentValue = offerDateEditor.stop;
}
Every time I reach this function, it throws up an error because 'start' and 'stop' are both null ... but should have been initialized and bound already. If I look at the variables in the debugger, I can confirm that values on the right side of the assignment expression are valid, and not what is causing the error.
I am not real familiar with how initialization works in Flex, and I assumed as long as I instantiated the component as seen in the first code snippet at the top of my post, it would initialize all the class variables, and setup the bindings. Am I missing something? Perhaps I am not properly initializing the model or class data for AddForm.mxml or AddFormModel.as, thereby binding null references to the start/stop fields in my OfferWindowDatesFragment class?
Any help would be greatly appreciated. Thanks!
EDIT:
I looked into this further and tried using Mate to inject the 'model' variable inside AddOffer.mxml with a valid AddOfferModel object:
<Injectors target="{AddOffer}" debug="{debug}">
<ObjectBuilder generator="{AddOfferModel}" constructorArguments="{scope.dispatcher}" cache="local"/>
<PropertyInjector targetKey="model" source="{lastReturn}" />
</Injectors>
I load the AddOffer.mxml dialog as the result of a button click event on another form. The function that pops it up looks like this:
public function addOffer():void
{
var addOfferDialog:AddOffer = new AddOffer();
addOfferDialog.addEventListener("addOffer", addOfferFromDialog);
modalUtil.popup(addOfferDialog);
}
It doesn't seem to be assigning anything to the 'model' variable in AddOffer.mxml. Does loading a view/dialog this way not trigger an injection from Mate by chance? (I realize this last part might belong in the Mate forums, but I'm hoping somebody here might have some insight on all of this).
In AddOffer.mxml, you have this code:
[Bindable]
public var model:AddOfferModel;
Is there something outside AddOffer.mxml that is setting this to a valid AddOfferModel? There should be. The nature of how the Flex component life cycle means that you can expect that things may be null at times as a View builds. So you should build your components to be able to "right themselves" after receiving bad data, if the data eventually comes good.
Data binding is one way to do this, but it may not paper over everything depending on what else is going on.
Have you verified that the model value you're getting is not null at the point where the user selects the date and that its offerStartDate and offerEndDate properties have been populated with valid EditableInstants? If both of those are correct, I'd start looking for pieces of the Views that expect to have stuff at a given instant and then don't recover if it is provided later.

Listen to bindable property in bindable Arraycollection

I've got a bindable model class (lets call it myModel) with two properties, label and value. The value gets updated frequently, so it is marked as bindable.
Works fine so far, the data is updated and the standard property change event is dispatched.
Now I have to make an ArrayCollection from the object instances of this model to use it as a data provider in a data group. The data gets then passed to a custom itemRenderer in which I access the myModel properties via data.label and data.value.
The only problem I've got now is that the myModel value property doesn't change any more (I suppose because I stored the objects in the ArrayCollection).
The ArrayCollection is marked bindable as well btw, because new object instances of myModel can be added during runtime.
Is there any way to make this work? Any help regarding this would be much appreciated!
Edit: I almost forgot, the value object in the myModel class is updated by another bindable class. Yes, I know that's bonkers but that's why I'm here, to get some input on a simpler (and in fact working) way to solve this problem.
2nd edit: Allright guys, a little bit of code to illustrate the issue;
Lets start with the first bindable class;
[Bindable]
public class FirstClass
{
public var name:String;
public var firstValue:Number;
public var secondValue:Number;
public var thirdValue:Number;
public function FirstClass()
{ }
}
The values (first to third) get updated by a controller class. So far so good.
Now to the second model class (for matters of consistency, lets keep the MyClass name)
[Bindable]
public class MyClass
{
public var label:String;
public var value:Number;
public function FirstClass()
{ }
}
These are the two model classes. Background behind this is that I need a String value (a label) for each property of an instance of FirstClass. I'd like to make this simpler, so I'm really not settled on this "solution" cough ;).
Anyhow, we've got the two models, now to my .mxml class;
[Bindable] private var firstClassInstance:FirstClass;
I create a new ArrayCollection and add objects like this;
myArrayCollection.addItem(new MyClass("This is a label", firstClassInstance.firstValue));
And again, the DataGroup uses this ArrayCollection as a data provider.
As we already established (thank you #Windowns), the ArrayCollection looks only for objects being added or removed, not property changes of these objects.
Call itemUpdated on your ArrayCollection when you update a "piece" of an item stored in it.
There could be many issues with binding. Please post code to help us see what is happening. Here are some "high level" things to watch out for that might answer your question
When using an bindable arraycollection of objects, it's important to note that the binding for the arraycollection only looks at each object instance and if it's added or removed from the collection. It will not know about any property changes that occur to your object. Commonly when you use an itemrenderer, the properties are bound to display elements. Like maybe the "value" property bound to a label in the itemrenderer. Now when your object instance (myModel) changes it's "value" property the label should pick it up. Also note that you need to mark any properties you intend to bind to visual elements with the [Bindable] meta-tag.
public class myModel
{
[Bindable]
public var label:String;
[Bindable]
public var value:String;
public function myModel() {}
}
Answer after code post:
When you do the following:
myArrayCollection.addItem(new MyClass("This is a label", firstClassInstance.firstValue));
You are taking the value of firstClassInstance.firstValue and supplying it as a hard value (as in not passing value by reference). So if you do the following:
myArrayCollection.getItemAt(addedClassIndex).value = 5;
Will not cause any changes to be noted in the firstClassInstance.firstValue as there is no "referening information" stored. We are only working with the basic type of Number which is never passed by reference like all other objects are in Flex.
Maybe try this:
[Bindable]
public class MyClass
{
public var label:String;
[Bindable] //might be redundant due to global [Bindable] flag, been a while since i've used a global one
public function get value():Number{
return m_objRef.firstValue;
}
public function set value(value:Number):void{
m_objRef.firstValue = value;
}
private var m_objRef:FirstClass;
public function MyClass(_label:String, _valueObj:FirstClass) {
m_objRef = _valueObj;
label = _label;
}
}
Allright guys (and gals ;)) after two hours of messing around with BindingUtils, I finally found the solution to my problem.
The two model classes can remain the way they are, so passing the instance of FirstClass isn't necessary.
Simply binding the value properties of FirstClass to the value field of MyClass works as expected and the values in the ArrayCollection get updated as well.
So the solution;
myClassObject = new MyClass();
myClassObject.label = "This is a label";
BindingUtils.bindProperty(myClassObject, "value", firstClassObject, "firstValue");
And then simply add the myClassObject to the ArrayCollection.
Keep in mind that all the code here is pseudo code, so never mind any typos.
Still, #Windowns suggesting with passing the FirstClass object to the MyClass will be incorporated into my final solution as it makes switching between properties a lot easier (FirstClass has got lots of them, not just the 4 in my first post). Many thanks for that!
I took Amy's advice and researched a little further on the itemUpdated method. Turns out, the solution was right there.
See here: http://flex4examples.wordpress.com/2009/08/28/1st/
I applied this methodology (with little variations) to my code and it works quite good. Performance on the iPad2 is good and so is the memory usage of my component.
Let's hope that Amy is fine with this solution as well. Fingers crossed. ;)

{Bindable on function/ methods

Can we put [Bindable] on functions/methods? I know that bindable is used to change the value of the source property to destination property. But not sure if we can use that for methods. Can you guys give me reason why we cannot put/ if we can then what will be the outcome?
Can you guys give me reason why we cannot put/ if we can then what
will be the outcome?
You can use Bindable on get/set properties; which are implemented as methods. Sort of like this:
private var _myValue : Boolean;
[Bindable(event='myValueChanged']
public function get myValue():Boolean{
return _myValue;
}
public function set myValue(value:Boolean):void{
_myValue = value;
dispatchEvent(new Event('myValueChanged'));
}
[Disclaimer I wrote this code in the browser]
The purpose of Binding is to 'magically' link two properties together. So, when the source property changes, the destination property also changes.
How are you expecting to apply this concept to a function?

why and when to use properties

I am very confused with properties in asp.net.
I just don't understand why we use properties and when I should use them. Could anybody elaborate a little on this.
public class Customer
{
private int m_id = -1;
public int ID
{
set
{
m_id = value;
}
}
private string m_name = string.Empty;
public string Name
{
set
{
m_name = value;
}
}
public void DisplayCustomerData()
{
Console.WriteLine("ID: {0}, Name: {1}", m_id, m_name);
}
}
Properties provide the opportunity to protect a field in a class by reading and writing to it through the property. In other languages, this is often accomplished by programs implementing specialized getter and setter methods. C# properties enable this type of protection while also letting you access the property just like it was a field.
Another benefit of properties over fields is that you can change their internal implementation over time. With a public field, the underlying data type must always be the same because calling code depends on the field being the same. However, with a property, you can change the implementation. For example, if a customer has an ID that is originally stored as an int, you might have a requirements change that made you perform a validation to ensure that calling code could never set the ID to a negative value. If it was a field, you would never be able to do this, but a property allows you to make such a change without breaking code. Now, lets see how to use properties.
Taken From CSharp-Station
There are a couple of good reasons for it. The first is that you might need to add validation logic in your setter, or actually calculate the value in the getter.
Another reason is something to do with the IL code generated. If you are working on a large project that is spread over multiple assemblies then you can change the code behind your property without the application that uses your assembly having to recompile. This is because the "access point" of the property stays the same while allowing the implementation code behind it to be altered. I first read about this when I was looking into the point of automatic properties as I didnt see the point between those and a normal public variable.
It's easy.
All fields in class MUST be private (or protected). To show fields to another class yyou can use properties or get/set methods. Properties a shorter.
P.S. Don't declare write-only properties. It is worst practices.
Properties are a convenient way to encapsulate your classes' data.
Quoting from MSDN:
A property is a member that provides a flexible mechanism to read,
write, or compute the value of a private field. Properties can be used
as if they are public data members, but they are actually special
methods called accessors. This enables data to be accessed easily and
still helps promote the safety and flexibility of methods.
Let's consider two common scenarios:
1) You want to expose the Name property without making it changeable from outside the class:
private string m_name = string.Empty;
public string Name
{
get
{
return m_name;
}
}
2) You want to perform some checks, or run some code every time the data is accessed or set:
private string m_name = string.Empty;
public string Name
{
get
{
return m_name;
}
set
{
m_name = (String.IsNullOrEmpty(value)) ? "DefaultName" : value;
}
}
see:
http://msdn.microsoft.com/en-us/library/x9fsa0sw.aspx
The most important reason is for validation purpose in setter and manipulation part can be implemented in get part.
For Ex.
Storing weekdays, which should be from 1-7, if we take normal variable and declare it as public, anyone can assign any value.
But in Properties setter you can control and validate.
The next one you can use it for tracking. That means, you can know how many times set and get functions has been called by clients (statistical purpose, may be not useful frequently).
Finally, you can control read only, write only and read/write for the properties according to your requirements.

Flex: Which way should I add this event handler?

I use a unit of work pattern a lot in my flex projects. I'll have a class that might call a web service, put the data in a sqlite db, refresh a model with the data then raise an event.
I usually call these inline and pass in some singleton classes:
protected function CareerSynced():void
{
var process:ProcessWorkouts = new ProcessWorkouts(_dataModel, _trainerModel, _databaseCache, _database.Conn);
process.addEventListener("AllWorkoutsProcessed", AllWorkoutsProcessed);
process.UpdateAllUnprocessed();
}
I'll then get the response like this:
private function AllWorkoutsProcessed(event:DataReceivedEvent):void
{
//do something here
}
My question is, am I adding that event listener correctly? I think I might be causing a memory leak, but I'm not sure. I've also thought about using a weak reference. I'm confused about when to use them. Would this be one of those cases?
Should it be like this?
process.addEventListener("AllWorkoutsProcessed", AllWorkoutsProcessed,false, 0, true);
I would either go with the weak reference or just remove the listener:
private function AllWorkoutsProcessed(event:DataReceivedEvent):void
{
event.target.removeEventListener("AllWorksoutsProcessed",AllWorkoutsProcessed);
}
I could list out my reasons but I'll just point you to this.

Resources