Custom Binding of multiple fileds in Custom DataGridViewColumn(WinForms) - data-binding

I have a question regarding a data binding(of multiple properties) for custom DataGridViewColumn.
Here is a schema of what controls that I have, and I need to make it bindable with DataGridView datasource. Any ideas or a link to an article discussing the matter?
Controls
Graph Control(custom): Displayed in
the custrom DataGridView column. Has
properties like "Start Date",
"EndDate", Windows Chart control,
which is itself, bindable, etc.
Custom cell(DataGridViewCustomCell inherits
from DataGridViewCell) that holds
the Graph control and processes some
events(OnEnter event, for example,
passes the focus to the custom Graph
column for drag-n-drop type of
events, etc.)
Custom column(DataGridViewCustomColumn
inherits from DataGridViewColumn)
that defined the cell template type:
CellTemplate = new
DataGridViewCustomCell(); and also a
primary choice for data binding
Data Structure:
Main table to be displayed in other DataGridView Columns
Graph table - related to the Main table via parent-child relationship. Holds graph data
Chart table related to the graph table via parent-child relationship. Holds data for the win-form chart, which is a part of my Graph control.
So far I cannot even bind data from the Graph table to by Graph control or Graph-holding Column/Cell.

Thank you for your answer. My data sources is not a SQL data source, and as a matter of fact I was talking about datagridview for win-forms(I'm not sure that was clear).
As I did not get the reply on any of the forums I was asking the question, I figured, I would outline a solution I came up with, for those who may have a similar problem and for possible critique. :-)
(steps 1-2 are also explained in the famous MS example)
1. Create your own classes that inherit from DataGridViewColumn and DataGridViewCell, setup the column template;
2. Create your "CustomEdit" control
In the data item, whatever that is, a DataRow, or a List item, add a read-only property, that return the object itself. This property is bound to the custom column.
Custom Cell:
public partial class MyCell : DataGridViewCell
{
protected override void Paint(...)
{...} // draws control
// receives data item as a value
// in my case I have to custom-draw entire control in this fnc.
public override void InitializeEditingControl(...)
{...} // initialize control editing
// override some other properties
public override Type EditType {
get{
return typeof(MyEditControl);
}
}
public override Type ValueType{
get{
return typeof(MyItem);
}
}
}
Custom Column:
public partial class MyColumn : DataGridViewColumn
{
public MyColumn(){ ...
CellTemplate = new MyCell();
}
}
Edit Control:
public partial class MyEditControl : UserControl, IDataGridViewEditingControl
{... // implements IDataGridViewEditingControl
// value is our data item
}
Data Item, the data sources becomes List<MyItem>
public class MyItem:Object{
...
[XmlIgnore] // I need it because I do serialization
public MyItem Self {
get {
return this;
}
}
}

See my question Here
It's easy to do, you just don't use the IDE to do it, you do it all in code. It's a lot of work, but it's not that difficult if you know what your doing. I went from knowing nothing to being able to do it in less than a day so I'm sure you'll be able to do it.
Edit: you can also use a Join in the sql that populates the datagridview

Related

How do I redraw UICollectionView when MvxCollectionViewSource's data changes?

I am using Xamarin and MVVMCross to implement an IOS app. A view I'm working on is displaying correctly, but ONLY when I hard-code the data being bound to inside my ViewModel and NOT when (as by design and necessity) my data arrives late from SQLite, only an indeterminate time after the view is shown.
What I am using and accomplished so far:
Working/Showing storyboard for my View that has a UICollectionView
inside (called: CollectionView in code below)
Custom layout and XIB file for every UICollectionViewCell that also displays correctly in my view
A view that works and displays correctly only if ViewModel data is fully populated the moment ViewDidLoad() is called.
Problem:
My data in my ViewModel is updated by the Model's databases in an uncertain amount of time whilst the view is happily being shown. When I bind the data as shown below (and trying two-way/one-way bindings and the like as well), I don't get updates on my view as the final data comes in later.
What I can't seem to do:
Redraw the UICollectionView or maybe refresh the
MvxCollectionViewSource below to ensure that as the ViewModel's data changes, I can actually redraw the UICollectionView and show my
custom cells with new and updated data.
THE CODE(TM)
The CollectionView cells are implemented as follows. I followed all examples online and from that Stuart Bloke and his Kittens to make sure I implement all the patterns exactly the same:
[Register("MyCell")]
public partial class MyCell : MvxCollectionViewCell
{
public static readonly UINib Nib = UINib.FromName("MyCell", NSBundle.MainBundle);
public static readonly NSString Key = new NSString("MyCell");
public MyCell(IntPtr handle) : base(handle)
{
this.DelayBind(() => {
var set = this.CreateBindingSet<MyCell, SomeModelClass>();
set.Bind(Label1).To(item => item.Label1);
set.Bind(Label2).To(item => item.Label2);
set.Apply();
});
}
public static MyCell Create()
{
return (MyCell)Nib.Instantiate(null, null)[0];
}
}
My ViewDidLoad() in the View looks something like this:
CollectionView.RegisterNibForCell(MyCell.Nib, MyCell.Key);
var source = new MvxCollectionViewSource(CollectionView, MyCell.Key);
CollectionView.Source = source;
var set = this.CreateBindingSet<MyView, MyViewModel>();
set.Bind(source).To(vm => vm.ListOfStuff);
set.Apply();
CollectionView.ReloadData();
NB! The ListOfStuff shown above is really just a List of a custom class containing 2 strings right now.
TL:DR: I don't know ListOfStuff's values the moment I call the above code. When I hard-code them in the ViewModel, I get joy. If I don't, I don't, even as data gets updated correctly later.
I now reach out to you, the neurons of the brain of crowdsourcing...
Instead of using a List<T> use ObservableCollection<T> and new items should be added to the CollectionView.
The UI needs to know when the collection has changed. ObservableCollection<T> implements INotifyCollectionChanged and INotifyPropertyChanged and communicates with the UI when the collection changes.
You shouldn't need ReloadData() anymore if you're using ObservableCollection<T>.
This extension method might be of use when adding range of IEnumerable<T>
public static class ObservableCollectionExtensionMethod
{
public static void AddRange<TSource>(this ObservableCollection<TSource> source, IEnumerable<TSource> collection)
{
foreach (var i in collection) source.Add(i);
}
}

swt/jface databinding: PojoProperties vs PojoObservable

I'm writing a JFace dialog, and I'd like to use databing to a model object.
Looking at code I can see that there are times when I find a PojoProperties used to build the binding, while other time it is used a PojoObservables.
Looking at the Javadoc I can read:
PojoObservables: A factory for creating observable objects for POJOs (plain old java objects) that conform to idea of an object with getters and setters but does not provide property change events on change.
PojoProperties: A factory for creating properties for POJOs (plain old Java objects) that conform to idea of an object with getters and setters but does not provide property change events on change.
The same question applies to the difference that exists between BeansObservables and BeansProperties
The (obvious) difference sems to be that the observable allows to observe objects and the properties allows to observe properties, but since a Pojo has a getter and a setter for its data, what is the difference between them? And which of them should I choose for my dialog?
Here follows a code excerpt:
The POJO:
public class DataObject {
private String m_value;
public String getValue() {
return m_value;
}
public void setValue(String i_value) {
m_value = i_value;
}
}
The DIALOG (relevant part):
#Override
protected Control createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
m_combo = new Combo(container, SWT.BORDER);
m_comboViewer = new ComboViewer(container, SWT.NONE);
}
The BINDING (relevant part):
// using PojoObservable
IObservableValue observeValue = PojoObservables.observeValue(m_dataObject, "value");
IObservableValue observeWidget = SWTObservables.observeSelection(m_combo);
// using PojoProperties
IObservableValue observeValue = PojoProperties.value("value").observe(m_dataObject);
IObservableValue observeWidget = ViewerProperties.singleSelection().observe(m_comboViewer);
I understand that one time I'm using a combo and another I'm using a ComboViewer, but I can get the combo from the viewer and bind the other way if I need...
Also, can I mix the two, for example use the observeValue with the ViewerProperties?
IObservableValue observeValue = PojoObservables.observeValue(m_dataObject, "value");
IObservableValue observeWidget = ViewerProperties.singleSelection().observe(m_comboViewer);
I am playing around a little with JFace viewers (especially ComboViewer) & databinding and discovered that if I use
SWTObservables.observeSelection(comboViewer.getCombo());
then databinding is not working correctly.
However, if I use
ViewersObservables.observeSingleSelection(comboViewer);
Then everything is working as expected.
Maybe this is a special for my case, so to get it a better overview I'll describe my set up in following paragraph.
I have modelObject with field named selectedEntity and entities and bind this ComboViewer to the modelObject.
I want to display all "entities" in model object, if I add any entity to the modelObject.entities collection then I want to this entity be added to combo automatically.
If user selects some item in combo I want to modelObject.selectedEntity be set automatically.
If I set modelObject.selectedEntity I want to combo selection be set automatically.
Source code can be found at: https://gist.github.com/3938502
Since Eclipse Mars, PojoObservables is deprecated in favor of PojoProperties and BeansObservables is deprecated in favor of BeanProperties so the answer to which one should be used has now become evident.

Databinding a combobox column to a datagridview per row (not the entire column)

There are a few posts about this, but after hours of searching I still can't find what I need.
The answer in the following post almost gets me what I want:
Combobox for Foreign Key in DataGridView
Question 1:
Going off that example where a Product has many Licenses, my database mappings are all many-to-one relationships which means my License class holds a reference to the Product class. The License class does not have a property for the ProductId since that can be retrieved via the Product reference. I don't want to muck up the License class with both a reference to Product and a ProductId property just to make binding in the UI easier.
Because of this I can't set the DataPropertyName to an Id field. It needs to be the class reference name like so:
DataGridViewComboBoxColumn dataGridViewComboBoxColumn =
(DataGridViewComboBoxColumn)myDataGridView.Columns("LicenseComboBoxColumn");
dataGridViewComboBoxColumn.DataPropertyName = "License"; // not LicenseID
****Update****
I was able to get this to partially work without creating the ProductId property by specifying the Product.Id as the DataPropertyName like so:
dataGridViewComboBoxColumn.DataPropertyName = "License.Id";
However, when doing so, it broke databinding which caused me to manually get and set the cell value.
I've also seen posts about binding to the DataGridView cell, but databinding breaks when I do that and the datasource itself is never updated:
// populate the combo box with Products for each License
foreach (DataGridViewRow row in myDataGridViewProducts.Rows)
{
IProduct myProduct = row.DataBoundItem as IProduct;
DataGridViewComboBoxCell cell = (DataGridViewComboBoxCell)row.Cells("myProductCol");
cell.DataSource = getListOfILicenseObjectsFromDao(myProduct.Id);
cell.Value = myProduct.License.Id;
}
Maybe I'm doing something wrong, or maybe there's a different way. Can anyone help here?
Question 2:
How do I display a different list of Licenses for each Product?
In other words, the combobox list of Licenses will be different for each Product in the grid. I'd like to do this using databinding so I don't have to get and set the values myself.
I found the answer myself. I had this same issue a while ago and found the solution in some old code I dug up. The solution was to add a Self property to the object I wanted to databind to in the combobox (in the example above it would be the License class) and use that property as the ValueMember like so:
foreach (DataGridViewRow row in myDataGridViewProducts.Rows)
{
IProduct myProduct = row.DataBoundItem as IProduct;
DataGridViewComboBoxCell cell = (DataGridViewComboBoxCell)row.Cells("myProductCol");
cell.DataSource = getListOfILicenseObjectsFromDao(myProduct.Id);
cell.DataPropertyName = "License";
cell.DisplayMember = "Name";
cell.ValueMember = "Self"; // key to getting the databinding to work
// no need to set cell.Value anymore!
}
The License class now looks like this:
Public class License
{
public string Name
{
get; set;
}
public ILicense Self
{
get { return this; }
}
// ... more properties
}
Granted I had to "muck" up the Business classes with a property named Self, but that's much better (less confusing to the programmer) than having both a reference to License and a LicenseId property in the Product class IMO. Plus it keeps the UI code much much simpler as there's no need to manually get and set the values - just databind and done.

Silverlight Custom Control and Databinding doesn't work properly in WP7

I'm trying to create my calendar control with databinding.
public partial class Calendar : UserControl
{
public static readonly DependencyProperty DateProperty =
DependencyProperty.Register("Date", typeof(DateTime),
typeof(Calendar), null);
public object Date
{
get { return GetValue(DateProperty); }
set
{
SetValue(DateProperty, value);
OnPropertyChanged("Date");
}
}
public Calendar()
{
// Required to initialize variables
InitializeComponent();
DayText.Text = ((DateTime)Date).ToString("dd");
MonthText.Text = ((DateTime)Date).ToString("MMM");
this.Loaded += new RoutedEventHandler(Calendar_Loaded);
this.GotFocus += new RoutedEventHandler(Calendar_Loaded);
}
void Calendar_Loaded(object sender, RoutedEventArgs e)
{
DayText.Text = ((DateTime)Date).ToString("dd");
MonthText.Text = ((DateTime)Date).ToString("MMM");
}
}
But When I create the listbox with this control, same calndar have the wrong date. I'm sure that the Date passed thorough databinding is correct but I don't understand why same calender show a different day (I'm noticed that is the day of a previous calendar control intance)
Thank you for supporting!
Hmm ... where do we start? Here's a few things I've noticed:
If you're using a dependency property, there's no need to call OnPropertyChanged from the Date property setter.
The dependency property declares the type as DateTime, but your public exposed property is of type object, which then requires you to cast it elsewhere.
If Calendar_Loaded is to be called in more situations than in response to the Loaded event (such as the GotFocus event, then I'd recommend that you call it something else, or create a method with a relevant name (e.g. UpdateDateParts) and call it from properly named separate event handlers.
Using fixed format specifiers when processing date strings does not localize well.
In addition to that, I'd suggest that you could implement the user interface in a manner that supports databinding (and re-templating) by using bindings and exposing the date parts of the Date dependency property instead of manually updating the Text property of some text blocks/boxes in event handlers. In fact, if you derive from Control instead of UserControl then you can create and actuall lookless control that has it's user interface defined by a style in themes\generic.xaml that can be re-defined by users of your control.
As for why the date is incorrect in different instances of your calendar control, we'd need to see some of your XAML/code to see how the control is being used and initialized to be able to provide a better answer. However, I thought the above was worth putting in an Answer, instead of trying to say it in a Comment.

Dynamically bind a DataRepeater (Microsoft.VisualBasic.PowerPacks)

I am using a DataRepeater to show data from a business objects on the screen. I am using windows forms in C# to accomplish this. The datasource is not available at compile time so I want to bind the datasource at runtime.
Here is the simplified scenario. I'm using this business class:
public class Product
{
private double _price;
public double Price
{
get
{
return _price;
}
set
{
_price = value;
}
}
}
I have created a ProductDataSource with the VisualStudio interface and bound the price to a label. Now I filled the datasource of my repeater in code:
dataRepeater1.DataSource = _productDataAgent.GetProducts();
When I startup my application the prices are correctly filled in the labels. So far so good.
Now I want the price labels to be updated when the product is updated. The Visual Studio interface helps me, and let me choose a 'Data Source Update Mode'. So I choose "OnPropertyChanged".
Here comes the tricky part. How does the .NET runtime know that the price property is updated from the backend. So I modify my business class to implement INotifyPropertyChanged. Like this:
public class Product : INotifyPropertyChanged
{
private double _price;
public double Price
{
get
{
return _price;
}
set
{
_price = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Price"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
The problem is this doesn't work. When I update a product it remeanes un-updated in the interface. When I debug and change the property, I see that the PropertyChanged event is null so no one is listening.
Delving a little deeper in to the problem I found the following on the System.Windows.Forms.Binding Constructor page on MSDN:
An event named PropertyNameChanged.
So I tried using a (custom) PriceChanged event, but that did not work.
Am I doing something wrong here? I am comming from using WPF, so maybe this works a little different in Windows Forms? Is this because I am binding at runtime?
Jep found the sollution. Apparently you cannot simply bind to a list of products. You will see the products initially, but they will not be updated when a property is changed. Instead you need to statically bind to a BindingSource. Just create an object datasource using the Visual Studio (in the data menu). Code like this is generated:
private System.Windows.Forms.BindingSource beursProductDisplayBindingSource;
this.beursProductDisplayBindingSource = new System.Windows.Forms.BindingSource(this.components);
this.dataRepeater1.DataSource = this.beursProductDisplayBindingSource;
Now you can dynamically bind like this:
BindingSource productBinding = ((BindingSource)dataRepeater1.DataSource);
_productDataAgent.BeursProducts.ForEach(product => productBinding.Add(product));
Now when implementing INotifyPropertyChanged in your data object like I did is works like expected. Just forgot one step which is not needed when using WPF.

Resources