I can't believe I am stumped with this fairly straightforward thing. I originally posted this in the WPF datagrid codeplex discussions but got no response. So I am trying here:
I can't seem to find a way to do this. I create a datagrid whose datacontext is initially filled with rows from a table. I have implemented a search functionality that will return some rows based on a condition. Suppose I want to display only those rows, how do I destroy the initially created datacontext and add the newly filtered collection?
I naively started doing it like this:
(Late Edit: I can't seem to type Generics code here -- the cast in the following line is suppoed to cast datagrid.Items to MyType (for example))
IEnumerable rows = datagrid.Items.Cast();
IEnumerable filteredRows = rows.Where(row => row.someCondition == true);
how do I now make my datagrid display only the filteredRows? Just doing:
datagrid.DataContext = null;
datagrid.DataContext = filteredRows;
doesn't work (it even smells stupid for some reason).
I also need to do the reverse (once I get this working). Some buttonclick should allow the user to "clear" the search results and re-plug the DataContext back to "rows" (in the above snippet).
What am I missing?
I came across similar issue. Needed to re-apply converters on my DataGrid after changing some style values.
For me this worked:
myGrid.Items.Refresh()
It appears to re-apply all of the rules so it may work for you.
myGrid.Items.Refresh() worked for me too, just re-set the context before
public void GridExamsRefresh()
{
grdExamenes.ItemsSource = (this.objPacienteOfContext).Exams;
grdExamenes.Items.Refresh();
}
It seems like some similar problems were encountered in this question. In the comments, he even says setting the datacontext to null and then re-assigning it doesn't work.
Perhaps you have to modify the items collection as mentioned in that answer?
Have you tried setting the ItemsSource property?
Related
I've got a new Problem here. I've got a MainWindow in which is a ContentGrid and in this is a Frame. Now I've created different Pages which can be shown in this "content-area". In One of these pages there is a Datagrid bound to a CollectionViewSource which Source is a Database (via EntityFramework). Now, when a Change on this Database-Table happens (solved via ServiceBroker and SQLDependency, firing works fine) The Datagrid have to update.
Now the Problem:
The "Dependency_OnChange"-Event is working in the MainWindow-Thread. When i try to access the CollectionViewSource of the Page to Update it (cvs.View.Refresh) i get an Exception that this is not possible because of another Thread which own this CVS.
I've tried it with different Dispatching like:
Application.Current.Dispatcher.Invoke((Action)(()=>
{
cvs.Source = _db.Table.OrderByDescending(nr => nr.Date).Take(200);
cvs.View.Refresh();
}));
This Codeblock doesn't brings an Exception but i wont update the UI too... It seems that it does nothing.
Can anyone help me?
You data grid will update if your LINQ query evaluates. Right now it just specifies the LINQ IEnumerable but is not evaluating it.
cvs.Source = _db.Table.OrderByDescending(nr => nr.Date).Take(200).ToList();
should do the evaluation of the LINQ for you...
Although I must say your cvs.View.Refresh() call is very expensive as it causes entire grid to refresh. You may have to consider a better design here.
Why dont you set the dataGrid.ItemsSource = _db.Table.DefaultView as the item source to the datagrid directly. I guess if your table updates (and peforms _db.Table.AcceptChanges();) the view would automatically notify the changes to the grid and grid would possibly update itself faster!
But thats just my opinion as I am not aware of your threading context here. But still do try and let me know.
I have a listview that's bound to a ListCollectionView. The LCV has a single sortdescription at any time. I am updating the collection in this manner:
IEditableCollectionView IEditView = lvBatches.Items as IEditableCollectionView;
IEditView.EditItem(m_collectionView.CurrentItem);//I've also tried passing MyListView.SelectedItem
((TestData)IEditView.CurrentEditItem).start = frm.newDate;
((TestData)IEditView.CurrentEditItem).edited = true;
IEditView.CommitEdit();
However, when I do, nothing happens to the listview's items. If I re-sort the list, the changes are then reflected. A Refresh() on the collection also updates the listview, but that's like using a stick of dynamite to open a soda can, from what I gather.
Does anyone have any ideas. My above code looks like the examples I'm seeing around the 'net so I don't think that's the problem. Are there any common mistakes people make anyone is aware of, maybe something to do with the sorting? I had it working and now it's not and I have no idea what broke it.
Thanks in advance.
See my answer about creating a VeryObservableCollection.
The problem you are experiencing is that collections do not update with mere property changes -- CollectionChanged only fires if you add or remove elements. So you need to hook PropertyChanged and send a CollectionChanged when a property changes, which is what VeryObservableCollection does.
Are you calling NotifyPropertyChanged? If a Refesh() shows the correct values then most likely they are in the collection but the UI has to know to update value.
I have a Window that uses DataTemplates to display a different UserControl (view) in a ContentPresenter based on the type of its Content property, which is bound to a property that holds the current viewmodel. In this way, by changing the viewmodel property with an event, I can facilitate the basic back/forward navigation I need.
When creating a new viewmodel, it is passed a reference to the current one. Going back to the old viewmodel instance works fine for a CheckBox control, but not for a UserControl I made that contains a TextBlock and a ComboBox.
The problem is that, when the view containing the ComboBox gets unloaded, the ComboBox's ItemsSource gets nulled, which triggers it to clear its SelectedItem/Text properties, which are for some reason still bound to my viewmodel--thus clearing the data it stores. I don't know how to manually unbind them at the appropriate time. (Again, the CheckBox works just fine.)
I have read that other users have had this exact same problem. For them, changing the declaration order of the ItemsSource and SelectedItem/Text bindings so that the attributes for the latter are placed before the former fixes the issue. However, in my case, it does not. Others have also fixed the issue by ignoring null/empty values, but this won't work in my case.
I could work around the issue by copying the interesting data to a separate object, and reloading it from that, but I would need to add code to trigger reloading the data = more data linkage code to maintain.
I could also avoid using DataTemplates and manually add the UserControls in the codebehind, which would allow me to break the data binding before removing the UserControl. But this runs counter to the point of MVVM.
I'm not above modifying my very non-MVVM UserControl to handle any events on the ComboBox it contains to work around this issue.
UPDATE:
I have narrowed down the issue a little bit. I refactored the code so that it manually creates and adds the view UserControl based on which viewmodel has been set. The issue now only occurs when I set the DataContext of the view UserControl to null. If I simply replace the view without removing the reference, it no longer erases the values in question. Is this a usable workaround, or does it create issues like memory leaks?
Maybe something that would "open mind" for a simpler solution... If I understand your problem, it's similar to a past problem we had. In our case, we simply made the assumption that it's not possible to set a specific value to null when accessed by the bound property, so we tweaked the appropriate ViewModel Properties a bit:
public MyItem SelectedItem {
get {
return Model.MyItem;
}
set {
if (value != null) {
// Set and notify if not null
Model.MyItem = value;
OnPropertyChanged("SelectedItem");
}
else // just notify when trying to set to null
OnPropertyChanged("SelectedItem");
}
}
Using such tweaked properties we were able to block any try to set the value to null, by calling OnPropertyChanged(..) insead, the existing value was recalled by the UI. If there is a need to be able to set a value to null, you have to provide a seperate property allowing that.
Not sure if this applies to your problem.
Good luck.
UPDATE
oh, I see probably this describes same method as "Others have also fixed the issue by ignoring null/empty values" which seems not to work in your case. But I dont unterstand why it shouldn't.
This is a known bug in the early versions of WPF caused by event leapfrogging. It was fixed for the Selector-derived controls in .NET 4.0.
See this blog post for more details: http://blogs.interknowlogy.com/2011/03/09/event-leapfrogging/
I have worked around the issue by adding a property Active and corresponding Activate()/Deactivate() methods to my base viewmodel class, and calling these as appropriate when swapping out viewmodels. This fits into my application pretty well. I'm still open to other suggestions, of course.
I want to do something that I thought would be very simple. I want to bind a generated Entity Framework EntityCollection to a WPF DataGrid. I also want this grid to be sortable.
I have tried all kinds of things to make this happen, including using a CollectionViewSource. However, nothing seems to work. Using a normal CollectionViewSource around the EntityCollection gives me:
'System.Windows.Data.BindingListCollectionView' view does not support sorting.
Ok...strange. I would have thought this would work. Next on the CollectionViewSource, I try setting:
CollectionViewType="ListCollectionView"
Great, sorting now works. But wait, I can't add or remove entities using the grid now, presumably because ListCollectionView doesn't support this with an entity framework context.
So, I guess I need to capture events coming out of the datagrid in order to add or remove entities manually from my context. Now I can't find an event to capture to detect an add...!
Why is this so hard? This should be the standard "demo" case that Microsoft should have designed around.
Any ideas?
BindingListCollectionView is not directly the problem. See 'System.Windows.Data.BindingListCollectionView' view does not support sorting on Microsoft Connect for details why it does not support sorting.
On the other hand ListCollectionView supports sorting obviously using a different technique.
I have also tried the following code and it worked beautifully. I have basically implemented your XAML from the other post in code.
DatabaseContext.ObjectStateManager.ObjectStateManagerChanged += (o, args) => Debug.WriteLine(args.Element.ToString());
var collectionViewSource = new CollectionViewSource();
((ISupportInitialize)collectionViewSource).BeginInit();
collectionViewSource.CollectionViewType = typeof (ListCollectionView);
collectionViewSource.Source = ((IListSource) DatabaseContext.Survey).GetList();
collectionViewSource.SortDescriptions.Add(new SortDescription {PropertyName = "Name"});
((ISupportInitialize)collectionViewSource).EndInit();
var editableCollectionView = (IEditableCollectionView)collectionViewSource.View;
var survey = editableCollectionView.AddNew();
// Before this point ObjectStateManager event has occurred and Debug Output is written to.
editableCollectionView.CommitNew();
DatabaseContext.SaveChanges(); // THIS WORKS TOO!
My DatabaseContext.Survey is an ObjectQuery<Survey>. Are you showing an ObjectQuery or a Linq-to-EF query? The former obviously works for me. The latter is where I see a problem. That is not supposed to work.
It seems like, the View just doesn't get notified, when chages occur. So, I just do
myCollectionViewSource.View.Refresh(); //refresh CollectionViewSource of CollectionViewType="ListCollectionView"
after add/remove of list items.
But then the whole state gets refreshed (e.g. you have to reset preselected sorting again). You need to check, if this fits your needs.
I have several datagrid where I need to update the informations. Things is, since more than one person works on the system at the same time, the datagrid need to be refreshed on a regular basis. When I refresh, I lose the sorting that user had.
Is there a way to keep it?
thanks
Just update the contents of the bound collection - don't replace the collection itself. Then you will not get a new CollectionView so your sorting won't be affected.
Note that this is untested, but could you do something like this?
ListCollectionView lcv = (ListCollectionView)CollectionViewSource.GetDefaultView(myDataGrid.ItemsSource);
IComparer mySort = lcv.CustomSort; // assumes you've already set it beforehand
... // stuff happens
lcv.CustomSort = mySort;
I am still learning WPF myself, but hope this is some help...
-Matt.