I am using Binding IsAsync property to keep UI responsive and loading data from the get accessor of the property and proved to be a good option while using MVVM. This approach is great and doesn't need any manual code for async operations. There are few instances where my dataload is taking few seconds and during this time it is very difficult to differentiate between "no data" vs "data loading". Is there a property which I can detect the state of the binding "IsBusy" or "Loading", so that I can show some message that the loading operation is not complete?
Any help is appreciated.
I know, its an old thread. But if anybody is still interested...
You could use PriorityBinding, there is a superbly explained example in this article:
http://www.switchonthecode.com/tutorials/wpf-tutorial-priority-bindings
The idea is to stipulate a PriorityBinding which in turn defines several regular bindings like this:
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock.Text>
<PriorityBinding>
<Binding ElementName="MainWindow" Path="Slow" IsAsync="True" />
<Binding ElementName="MainWindow" Path="Fast" />
</PriorityBinding>
</TextBlock.Text>
</TextBlock>
The order of the bindings decides the priority, with the highest priority first. In this case the Fast binding (lowest priority) will populate the textblock immediately because you might have that bound to a string property "Loading..." or "Sorting..." depending on what is happening at the time, and there is no delay.
But later when the slow async binding's property returns a value, it's higher priority means it will then take over, since it is earlier in the list, and its results will be bound instead, showing actual results.
If you need to populate a progress popup you may be able to implement that in the getter of the bound property in your ViewModel, though I haven't tried anything like this.
According to the docs,
While waiting for the value to arrive, the binding reports the FallbackValue, if one is available, or the default value of the binding target property.
You can use this value to display a message to the user while the binding is loading.
Related
I am familiar with bindings with curly braces, like {{variable}}, from Polymer 0.5.
However, in examples and code snippets for the release version of Polymer, I've begun to notice bindings with square brackets, such as [[variable]], as well.
Does {{variable}} mean something different now, or is it the same and [[variable]] is just an addition? What is the difference between binding to [[variable]] and {{variable}} in Polymer?
Just as you've noticed, there are now two different syntaxes for data-binding, which have different purposes:
{{variable}} indicates that you would like Polymer to automatically detect whether or not the binding should be one-way or two-way.
[[variable]] indicates that you want the binding to one-way only.
Why the change?
Polymer 1.x differs from older versions is that bindings are now one-way by default, much unlike 0.5, where they were always two-way.
In other words, if you write
<my-element some-property="{{myVariable}}"></my-element>
then by default, when
myVariable is changed, Polymer updates the binding, and thus updates my-element's someProperty.
someProperty is changed, Polymer does not update the binding to myVariable.
This is always the case unless you set notify:true on the property inside my-element:
Polymer({
is: 'my-element',
properties: {
someProperty: {
notify: true,
...
With notify: true, the binding is now two-way, so when
myVariable is changed, Polymer updates the binding to someProperty.
someProperty is changed, Polymer also updates the binding to myVariable.
This behaviour (when using notify: true) used to be default in 0.5; now you must ask for it explicitly.
When to use [[variable]]
There's no technical reason why you must use [[variable]], because Polymer will automatically detect whether bindings are one or two-way with {{variable}}. So why would you use it?
Let's say you're working in a large project, and you know that based on the way that data flows in a particular page/element, a certain property should never be changed by the element it is being bound to, for example in the case of an element which functionally serves a purpose as a label:
<display-data source-data="{{data}}"></display-data>
...
<data-editor source-data="{{data}}"></data-editor>
Everything looks good! The data property is bound to both the display-data element and data-editor elements, and will be automatically shared between them. (In this example, assume display-data's sole purpose is to preview the data that it is bound to.)
One day, you or someone else is editing display-data, and you forget about the situation in which it is being used in above. For an entirely different use-case, you or the other developer would like display-data to also format or otherwise modify the data it is given and push it back towards any other elements that may be bound to it. You/they edit display-data as such:
Add notify: true to sourceData, to allow two-way data-binding.
Add code into display-data which modifies the sourceData property.
This works great for all the pages that needed this functionality. But on the page mentioned before, this was not intended and ends up garbling the data that data-editor sees!
This problem would have been avoided had:
The dev team communicated better and had been more considerate of where elements are being used,
and/or [[data]] was used instead of {{data}} in the page/element in question.
With
<display-data source-data="[[data]]"></display-data>
...
<data-editor source-data="{{data}}"></data-editor>
data-editor can change data, but display-data will only ever be able to read data, and won't be able to change its value when it changes the value of its sourceData property, even when notify: true is set on sourceData.
Therefore, it could potentially be a good idea to:
Use [[variable]] whenever you need to bind to variable. This way, you enforce the direction through which data should flow in your element/page/application.
Use {{variable}} whenever you know that the binding must be two-way.
According to the documentation,
To make your code more easier to read, you may want to use the [[property]] form by default, and only use {{property}} for two-way bindings.
This being said, however, it ultimately comes down to a matter of choice. If you want to forego the use of [[variable]], no one is stopping you and you will not start any fires.
I was wondering how to bind values where the source of the bind could be null.
I have a property:
private ObjectProperty<Operation> operation = new SimpleObjectProperty<>(null);
I also have a text field:
#FXML
private Text txtCurrentOperation;
I would like to bind the textProperty of the field to the value of the operation object.
My first thought was to use FluentAPI with its when/then/otherwise construct, but it is eagerly evaluated so the solution:
Bindings.when(operation.isNotNull())
.then("null")
.otherwise(operation.get().getName()));
will throw a NPE, because the parameter of otherwise is evaluated no matter what the result of the when.
My next idea was to use lambda somehow:
txtCurrentOperation.textProperty().bind(() ->
new SimpleStringProperty(
operation.isNotNull().get() ? "Null" : operation.get().getName()
));
But the bind has no lambda enabled solution. (Later I realized that it couldn't have, becasue the real work goes backward: the change of the binded object (operation) will trigger the update of the binder (the field text property).)
Some articles I found suggested to use an "extremal" value for the property instead of null. But Operation is a complex and heavy weight component so it is not trivial to construct an artifical instance to represent null. Even more, this seems to me boilercode, something the binding mechanism is designed to help eliminating.
My next try was to logically swap the binding direction and add listener to the operation property and let it update the field programatically. It works and rather simple as long as the need of update only depends the operation object instances:
operation.addListener((e) -> {
txtCurrentOperation.setText(operation.isNull().get() ?
"Null" : operation.get().getName());
});
operation.set(oper);
It is relatively simple, but doesn't work: it throws "A bound value cannot be set." exception and I don't see why is the text property of the control regarded as bound.
I ran out of ideas. After much searching, I still cannot solve the simple problem to update a text field differently based on whether the source is null or not.
This seems so simple and everyday problem, that I am sure I missed the solution.
If a 3rd party library is an option, check out EasyBind. Try something like this:
EasyBind.select(operation)
.selectObject(Operation::nameProperty)
.orElse("null");
There's also a JavaFX JIRA issue for the type of functionality provided by EasyBind. If you don't want to use a 3rd party library, try Bindings.select:
Bindings.when(operation.isNotNull())
.then("null")
.otherwise(Bindings.select(operation, "name"));
Be aware the null checking in Bindings.select isn't super efficient. There's a JIRA issue for it.
Just in case if somebody using not Java itself but Kotlin.
It is a good idea to use wonderful tornadofx library.
There you can just use operation.select{it.name}. Although, this feature seems not to be documented yet, so it took some time to discover it.
In my main window (QMainWindow) I have a QTableView (named commandsTableView). Now I want to react on its selection changes.
I made a slot and connected it manually to ui.commandsTableView->selectionModel(). All works fine.
But then I thought: why not use auto-connection (especially that there will be more connections to be done)? At least it will add more force to consistent naming rules.
Yet I wasn't able to find proper name syntax. I tried:
on_commandsTableView_selectionModel_selectionChanged,
on_commandsTableViewSelectionModel_selectionChanged,
on_commandsTableView_selectionChanged,
on_commandsTableView___selectionChanged
but neither worked. In all cases there is there is a message on output when running the app (with corresponding slot name, here only first given as an example):
QMetaObject::connectSlotsByName: No matching signal for on_commandsTableView_selectionModel_selectionChanged(QItemSelection,QItemSelection)
(Why there are no assertions in response for connection errors - that I cannot understand. I lost much time wondering what is wrong before I spotted those - and alike - messages on output.)
The object returned by ui.commandsTableView->selectionModel() has an empty name. But setting it to selectionModel prior to making a call to connectSlotsByName doesn't help either.
According to the documentation connectSlotsByName() only supports signatures like
void on_<object name>_<signal name>(<signal parameters>);
According to the sources that's the only form it checks (watch how it collects a list of children, then matches parent's method names against names of the children).
Hence, to be able to use auto-connection you would have needed a named selection model, which would continue existing from the call to connectSlotsByName() onwards. Each time you change the selection model (not likely) or the model (likely) you'd have to name the selection model and auto-connect again. But alas connectSlotsByName() will duplicate all other connections as it doesn't seem to check if connections are unique, so we have to connect signals to such dynamic children as models, scenes etc manually.
I think it's
on_selectionModel_selectionChanged(const QItemSelection & selected, const QItemSelection & deselected)
How can I refresh view after a certain event?
I have a view which contains multiple groups. I want to show or hide some groups.
onCreationComplete() or initialize() method works only at the beginning of the view creation.
Try invalidateDisplayList() on the view
Let me know if that doesn't do the trick and we'll try some other tricks.
I personally don't like the answer that says to call invalidateDisplayList (sorry no offense Nate nothing personal). I feel it's too vague and doesn't explain what this does under the hood and furthermore you shouldn't have to call it directly in cases such as the one explained in the OPs question. You can simply create booleans that are bindable for each of the groups you'd like to show/hide then in the event handler set those booleans to the appropriate value and if they are bound to the visible and include in layout properties of the containers those containers will internally call invalidateDisplayList after calling set visible and consequently commitProperties.
This is basically what happens under the hood as I understand it: The way this works is values aren't committed or used to update the display until the next frame this way it doesn't get bogged down doing unnecessary layout calculations. So you update the bindable property which fires an event which triggers a notification in the listener (in this case a function that sets the property on your control), that in turn passes along the value to the control which sets an internal flag to update the property and calls invalidateProperties. When it hits the next frame redraw it sees that the properties flag is dirty (true) and then calls commitProperties, this computes/sets the appropriate values (possibly also invalidating then "fixing" the size using invalidateSize() and measure()) and calls invalidateDisplayList, then during the same frame it sees that the display list flag is dirty so it calls updateDisplayList, here it uses the values of the properties to draw appropriately.
You should also be able to achieve this using states, which add or remove children from the display list based on an array of "actions" for each state.
printableInvoice.addEventListener(batchGenerated, printableInvoice_batchGeneratedHandler);
Results in this error:
1120: Access of undefined property batchGenerated. I have tried it as FlexEvent.batchGenerated and FlashEvent.batchGenerated.
The MetaData and function that dispatches the even in the component printableInvoice is all right. It I instantiate printableInvoice as an mxml component instead of via action-script it well let put a tag into the mxml line: batchGenerated="someFunction()"
Thanks.
batchGenerated should be a string.
It looks like your application dispatches an event whenever the batch is generated.
I'm assuming inside your code you have something along the lines of either:
dispatchEvent( new BatchEvent("batchGenerated") );
or
dispatchEvent( new BatchEvent(BatchEvent.BATCH_GENERATED) );
The second way is usually preferred as using variables instead of magic strings gives you an extra level of compile time checking.
The first required parameter of events is typically the type of the event - Event.CHANGE (aka "change"), FlexEvent.VALUE_COMMIT (aka "valueCommit") etc.
This is what the event listener is actually comparing against.
So in your event listener code above, you would want to change the line to be either:
printableInvoice.addEventListener("batchGenerated", printableInvoice_batchGeneratedHandler);
or hopefully
printableInvoice.addEventListener(BatchEvent.BATCH_GENERATED, printableInvoice_batchGeneratedHandler);
If you want to go further, the Flex documentation goes into some detail as to how the event system works, and how the events are effectively targeted and handled through the use of the Capture, Target, and Bubble phases.