My team is evaluating JavaFX as a platform for a database application which will make intense use of TableViews. We are under impression that in order to display data in tables we will have to sub-class TableView and write our own ValueFactory classes for each column data type and presentation mode we are going to need.
For example if we wanted to display bit fields as Yes/No text and on/off checkboxes, we would need 2 ValueFactories or one ValueFactory and two CellFactories for bit data type.
Q1: Is our understanding correct?
Q2: Do any 3d party libraries exist that would allow us to simply set a data binding property of their version of TableView to a ResultSet for example and automatically display data with minor tweaking of display mode?
As evaluation goes on there are more questions arising.
Q3: Willl we have to create a data row class for every SQL query and ObservableList for every class, which would mean that every time we changed returned columns, we would have to re-write data row class? Would we have to implement paging by keeping resultsets in memory and re-populating the ObservableLists on scrolling too?
Q1 - For each column you should specify valueFactory - very easy. If you don't want to show value as default you can specify cellfactory - not so easy. I think best practice is create own class which will extends TableView and you will specify everything you need. You can also create your own TableCell classes etc. I think this work is not so hard in developing javafx app.
Q2 - I don't know but i would create own classes.
Q3 - Observablelist should contain your entity class. Each query should return list of entity objects. Value factory is link with some entity object property.
Related
Trying to build an application with a UI in QML and accessing data from a Sqlite database.
The QML view has a TableView to display information in a data grid with a model in C++.
The model is a class inheriting from QSqlQueryModel with a query to the database: setQuery("SELECT * FROM Samples", GetDataBase())
I am adding a new row in the database table every second in another thread.
When I navigate to the view where the TableView is placed, the grid is populated with the information in the table. All good. But then, every time I add a new row I call setQuery again but the table is not updated. If I go back and forth to the view again it is populated with all the new rows.
I thought the view was "automatically" notified whenever the model changed but I suppose I am missing any kind of notification to let the view know that there is new rows or something??
Also...this is just a testing application but I foresee that in my real app the information to be displayed in the grid will change very fast and the table can have several rows of information (order hundred thousand rows) so I wonder if QSqlQueryModel is the right model for this kind data.
I am using Qt's Model View Programming on a database, where an object is represented using multiple tables. Assume the following object and coresponding database tables which perfectly fit my design:
TagObject
- id
- name
- usable
- information
tag_table
- id
- name
- usable
tag_info_table
- id_ref
- info
As you may see, the information property is separated into another table to prevent existence of NULL because this property is optional.
In the database I have a view which aggregates the values into one 'table' which can be queried using QSqlTableModel. Note that INSERTing data is not possible this way. As far as I could understand, the database design is not supported by Qt's classes, neither QSqlTableModel nor QSqlRelationalTableModel do support this. (Additionally QSqlQueryModel does not support inserts at all so this is out of question.)
Am I missing something? Is there any way to do this using Qt's SQL classes? Or is the only way to achive this subclassing QSqlQueryModel as pointed out here?
The model is read-only by default. To make it read-write, you must subclass it and reimplement setData() and flags(). Another option is to use QSqlTableModel, which provides a read-write model based on a single database table.
Edit: As for subclassing I found this reference as a nice entry point.
Ideally, the view should have appropriate triggers that will modify the underlying tables. Make the view writable and your problems go away: you can use a QSqlTableModel directly on that view, then.
Alternatively, you can have a QSqlTableModel for each table, and then write a custom proxy model that supports inserts and translates between the source models and forms the writable view. It'll be more work than writing the SQL triggers.
I have large collection of MyFile objects which are linked in all kind of ways between each other like spaghetti.
In addition, from this collection I create smaller subcollections of some items that are equal by some criteria.
(for example all files with the extension .txt, all files that belong to certain directory etc...)
Basically I have complex structure of linked lists in my business logic. Now I want to create ViewModel for this
in order to prepare it for View and this is where I hit the wall. I just can't figure out how to prepare this mess
and still keep everything efficient and organized.
First problem is that wrapping each collection in collectionViewModel by enumerating item by item and creating itemViewModel
will create duplicate itemViewModel for each item (since one item can be contained in several collections)
Second problem is how to keep everything updated? If for example an item1 in business logic changes its reference from item2
to item3, then ViewModels should update them accordingly.
I am really tempted to break from the MVVM pattern here even though I dont want it, and put bussines + presentation logic
in one object/class since this spaghetti structure seems a bit too much for my level of understanding of MVVM.
Thanks
Maybe I'm barking up the wrong tree here, but here goes.
You could have a Model which acts as a repository for all your file objects, and that also exposes an ItemAdded and ItemRemoved event, plus a Query method. You can then have a common ViewModel type that represents your view on this model (a ViewModel), but specializes by composing a query. In this way you can have ViewModel+Query (e.g. all files with extension txt) instance for each view you need to represent. The ViewModel would be responsible for executing the query on your Model (by calling the query method) and then turning the results into an observable collection of file items (or what-have-you). You can update your ViewModel in response to Model changes by subscribing to ItemAdded and ItemRemoved events. If on an ItemRemoved event your ViewModel file items collection contains the item, then remove it. If on an ItemAdded event the item matches the query condition for that ViewModel instance, then add it to the collection.
This allows you to have a single Model for all your files, and then a ViewModel(+Query) instance for each type of view you wish to represent. The ItemAdded and ItemRemoved event allow you to update your ViewModel. As the items in the ViewModels are observable collections, your databound views will update themselves.
Often I need to combine data from multiple tables and display the result in a GridView control.
I can write a Linq query inline in the Page_load event, return an anonymous type that combines all the fields that I need, and databind the result to the GridView control.
Problem: I use 'helper methods' as described by Scott Guthrie on his blog. Such a helper method cannot return an anonymous type. The query would have to be inline for this approach.
I can write a database view that returns the data that I need, and write a helper method with a query against this (new and known) type that it returns.
Problem: I will need a lot of views in my database schema, and I will introduce a lot of redundant aspects of my data. I also lose some of the advantage of using Linq - removing all business logic from the database.
I would like to take an approach that lets me keep the Linq queries in helper methods, yet allows me to access all the attributes that I need on the grid in their respective databinding expressions. Can this be done?
I asked the wrong question, as I frequently do. What prompted me to look into anonymous types was an apparent limitation of the GridView - my inability to use a databinding expression in an <asp:BoundField> (the DataField parameter only accepts column names of the table that the Linq query pulls in).
Turns out that in a TemplateField it is possible to use Eval and access members of the Linq data item, and Linq takes care of the query for me.
In other words, I can keep the query in my helper method, have it return a primary database table type (e.g. Account), and I bind the Accounts to the GridView.
In the databinding expressions I can access data members of the Account objects that reside in other tables, without having to explicitly pull them in in the query. Perfect.
I don't know if there is a viable way to achieve this using anonymous types. But I have a suggestion that will work in WinForms, but I am not sure about ASP.NET.
What you need is a type with properties where neither the number of properties, nor the types and names of the properties are known at compile time. One way to create such a thing is ICustomTypeDescriptor.
You have to create a type implementing this interface with an private backing store of objects backing the properties returned by the query for one row from the query. Then you implement GetProperties() to return one PropertyDescriptor per column and PropertyDescriptor.GetValue() and PropertyDescriptor.SetValue() to access the backing array.
By implementing PropertyDescriptor.Name you will get the correct column name; this will probably require another backing store storing the property names. And there is a lot more to implement, but in the end your new type will behave almost like a normal type - and now the if - if the control you are binding to knows about and uses ICustomTypeDescriptor.
UPDATE
I just found an bit of text stating that ASP.NET data binding knows and uses ICustomTypeDescriptor.
Scott's earlier post in the series talks about shaping the result set before inserting into a grid:
Part 3 - Querying our Database
Scroll down to "Shaping our Query Results".
We're planning to create a web application where users can build custom "forms," choosing which fields they would like, and how the data in those fields should be represented. Users can then fill out these forms in a DetailsView-like control, thereby creating "documents." The documents can be shown in a DetailsView, or certain fields of several of them can be shown in a GridView. At least, that's the idea.
The problem is that GridView and DetailsView seem to be specifically designed to access Properties on objects that come out of a DataSource. Since we want to have completely arbitrary forms, we can't restrict ourselves to building a class with Properties to represent each field. We have to be able to have any number of dynamically-specified fields on a form.
Is there any way to leverage the existing controls so we don't have to re-implement paging, sorting, and all the other things that GridViews are already set up to do, or will I just have to create my own GridView-like control from scratch?
Edit:
More specifically, the difficulty I am having is in getting inline editing to work on the GridView. For example, let's say that one of the "fields" that is added to a "form" is a calendar field, which should display a date as text in read-only mode, and display a calendar control in edit mode. When the "save" button is clicked, the date selected by the calendar control needs to be saved to the database as the new value for the given field of the given document (i.e. instance of the form). My initial idea was to create a special DataControlField class which, given a form field key, would know how to databind thusly:
FormDocument doc = DataBinder.GetDataItem(cell) as FormDocument;
FormFieldValue fieldValue = doc.FieldValues[FieldKey];
fieldValue.AddReadOnlyControls(cell);
... instead of:
Object dataObject = DataBinder.GetDataItem(cell);
cell.Text = DataBinder.GetPropertyValue(dataItem, FieldKey);
This would probably work for displaying the field values, but if the user tries to edit and save one of the FormDocuments I don't know how I would convince the GridView to do something like this:
doc.FieldValues[FieldKey] = newValue;
Currently, the API for DataControlField uses the ExtractValuesFromCell method to put the property name and value into an IOrderedDictionary. Those values are then applied to the given properties of the objects in the GridView's databound IEnumerable. The problem is, I can't work with properties of an object because in this case the object needs to have a completely arbitrary number of fields.
A GridView can be bound to any object that implements IEnumerable. The advantage of using one of the xDataSource controls is that it can implement paging and sorting for you without any additional code, but you certainly aren't tied to them.
If I understand your question correctly, you do not know the number of columns to display in the GridView until runtime. In that case, I would recommend building an array from your form data and binding the grid to that. You will have to implement paging and sorting yourself.
The DetailsView is not very customizable so you should take a look at the FormView. However, I think you are going to end up dynamically adding controls to whatever container you use.
What you need is totally dynamic GridView. I quess you would have to extend it with the controls ( functionalities ) in your description
Here's what I ended up doing:
I created a new data type that contained a Dictionary of answers, indexed by Field ID.
I created a new type of DataControlField with a FieldId property, which retrieves the proper answer value for that FieldId from the Dictionary mentioned above.
I added data type and data keys properties to this custom DataControlField and overrode the ExtractValuesFromCell method so that it could create a new instance of the answer class and add those values to a Dictionary, which was stored under the property name by which that dictionary would be found in the new data type mentioned in step 1.
I used my own GridView class, used the .NET Reflector to see how the normal GridView calls the ExtractValuesFromCell method, and then changed that so that it would pass the same Dictionary object in to each DataControlField. This way, each field could add to the same Dictionary, rather than replacing the Dictionary that the last one had added under the same property name.
I used a DataFieldGenerator to generate the one of my custom DataControlFields for every field associated with a given form, and I told the GridView to use that DataFieldGenerator to auto-generate its fields.
I set up my ObjectDataSource so that it would know how to save all the answer values from an object of the type mentioned in step 1.
It was tricky, but worthwhile.