How to make JavaFX ListProperty modifiable only through custom methods - data-binding

I have a private list and I don't want that it can be modified from outside in general. Just adding from outside is allowed and only if the object is valid. Therefore I used to write it like this:
private List<Object> list = new ArrayList<>();
public List<Object> getList()
{
return Collections.unmodifiableList(list);
}
public void addObject(Object object)
{
if (isObjectValid(object)) //any validation
list.add(object);
}
Now for JavaFX purposes I turn the list to a property:
private ListProperty<Object> list =
new SimpleListProperty<>(FXCollections.observableArrayList());
To profit from the benefits of an property like data binding and the ListChangeListener I have to provide the property to the outer world. But then access to all methods of a list is provided, too. (To use a ReadOnlyListProperty has no effect since the list instance itself will never change.) What can I do to achieve all goals:
private ListProperty
ListChangeListener can be added from outside
Usable for binding dependencies from outside (the create methods form class Bindings)
No modifying of the property or list instance itself
Modifying of list content from outside only through my own methods

Not tested, but try:
private ListProperty<Object> list = new SimpleListProperty<>(FXCollections.observableArrayList());
private ReadOnlyListWrapper<Object> publicList = new ReadOnlyListWrapper<>();
and in the constructor:
publicList.bind(Bindings.createObjectBinding(
() -> FXCollections.unmodifiableObservableList(list.getValue()),
list));
then your accessor method is
public ReadOnlyListProperty<Object> getList() {
return publicList.getReadOnlyProperty();
}

Related

How to sort a JavaFX ListProperty

it seems I have encountered a problem with ListProperties. ObservableLists implement the marker interface SortableList that allows them to be sorted efficiently, firing only a single event. ListProperties do not implement this interface (how could they...?). Instead they use the default implementation of the List interface, firing a lot of changes.
The only solution I can see would be to call sort() on the underlying List directly. But this collides with the scheme of returning the Property itself:
public ObservableList getSomeList()
{
return someListProperty();
}
which ensures that ListChangeListener remain registered when the underlying List is exchanged.
I would be happy to get some input, maybe I missed something?
I guess the SortableList you refer to is the one used in FXCollections.sort.
ListProperty could implement the SortableList interface.
It may indeed be a good idea, since this would allow you to choose the way the wrapped list is sorted, if e.g. FXCollections.sort is used on the property. You could use FXCollections.sort on the contained list in this case.
How could they? Like this:
class MyListProperty<T> extends ListPropertyBase<T> implements SortableList<T> {
...
#Override
public void sort() {
ObservableList<T> list = getValue();
if (list != null) {
FXCollections.sort((ObservableList<Comparable>) list);
}
}
#Override
public void sort(Comparator<? super T> comparator) {
ObservableList<T> list = getValue();
if (list != null) {
FXCollections.sort(list, comparator);
}
}
}
The only problem is, that SortableList is inside the com.sun.javafx.collections package (see It is a bad practice to use Sun's proprietary Java classes?).
About your collision with the property scheme: there is none, if you define the property the intended way, see Using JavaFX Properties and Binding section Understanding Properties
The property would be implemented like this:
private final ListProperty<MyClass> someList = ...;
public ObservableList<MyClass> getSomeList() {
return someList.get();
}
public void setSomeList(ObservableList<MyClass> newList) {
someList.set(newList);
}
public ListProperty<MyClass> someListProperty() {
return someList;
}
The ListProperty has to ensure the ListChangeListeners registered to it receive the change events from the wrapped list.
Maybe you got confused with readonly list properties used in fxml, but a ListProperty is not readonly.
You could still use this property in a fxml file, but you'd need to use a value of type ObservableList:
<!-- imports -->
<ContainingClass xmlns:fx="http://javafx.com/fxml/1">
<someList>
<FXCollections fx:factory="observableArrayList">
<!-- list content goes here -->
</FXCollections>
</someList>
</ContainingClass>

Flex - how to detect if Object DATA has changed?

In Flex (Flash Builder 4), I need a way to know if something in an array collection has changed.
I have a custom object:
[Bindable]
public var _myobject:MyObject;
It's basically just a class containing a bunch of different String and Number properties.
I need a reliable way to know if any of the properties have been changed. For example, I am binding the properties to a user interface (fields), but it's also possible for some of the properties to change through code.
Is there a way to do this? I found ChangeWatcher, but that looks like it only looks at a single simple property, such as a String or Number. I need to watch or detect changes in all the properties in my object, hopefully without having to add ChangeWatcher events to every property. Is this possible?
You're probably better off just dispatching binding events on the specific properties you want bindable. Better yet, dispatch a custom binding event, so that all of the things that are bound don't have to filter for "is this the property I care about?" It's really easy with Flash Builder 4.5 to do this, just select your variable name and press Ctrl-1, select "Create getter and setter," select getter and setter and check "Bindable" and "create custom event."
This will create code for you that looks something like this:
private var _yourProperty:String;
[Bindable (event='yourPropertyChange')]
public function get yourProperty():String {
return _yourProperty;
}
public function set yourProperty(value:String):void {
if (value !=== _yourProperty) {
_yourProperty = value;
dispatchEvent(new Event('yourPropertyChange'));
}
}
This will be much less verbose and more performant than the code that Flash Builder generates for you behind the scenes when you just use the Bindable tag on its own.
If you use defined classes as VO/DAO and apply the [Bindable] tag to the class, this will do binding on all properties for you (so long as they are read/write).
Anonymous object detection is difficult at best, let alone adding additional headaches of loosing compiler type checking.
Super basic example: - the key is to tie it to the dispatcher, so internally it can send out the PropertyChangeEvent.
[Bindable]
public class Actor extends EventDispatcher
{
public var fName:String;
public var lName:String;
public var age:uint;
public function get displayName():String
{
return lName +', '+ fName;
}
public function Actor()
{
super();
}
}
public class BindableDictionary extends EventDispatcher {
public function BindableDictionary() {
super();
}
public var dictionary:Dictionary = new Dictionary();
[Bindable("change")]
public function get(key:Object):Object {
return dictionary[key];
}
public function put(key:Object, value:Object):void {
dictionary[key] = value;
dispatchEvent(new Event(Event.CHANGE));
}
}
maybe this class will give you some new idea

AutoMapper pass parent reference when mapping child object

I am trying to use AutoMapper to map some DTO (data contract) objects received from a web service into my business objects. The root DTO object contains a collection of child objects. My business object also has a child collection of child business objects. In order to get AutoMapper to work, I had to include a setter on the collection property in my business object or the collection would always be empty. In addition, I had to add a default constructor to the collection type. So, it appears to me that AutoMapper is instantiating a new collection object, populating it and setting as the collection property of my business object.
While this is all well and good, I have additional logic that has to be wired up when the collection is created and having the default constructor defeats the purpose. Essentially, I am establishing the parent-child relationship and wiring up some events so they bubble from child to parent.
What I would like to do is to have AutoMapper simply map the child objects from the DTO's collection to the existing collection on my BO. In other words, skip creating a new collection and simply use the one the business object already has.
Is there any way to easily accomplish this?!?!?
UPDATE
Perhaps a better question, and simpler solution to my problem, is if it is possible to define arguments that AutoMapper will pass to the collection when instantiated? My child collection is defined like this:
public class ChildCollection : Collection<ChildObjects>
{
public ChildCollection(ParentObject parent) { Parent = parent; }
}
If I can configure AutoMapper to use this constructor and pass in the proper object, that would be PERFECT!
ANOTHER UPDATE
For the sake of clarity, here are the other classes in the problem space:
public class ParentObject
{
private ChildCollection _children;
public ChildCollection Children
{
get
{
if (_children == null) _children = new ChildCollection(this);
return _children;
}
}
}
public class ParentDTO
{
public ICollection<ChildDTO> Children { get; set; }
}
public class ChildDTO
{
public String SomeProperty { get; set; }
}
I configure AutoMapper this way:
Mapper.CreateMap<ParentDTO, ParentObject>();
Mapper.CreateMap<ChildDTO, ChildObject>();
Doing so this way and I have to add a setter to the Children property in ParentObject and a default (parameterless) constructor to ChildCollection. While I can work around the need to define the parent-child relationship, it seems that it would be logical to expect AutoMapper to support configuring the map to use a specific constructor when creating the child collection. Something like this:
Mapper.CreateMap<ParentDTO, ParentObject>()
.ForMember(obj => obj.Children, opt.MapFrom(dto => dto.Children))
.ConstructUsing(col => new ChildCollection(obj));
Notice that I am passing in the reference to "obj" which is the ParentObject instance being mapped.
It turns out that the answer was right there all along. The UseDestinationValue option does exactly what I want.
This options instructs AutoMapper to use the existing property on the target object and map any child properties or collection items into that object rather than creating a new proxy object.
So, here's all I have to do in my application:
Mapper.CreateMap<ParentDTO, ParentObject>()
.ForMember(obj => obj.Children,
opt.UseDestinationValue());
And, voila! Now I can instantiate the child collection, with parent reference, and setup the reference back to the parent in each item as it is added to the collection.
If I understood your problem, you should be able to use ConstructUsing as stated in this answer:
Automapper - how to map to constructor parameters instead of property setters
Its possible for EntityFramework (mvc or core) with AutoMapper.Collection.EntityFrameworkCore or EntityFramework by matching child ids to destination object ids like below
_config = new MapperConfiguration(cfg =>
{
cfg.AddCollectionMappers();
cfg.CreateMap<Order, OrderDto>()
.EqualityComparison((odto, o) => odto.Id == o.Id)
.ReverseMap();
cfg.CreateMap<OrderDetail, OrderDetailDto>().EqualityComparison((odto, o) => odto.Id == o.Id).ReverseMap();
});
In my case i have a List<Order> and one of my order contains a list of items such as List<OrderDetails> if i want to map List<Order> to List<OrderDto> with List<OrderDetailDto> that is not possible to mapping configuration. But i done it by seperating them like above. And i can use it like below
public int AddMany(List<OrderDto> orderDtos)
{
try
{
List<Order> orders = new List<Order>();
foreach (var oi in orderDtos)
{
var oneOrder = _mapper.Map<OrderDto, Order>(oi);
oneOrder.OrderDetails = new List<OrderDetail>();
foreach (var oid in oi.OrderDetails)
{
var oneOrderItem = _mapper.Map<OrderDetailDto, OrderDetail>(oid);
oneOrder.OrderDetails.Add(oneOrderItem);
}
orders.Add(oneOrder);
}
_orderRepository.InsertMany(orders);
return _uow.SaveChangesAsync().Result;
}
catch (Exception ex)
{
return 0;
}
}
There would be a manner to configuring it from the top but its very difficult, i couldn't find it now. But this maybe a resulation for someone.
Also in my opinion Mapster powerfull than autofac for those mapping configurations.

Setting a generic delegate to a class-level variable

I bumped into an additional question that I needed in regards to this: Using an IEnumerable<T> as a delegate return type
From the above solution, the following was suggested:
class Example
{
//the delegate declaration
public delegate IEnumerable<T> GetGridDataSource<T>();
//the generic method used to call the method
public void someMethod<T>(GetGridDataSource<T> method)
{
method();
}
//a method to pass to "someMethod<T>"
private IEnumerable<string> methodBeingCalled()
{
return Enumerable.Empty<string>();
}
//our main program look
static void Main(string[] args)
{
//create a new instance of our example
var myObject = new Example();
//invoke the method passing the method
myObject.someMethod<string>(myObject.methodBeingCalled);
}
}
Notice that in someMethod, the delegate "method()" is called. Is there anyway to set a class-level delegate that is called later on?
I.e:
class Example {
//the delegate declaration
public delegate IEnumerable<T> GetGridDataSource<T>();
//this fails because T is never provided
private GetGridDataSource<T> getDS;
//the generic method used to call the method
public void someMethod<T>(GetGridDataSource<T> method)
{
getDS = method;
}
public void anotherMethod() {
getDS();
}
}
Depending on what you are trying to achieve and where you have flexibility in your design, there are a number of options. I've tried to cover the ones that I feel most probably relate to what you want to do.
Multiple values of T in a single instance of a non-generic class
This is basically what you seem to want. However, because of the generic nature of the method call, you'll need a class level variable that can support any possible value of T, and you will need to know T when you store a value for the delegate.
Therefore, you can either use a Dictionary<Type, object> or you could use a nested type that encapsulates the class-level variable and the method, and then use a List<WrapperType<T>> instead.
You would then need to look up the appropriate delegate based on the required type.
class Example {
//the delegate declaration
public delegate IEnumerable<T> GetGridDataSource<T>();
//this works because T is provided
private Dictionary<Type, object> getDSMap;
//the generic method used to call the method
public void someMethod<T>(GetGridDataSource<T> method)
{
getDSMap[typeof(T)] = method;
}
//note, this call needs to know the type of T
public void anotherMethod<T>() {
object getDSObj = null;
if (this.getDSMap.TryGetValue(typeof(T), out getDSObj))
{
GetGridDataSource<T> getDS = getDSObj as GetGridDataSource<T>;
if (getDS != null)
getDS();
}
}
Single value of T in a single instance of a non-generic class
In this case, you could store the delegate instance in a non-typed delegate and then cast it to the appropriate type when you need it and you know the value of T. Of course, you'd need to know T when you first create the delegate, which negates the need for a generic method or delegate in the first place.
Multiple values of T in multiple instances of a generic class
Here you can make your parent class generic and supply T up front. This then makes the example you have work correctly as the type of T is known from the start.
class Example<T> {
//the delegate declaration
public delegate IEnumerable<T> GetGridDataSource<T>();
//this works because T is provided
private GetGridDataSource<T> getDS;
//the generic method used to call the method
public void someMethod<T>(GetGridDataSource<T> method)
{
getDS = method;
}
public void anotherMethod() {
if (getDS != null)
getDS();
}
}
You either need to make the type generic as well, or use plain Delegate and cast back to the right type when you need to invoke it. You can't just use T outside a generic context - the compiler will think you're trying to refer to a normal type called T.
To put it another way - if you're going to try to use the same type T in two different places, you're going to need to know what T is somewhere in the type... and if the type isn't generic, where is that information going to live?

Is it possible to remove properties from a dynamic class?

I have a dynamic ActionScript Class that is used to send parameters to a WebService. Some of these parameters are always present, so they are public properties of the Class:
package
{
[Bindable]
public dynamic class WebServiceCriteria
{
public var property1:int;
public var property2:String;
public var property3:String;
public var property4:String;
}
}
But, I am also adding properties at runtime that can change over time:
criteria.runTimeProperty = "1";
I'm not very familiar with using dynamic classes, so I was wondering if it is possible to "remove" the new property. Let's say the next time I call the WebService I don't want that property sent - not even as a null. How can I remove it from the Class instance without creating a new instance each time?
I believe all you'd need to do is this:
delete criteria.runTimeProperty;
or
delete criteria["runTimeProperty"];
Either should do the same thing.
See the delete documentation for specifics.

Resources