这篇文章很长,所以我想用解决方案“回答”我的问题,而不是“编辑” 显示解决方案的问题是最合适的。我将编辑问题以更准确地反映问题的参数(即要求解决方案不包含任何额外的 Flex 框架,例如 Cairngorm 或 PureMVC,以保持简单)。
我也承认这个解决方案有点弱。目前,我有一个额外的事件触发,我需要弄清楚并删除它 - 但它确实有效并且符合业务/技术要求。这也感觉好像我在“重新发明轮子”,我宁愿不这样做。因此,如果有人有一个示例(一些设计模式?),其中包括“客户端和服务器验证”,以及对 itemEditor 的某些更改使用 Flex 验证框架(我需要的是 DataGrid cell edit),我真的会如果您将其列为答案,将不胜感激,也许我可以为您提供一些积分!
我也不完全确定我关闭/提交编辑器的方式。我确实尝试过使用destroyItemEditor(),但它似乎对我不起作用。
这是我的源代码:
MyPage.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:validators="validators.*"
preinitialize="myPage_preinitializeHandler(event)"
initialize="myPage_initializeHandler(event)"
creationComplete="myPage_creationCompleteHandler(event)">
<mx:Script>
<![CDATA[
import entities.MyModel;
import entities.MyUser;
import events.MyValidatorEvent;
import mx.collections.ArrayCollection;
import mx.controls.TextInput;
import mx.events.DataGridEvent;
import mx.events.DataGridEventReason;
import mx.events.FlexEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.remoting.mxml.RemoteObject;
import services.UserRemoteObjectService;
import validators.UserValidator;
private var _userValidator:UserValidator;
private var _securedPageService:RemoteObject;
private var _securedUsersService:RemoteObject;
private var _userRemoteObjectService:UserRemoteObjectService;
[Bindable]
private var _myModelList:ArrayCollection;
protected function myPage_preinitializeHandler(event:FlexEvent):void
{
_userValidator = new UserValidator();
_myModelList = new ArrayCollection();
}
protected function myPage_initializeHandler(event:FlexEvent):void
{
_securedPageService = new RemoteObject();
_securedPageService.destination = "securedPageService";
_securedPageService.getAllData.addEventListener("result",getAllData_resultHandler);
_securedUsersService = new RemoteObject();
_securedUsersService.destination = "securedUsersService";
// For client-side and server-side validation using a RemoteObject service
_userRemoteObjectService = new UserRemoteObjectService(_securedUsersService);
_userValidator.userService = _userRemoteObjectService;
}
protected function myPage_creationCompleteHandler(event:FlexEvent):void
{
initializeModelList();
}
private function initializeModelList():void
{
_securedPageService.getAllData();
}
private function getAllData_resultHandler(event:ResultEvent):void
{
var untypedList:ArrayCollection = (event.result as ArrayCollection);
var myModel:MyModel;
for each(var m:Object in untypedList)
{
myModel = new MyModel(m.auditModelId, m.groupName,
m.reviewRequired, m.fieldNeedingValidation, m.lastReview)
_myModelList.addItem(myModel);
}
}
private function verifyInputIsValid(dgEvent:DataGridEvent):void
{
if (dgEvent.reason == DataGridEventReason.CANCELLED)
{
return; // Edit is "cancelled", do not update
}
// For the fieldNeedingValidation column only
if(dgEvent.dataField == "fieldNeedingValidation") {
// Get the new data value from the editor.
var userID:String = TextInput(dgEvent.currentTarget.itemEditorInstance).text;
_userValidator.addEventListener("totallyComplete",userValidator_completeHandler);
_userValidator.addEventListener("error",userValidator_errorHandler);
_userValidator.validateSystemUser(userID, myPageGrid.itemEditorInstance, dgEvent);
}
}
private function userValidator_completeHandler(event:MyValidatorEvent):void
{
TextInput(event.target.itemEditorInstance).errorString = "";
event.target.dataGridEvent.itemRenderer.data.fieldNeedingValidation = (event.myUser as MyUser).fullName;
myPageGrid.editedItemPosition = null;
myPageGrid.selectedIndex = -1;
}
private function userValidator_errorHandler(event:MyValidatorEvent):void
{
// Prevent the user from removing focus, and leave the cell editor open.
// The edit will not continue and store the blank value
(event.target.dataGridEvent as DataGridEvent).preventDefault();
// Write a message to the errorString property.
// This message appears when the user mouses over the editor.
TextInput(event.target.itemEditorInstance).errorString = event.errorMessage;
return;
}
]]>
</mx:Script>
<mx:Panel title="My Page">
<mx:DataGrid id="myPageGrid" dataProvider="{_myModelList}"
itemEditEnd="verifyInputIsValid(event)" editable="true">
<mx:columns>
<mx:DataGridColumn dataField="someField" headerText="Something" editable="false" />
<mx:DataGridColumn dataField="fieldNeedingValidation" editable="true" headerText="Input User ID"/>
</mx:columns>
</mx:DataGrid>
</mx:Panel>
</mx:Panel>
UserValidator.as
package validators {
import entities.IMyUser;
import entities.MyUser;
import events.MyValidatorEvent;
import flash.events.Event;
import mx.controls.TextInput;
import mx.controls.listClasses.IListItemRenderer;
import mx.events.DataGridEvent;
import mx.events.ValidationResultEvent;
import mx.rpc.AsyncToken;
import mx.rpc.Responder;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.validators.ValidationResult;
import mx.validators.Validator;
import services.IUserService;
public class UserValidator extends Validator
{
public var userService:IUserService; //Service delegate to process the remote validation
private var _itemEditor:IListItemRenderer;
private var _dataGridEvent:DataGridEvent;
private var _inputValue:String = null;
public function UserValidator()
{
super();
}
/**
* The "Core Method" of this class. Invokes validation of a userIDToValidate
* and later takes the appropriate action on UI components as need be.
*/
public function validateSystemUser(userIDToValidate:String, itemEditor:IListItemRenderer ,dgEvent:DataGridEvent):void
{
this._dataGridEvent = dgEvent;
this._itemEditor = itemEditor;
var validatorResult:ValidationResultEvent = this.validate(userIDToValidate);
if(validatorResult.type==ValidationResultEvent.INVALID){
if(validatorResult.results[0].errorCode == "validating"){
// Prevent the user from removing focus, and leave the cell editor open.
// Also, the edit will not continue and store the blank value
dgEvent.preventDefault();
// Write a message to the errorString property.
// This message appears when the user mouses over the editor.
TextInput(itemEditor).errorString = validatorResult.message;
trace("Please wait, server is validating...");
return;
}
else{
// A client-side "invalid", handled the same. This time the message
// does not include "Please wait" text
dgEvent.preventDefault();
TextInput(itemEditor).errorString = validatorResult.message;
return;
}
}
else if(validatorResult.type==ValidationResultEvent.VALID){
// Everything was successful, update the UI
TextInput(itemEditor).errorString = "";
TextInput(itemEditor).text = userIDToValidate;
return;
}
}
// Overide this method to start the validation process
override protected function doValidation(value:Object):Array
{
if (_inputValue != String(value)){
_inputValue = String(value);
}
var results:Array = super.doValidation(value); // Call base class doValidation().
if(results.length > 0){
return results; // Return if there are errors.
}
//Business rules for client side validation will determine this
var someErrorCondition:Boolean = false;
if (someErrorCondition == true)
{
results.push(new ValidationResult(true, null, "errorCode", "Error description"));
return results;
}
else{
trace("All client-side validation has passed");
/**
* Call the remote service, return an 'error' indicating server validation
* is pending. The String identifier is meaningless, except to indicate
* that it should be handled differencly by the consumer of the validation.
*/
results.push(new ValidationResult(true, null, "validating",
"Please wait: \nThe server is validating this corpID."));
var token:AsyncToken = this.userService.service_findByID(_inputValue);
token.addResponder(new Responder(userValidator_resultHandler,
userValidator_faultHandler));
return results;
}
}
private function userValidator_resultHandler(re:ResultEvent):void
{
if(re.result.errorMessage == null)
{
var myUser:IMyUser = new MyUser(re.result.corpID,re.result.fullName,re.result.managerFullName);
var validatorCompleteEvent:Event = new MyValidatorEvent("totallyComplete", "", myUser);
this.dispatchEvent(validatorCompleteEvent);
}
else
{
trace("ERROR: Something went wrong in the userValidator_resultHandler");
}
}
/**
* This fault handler is invoked because my Server (via BlazeDS) actually
* returns/throws a custom Exception. This will dispatch an error to it's consumer
* (MyPage.mxml) using the details of that Exception/FaultEvent, used later to populate
* the same UI component as Flex's standard "Validator" (client-side) would.
* @see: http://livedocs.adobe.com/flex/3/html/help.html?content=validators_2.html
*/
private function userValidator_faultHandler(fe:FaultEvent):void
{
var myUser:IMyUser = new MyUser(this._inputValue,null,null);
var errorEvent:Event = new MyValidatorEvent("error", fe.fault.rootCause.message, myUser);
dispatchEvent(errorEvent);
}
public function get itemEditorInstance():IListItemRenderer
{
return _itemEditor;
}
public function get dataGridEvent():DataGridEvent
{
return _dataGridEvent;
}
}
}
UserRemoteObjectService.as
package services
{
import mx.rpc.AsyncResponder;
import mx.rpc.AsyncToken;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.remoting.mxml.RemoteObject;
public class UserRemoteObjectService implements IUserService
{
private var _userService:RemoteObject;
public function UserRemoteObjectService(userService:RemoteObject)
{
this._userService = userService;
}
public function service_findByID(userID:String):AsyncToken
{
var token:AsyncToken = _userService.findById(userID);
token.addResponder(
new AsyncResponder(findByID_resultHandler,
findByID_faultHandler)
);
return token;
}
private function findByID_resultHandler(event:ResultEvent, token:AsyncToken=null):void
{
event.token.dispatchEvent(event);
}
private function findByID_faultHandler(event:FaultEvent, token:AsyncToken=null):void
{
event.token.dispatchEvent(event);
}
}
}
这就是当前的代码,@drkstr 和@Kyle 我很想看看你的想法。
感谢 StackOverflow,@drkstr 您今天获得了“已接受”复选标记,您启发了我的解决方案。