Does (ReactiveUI 6.2) ReactiveList Support Binding in Winforms DataGridView Datasource? - winforms

I am re-factoring an old winforms project into using MVVM via ReactiveUI. The binding part works great so far except the Grid.Datasource = ReactiveList doesn't seem to give any update on changing/adding/deleting.
I just wanted to confirm here, since the DataGridView.Datasource support databinding list only, ReactiveUI.ReactiveList will not work here? or there could be some possible get arounds.

I've just been struggling with this, the approach I've come up with is to wrap a ReactiveList on the ViewModel with a ReactiveDerivedBindingList.
I've created a BindingSource based on the item ViewModel class for design time support, then I replace this at runtime:
private void CreateDerivedBindings()
{
this.Articles = this.ViewModel.Articles.CreateDerivedBindingList(x => x);
this.ViewModel.Articles.ItemChanged.Subscribe(_ => this.Articles.Reset());
//this.Articles.ChangeTrackingEnabled = true;
this.articlesDataGridView.DataSource = this.Articles;
}
private IReactiveDerivedBindingList<ArticleViewModel> Articles { get; set; }
Subscribing to ItemChanged of the underlying ReactiveList (which has ChangeTrackingEnabled turned on) enables items in the grid to update as they are changed. Setting ChangeTrackingEnabled on the derived binding list didn't do anything. This is a brute force approach, I'd guess causing a full refresh of the grid, maybe there is a more finessed approach.
A simpler approach could be to use a ReactiveBindingList on the ViewModel, but I've not tried this as the class is winforms specific and I'm aiming for a ViewModel which could be reused with WPF.

ReactiveList supports INotifyCollectionChanged, I don't know of any other way that lists can signal they have changed. I could be misinformed about Winforms Grid though!

Related

How to bind to user controls using ReactiveUI and winforms

I am trying to learn ReactiveUI. I have been looking at the wpf sample project in the repository https://github.com/reactiveui/ReactiveUI/tree/master/samples/getting-started
I decided to try to convert this to winforms but have a problem.
In the wpf example the search function populates, via OAPH, a property of the 'Main' ViewModel (AppViewModel) called SearchResults which is an IEnumerable of 'Child' ViewModels (NuGetDetailsViewModel)
public IEnumerable<NugetDetailsViewModel> SearchResults => _searchResults.Value;
in the 'Main' View (MainWindow) there is a listbox which has its ItemSource bound to the SearchResults i.e. the IEnumerable of ViewModels.
There seems to be some wizardry going on that finds and displays the appropriate View for the given ViewModel. It even says so in the comments:
In our MainWindow when we register the ListBox with the collection of NugetDetailsViewModels if no ItemTemplate has been declared it will search for a class derived off IViewFor and show that for the item.
In winforms I think I have two problems, but I maybe out by one.. or more:
It doesnt seem like the same wizardry of finding the View for the ViewModel is working, however this may be due to problem two.
How can I bind the IEnumerable of ViewModels to a winforms control?
In winforms I am using a flowlayoutpanel in place of the ListBox and have tried several variations of:
this.OneWayBind(ViewModel, vm => vm.ResultsList, v => v.flowLayoutPanel1.DataBindings)
I have been able to use some conversion code directly in the View to update the flowLayoutPanel directly but it requires direct knowledge of the Child View and doesn't sit well with me, and isn't as automatic as I would like.
this.OneWayBind(ViewModel,
vm => vm.ResultsList,
v => v.flowLayoutPanel1,
selector: value =>
{
this.flowLayoutPanel1.Controls.Clear();
foreach (var value in values)
{
this.flowLayoutPanel1.Controls.Add(new AssemblyInfoView() { ViewModel = value });
}
return this.flowLayoutPanel1;
} ));
For clarity the 'Child' View linked to my 'Child' ViewModel also derives from ReactiveUserControl.
I use the following code to register the Views:
Locator.CurrentMutable.RegisterViewsForViewModels(Assembly.GetCallingAssembly());
and have checked that they are registered.
If anyone is able to help that would be appreciated.
As an addendum if anyone knows of some more complex sample projects using ReactiveUI particularly using winforms that would be very helpful.
Thank you.
In ReactiveUI 9.11 there is a new feature which allows you to bind to either any control that has Control.ControlCollection or to a TableLayoutControlCollection
This will allow you to have it automatically add to the Control's.
This is made available by a new interface called ISetMethodBindingConverter which allows you to override how the 'Set' in our binding engine works.
There is now a sample for the WinForms application found here: https://github.com/reactiveui/ReactiveUI.Samples/tree/master/winforms/ReactiveDemo

Implementing Telerik VirtualQueryableCollectionView with MVVM pattern

I have an application that was implemented using the Telerik RadGridView control and Caliburn.Micro MVVM framework. Because of some performance problems, I needed to implement the Telerik VirtualQueryableCollectionView in place of the direct control-to-ObservableCollection binding that was being used. The original code has the ItemsSouce property of the RadGridView was bound to the Prices property of the view model. I had to eliminate that binding and this in the code-behind:
public PricingView(PricingViewModel vm)
{
InitializeComponent();
var dataView = new VirtualQueryableCollectionView()
{ LoadSize=20, VirtualItemCount = vm.Prices.Count };
dataView.ItemsLoading += (sender, e) =>
{
var view = sender as VirtualQueryableCollectionView;
if (dataView != null)
{
view.Load(e.StartIndex, vm.Prices.Skip(e.StartIndex).Take(e.ItemCount));
}
};
this.PricesGridView.ItemsSource = dataView;
}
Since this code only deals with UI specific functionality and it is specific the the view implementation, I am comfortable that this code belongs in the code-behind rather than the ViewModel as it would be a departure from ther MVVM pattern to put a reference to VirtualQueryableCollectionView in the ViewModel. The part that I am not happy with is passing the reference to the ViewModel into the constructor of the View. Is there a good way to get the reference in the code-behind without having to pass the reference in the constructor?
Or is there a better way to do all of this?
My application is implemented with MVVM Light, in my case I used the VirtualQueryableCollectionView class in the ViewModel instead the View.
I did so because I think this class is very similar to the ObservableCollection although it is not part of the core classes.
Actually, VirtualQueryableCollectionView is not limited to the Telerik controls but many other standard controls like the ListView.
The fetch is in my case implemented in the Model.
void MainViewModel()
{
this.Traces = new VirtualQueryableCollectionView<MyEntityClass>()
{
// ViewModel also manages the LoadSize
LoadSize = this.PageSize,
VirtualItemCount = myModel.TotalCount
};
this.Traces.ItemsLoading += (s, args) =>
{
this.Traces.Load(args.StartIndex,
myModel.FetchRange(args.StartIndex, args.ItemCount));
};
}
Not sure what "performance problems" means, but I'm going to assume that means that when you fill the collection from the UI thread it blocks the application long enough it appears unresponsive.
There are two common solutions for this. First is to simply fill your collection from a background thread.
The naive implementation is to simply push the loading onto a ThreadPool thread, then use the Dispatcher to marshall the calls to add items to the ObservableCollection onto the UI thread.
A nicer approach (one that doesn't involve the ViewModel at all) is to use asynchronous bindings. You configure the fallback to some value that indicates to the user you are loading. Sometimes (depending on the situation) you can use a PriorityBinding to gradually fill your UI.
Other alternatives are to load and cache your data beforehand while displaying a splash screen. They're a bit different in WPF, it isn't like the old "display this form for a bit while I do work, then show the main form" mode of winforms. And, of course, there is always the classic data pagination. Its tough to code, but effective. Actually, I should say its tough in the UI. Its easy now in code (database.Skip(pageNumber * pageSize).Take(pageSize)).

WPF MVVM ListView does not update!

I'm using Prism v4 , and MVVM.
In my viewmodel i have:
private TB_COMPANY tb;
public TB_COMPANY Tb {
get {
return this.tb;
}
private set {
if ( this.tb != value ) {
this.tb = value;
this.RaisePropertyChanged(() => this.Tb);
}
}
}
In my Page, i have a datagrid (i tried with a listview too, don't work!):
<DataGrid ItemsSource="{Binding Tb.TB_ADDRESS.RL_ADDRESS_PHONE}" .../>
RL_ADDRESS_PHONE is a list of phones of the company...
So, in some moment i add phone to the list:
private void MyCommand()
{
...
Tb.TB_ADDRESS.RL_ADDRESS_PHONE.Add(
new RL_ADDRESS_PHONE
{
TB_PHONE = new TB_PHONE
{
NU_PHONE = _txtTelefone,
ST_TYPE = _txtTipoTelefone
}
});
...
}
But nothing happens to the UI...
But in the Debug, the list is fullfiled....
What should i do to update the UI?
The RL_ADDRESS_PHONE property of TB_ADDRESS must implement INotifyPropertyChanged as well. If it is a List, you should use ObservableCollection which implements INotifyCollectionChanged which is necessary for the behaviour you are trying to achieve.
Also, as a piece of advise - have a look into the design guidelines and naming convention of the C# language, you can find it in the msdn (while it says .net 1.1, it still applies for any following versions of the framework).
Does your binding work? Have you checked the Output window? Are all the properties on your binding path public? Needs more code.
All property notifications aside: If your binding finds the ObservableCollection it will update if you add objects. So i think you might be using a field or a non-public property somewhere on the path.
If this is not the case make sure you do not overwrite the reference to the ObservableCollection unless you have a proper PropertyChanged notification in place. (You should implement that interface (INotifyPropertyChanged) in every class on your binding path since every overwritten reference that the view is not notified of will break your update).
You mentioned the use of a WCF service. Is it possible that your observable collection is being created on a different thread to the UI thread. If this is the case you UI will not be able to bind to it. Bea Stollnitz discusses issues with cross thread binding on her blog here -> http://bea.stollnitz.com/blog/?p=34.
You should be able to get round it by invoking the creation of the observable collection onto the UI thread.

WPF MVVM application - ICollectionView/Threading/General Questions

I have a few questions regarding to building WPF MVVM applications.
1) I'm using ICollectionView objects for databound controls such as ListView and ComboBox. I found this was the simplest way of gaining access to/tracking the selected item of these controls. What is the best way to replace the contents of ICollectionView? Currently I'm doing it like so:
private ICollectionView _files;
public ICollectionView Files {
get { return _files; }
}
void _service_GetFilesCompleted(IList<SomeFile> files) {
this.IsProcessing = false;
_files = CollectionViewSource.GetDefaultView(files);
_files.CurrentChanged += new EventHandler(FileSelectionChanged);
OnPropertyChanged("Files");
}
I didn't know whether it was necessary to reattach the handler every time I refresh the list of files?
2) Now that I've got my head round it, I am starting to like the MVVM pattern. However, one concept I'm not completely sure about is how to send notifications back down to the view. Currently I am doing this by binding to properties on my ViewModel. For example, in the above code I have an "IsProcessing" property that I use to determine whether to display a ProgressBar. Is this the recommended approach?
3) Following on from 2) - there doesn't seem to be a standard way to handle exceptions in an MVVM application. One thought I had was to have one method on my ViewModel base class that handled exceptions. I could then inject an IMessagingService that was responsible for relaying any error messages. A concrete implementation of this could use MessageBox.
4) I have a few tasks that I want to perform asynchronously. Rather than adding this logic directly in my service I created a decorator service that runs the underlying service methods on a new thread. It exposes a number of events that my ViewModel can then subscribe to. I have listed the code below. I understand that BackgroundWorker is a safer option but did not know whether it was suitable for running multiple asynchronous tasks at once?:
public void BeginGetFiles()
{
ThreadStart thread = () => {
var result = _serviceClient.GetUserFiles(username, password);
GetFilesCompleted(result.Files);
};
new Thread(thread).Start();
}
Finally, I realize that there are a number of MVVM frameworks projects that handle some of these requirements. However, I want to understand how to achieve the above using built-in functionality.
Thanks
If you have ListViews and ComboBoxes, you should really be considering an ObservableCollection<> to bind to these controls. Adding and removing items from the collection will automatically notify the control the property has changed.
If you're doing background processing, you can look at the BackgroundWorker or DispatcherTimer to handle updates to the UI. These both have the capability of acting on the UI thread, and can be thread safe.
To get the selected item from a combo box, expose an INotifyCollectionChanged object such as ObservableCollection and bind it to the itemsource, then create another property for the current item and binding ComboBox.SelectedItem (or ComboBox.SelectedValue if required) to it. You will need to manage the selection when updating the collection.
On the face of it, ICollectionView seems like the obvious choice but the WPF implementation really forces your hand on some threading code that you really shouldn't be troubled with.
I used ICollectionView and CollectionViewSource recently (for filtering) and have become frustrated with how many dispatcher issues have crept in. Today I am probably going to revert to the method i describe above.

WPF Collections and Databinding

I am new to WPF and trying to wrap my head around WPF's framework, what it does and does not do for you.
To clarify this, I would like to know what is the difference between this:
public List<MyCustomObject> MyCustomObjects
{
get { return (List<MyCustomObject>)GetValue(MyCustomObjectsProperty); }
set { SetValue(MyCustomObjectsProperty, value); }
}
public static readonly DependencyProperty MyCustomObjectsProperty =
DependencyProperty.Register("MyCustomObjects", typeof(List<MyCustomObject>),
typeof(Main), new UIPropertyMetadata(new List<MyCustomObject>()));
and this:
public ObservableCollection<MyCustomObject> MyCustomObjects { get; set; }
public Main ()
{
MyCustomObjects = new ObservableCollection<<MyCustomObject>();
}
Ok, we must put some order into things, there's a few concepts mixed in together here.
First of all, you're asking what the difference is between a field-backed property and a dependency property. Google would be your best friend, however I recommend this blog post by WPF's vanguard Josh Smith: Overview of dependency properties in WPF
In short: dependency properties support the richness that is WPF: Styling, animation, binding, metadata, and more.
Secondly, you're asking what the difference is between a List and an ObservableCollection. Well the latter provides change notifications (in the forms of events) on any change to the collection (addition, removal, change of order, clearing, etc.), and the former does not. You can read more about that here: The ObservableCollection Class
In short: ObservableCollection provides change notifications which are required for the UI to automatically reflect changes in the view model.
In addition to Aviad and Reed's answers, I would like to point out a serious bug in your first code sample :
public static readonly DependencyProperty MyCustomObjectsProperty =
DependencyProperty.Register("MyCustomObjects", typeof(List<MyCustomObject>),
typeof(Main), new UIPropertyMetadata(new List<MyCustomObject>()));
The new List<MyCustomObject>() used as the default value will be created only once, so by default all instances of your type will share the same List<MyCustomObject> instance, which is probably not what you want... The only sensible default value here is null
In the first case, you're setting up a Dependency Property containing a List<T> instance.
In the second, you're making a normal CLR property, but having it setup as an ObservableCollection<T>.
For WPF Data Binding, there are some differences here.
Typically, you want all of your properties in the DataContext (which is the object that, by default, things "bind" to) to either implement INotifyPropertyChanged or to be a Dependency Property. This lets the binding framework know when changes are made to that object. Normally, though, you'd only use a Dependency Property if your working with a custom control - it's usually a better idea to have your object to which your data bound be a separate class, assigned to the DataContext. (For details here, see Josh Smith on MVVM or my recent detailed post on MVVM...)
However, with a collection, you typically also want the binding system to know when the items within the collection change (ie: an item is added). ObservableCollection<T> handles this by implementing INotifyCollectionChanged.
By using the second approach (using an ObservableCollection<T>), your UI can tell when items were added or removed from the collection - not just when a new collection is assigned. This lets things work automatically, like a ListBox adding elements when a new item is added to your collection.
1:
You're using a dependency property to "tell" the framework when that property is changed. This will have the following consequences for your binding:
MyCustomObjects.Add(new MyCustomObject()); //Wont update the view through databinding
MyCustomObjects = new List<MyCustomObject>(); //Will update the view through databinding
You could gain the same databinding functionality by implementing INotifyPropertyChanged on which ever class exposes the property, but dependency properties a capable of much more than just notifying about changes. These are rather advanced features though, which you aren't likely to come across in your average joe app :)
2:
You're using an observable collection, which implements INotifyCollectionChanged for you, to tell the databinding whenever the content of the collection has changed. This will have the opposite consequences than #1:
MyCustomObjects.Add(new MyCustomObject()); //Will update the view through databinding
MyCustomObjects = new ObservableCollection<MyCustomObject>(); //Won't update the view through databinding

Resources