problem with two controls having the same datasource - winforms

I am building a winforms application, i have two comboboxes which have the same datasource, the datasource is a DataTable. Now, when I select a value in one comboBox, the value of another comboBox is changed too. Is there a way make it change without affecting the other?

In that type of scenario, you can create two different binding sources, one bound to each of your combo boxes. If you set the DataSource property of each of the binding data sources to your DataTable, then your combo boxes will work independently, while still showing the same data.
The initialisation would be something like:
// Initialization of the binding sources(assuming dataTable is a populated DataTable)
bindingSource.DataSource = dataTable;
bindingSource2.DataSource = dataTable;

The WinForms binding system is detecting that both comboboxes are hooked up to the same DataSource and is (helpfully) syncing changes across the two.
To avoid this you need to ensure each combobox has a distinct DataSource.
One way is to use the appropriate non-visual component from the Toolbox (BindingSource).
Another, if you're setting up your bindings with code, is to use BindingList. Note that there is one trap with BindingList - it can act as a wrapper:
[The] BindingList constructor creates a WRAPPER collection around the original list. It doesn't create a new list containing the same elements. (I've never seen this documented, but have verified with Reflector).
-- http://www.nichesoftware.co.nz/blog/200809/databinding-lists
Instead of:
editDebitAccount.DataSource = accountsList;
editCreditAccount.DataSource = accountsList;
use this:
editDebitAccount.DataSource = new BindingList(accountsList);
editCreditAccount.DataSource = new BindingList(accountsList);

Related

Filtering WinForm DataGridView

I have a DataGridView control that is bound to a custom typed list (that inherits BindingList). I would like to be able to filter rows based on a simple column value (bool type). Ultimately, the fonctional goal is to be able to mark an item as deleted but just flag it as deleted in the DataSource, not remove it. Juste remove it from the grid, not the DataSource.
Any idea ?
You can use LINQ to filter your data then create a new BindingList and reassign it to the dataGridView.
Assuming you have a flag in the person class called WillBeDeleted:
dataGridView1.DataSource = new SortableBindingList<Person>
(SampleData.Where(p => !p.WillBeDeleted).ToList());
Good luck!
Just to make it clearer, I used this code to create the SortableBindingList http://www.timvw.be/presenting-the-sortablebindinglistt-take-two/ (I translated it to VB.NET)
Then, I have my own collection object that contains properties and a SortableBindingList of my entities.
Private mListeNotes As New SP1ZSortableBindingList(Of SP5004ZNoteEvolutiveEntite)
And that is what I bind my grid to so I it is now sortable. So I need it to remain of that type, not generic list.

Problems binding Self-Tracking Entity's Navigation Property WPF

I have a WPF application consuming data using Entity Framework 4 and Self-Tracking Entities. In which I have a window with 2 controls in it, one that shows the "Details" portion of an object using a ContentControl and templates from a merged resource dictionary. Another with a ListBox of Groups the object in question belongs to and a ComboBox of available groups it could belong towith a button wired up via a command to the control to add/remove items from the bound collection of Groups based on the SelectedItem of the ComboBox. All this is bound together by DependencyPropertys.
In my Window I have DP's for the Object, EditedItem we are editing and a read only property with a List of Group of the groups it could belong to and bind that to my controls via XAML.
SO....
If I create a new instance of one of my entities, set it's properties like so: (Really this is the exact code)
Employee employee = Context.CreateObject<Employee>();
employee.Name = "Joe Nobody's Brother Steve";
employee.Active = true;
employee.Username = "snobody";
Group group = Context.CreateObject<Group>();
group.Name = "Losers";
group.DisplayName = "Spirit Squad";
employee.Groups.Add(group);
And set it as my Window's EditedItem it works FLAWLESSLY!
If I however fetch this exact same entity from my Database the Groups ListBox is empty.
Any ideas?
It turns out I had made a mistake else where:
I needed to call:
ObjectContext.LoadProperty(entity, navigationProperty);
on my navigation properties for them to get populated. I think this has something to do with my objects all being derived from a core object and the fact that I select them using OfType on the ObjectSet of the core object. Or it could be behavior but I would think I would have encountered it before now.
But hey I'll take working, and this is easy enough to integrate into my selection methods and properties.
Chalk this one up to ignorance of EF4.

How can I execute WPF filters on a background thread?

I'm using filters in WPF and I'm following the pattern suggested here.
To summarize, this involves a text property being exposed on the ViewModel which represents the text to filter by. When the property is set (by the binding from the textbox in the View) it uses CollectionViewSource.GetDefaultView(MyItems).Filter = blah to filter the visible list of items.
This works great, but the problem comes when the collection of items is very large, as the filtering is performed on the foreground thread and thus hangs the UI. Does there exist a pattern for performing filtering on a background thread, and how does this fit in the Model-View-ViewModel pattern?
Instead of using CollectionView for filtering, do your own: In your ViewModel create a property that contains the filtered data and one to hold the filter. Whenever the filter is changed, fire off a work item in a separate thread to computed the new filtered data property then update that property when it is done. When updating the property, either update the existing collection or replace it depending on how many changes were made.
I use a class I use that automates this so it is as easy as declaring the one collection to be a filtered version of the other.

ItemsControl that loads items one by one asynchronously

I am creating a custom DataGrid by deriving the traditional tookit based WPF DataGrid. I want a functionality in the grid to load items one by one asynchronously, wherein as soon as ItemsSource is changed i.e. a new collection is Set to the ItemsSource property or the bound collection is Changed dues to items that rae added, moved or removed (wherein the notifications comes to the data grid when the underlying source implements INotifyCollectionChanged such as ObservableCollection).
This is because even with virtualising stackpanel underneath the datagrid takes time to load (2-3 seconds delay) to load the data rows when it has several columns and some are template based. With above behavior that delay would "appear" to have reduced giving datagrid a feel that it has the data and is responsive enough to load it.
How can I achieve it?
Thx
Vinit.
Sounds like you are looking for data virtualization', which typically means creating your own custom type that resembles IList, and doing a lot of work to hydrate objects after-the-fact.
You will end up having your data that the grid is displaying look something like this:
Index 0: new MyDataObject(0);
Index 1: new MyDataObject(1);
And MyDataObject implements INotifyPropertyChanged.
In the constructor, you do the logic necessary to time, schedule, or interpret when the real results should be read. Until then, you return rather empty data... null and string.Empty from your properties.
Then, once the data becomes available (ideally in a background thread, read from wherever - your own local data, or a database or web service), then you can update the real underlying property values and fire the property change notifications so that the UI gets properly loaded then.
It's a little too complex to just jump into, so some searching will help. Hope this gets you started.

Moving to new record on Collection

I'm just getting started with collections (ObservableCollections) and I've hit a wall that I assumed would be easy. I'm sure it is easy but I'm just not finding the answer.
I have a WPF screen with a DataGrid to the left and TextBoxes to the right of the screen. The DataGrid is bound to the ObservableCollection (Activities) and I can click up and down the DataGrid and see my TextBoxes refresh with the correct info. I can then alter the info in the TextBoxes and save it back to the DB. All works perfectly!
However, when it comes to Adding a record to the collection I'm lost as to the correct approach. I'm using the Add method as shown below, but how do I move to this newly created record so it can be edited? I've tried a dozen approaches but I've yet to find a correct approach. The TextBoxes just remain focussed on the last edited record. Any ideas?
Private Activities As ObservableCollection(Of ActivityRecord)
Private Sub AddMode()
Dim _ActivityRecord As New ActivityRecord(0, DateTime.Now, Nothing, "", gWorkerID, "")
Activities.Add(_ActivityRecord)
'Code to move to the newly created record should go here
In WPF, every ItemsControl derived control (list your DataGrid) secretly uses a derivative of CollectionView to facilitate the navigation between records/items - in effect it is the class which provides the currency mechanism that help other controls (like the textbox) determine which data bound item is current.
If you create a new object and add it to your ObservableCollection, you can use one of the CollectionView's MoveXXX methods to move to make that item current. You can (depending on what sort of CollectionView you get) also call the Add method on the CollectionView, and it will automatically call the Add method on your underlying ObservableCollection.
Either way, retriving a reference to the CollectionView is the secret. You can either use the CollectionView's static method (I forget it's name) to retrieve the view being used for your DataGrid, or (and this is my preferred method) you can explicitely create a ListCollectionView and bind your DataGrid to it, instead of the ObservableCollection.

Resources