Xamarin.Forms seems to be offering an alternative approach called "behaviors" to subclassing controls. Why was this ever required in the first place? What is the advantage and when should we use it instead of subclassing?
One possible reason I am thimking might be that subclassed controls cannot use the styles targeted for their parent controls. But I don't understand the reason of that restriction either.
You can check Xamaron.Forms Behavior documentation, https://developer.xamarin.com/guides/xamarin-forms/behaviors/
Note: I am not exactly sure, I understand what you mean here.
One possible reason I am thinking might be that subclassed controls cannot use the styles targeted for their parent controls. But I don't understand the reason of that restriction either.
But, I will try to provide an answer to questions mentioned in this paragraph.
Xamarin.Forms seems to be offering an alternative approach called "behaviors" to subclassing controls. Why was this ever required in the first place? What is the advantage and when should we use it instead of subclassing?
As mentioned in the documentation, behaviors allow you to extend functionalities for controls without having to derive them. I guess it would make more sense to implement a behavior, rather then subclass a control, in following cases:
If functionality can be shared across multiple control types
Simplest example would be implementing max-length/regex/min-length validation for controls that support input such as Entry, Editor etc.
<Entry>
<Entry.Behaviors>
<local:TextBehaviour MaxLength="25" MinLength="2" RegexPattern="[ae]" />
</Entry.Behaviors>
</Entry>
<Editor>
<Editor.Behaviors>
<local:TextBehaviour MaxLength="250" MinLength="2" />
</Editor.Behaviors>
</Editor>
If functionality needs to be extended for controls used in an existing code-base
For example, we can extend, and attach behaviors to various controls using implicit styles and attached properties without having to update each control usage in code.
<Style TargetType="Label">
<Setter Property="local:ShadowEffect.HasShadow" Value="True" />
</Style>
<Style TargetType="Entry">
<Setter Property="local:Validation.MaxLength" Value="35" />
</Style>
<Style TargetType="Editor">
<Setter Property="local:Validation.MaxLength" Value="250" />
</Style>
These are the scenarios I can think of at this point. I will add more, if I come across any more.
It's a concept coming from WPF, you can read more about it on this great tutorial page.
The ideas behind behaviors are to give the interaction designer more flexibility to design complex user interactions without writing any code.
Example of a behaviors are drag&drop, input validation, pan and zoom,
re-position of elements, etc... The list of possible behaviors is very
long.
Imaging an application that has a list of customers and the user can
add some of them to subscriber lists. This interaction can be designed
by providing an "Add" button next to each subscriber list. But if the
interaction designer wants to add drag&drop functionality, he needs to
discuss it with the developer and wait until the implementation is
done. With behaviors he just drags a drag and drop behavior on each
list and we are done.
So in a company, it allows a better workflow between designers and developers.
Another reason, in addition to the already mentioned, could be the possibility of switching behaviours during runtime.
Related
I have been using Flex / Flash Builder for a number of years. The latest release of Flash Builder (4.7) seems to come with quite a few problems, the biggest of those being:
Does not detect component IDs in MXML. For example, you cannot Find Usages of the ID of a component. Keeping the cursor on the ID of a component does not even mark occurrences of the ID. Instead, it marks occurrences of the actual id words in the MXML.
Extremely slow.
I am seriously evaluating moving over to IntelliJ IDEA 12, especially after reading many experienced Flex devs raving about it and recommending it.
I tried it. It took me a while to get to terms with the new terminologies of the IDE (made easy by this doc and very helpful support personnel at JetBrains).
I was able to setup my (large) projects in IDEA with Adobe Flex 4.6 SDK and got it to compile fine. But I noticed many "errors" highlighted in my AS files which are all actually false alarms.
The ActionScript editor doesn't seem to recognise the objects defined in MXML. Apparently, this is a known bug in IDEA (tracked here). And this bug has existed for more than 2 years!
Quoting the JetBrains support personnel:
I must admit that highlighting of ActionScript files which do not contain classes, but instead included in mxml as <fx:Script source="some_file.as"/> is probably the only weak part of IntelliJ IDEA code highlighting. False error highlighting will go away if you embed AS code inside CDATA of <fx:Script/> instead of referencing as external *.as file. Though I understand that this is not always desired.
I'm afraid the fix won't go into 12 release because the release is very soon and the fix is too risky. Priority of the issue depends on votes and user feedback. So far we have only 2 votes (http://youtrack.jetbrains.com/issue/IDEA-52598) and as the fix is pretty complex we still haven't implemented it thinking that this is a rare use case. I hope to fix it in one of 12.x update releases.
My project is a huge one, with huge MXML files and even more huge AS code for each MXML. So, for organisation purposes, I need to logically split them into smaller files. So, merging the AS code with the MXML is not practical. The false error highlighting just drastically reduces the readability of the code. Also, it does not allow Control / Command-clicking component IDs in AS code to quickly navigate to the definition of the component in MXML (which, incidentally, is now broken in FB 4.7 as well, but worked well in FB 4.6).
This bug in IDEA is unfortunately a deal-breaker for me. But I am wondering how other Flex devs are able to overcome / work around this seemingly critical bug.
It seems unbelievable to me that just 2 people have been affected by this bug, especially with so many Flex devs recommending IDEA. Maybe I am doing something wrong?
All you Flex developers, I would appreciate your thoughts.
UPDATE
This is in response to RIAStar's excellent and detailed answer. But it doesn't quite help me completely. Let me explain why and how I use <fx:Script source>. I am using Flex 4.x, with almost only Spark components.
Suppose a brand new Flex project. The main application is an MXML file.
In this MXML file, suppose I have a signup form.
On editing the form (in each field), suppose I have to run validations and enable the Submit button only if the form is completely valid. This would mean I need to assign change event handlers to the form items. The event handlers is AS code.
Suppose there is a username field which needs an on-type uniqueness check, by calling the server asynchronously. The server communication code is also AS code.
And then of course, there is the Submit button handler, which is also AS code.
I usually put all the AS code in separate .as files and include it in the MXML using <fx:Script source>. This AS code is usually quite heavy, with a lot of functional and behavioural logic. Many times, based on user action, even the components in the MXML and layout of the elements is modified through this AS code.
If I understand you guys right, none of this event handler code should be in these MXML script files. So, where should it be? How do you guys do it? I am not sure how the Spark Skinning architecture has anything to do with this.
Since I can't think of a gentle way of putting this, I'll just be blunt: I'm afraid the reason only two people think this is a critical bug, is that most seasoned Flex developers will agree that using <fx:Script source="some_file.as"/> is bad practice.
You effectively create two files that represent one class. From a readablity POV, which you seem concerned about, that's not a good move. One of these files (the .as file) is just a bunch of functions that cannot exist in their own right: they are tightly coupled to another file/class, but just looking at the .as file there is no way of knowing which class it is coupled to. Of course you can use some kind of naming convention to work around this, but in the end ActionScript/Flex is supposed te be used as a statically typed language, not a scripting language relying on mixins and naming conventions (don't get me wrong: I'm not saying scripting languages are bad practice; it's just not how ActionScript was conceived).
So what are your alternatives?
I suppose the main reason behind this construct is that you wish to separate MXML from ActionScript code, or in more abstract terms: separate the view from the logic. Fortunately this can be achieved in a few other, cleaner ways. Which solutions are available to you depends whether we're talking Flex 3 (or earlier) or Flex 4.
I realise that you may not have time to refactor your code to one of the proposed solutions, but I didn't want to leave you with just a "that's not good practice" answer.
Flex 3 (mx)
Code behind: A lot of developers used the so-called "code behind" pattern to separate their logic from their view. You can find plenty of information on the topic by Googling "flex code behind". I don't need to repeat all that in here. I'm not much of a fan of the concept because it relies heavily on inheritance and the two resulting classes are still pretty tightly coupled, but at least we're talking two classes. If you design your architecture well, you may even be able to reuse some of your base classes.
Compose model en controller: I used to create a separate "presentation model" class and a "controller" class for each MXML view and then use it something like this:
<!--MyView.mxml-->
<mx:VBox>
<m:MyModel id="model"/>
<c:MyController model="{model}" view="{this}"/>
...
</mx:VBox>
MVC purists won't like this, but it worked pretty well for me in thencontext of Flex applications.
Later when Direct Injection supporting frameworks (like Parsley) made their appearance, I could use injection to wire all those classes instead of hard-wiring them like in this example.
MVC frameworks: My knowledge of this topic is sparse (because in my opinion Flex is a very decent MVC framework that requires no third-party additions, but that's another disussion), but in short: they can help you separate logic from view in a clean way.
Flex 4 (Spark)
With Flex 4, the Spark skinning architecture was introduced, which allows for very nicely separated view and logic. You create a so-called 'host component' class in plain ActionScript, which contains all of the behavioural code, and a 'skin' class in MXML which defines the visual representation of the component. This makes designing reusable components very easy.
As per your request, here's a simplified example of how you might use Spark skinning to create your signup form.
Let's start with the skin class since it's easy to understand. It's just a form with some input fields. The HostComponent metadata tells the skin it's supposed to work together with the SignUp host component.
<!--SignUpSkin.mxml: the visual representation-->
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Metadata>
[HostComponent("net.riastar.view.SignUp")]
</fx:Metadata>
<s:Form>
<s:FormHeading label="Sign up"/>
<s:FormItem label="User name">
<s:TextInput id="userInput"/>
</s:FormItem>
<s:FormItem label="Password">
<s:TextInput id="passwordInput" displayAsPassword="true"/>
</s:FormItem>
<s:Button id="submitButton" label="Submit"
enabled="{hostComponent.canSave}"/>
</s:Form>
</s:Skin>
And now the host component in pure ActionScript. It has to extend SkinnableComponent to be able to use our skin (there's also SkinnableContainerwhich I've just recently explained in this question: Flex mxml custom component - how to add uicomponents?, but we won't be needing that here).
public class SignUp extends SkinnableComponent {
[SkinPart(required="true")]
public var userInput:SkinnableTextBase;
[SkinPart(required="true")]
public var passwordInput:SkinnableTextBase;
[SkinPart(required="true")]
public var submitButton:IEventDispatcher;
[Bindable]
public var canSave:Boolean;
override protected function partAdded(partName:String, instance:Object):void {
super.partAdded(partName, instance);
switch (instance) {
case userInput:
userInput.addEventListener(TextOperationEvent.CHANGE,
handleUserInputChange);
break;
case passwordInput:
passwordInput.addEventListener(TextOperationEvent.CHANGE,
handlePasswordInputChange);
break;
case submitButton:
submitButton.addEventListener(MouseEvent.CLICK,
handleSubmitButtonClick);
}
}
private function handleUserInputChange(event:TextOperationEvent):void {
validateUsername(userInput.text);
}
...
}
What's important here?
The variables marked as SkinPart will automatically be assigned the components with the same id that exist in the Skin you just created. For instance <s:TextInput id="userInput"/> will be injected into public var userInput:SkinnableTextBase;. Note that the type is different: SkinnableTextBase is the base class of TextInput; this allows us to create another skin with e.g. a TextArea instead of a TextInput and it'll work without touching the host component.
partAdded() is called whenever a SkinPart is added to the display list, so that's where we hook up our event listeners. In this example we're validating the username whenever its value changes.
When the validation is done, you can simply set the canSave property to true or false. The binding in the skin on this property will automatically update the Button's enabled property.
And to use both of these classes together:
<v:SignUp skinClass="net.riastar.skin.SignUpSkin"/>
I actually have become quite fond of using RobotLegs.
In my MXML views I try to keep all logic outside of the MXML and simply dispatch events out to the mediator. From there I can put code in the mediator to the heavier AS needed.
There is a table like this:
<h:panelGroup rendered="#{ImportFromCSVFile.step2Visible}">
<div style="width: 100%; overflow: auto; max-height: 400px;">
<tr:table id="step2ColumnMappings" var="columnMappingEntry" rows="0" rowBandingInterval="1" value="#{ImportFromCSVFile.columnMappings}">
<tr:column>
<tr:outputLabel value="#{columnMappingEntry.columnIndex}"/>
</tr:column>
<tr:column>
<tr:outputLabel value="#{columnMappingEntry.columnValue}"/>
</tr:column>
<tr:column>
<h:selectOneMenu value="#{columnMappingEntry.columnType}" validator="#{ImportFromCSVFile.validateColumnType}" onchange="submit()" valueChangeListener="#{ImportFromCSVFile.columnMappingChanged}">
<f:selectItems value="#{ImportFromCSVFile.columnsToBeMapped}" />
</h:selectOneMenu>
</tr:column>
</tr:table>
</div>
</h:panelGroup>
which renders (properly) as a table with three columns: text in the first two and dropdowns in the last one. dropdowns are also properly initialized based on values in the model.
What I need to do is to be able to run some logic everytime a value in any of the dropdowns changes. I was thinking of using valueChangeListener on selectOneMenu, as you can see in the code, but it doesn't get called. The only thing that comes to mind right now is working with POST parameters when the form is submitted, which would not be optimal.
Do you know how I can get valueChangeListener to work in this context? JSF 1.2. I may be missing an obvious or known solution, but unfortunately I have very very little prior experience with JSF and do not work with it on a regular basis.
Thank you very much in advance!
xmlns:h="http://java.sun.com/jsf/html"
xmlns:tr="http://myfaces.apache.org/trinidad"
The easiest thing to do would be to use <tr:selectOneChoice instead of <h:selectOneChoice. Use it's valueChangeListener in the same way. However, you can't just submit the form via Javascript like that because it is not aware of the JSF life-cycle (not post'ing the right stuff and your code shouldn't interact with that level of JSF internals anyway). If you set <tr:selectOneChoice autoSubmit="true"... this will cause a post to occur when the drop-down menu value changes that calls your value change listener.
Invoking a javascript function like the way you mentioned in the code snippet will not submit your form.To invoke
valuechange
listener you need to submit a request to the backing bean which will check your application level logic. You can try removing the
onClick
attribute and also please put a message as you have placed a
validator
. At times it so happen, that when validation is not succeeded and you have not attached a corresponding message or notification for the same, the desired action won't be performed. So even though your logic might be write but he JSF lifecycle interrupts at
validation phase
and your remaining action is not invoked.
I want to add a bunch of classes to some text fields so i can get their values with jquery. This seems like standard practice when using jQuery and this post suggests it as the answer but how does this affect page loading? Won't it be trying to find all these classes? I have been told in the past to try minimise the amount of classes used on controls.
I have about 12 controls i'll want to add unique classes to to get their value. I am using asp.net so I can't use the id. I also can't use the ClientID as the controls are in a table (but only 1 set of controls will show at any one time).
e.g.
<asp:TextBox ID="txtValue1" runat="server" CssClass="value1" Text='value1' />
<asp:TextBox ID="txtValue2" runat="server" CssClass="value2" Text='value2' />
<asp:TextBox ID="txtValue3" runat="server" CssClass="value3" Text='value3' />
...
var value1 = $('.value1').val();
var value2 = $('.value2').val();
var value3 = $('.value3').val();
And none of the class names will exist in css.
Thanks
Edit:
I know this works but I was more curious about the affect it had on page loading. There was an answer (seems to be deleted now) that said something like the html parser ignores the classes. The css parser will only look at classes that are defined. So it sounds like it would be completely ignored and have no affect on page load. Is this right?
It is okay to use a CSS class that doesn't exist, but if they are unique you want to use id, not class.
You say you are using ASP.Net so you can't use the ID parameter, but you can. In JQuery you can get the controls using the below
var value1 = $('[ID$=yourID]').val();
For more info on JQuery Selectors check out: JQuery Selectors and Attribute Ends With Selector
The above selector basically finds the id ENDING in "yourID" so ignoring all the masterpages extra text at the start. You just have to make sure these are unique. e.g. don't have ids like "HSBC" and "SBC" as the above selector on "SBC" will find both.
I don't think it's a problem. The only times I've had problems with non-existant classes or ID's is one time I had an onclick reference an ID that didn't exist. This messed things up...Other than that I think classes are pretty harmless. I'd be interested to know though..
Any other thoughts??
Which version of asp.net are you using? In asp.net 4.0, you have the ability to use unmangled ids. It looks like the simplest solution would be to set ClientIDMode="Static" to all of your textboxes and then refer by id. Otherwise, sure, I've created classes that don't exist to refer to things.... all the time.
Edit: (in response to your comment about the effect page load).
I think your question about having extra classes in a div that are not currently used is not a bad question (at least in a theoretical sense), and I honestly don't know the precise answer. I do believe any effect is quite minuscule. If you consider best practices to write html, you generally write and structure the HTML, with it's classes, before you write the CSS. This means at the time you write the CSS, certainly some classes will not be used. Indeed, after styling the basic tags (body, h1, a, etc), you may find you never need to create selectors with those classes for some particular design. And yet for the next design, you might need those classes. I'm pretty sure the technology behind CSS was built with those kinds of scenarios in mind, and I bet millions if not billions of pages on the internet follow that exact scenario, especially if they use something like Modernizr, which adds classes to the html element of the page as a way of providing you classes you can select against considering the possible capabilities of the current browser. You may never need those classes, but they are there if you need them.
In Flex 3, MX effects could be triggered like this:
<mx:Resize id="myEffect" />
<mx:Button mouseDownEffect="{myEffect}" />
In Flex 4, Spark effects are triggered like this:
protected function onClick(event:MouseEvent):void {
resizeEffect.end();
resizeEffect.play();
}
...
<s:Resize id="resize" />
...
<s:Button click="onClick(event)" />
What was the reason to use this less declarative and longer approach? I couldn't find the answer anywhere in the docs.
(Two things to note:
There might be small differences between mouseDown trigger and the click event, please ignore that, it's just an example.
I'm not sure whether triggers would or would not work reliably for Spark effects. Maybe they would but I guess there is a reason why this possibility is not even mentioned in the official docs.
)
Effect triggers are not officially supported in spark in the current release. You can track the progress of this feature here: http://bugs.adobe.com/jira/browse/SDK-19743
I'll add that the Flex 4 button still has effect triggers documented in the ASDocs, including a mouseDownEffect. Are you sure they don't work?
That said, behind the scenes, in the component's code, effect triggers work the same way as your second sample. Some code somewhere to get the effect, if it exists, and manually deal with the effect's playback.
Since Spark has a half baked component set, it is possibly such things were not implemented yet. It is also possible that the effect is not being passed to your button skin class which, I suspect, should probably be dealing with such visual changes.
Perhaps you should provide us with some runnable samples?
Is there any component that does handle validation errors similarly to ASP.NET's ValidationSummary control in flex? (See screenshot)
alt text http://i.msdn.microsoft.com/ms972961.pdc_userinput_fig2(en-us,MSDN.10).gif
Component should really only display all the errors for the validator it watches.
I'm convinced I already used it but I was unable to find it anywhere in the doc.
There is no component in Flex specifically designed to show a collection of all the validation errors in a form. Some built-in components have support for validation error indicators. TextInput, for instance, can display a red border with an error tooltip that appears on mouse roll over.
Flex Validators work a bit differently than this but check out the Validator Samples in Tour de Flex.
Well, I achieved the results I was expecting with a bit of work.
Sharing in the event that somebody has the same needs that I had ;-):
Made a component that overrides validationResultHandler and manages validation errors
Made sure that all the validators that had to be shown in the component had their listener property set to the component's instance
And thats pretty much it.
<my:ValidationView id="vv" />
<mx:StringValidator listener="{vv}" ... />
<mx:Validator listener="{vv}" ... />