Route PropertyChanged Event from static ObservableCollection to non-static wrapper class - data-binding

I am trying to bind an ObservableCollection, which is filled in a Background thread, to a charting Control in the UI.
Therefore i have a static class "Core", which have a member "DataState". This DataState class owns the ObservableCollection "SensorData", which is filled in the aforementioned Background Task.
As there is no possibility to do UWP XAML Binding for static properties i wrote a wrapper class "DataWrapper" which is nonstatic and refers to the static Core.DataState.SensorData-object.
Here's some of my Code:
Core.cs:
public static partial class Core
{
private static DataState m_DataState;
public static DataState DataState
{
get
{
return m_DataState;
}
set
{
if (value != null)
{
m_DataState = value;
}
}
}
}
DataState.cs:
public class DataState
{
private ObservableCollection<SensorData> m_SensorData = new ObservableCollection<SensorData>();
public ObservableCollection<SensorData> SensorData
{
get
{
return m_SensorData;
}
set
{
if (value != null)
m_SensorData = value;
}
}
DataWrapper.cs:
public class DataWrapper
{
public ObservableCollection<SensorData> SensorData
{
get
{
return Core.DataState.SensorData;
}
}
}
XAML:
<Charting:LineSeries Name="MySeries" Title="Title" IndependentValuePath="X" DependentValuePath="Y" ItemsSource="{x:Bind DataWrapper.SensorData}"></Charting:LineSeries>
where X and Y are the variables contained in the SensorData-Object.
So, if i wait to Show the Charting-Control until there's some data in the ObservableCollection this data is nicely plotted into my Control. But after that recently added data is not plotted anymore.
Therefore i am looking for a way to route the PropertyChanged-Event from Core.DataState.SensorData somehow to DataWrapper.SensorData. Is there any possibility to do this?
Is the structure of this Problem clear to you? I think my descriptions sounds a bit confusing...
Thank you in advance for any help :-)

Related

Binding labels textProperty to object's property held by another final ObjectProperty

In app I'm bulding I used data model presented by James_D here:
Applying MVC With JavaFx
I just can find a way to bind labels text to property of object held in DataModel
Data is structured like this:
model class Student
//partial class
public class Student {
private final StringProperty displayName = new SimpleStringProperty();
public final StringProperty displayNameProperty(){
return this.displayName;
}
public Student(){
}
public final String getDisplayName() {
return this.displayNameProperty().get();
}
public final void setDisplayName(String displayName) {
this.displayNameProperty().set(displayName);
}
}
Student instaces are held by StudentDataModel class
public class StudentDataModel {
// complete student list
private final ObservableList<Student> studentList = FXCollections.observableArrayList();
private final ObjectProperty<Student> selectedStudent = new SimpleObjectProperty<>(new Student());
public final Student getSelectedStudent() {
return selectedStudent.get();
}
public final ObjectProperty<Student> selectedStudentProperty() {
return selectedStudent;
}
public final void setSelectedStudent(Student student) {
selectedStudent.set(student);
}
}
StudentList is displayed by Table View, there is change listener that sets selectedStudent like this:
public class TableViewController {
public void initModel(StudentDataModel studentDM) {
// ensure model is set once
if (this.studentDM != null) {
throw new IllegalStateException("StudentDataModel can only be initialized once");
}
this.studentDM = studentDM;
tableView.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
if (newSelection != null) {
studentDM.setSelectedStudent(newSelection);
}
});
}}
There is another controller ActionsBarController that has label to display selected student (this seems redundant, but there is option for selecting multiple objects to perform bulk operations).
StudentDataModel is initialized properly (I can see it in debuger) but below doesn't do anything:
chosenStudentLabel.textProperty().bind(studentDM.getSelectedStudent().displayNameProperty());
//this shows class name with instance number changing correctly
chosenStudentLabel.textProperty().bind(studentDM.selectedStudentProperty().asString());
I could inject ActionsBarController to TableViewController and change label text from change Listener there, but this seems counter productive with data model.
What am I doing wrong?
Your code doesn't work, because you call (and evaluate) getSelectedStudent() at the time the binding is created (i.e. when you initialize the model). As a consequence, you only bind to the displayName property of the student that is selected at that time. (If nothing is selected, you'll get a NullPointerException.) The binding will only change if that initially-selected student's display name changes; it won't change if the selection changes.
You need a binding that unbinds from the old selected student's display name, and binds to the new selected student's display name, when the selected student changes. One way to do this is:
chosenStudentLabel.textProperty().bind(new StringBinding() {
{
studentDM.selectedStudentProperty().addListener((obs, oldStudent, newStudent) -> {
if (oldStudent != null) {
unbind(oldStudent.displayNameProperty());
}
if (newStudent != null) {
bind(newStudent.displayNameProperty());
}
invalidate();
});
}
#Override
protected String computeValue() {
if (studentDM.getSelectedStudent() == null) {
return "" ;
}
return studentDM.getSelectedStudent().getDisplayName();
}
});
Note that there is also a "built-in" way to do this, but it's a bit unsatisfactory (in my opinion) for a couple of reasons. Firstly, it relies on specifying the name of the "nested property" as a String, using reflection to access it. This is undesirable because it has no way to check the property exists at compile time, it requires opening the module for access, and it is less good performance-wise. Secondly, it gives spurious warnings if one of the properties in the "chain" is null (e.g. in this case if the selected student is null, which is will be initially), even though this is a supported case according to the documentation. However, it is significantly less code:
chosenStudentLabel.textProperty().bind(
Bindings.selectString(studentDM.selectedStudentProperty(), "displayName")
);

Prism6 shared service and dependency property

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 ) );
}

Calling em.merge() on child entity gives parent object in return while using SINGLE_TABLE inheritence

Eclipselink 2.6.3 with JPA 2.0
I have an issue with SINGLE_TABLE inheritance strategy as you can see I have class A which is extended by Z & X. When I query and fetch List of Z or X entities and try to change something and update them one by one, in the process when I call em.merge() for fetching merged clone object it gives back class A which is strange.
As I already have class extractor which decides what class should be returned based on a specific field value.
This issue is intermittent and can't be replicated every time, I've also debugged in UnitOfWorkImpl method
public Object mergeCloneWithReferences(Object rmiClone, MergeManager manager) {
if (rmiClone == null) {
return null;
}
//this line should always give correct entity back.. but doesnt happen why ?
ClassDescriptor descriptor = getDescriptor(rmiClone);
if ((descriptor == null) || descriptor.isDescriptorTypeAggregate()) {
if (manager.getCascadePolicy() == MergeManager.CASCADE_BY_MAPPING){
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("not_an_entity", new Object[]{rmiClone}));
}
return rmiClone;
}
//CR#2272
logDebugMessage(rmiClone, "merge_clone_with_references");
ObjectBuilder builder = descriptor.getObjectBuilder();
Object implementation = builder.unwrapObject(rmiClone, this);
Object mergedObject = manager.mergeChanges(implementation, null, this);
if (isSmartMerge()) {
return builder.wrapObject(mergedObject, this);
} else {
return mergedObject;
}
}
Can someone point out what's going wrong ?
Class A
#Entity
#Table(name="TABLE_A")
#Customizer(ACustomizer.class)
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#ClassExtractor(AExtractor.class)
#InstantiationCopyPolicy
#Cacheable
#Cache( alwaysRefresh=true,
refreshOnlyIfNewer=true,
expiry=300000,
coordinationType = CacheCoordinationType.SEND_NEW_OBJECTS_WITH_CHANGES)
public class A implements Serializable {
#Column(name="ABC")
private String abc;
//some fields
}
Class Z
#Entity
#Customizer(ZCustomizer.class)
public class Z extends A{
//some fields
}
class X
#Entity
public class X extends A{
//some fields
}

structuremap enrichwith not overriden

I am trying to find a way to override a structuremap registry statement containing EnrichWith like so (here is the Registry class):
public class MyRegistry : Registry
{
public MyRegistry()
{
For(typeof(IMyList<int>)).EnrichWith(x => DecorateMyList(x)).Use(typeof(MyListA<int>));
For(typeof(IMyList<int>)).Use(typeof(MyListB<int>));
For<IMyList<string>>().Use<MyListA<string>>();
For<IMyList<string>>().Use<MyListB<string>>();
}
private object DecorateMyList(object o)
{
var genericParameters = o.GetType().GetGenericArguments();
var myListDecoratorType = typeof(MyListDecorator<>).MakeGenericType(genericParameters);
var decorated = Activator.CreateInstance(myListDecoratorType, new []{o});
return decorated;
}
}
public class MyRegistryUser
{
ObjectFactory.GetInstance<IMyList<string>>(); // Good: Returns an instance of MyListB<string> as expected
ObjectFactory.GetInstance<IMyList<int>>(); // Bad: Returns an instance of the decorator containing MyListB<int> - my second rule should have overridden the EnrichWith as well.
}
Am I right to think that there is a glitch in structure map or is there something I'm not seeing?
Thanks in advance

flex inheritance class share

//Base.as
public class Base
{
private var _foo:String;
[Bindable]
public function set foo(value:String):void
{
_foo = value;
}
public function get foo():String
{
return _foo;
}
/*
Many many setter/getter, methods, events
*/
}
//Control.as
public class MyControl extends Group
{
public function MyControl()
{
}
}
//Window.as
public class MyWindow extends spark.components.Window
{
public function MyWindow()
{
}
}
//Module
public class MyModule extends spark.modules.Module
{
public function MyModule()
{
}
}
I want to expose (friendly) Base properties, methods and events on the other classes. Something like this:
var window:MyWindow = new MyWindow();
window.foo = 'Hello World!';
var module:MyModule = new MyModule();
module.foo = 'bar';
<namespace:MyControl foo="Hello World!"/>
I don't want define all the properties in each class because they are many and the same for all of them.
Ideally would define something like:
public class MyControl extends Group, Base
{
public function MyControl()
{
}
}
(I know it can't be done.)
Thanks!
UPDATE:
Thanks again!
Maybe this clarify more my need... On business layer I have a variable called processID (and businessID, operationID, localityID, etc.) what be passed to Window from Menu, and Window passes it to Module. On Module Container, I have a CustomComponent what query database using this variable as parameter. This applied for all (almost) Components on Module. These variables are defined as level business layer, then I define a Class to store and manage these variables (and some related methods operating with these variables using business logic), so I can make a standalone class (or library) for every environment to reusing my common components. The idea is... insert a new CustomComponent and set these variables via mxml, like this:
<custom:MyCustomComponent id="zzz" processID="{processID}" businessID="{businessID}"/>
Module has the business logic for set (o not) any of the variables.
Otherwise, I would have to implement different logic for the CustomComponent (and Module) for read parent's variables and define these variables only in MyWindow (using composite pattern).
You can get your answer from following link -
http://flexinonroids.wordpress.com/2009/05/27/flex-3-dynamically-loading-components-at-runtime/
http://thecomcor.blogspot.in/2007/11/adobe-flex-dynamically-loading-classes.html
Or you can follow below approach -
1) Create an Interface as base
2) Extend your class with interface
3) Load class at runtime with SWFLoader.loaderContext.applicationDomain.getDefinition method
Thanks,
Varun
You can place your classes that require friendly access in the same package as your Base class, and define private fields without any access modifier( it is equivalent to internal modifier).
Otherwise, you can define your namespace like that:
namespace my_internal;
and then define class members like that:
my_internal var _foo:String;
after that, those members will be hidden for all code, except for code that contains
use namespace my_internal;
You can read more here:
http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f9e.html#WS5b3ccc516d4fbf351e63e3d118a9b90204-7f91
However, using 'friend access' can be an evidence of bad design, so if I were you I'd think twice before defining namespaces.
Update:
pseudo-superclass 1:
package proxy
{
public class Simple1
{
public var x:int;
public var y:int;
}
}
pseudo-superclass 2:
package proxy
{
import mx.controls.Alert;
public class Simple2
{
public var name:String = 'noname';
public function doAlert():void{
Alert.show(name);
}
//not normal method to replace 'this' with proxy
Simple2.prototype.doCrossClass = function doCrossClass():void{
Alert.show(''+(Number(this['x'])+Number(this['y'])));
}
}
}
Code for testing the result (looks as what you are expecting?):
var mega:Mega = new Mega();
mega.x = 100;
mega.y = 200;
mega.name = 'Multiple inheritance';
mega.doAlert();
mega.doCrossClass(); //300
And now pseudo-subclass with multiple inheritance:
package proxy
{
import flash.utils.Proxy;
import flash.utils.flash_proxy;
public dynamic class Mega extends Proxy
{
public function Mega()
{
super();
}
public var superArray:Array = [new Simple1(), new Simple2()];
flash_proxy override function getProperty(name:*):*{
for each(var superClass:Object in superArray){
if( name in superClass){
return superClass[name];
}
}
throw new Error('no such property');
}
flash_proxy override function setProperty(name:*, value:*):void{
for each(var superClass:Object in superArray){
if( name in superClass){
superClass[name] = value;
return;
}
}
throw new Error('no such property');
}
flash_proxy override function callProperty(name:*, ...args):*{
for each(var superClass:Object in superArray){
if( name in superClass){
var f:Function = superClass[name] as Function;
return f.apply(this, args);
}
}
throw new Error('no such function');
}
}
}
You can also want to use javascript-like class construction(i.e. just using simple Object and assigning properties and functions to it in any combinations you want).

Resources