Related
I have an issue where several of my pages are using the SfBackdropPage control from Syncfusion. This control requires the page to have a base of SfBackdropPage and not the usual ContentPage otherwise it just won't work.
To make MVVMCross work, the page needs have a base such as MvxContentPage
You see where this is going ?
I opened a ticket with Syncfusion to see if they could work around this issue but basically they just said its not possible. So since I needed to have that control as part of the page I had to leave the base as it was.
How do I setup MVVMCross to work with these pages without having the page inherit from MvxContentPage ?
I've used the following in the setup.cs in the Android project:
protected override IMvxViewsContainer InitializeViewLookup(IDictionary<Type, Type> viewModelViewLookup)
{
viewModelViewLookup.Add(typeof(SitesViewModel), typeof(SitesView));
return base.InitializeViewLookup(viewModelViewLookup);
}
I can navigate to the page but I get a null reference exception due to the binding context not been set. I've tried to set this in the XAML but it requires a parameterless constructor but that's not possible as the view model uses Dependency Injection as it relies on these object been passed in.
Can anyone give any pointers, I'm still learning MVVMCross so hopefully I've just missed something.
XF: 4.8.0.1687
MVVMCross: 7.1.2
UPDATE 1:
I've tried to find something in the MVVMCross source to see how it does the setup for the binding context, but I've not found anything. So for now, I'm manually creating the binding context in the page code behind and using Mvx.IocProvider.Resolve<> to pass the required interfaces.
I'm not sure if this is the best to workaround this issue but it works. Maybe there is a better way ?
UPDATE 2:
It seems that update 1 route is no good as the doing this creates a new instance of the VM which is to be expected but an instance already exists which is created by the MVVMCross framework. The question is how do I get the VM instance from the code behind ? The only way I have found so far is to use IMvxOverridePresentationAttribute and the cast the request to MvxViewModelInstanceRequest which then allows access to the VM instance which I assign to the binding context. I may be better off creating another question as to the best approach for this method.
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.
I have a PivotViewer app I am working on, but, I cannot get it to run.
I have a good .cxml file (I used Pauthor to generate the related deep-zoom files). I have tried running it from inside VS 2010 int debug and even built it and tried running it from my localhost. I've checked it in both Firefox and IE. I've made sure it is in a container with set width and height. I've made sure I have the most current silverlight.js, I've set the appropriate MIMEs on IIS.
My XAML:
<UserControl x:Class="DomPivot.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:pivot="clr-namespace:System.Windows.Pivot;assembly=System.Windows.Pivot"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="400" Loaded="UserControl_Loaded">
<Grid x:Name="LayoutRoot" Background="White" Width="400" Height="400">
<pivot:PivotViewer x:Name="myPivot" Height="350"></pivot:PivotViewer>
</Grid>
</UserControl>
My error:
Error: Unhandled Error in Silverlight Application Set property 'System.Windows.FrameworkElement.Style' threw an exception. [Line: 11 Position: 52]
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at DominionPivot.MainPage.InitializeComponent()
at DominionPivot.MainPage..ctor()
at DominionPivot.App.Application_Startup(Object sender, StartupEventArgs e)
at MS.Internal.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args)
at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName)
Source File: DomPivotTestPage.aspx
Line: 0
Line 11 Position 52 of the main.xaml is now the equal sign for the Height property of the pivotviewer. Interesting that BEFORE I added the height property, the project threw this error at the equal sign for the x:Name property.
I don't understand why I'm getting this error and would appreciate some help. I've investigated the other topics here but none of those answers either worked or pertained to my situation.
UPDATE:
I've attempted to make sure it isn't some kind of other error cascading into an inability for the control to load by attempting to load a .CXML file from a public source. Same result. I don't think the control itself is loading, so, I can't even debug the code that loads the collection.
Googling "Unhandled Error in Silverlight Application Set property 'System.Windows.FrameworkElement.Style' threw an exception." is no help. It returns 24 hits. Half of those are unrelated. The other half is another person with what appears to be the same problem posting to half-dozen or more forums and getting no answer either.
OK....so here are a number of issues that a lot of frustrating googling and futzing revealed:
Loaded="UserControl_Loaded"
I'm not entirely sure how this parameter ended up in my UserControl tag, but, it is unnecessary and eliminated the error referenced in my question.
I also moved the LoadCollection method out of its own event and into the UserControl_Loaded event and got things to progress.
Next I found that if you are using Visual Studio to run the project, make sure you specify the port number both in your code and in your web project settings. These obviously need to be changed when you post to a live server.
Lastly, I was led to believe that you HAD to use either the freely available Pauthor tools or the Excel plug-in to transform your collection into a Deep Zoom. Which also requires futzing with IIS to allow .dzi and .dzc.
Not so. There is a freely available Microsoft Deep Zoom Composer tool. In that tool you can compose your deep zoom and export the collection. You'll end up with several xml files and image folders. I found that all you have to do is then reference the output_dzc.xml file in your collection.cxml as your ImgBase and make sure your IDs match between the two files. That's all.
I hope this saves someone the frustration I've experienced the last few weeks trying to use this awesome but pathetically under-documented control.
I would also recommend this blog entry:
http://indiandotnet.wordpress.com/2011/02/12/pivot-viewer-example-cricket-world-cup-2011/
It contains a link to a very simple pivotviewer VS 2010 solution file you can use to examine and familiarize yourself with file and directory structure as well as the necessary XML file structure and solution settings.
In Flash Professional CS4, I get "migration issue" warnings when I use mouse/keyboard input handler names such as onMouseDown, onKeyUp, etc., even though I have added event listeners for them. These names are perfectly legal for functions, but since these were automatically fired in ActionScript 2.0, we are now (albeit sensibly) warned that their use is no longer automatic in AS3.
I understand the purpose of the warnings, but they aren't useful for me. I want to suppress these warnings, but without suppressing any other warnings, which I generally do find useful.
E.g., when I use code like this:
/** #constructor */
public function MyClass() {
addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
}
protected function onMouseDown(e:MouseEvent):void {
I get an annoying warning like this:
Warning: 1090: Migration issue: The onMouseDown event handler is not triggered automatically by Flash Player at run time in ActionScript 3.0. You must first register this handler for the event using addEventListener ( 'mouseDown', callback_handler).
There are flex compiler (mxmlc) flags (and a Flash Pro setting) which can suppress actionscript warnings, or all warnings, but I don't want that. That's too general.
Ideally I could suppress a specific error/warning number (Warning #1090).
Edit: I've found more "advanced" compiler flags with mxmlc -help advanced, which look promising. Specifically, the following seem like likely candidates:
warn-deprecated-event-handler-error
warn-deprecated-function-error
warn-deprecated-property-error
How do I get Flash to use these?
Edit 2: I found a flex-info.xml style document in the Flash User Data dir.
[userdatafolder]/Adobe/Flash CS4/en/Configuration/ActionScript 3.0/FlexInfo.xml
However, this file contains a disappointing comment: <!-- Flash does not support most flex-config options. -->, and doesn't seem to respond to my directives even after restarting flash.
This is getting sad.
Edit 3: Found an issue "Erroneous, annoying "Migration issue" warnings" on Adobe bug tracker. A fix is confirmed for the Flex SDK, but no mention of Flash...
You can if you edit EnabledWarnings.xml in $Flash/$LOCALE/Configuration/Actionscript 3.0/EnabledWarnings.xml, where $Flash is the path to Flash inside your Applications/Program Files folder and $LOCALE is your language.
e.g.
/Applications/Adobe Flash CS4/en/Configuration/ActionScript 3.0/EnabledWarnings.xml
You will need to edit line 29, setting the enabled attribute to false for warning with id 1090:
<warning id="1090" enabled="false" label="kWarning_DepricatedEventHandlerError">EventHandler was not added as a listener.</warning>
Quick sidenote:
"Flash Builder (CS4)" is a confusing term. After Flex Builder 3, Flex Builder got renamed to Flash Builder, there is no Flash Builder CS4. The regular Flash IDE is known as Flash Professional/Flash Professional CS4, this was to avoid confusion between products with similar names: Flash Catalyst, Flash Builder(was Flex Builder), Flash Professional. Obviously it doesn't always work that great :)
What about changing the name of the function being called from onMouseDown to handlerOnMouseDown. Would it solve the issue?
Are you using Flex Builder?
If so, go to Project -> Properties -> Flex Compiler. There you can add arguments to the compiler.
Why are you overriding that? It never existed in the first place. The error message is actually telling you something useful. Don't suppress it.
If you want to create an event handler called onMouseDown, try something like
private function onMouseDown(e:MouseEvent) : void {
// statements
}
I agree with the previous post; the message is trying to tell you that you need to register that event handler. Just adding a method called onMouseDown() won't do it. What you need to do is to add something like
addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
in either your constructor or maybe in the parent component.
You can filter out these warnings using Flash Builder's problems filtering capability:
open problems view
on the right click on the small triangle that opens a drop-down menu
select Configure Contents...
on the left side, create a new configuration, name it as you wish
on the right side adjust its settings:
Scope: On any element in the same project (or anything you want)
Description: choose doesn't contain and type in Migration issue (this will filter out warnings with migration issue in the description)
choose at least Flex problems
You can combine predefined and custom configurations by selecting more then one on the left side.
I have an application that loads external SWF files and plays them inside a Adobe Flex / Air application via the SWFLoader Flex component. I have been trying to find a way to unload them from a button click event. I have Google'd far and wide and no one seems to have been able to do it without a hack. The combination of code I see people use is:
swfLoader.source = ""; // Removes the external link to the SWF.
swfLoader.load(null); // Forces the loader to try to load nothing.
// Note: At this point sound from the SWF is still playing, and
// seems to still be playing in memory.
flash.media.SoundMixer.stopAll();
// Stops the sound. This works on my development machine, but not
// on the client's.
If the SWFs are closed (hidden) this way, eventually the program crashes.
Any ideas? I have found tons of posts in various forums with people having the same problem. I assume I will get one wrong/incomplete answer here, and than my post will sink into nothingness as usual, but either way, thanks in advance!
Edit 1: I can't edit the actual SWF movies, they're created by the client. If I can't close any SWF opened through Flex, isn't that a problem with the Flex architecture? Is my only option sending the SWFs to the web browser?
... isn't that a problem with the Flex architecture?
Yes it is, and it also affects Flash in general. Until you can take advantage of the Loader.unloadAndStop() method in FP10 (AIR 1.5), you can't guarantee that externally loaded content will not continue to consume memory and cpu resources, even if you use the Loader.unload() method. (To be honest, I'm not 100% sure that even that will guarantee freeing of resources, but maybe I'm a pessimist.)
The next best thing is for you to insist that the creators of the content you load adhere to a set of guidelines, including exposing something like a dispose() method which your app can call to ask it to release as many resources as possible before you unload() it. If this isn't possible, then your application will almost definitely bloat in memory and cpu usage each time you load an external swf. Sorry.
If it makes you feel any better, you're not alone. ;)
It is a problem that a badly created SWF can sink your application, and many of the issues with this will be fixed in Flash Player 10, as others have mentioned. However, regardless of platform you will always risk having problems if you load third party code, there's always the possibility that it contains bugs, memory leaks or downright malicious code. Unless you can load content into a sandbox (and you can't in Flash, at least not yet), loading bad things will sink your app, it's as simple as that.
I'm sorry to say that unless you can guarantee the quality of the loaded content you can't guarantee the quality of your own application. Flash developers are notorious for writing things that leak, or can't be unloaded, because Flash makes it easy to do the wrong thing, especially for things that live on the time line. Loading any Flash content that you don't have control over directly is very perilous.
The best solution is
swfLoader.autoLoad = false;
swfLoader.unloadAndStop();
swfLoader.autoLoad = true;
In this way you stop the player, unload the content from memory and avoid the sound to remain playing..
Cheers
The problem resides in the loaded swf, it simply does not clean up the audio after itself.
Try attaching an unload event onto movieclips like this:
MovieClip(event.target.content).loaderInfo.addEventListener(Event.UNLOAD, unloadMovieClipHandler);
private function unloadMovieClipHandler(event:Event) : void
{
SoundMixer.stopAll();
}
I'd generally stay away from SWFLoader and use the classes in the mx.modules package.
Flex has a module system that enables this type of behavior. You can check it out here : http://livedocs.adobe.com/flex/3/html/help.html?content=modular_3.html . In general, dynamically loading and unloading swf components is tricky, especially if those modules modify any global state in the application (styles, etc..). But if you create an interface for your modules, and then each class you load/unload implement that interface as well as extend the flex module class, you can load and unload them cleanly.
Try the following:
try {
new LocalConnection().connect('foo');
new LocalConnection().connect('foo');
} catch (e:*) {}
That will force a Garbage Collection routine. If your SWF is still attached, then you've missed some sort of connection, like the audio.
There are a couple ways to force GC, which all kind of suck because they spike CPU, but the good news is that an official way is coming in Flash Player 10:
unloadAndStop
link: http://www.gskinner.com/blog/archives/2008/07/unloadandstop_i.html
Until then, I'm afraid you'll have to force it with hacks like I showed above.
You have not shown all of your code so I am going to assume you didn't use the unload method of the Loader class. Also swfLoader.load(null) seems wrong to me as the load method is expecting a URLRequest object. When you want to clean things up at the end, set the object's value to null instead of calling a null load. The fact that your still hearing audio indicates that your data wasn't unloaded, or the audio file does not reside inside the content that was unloaded. Lets walk through this.
Example below
var loader:Loader = new Loader();
var request:URLRequest = new URLRequest('test.swf');
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onSwfLoad, false, 0, true);
function onSwfLoad(e:Event):void
{
addChild(loader);
loader.contentLoaderInfo.addEventListener(Event.UNLOAD, onLoaderUnload, false, 0, true);
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onSwfLoad, false);
}
function onLoaderUnload(e:Event):void
{
trace('LOADER WAS SUCCESSFULLY UNLOADED.');
}
//Now to remove this with the click of a button, assuming the buttons name is button_mc
button_mc.addEventListener(MouseEvent.MOUSE_DOWN, onButtonDown, false, 0, true);
function onButtonDown(e:MouseEvent):void
{
loader.unload();
loader.contentLoaderInfo.removeEventListener(Event.UNLOAD, onLoaderUnload);
//When you want to remove things completely from memory you simply set their value to null.
loader = null;
button_mc.removeEventListener(MouseEvent.MOUSE_DOWN, onButtonDown);
}
I do hope that this was helpful, and I am sorry if it was redundant, but without seeing your code I have no way of knowing exactly how you approached this.