I am building a AS3 only project and got runtime error that said "Cannot access a property or method of a null object reference."
Here is my code:
main.as
public class videoMain extends Sprite{
private var videoPlayer:Player;
public function videoMain (){
loadPlayer()
loadProgress();
}
private function loadProgress():void{
//the code below gave me null object error.....
var byteLoaded:Number=videoPlayer.videoBytesLoaded; //the problem code
var byteTotal:Number=videoPlayer.videoBytesTotal; //the problem code
var percent:Number=Math.floor(byteLoaded/byteTotal)*100;
}
private function loadPlayer():void{
videoPlayer= new Player();
videoPlayer.createPlayer();
}
}
Player.as
public function createPlayer():void{
_loader = new Loader();
_loader.contentLoaderInfo.addEventListener(Event.INIT, onLoaderInit);
_loader.load(new URLRequest(playerType));
}
public function get videoBytesLoaded():Number{
return _Player.getVideoBytesLoaded(); //youtube api method
}
public function get videoBytesTotal():Number{
return _Player.getVideoBytesTotal; //youtube api method
}
private function onLoaderInit(event:Event):void {
_Player=_loader.content;
//only show part of codes....
}
I appreciate any help....Thanks!!!!!
_Player is only defined after the Event.INIT has fired so any call before the _Player value is defined will throw an error.
You should, at the minimum , have this:
public function videoMain (){
loadPlayer()
}
private function onLoaderInit(event:Event):void {
_Player=_loader.content;
//only show part of codes....
loadProgress();
}
but progress events are not static so really you should have an enterFrame event listener in order to listen to the changing values...
private function onLoaderInit(event:Event):void {
_Player=_loader.content;
//only show part of codes....
addEventListener(Event.ENTER_FRAME , enterFrameListener);
}
private function enterFrameListener(event:Event):void
{
loadProgress();
// and here you add some way to remove this event listener when
// the video is fully loaded
}
Related
I'd like to make wrapper to implement simple data binding pattern -- while some data have been modified all registered handlers are got notified. I have started with this (for js target):
class Main {
public static function main() {
var target = new Some();
var binding = new Bindable(target);
binding.one = 5;
// binding.two = 0.12; // intentionally unset field
binding.three = []; // wrong type
binding.four = 'str'; // no such field in wrapped class
trace(binding.one, binding.two, binding.three, binding.four, binding.five);
// outputs: 5, null, [], str, null
trace(target.one, target.two, target.three);
// outputs: 5, null, []
}
}
class Some {
public var one:Int;
public var two:Float;
public var three:Bool;
public function new() {}
}
abstract Bindable<TClass>(TClass) {
public inline function new(source) { this = source; }
#:op(a.b) public function setField<T>(name:String, value:T) {
Reflect.setField(this, name, value);
// TODO notify handlers
return value;
}
#:op(a.b) public function getField<T>(name:String):T {
return cast Reflect.field(this, name);
}
}
So I have some frustrating issues: interface of wrapped object doesn't expose to wrapper, so there's no auto completion or strict type checking, some necessary attributes can be easily omitted or even misspelled.
Is it possible to fix my solution or should I better move to the macros?
I almost suggested here to open an issue regarding this problem. Because some time ago, there was a #:followWithAbstracts meta available for abstracts, which could be (or maybe was?) used to forward fields and call #:op(a.b) at the same time. But that's not really necessary, Haxe is powerful enough already.
abstract Binding<TClass>(TClass) {
public function new(source:TClass) { this = source; }
#:op(a.b) public function setField<T>(name:String, value:T) {
Reflect.setField(this, name, value);
// TODO notify handlers
trace("set: $name -> $value");
return value;
}
#:op(a.b) public function getField<T>(name:String):T {
trace("get: $name");
return cast Reflect.field(this, name);
}
}
#:forward
#:multiType
abstract Bindable<TClass>(TClass) {
public function new(source:TClass);
#:to function to(t:TClass) return new Binding(t);
}
We use here multiType abstract to forward fields, but resolved type is actually regular abstract. In effect, you have completion working and #:op(a.b) called at the same time.
You need #:forward meta on your abstract. However, this will not make auto-completion working unless you remove #:op(A.B) because it shadows forwarded fields.
EDIT: it seems that shadowing happened first time I added #:forward to your abstract, afterwards auto-completion worked just fine.
I use Prism6 + Unity container for desktop application developing.
This is a long-read, sorry. So I ask at top: Prism SetProperty() function is not rising property changed event if input value is Unity singleton. And I understand why: because input value and save value have same reference to singleton instance. RaisePropertyChanged() don't help in this situation.
Long-read is statring...
So, I have a dependency property in my UserControl component:
public static readonly DependencyProperty WorksheetDataProperty =
DependencyProperty.Register("WorksheetData", typeof(WorksheetDataModel), typeof(SheetUserControl),
new PropertyMetadata(new WorksheetDataModel(), WorksheetDataPropertyChanged));
public WorksheetDataModel WorksheetData {
get { return (WorksheetDataModel)GetValue(WorksheetDataProperty); }
set { SetValue(WorksheetDataProperty, value); }
}
private void WorksheetDataPropertyChanged(WorksheetDataModel worksheetData) {
if (worksheetData == null)
return;
SheetGrid.Model.ActiveGridView.BeginInit();
this.ClearWorksheetModel();
this.ResizeWorksheetModel();
SheetGrid.Model.ActiveGridView.EndInit();
}
private static void WorksheetDataPropertyChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e) {
((SheetUserControl)d).WorksheetDataPropertyChanged((WorksheetDataModel)e.NewValue);
}
It's important for me to invoke actions from WorksheetDataPropertyChanged() function.
And scheme without shared service (singleton) is working well: this function is called.
But now I want to share data between several modules. How I see it: I have some "parent" module, which load\save data from storage and shared this data with several other modules, which can modificate shared data, but can't save it.
And EventAggregator is not convenient for me: I don't want to create copies of data and then collect it again after modifications.
So I register my "shared service" as singleton:
_container.RegisterInstance(new WorksheetDataModel());
Now I can load data from database in "parent" viewmodel to singleton object created in previous step:
var data = _container.Resolve<WorksheetDataModel>();
data.Header = args.Header;
data.User = args.User;
data.RowHeader = new WorksheetRowHeader(_model.ReadRowHeader(data.Header.WshCode));
data.ColHeader = new WorksheetColHeader(_model.ReadColHeader(data.Header.WshCode));
data.Cells = _model.ReadCells(data.Header.WshCode);
Further, I notify child viewmodels about new data in singleton:
data.OnDataChanged?.Invoke();
And now most important code from child viewmodel.
In delegate handler I "apply" new value:
WorksheetData = _container.Resolve<WorksheetDataModel>();
WorksheetData is:
private WorksheetDataModel _worksheetData;
public WorksheetDataModel WorksheetData {
get { return _worksheetData; }
set { SetProperty(ref _worksheetData, value); }
}
And problem in this line:
set { SetProperty(ref _worksheetData, value); }
It works only once at first call, because _worksheetData is null. But then refernce of _worksheetData (pointer) setted to singleton and in all next call value and _worksheetData are identical for SetProperty() and, as result, it just quit.
I tried next code:
set {
SetProperty(ref _worksheetData, value);
RaisePropertyChanged("WorksheetData")
}
But no effect. WorksheetDataPropertyChanged() callback in UserControl component is not calling.
So, I don't know now how to better share some data between several modules.
Thanks for any advice.
WorksheetData does not change, the contents of the WorksheetDataModel instance change.
So to update your bindings,
either WorksheetDataModel implements INotifyPropertyChanged and/or uses INotifyCollectionChanged-implementing collections
or you let the view model listen to WorksheetDataModel.OnDataChanged and raise its own PropertyChanged to update all bindings to WorksheetData.
Example:
private WorksheetDataModel _worksheetData;
public WorksheetDataModel WorksheetData
{
get { return _worksheetData; }
set
{
if (_worksheetData != null)
_worksheetData.OnDataChanged -= DataChangedHandler;
SetProperty(ref _worksheetData, value);
if (_worksheetData != null)
_worksheetData.OnDataChanged += DataChangedHandler;
}
}
private void DataChangedHandler( object sender, DataChangedEventArgs args )
{
RaisePropertyChanged( nameof( WorksheetData ) );
}
Ok - I've got a bit of a complicated asMock setup here; I've got a PureMVC async command that is attempting to call another class that implements interfaces in order to set up some asmocks for development without the backend.
import test.mix.common.business.MockInterbahnServiceFactory;
public class InitMockInterbahnServiceFactory extends AsyncCommand{
public static var mockServiceFactory:MockInterbahnServiceFactory = new MockInterbahnServiceFactory();
override public function execute(notification:INotification):void{
var serviceResult:IEventDispatcher = mockServiceFactory.mockRepository.prepare([EchoBusinessObjects, SendBusinessObjects]);
//serviceResult.addEventListener(Event.COMPLETE, onComplete);
}
private function onComplete(event:Event):void{
mx.controls.Alert.show("COMPLETE!");
var logMessage:String = "4 MOCK SERVICE FACTORY MOCKED !!!!!";
sendNotification( MixConstants.LOG_OUTPUT, logMessage );
//sendNotification(MixConstants.INTERBAHN_CONNECTED, mockServiceFactory);
// commandComplete() ;
}
}
This is actually trying to set up a MockRepositoryFactory:
public class MockInterbahnServiceFactory implements ServiceFactory
{
[Mock] public static var withMocks : Array = [
SendBusinessObjects, EchoBusinessObjects
];
//public static var mockRepository:MockRepository ;//= new MockRepository();
public var mockSendBusinessObjects:SendBusinessObjects;
public var mockEchoBusinessObjects:EchoBusinessObjects ;
public var mockRepository:MockRepository;
public function MockInterbahnServiceFactory(){
mockRepository = new MockRepository();
prepareMocks();
}
public function prepareMocks():void{
var prepareDispatcher:IEventDispatcher = mockRepository.prepare([SendBusinessObjects, EchoBusinessObjects]);
prepareDispatcher.addEventListener(Event.COMPLETE, setupMocks);
}
public function setupMocks(event:Event):void{
mockSendBusinessObjects = SendBusinessObjects(mockRepository.create(SendBusinessObjects));
mockEchoBusinessObjects = EchoBusinessObjects(mockRepository.create(EchoBusinessObjects));
SetupResult.forCall(mockSendBusinessObjects.sendOrder(new Order())).returnValue('wee');
}
public function createSendBusinessObjectService():SendBusinessObjects{
return mockSendBusinessObjects;
}
public function createEchoBusinessObjectService():EchoBusinessObjects{
return mockEchoBusinessObjects;
}
}
}
And at some point this factory is going to get passed around and utilized for the send / receive endpoints for multiple communications (true backend being a scala one).
I'm getting this error:
ArgumentError: returnValue must be assignable from :void
at asmock.framework.expectations::AbstractExpectation/set returnValue()[C:\Users\Richard\SVN\asmock\trunk\source\ASMock\src\asmock\framework\expectations\AbstractExpectation.as:107]
at asmock.framework::MethodOptions/returnValue()[C:\Users\Richard\SVN\asmock\trunk\source\ASMock\src\asmock\framework\MethodOptions.as:134]
at test.mix.common.business::MockInterbahnServiceFactory/setupMocks()[/Users/grimm/Documents/__WORK/__INVESTLAB/MIX/trunk/src/test/mix/common/business/MockInterbahnServiceFactory.as:56]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at Function/org.floxy:ProxyRepository/org.floxy:IProxyRepository:prepare/org.floxy:swfLoadedHandler()[C:\transfer\IdeaProjects\as3-interbahn\floxy\main\as3\src\org\floxy\ProxyRepository.as:218]
I'm assuming this is because of the interface functions I'm stubbing?
public interface SendBusinessObjects {
function sendFirmExchangePermission(frp:FirmExchangePermission):void ;
function sendFirm(f:Firm):void ;
function sendExchange(ex:Exchange):void ;
function sendFXConversion(fx:FXConversion):void ;
function sendInstrument(ins:Instrument):void ;
function sendQuote(q:Quote):void ;
It looks to me like SendBusinessObjects returns void, but you are calling returnValue when you are mocking the call to it. Remove the returnValue('wee') call and it should work as expected.
Below is my class, which simply reads an xml file and provides the contents in e4x format. Unfortunately, after the constructors executes and sets the xmlProperties property with the expected values, it some how becomes null. Anyone know what I'm doing wrong?
public class WebService
{
private var _propertiesReader:HTTPService;
private var _xmlProperties:XML;
public function WebService()
{
_propertiesReader = new HTTPService();
_propertiesReader.url = "../resources/properties.xml";
_propertiesReader.resultFormat = "e4x";
_propertiesReader.contentType = "application/xml";
_propertiesReader.addEventListener(ResultEvent.RESULT, function(event:ResultEvent):void
{
_xmlProperties = XML(event.result);
});
_propertiesReader.addEventListener(FaultEvent.FAULT, function(event:FaultEvent):void
{
Alert.show("Unable to load properties content: " + event.fault.message + "\nPlease try again later.", "Properties File Load Error");
});
_propertiesReader.send();
}
public function get xmlProperties():XML
{
return _xmlProperties;
}
}
_xmlProperties is being set by a File Load call (via a callback event). It is not being set directly in the constructor.
Are you sure you are waiting for the call to finish and the callback event to fire before you check the value of _xmlProperty?
In a previous application that I had written, I had a Class that extended AdvancedDataGrid (ADG). It contained the following code:
package
{
public class CustomADG extends AdvancedDataGrid
{
....
// This function serves as the result handler for a webservice call that retrieves XML data.
private function webServiceResultHandler(event:ResultEvent):void
{
var resultXML:XML = new XML(event.result);
dataProvider = new HierarchicalData(resultXML.children);
}
....
public function setOpenNodes(maxDepth:int = 0):void
{
var dataCursor:IHierarchicalCollectionViewCursor = dataProvider.createCursor();
while (dataCursor.current != null)
{
if (dataCursor.currentDepth < maxDepth)
dataProvider.openNode(dataCursor.current);
dataCursor.moveNext();
}
dataProvider.refresh();
}
}
}
In this implementation, the function setOpenNodes() worked fine - it did exactly what I intended it to do - pass it a number, and open all nodes in the dataProvider at or below that level.
Now, I am creating a new ADG Class and want to reproduce this functionality:
package view
{
import mx.collections.IHierarchicalCollectionViewCursor;
public class ReportADG extends AdvancedDataGrid
{
public function ReportADG()
{
super();
}
public function setOpenNodes(maxDepth:int = 0):void
{
var dataCursor:IHierarchicalCollectionViewCursor =
dataProvider.createCursor();
while (dataCursor.current != null)
{
if (dataCursor.currentDepth < maxDepth)
dataProvider.openNode(dataCursor.current);
dataCursor.moveNext();
}
dataProvider.refresh();
}
}
}
The dataProvider is set in the parent component:
<view:ReportADG id="reportADG" dataProvider="{reportData}" />
reportData is set in another file:
reportData = new HierarchicalData(resultXML.children);
However, I am getting runtime errors:
TypeError: Error #1034: Type Coercion failed: cannot convert ListCollectionViewCursor#6f14031 to mx.collections.IHierarchicalCollectionViewCursor.
I've tried casting dataProvider as ICollectionView. I've tried then casting the ICollectionView as IHierarchicalCollectionView. I've tried all sorts of casting, but nothing seems to work. Why won't this work in this new implementation as it did in the past implementation? What do I need to do?
*** Update:
I started debugging this. I added an override setter to my ADG Class to see when dataProvider was being set:
override public function set dataProvider(value:Object):void
{
super.dataProvider = value;
}
I added a breakpoint to this setter and to my setOpenNodes() function. Sure enough, the dataProvider is being set BEFORE setOpenNodes() is called, and it is HierarchicalData. But, when the setOpenNodes() the debugger says that the dataProvider is a null ArrayCollection. It seems like this is the root issue.
I needed to call commitProperties before attempting to access the dataProvider property.
public function setOpenNodes(maxDepth:int = 0):void
{
super.commitProperties();
var dataCursor:IHierarchicalCollectionViewCursor =
dataProvider.createCursor();
while (dataCursor.current != null)
{
if (dataCursor.currentDepth < maxDepth)
dataProvider.openNode(dataCursor.current);
dataCursor.moveNext();
}
dataProvider.refresh();
}