Flex Aviso: Não é possível vincular a propriedade 'foo' em 'Objeto' class (classe não é uma IEventDispatcher)
-
06-09-2019 - |
Pergunta
Eu tenho um objeto que contém uma dúzia de campos Quero ligam a elementos de formulário, para que eu possa usar esse objeto para enviar a de volta dados para o servidor para ser salva.
Definição do meu objeto container:
private static const emptyLink:Object = {
id: -1, title:'',
trigger1:'',trigger2:'',trigger3:'',trigger4:'',trigger5:'',
linkTitle:'', linkBody:'',
answer1:'',answer2:'',answer3:'',answer4:'',answer5:''
};
[Bindable] public var currentLink:Object = emptyLink;
currentLink
é atribuído em tempo de execução para um índice específico de uma ArrayCollection, eu só estou usando o objeto emptyLink
para inicialização fins, principalmente.
<mx:Panel id="triggerPanel" title="Trigger" width="33%">
<mx:VBox id="tpBoxes" width="100%" paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5">
<mx:TextInput id="trigger1" width="100%" textAlign="left" text="{currentLink.trigger1}" />
<mx:TextInput id="trigger2" width="100%" textAlign="left" text="{currentLink.trigger2}" />
<mx:TextInput id="trigger3" width="100%" textAlign="left" text="{currentLink.trigger3}" />
<mx:TextInput id="trigger4" width="100%" textAlign="left" text="{currentLink.trigger4}" />
<mx:TextInput id="trigger5" width="100%" textAlign="left" text="{currentLink.trigger5}" />
</mx:VBox>
</mx:Panel>
Claro, isso compila e exibe muito bem, mas há avisos de tempo de execução para cada instância:
Atenção: não é possível vincular a propriedade 'trigger1' na classe 'Object' (classe não é uma IEventDispatcher) Aviso: Não é possível vincular a propriedade 'trigger2' na classe 'Object' (classe não é uma IEventDispatcher) Aviso: Não é possível vincular a propriedade 'trigger3' na classe 'Object' (classe não é uma IEventDispatcher) Aviso: Não é possível vincular a propriedade 'trigger4' na classe 'Object' (classe não é uma IEventDispatcher) aviso: não foi possível vincular a propriedade 'trigger5' na classe 'Object' (classe não é uma IEventDispatcher)
E o objeto currentLink
não é atualizada quando os campos TextInput
são alterados.
A resposta óbvia é que o meu objeto precisa ser uma instância de uma classe que implementa IEventDispatcher
. O que essa resposta não me diz é os detalhes de implementação dessa interface, e se há uma maneira simples de fazer isso (o que é necessário o que não é?) - como um construído em classe que vai aceitar de bom grado minhas propriedades personalizadas e permitir para a ligação, sem me ter de se preocupar com os detalhes de implementação da interface.
O tal exist classe? Se não, qual é o padrão aceito mínimo e / ou para realizar esta tarefa?
Solução
Você precisa usar ObjectProxy (como Chetan menciona) - mas você também precisa usar valueCommit para obter o texto inserido na parte de trás de entrada em seu objeto:
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
import mx.utils.ObjectProxy;
private static const emptyLink:Object = {
id: -1, title:'',
trigger1:'',trigger2:'',trigger3:'',trigger4:'',trigger5:'',
linkTitle:'', linkBody:'',
answer1:'',answer2:'',answer3:'',answer4:'',answer5:''
};
[Bindable] public var currentLink:ObjectProxy = new ObjectProxy(emptyLink);
private function handleClick():void
{
trace(currentLink.trigger1);
}
]]>
</mx:Script>
<mx:Panel id="triggerPanel" title="Trigger" width="33%">
<mx:VBox id="tpBoxes" width="100%" paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5">
<mx:TextInput id="trigger1" width="100%" textAlign="left" text="{currentLink.trigger1}" valueCommit="{currentLink.trigger1 = trigger1.text;}"/>
<mx:Button label="Click" click="handleClick()"/>
</mx:VBox>
</mx:Panel>
</mx:WindowedApplication>
Outras dicas
Object
não despacha eventos. Apesar de ter feito a variável Bindable, as propriedades do objeto referenciado pelo currentLink
variável não pode ser vinculado.
Use ObjectProxy
vez.
[Bindable] public var currentLink:ObjectProxy = new ObjectProxy(emptyLink);
A primeira coisa que você vai querer saber é que obrigatório em Flex 3 não é bidirecional. A expressão de ligação irá assegurar que, se a fonte da expressão de ligação (currentLink.trigger1) muda que o alvo (TextInput) receberá a notificação da alteração e actualização em conformidade. Se você quiser a ligação para ir em outra direção, há pelo menos duas maneiras de fazer isso:
- Use o mx: Binding tag para trás TextInput.text direto ao objeto
- Use BindingUtils fazer isso programaticamente vez.
Em Flex 4 eles estão introduzindo uma nova sintaxe para a ligação bidirecional @ {some.binding.expression}, mas ele não está disponível em Flex 3.
Na 2ª parte: o erro que você está recebendo é porque você está ligando a um "genérico" protótipo Objeto. Quando você aplica a tag [Bindable] metadados para uma propriedade ou classe, o compilador mxmlc gera AS código que inclui o uso de utilitários de ligação e observadores de alteração de propriedade de fazer fazer a ligação acontecer. No entanto, você não pode fazer o objeto de protótipo fazer isso, já que é um built-in. Você pode criar uma classe ActionScript personalizado que é bindable (ou tem certas propriedades bindable). O compilador mxmlc irá gerar uma classe que implementa IEventDispatcher e, portanto, suporta ligação. Isto tem a vantagem de ser mais rápido do que objetos de protótipo e também lhe dá tempo de compilação verificação, ou seja, você receberá um erro do compilador se você faz referência uma propriedade inválida.
A outra alternativa é envolver o seu protótipo em ObjectProxy como um dos outros membros por isso tem sugerido.
Apenas uma dica sobre como descobrir o código incorreto em um projeto maior - colocar um ponto de interrupção em dois
trace("warning: unable to bind to property '"
linhas na classe PropertyWatcher do SDK (Navegar> Tipo Abrir> ...). Stacktrace irá ajudá-lo a encontrar o componente ui que mantém o quebrado vinculativo.
Em geral, a razão pela qual você obtém "incapaz de se ligam a foo propriedade em uma classe, é porque você está ou faltando um getter ou setter para foo . Você poderia também fazer foo escopo para uma variável pública, (embora este quebras de encapsulamento)
Então, você precisa de ambos para fazer isso ir embora:
public function set foo (o:FooObject) : void {
...
}
ou
public function get foo() : FooObject {
...
}
Eis as livedocs referência para a interface. É muito bonito o que seria óbvio.
Para citar:
Em geral, a maneira mais fácil para uma classe definida pelo usuário para obter capacidades de despacho de eventos é estender EventDispatcher.
Assim,
private static const emptyLink: EventDispatcher = {
Eu não tenho usado Flex por muito tempo, e isso pode não atender às suas necessidades, mas por que não usar XML? Eu acredito que você pode definir o valor de texto TextInput a atributos no XML.
Eu estou usando pseudo-código, mas algo como isto faz sentido para mim:
[Bindable] private static const currentLink:XML = <root>
<trigger1 value=""/>
<trigger2 value="" />
</root>;
...
<mx:TextInput id="trigger1" width ... text="{currentLink.trigger1.@value}" />
Algo assim, talvez?