My CollectionViewSource is not picking up changes - c#

I have a ListView which I'm binding to a CollectionViewSource in code behind with:
collectionView = CollectionViewSource.GetDefaultView(TableView.ItemsSource);
collectionView.SortDescriptions.Clear();
collectionView.SortDescriptions.Add(new SortDescription(propertyName, direction));
The TableView is the ListView, the propertyName is the name of the column I want sorted, and direction is either ascending or descending.
The XAML has the following for ItemSource:
ItemsSource="{Binding Rows}"
The code behind has the following for the Rows:
List<TableRow> rows;
public List<TableRow> Rows
{
get { return rows; }
set
{
rows = value;
UpdateProperty("Rows");
}
}
the update is as follows:
public void Update()
{
...generate a list of rows...
Rows = ...rows...
}
The problem occurs when the Update is called, the list view does update, but loses the sorting set previously on the CollectionViewSource.

If you are "newing" rows then any setting on the prior rows is gone. If you clear (not new) the rows then I think they will hold the setting.
And you don't even want Rows = rows in update.
After assign rows then.
NotifyPropertyChange("Rows");
So the UI know to update
If you are going to new then reassign
collectionView = CollectionViewSource.GetDefaultView(TableView.ItemsSource);
collectionView.SortDescriptions.Clear();
collectionView.SortDescriptions.Add(new SortDescription(propertyName, direction));
Maybe
private List<TableRow> rows = new List<TableRow>();
and have that the only place you new it

The answer is to reapply the sort descriptions after the update, as in:
collectionView = CollectionViewSource.GetDefaultView(TableView.ItemsSource);
collectionView.SortDescriptions.Clear();
collectionView.SortDescriptions.Add(new SortDescription(propertyName, direction));
Then the sorting isn't lost. Refresh on the collection view doesn't help.

If an item property value involved in one of the grouping, sorting and filtering operations is
updated, then the sorting/grouping/filtering will not be done again.
WPF 4.5 introduce a feature called live shaping which shapes the
collection view in live.
See this article for more info.

Did you try to do CollectionView.Refresh() after your update?
If this does not help then I think your problem occurs because you change the source of your CollectionView by assigning new value to your Rows list.
I don't know if it is possible to your code but don't assign new list just clear your previous one and insert new rows there.
if (Rows != null)
Rows.Clear();
Rows.TrimExcess();
else
Rows = new List<TableRow>();

Related

Edit the DataGrid after filter in WPF

I have a DataGrid bound to an ObservableCollection of DataRowView.
When I do any operations such as Insert/Delete/Copy/Paste/Undo/Redo, I manipulate the underlying DataSource.
Ex: When I have to paste data into a set of cells, I get their row and column indexes (the cell the context menu points to) and edit the DataSource. I store their previous values and their indexes to revert back when I do an "Undo" operation.
When I filter the grid, the view changes where as the DataSource remains the same. So, when I do a paste operation, the indexes I get don't match with the ones in the DataSource. I end up pasting in the wrong cells.
How can I manipulate the DataSource i.e get the actual indexes/data to do all the operations after filter is applied?
Based on what I understood after reading your question. New record which appear after Item1 should apppear after Item1 in source collection too. This is not happening right now as index is differing which will of course differ.
As you have not posted code, so I have posted sample code below :
// new employee to add
Employee empNew = new Employee() { Name = "New1", Address = "NewAdd1" };
// get corresponding item in filtered view after which you want to insert
Employee emp = (Employee)DgrdEmployees.SelectedItem;
// get true collection which is datasource
ObservableCollection<Employee> sourceCol = (ObservableCollection<Employee>)(CollectionViewSource.GetDefaultView(DgrdEmployees.ItemsSource).SourceCollection);
// find index of selected item after which we are inserting/pasting
int trueIndex = sourceCol.IndexOf(emp);
// insert it at exact location in true unfiltered source collection
sourceCol.Insert(trueIndex + 1, empNew);

How to remember the sorted

In a "Refresh" function for a WPF DataGrid, I'm trying to save the sorting criteria prior to the reload of items to the DataGrid, the new items loaded and then set the previous sorting criteria. I'm using this code:
void Refresh(DataGrid docsDataGrid) {
var sd = ListSortDirection.Ascending;
DataGridColumn sortCol = null;
foreach (var column in DocsDataGrid.Columns)
{
if (column.SortDirection != null)
{
sd = (ListSortDirection)column.SortDirection;
sortCol = column;
}
}
docsDataGrid.ItemsSource = GetLatestItems();
sortCol.SortDirection = sd;
}
With the code above, I do get the visual cue of "sorted column", but the newly loaded items are not really sorted, so it is a bit of a mirage. I tried with docsDataGrid.Items.Refresh() after sortCol.Direction = sd but the datagrid does not pick up the sorting direction set programatically.
How can I leverage the built-in sorting facilities of the DataGrid and programatically set the column to be sorted (and actually sort rows by that column)?
After some additional research the SortDataGrid example in this SO Q&A helped me: Sort a wpf datagrid programmatically
It seems that I should have dealt also with DataGridItems.SortDescriptions as well.
Not sure if this will help you but why not save the selected SortDirection in a setting and load it when you need it?

Repository item lookUpEdit resets after losing focus

I have this problem for days and can't find solution for it. I tried all possible solutions i found on internet, but seems like none suits this one.
Thing is that i added repository item to gridControls (i added it through designer, not through code). Then, in code i added data source to that repository lookUpEdit and i have items in dropDown in that column. But when i select item in repository and click on other cell, Selected item in repository is cleared and repository shows null value again...
Any ideas what i did wrong ?
EDIT:
Also, when i click on any cell in my grid, i have delay of second or two, and after that delay clicked cell is focused... Any solutions for all of this?
EDIT:
Don't know what code to show You, because I did all in devExpress designer. Here is part of the code where I set data source to repository item, and i will give You code from designer of that repository item.
private void ConfigureRepositoryItems()
{
BetService.SportManagerClient dbSportManager = new BetService.SportManagerClient();
BetService.BLOddsControlSettings[] oddsControlSettings = dbSportManager.GetOddsControlSettings("", "");
repositoryOddsControlSettings1.DataSource = oddsControlSettings;
}
And here is code from designer:
//
// repositoryOddsCalculationSettings1
//
this.repositoryOddsCalculationSettings1.AutoHeight = false;
this.repositoryOddsCalculationSettings1.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] {
new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Combo)});
this.repositoryOddsCalculationSettings1.Columns.AddRange(new DevExpress.XtraEditors.Controls.LookUpColumnInfo[] {
new DevExpress.XtraEditors.Controls.LookUpColumnInfo("ID", "ID", 20, DevExpress.Utils.FormatType.None, "", false, DevExpress.Utils.HorzAlignment.Default),
new DevExpress.XtraEditors.Controls.LookUpColumnInfo("Name", "Name")});
this.repositoryOddsCalculationSettings1.DisplayMember = "Name";
this.repositoryOddsCalculationSettings1.Name = "repositoryOddsCalculationSettings1";
this.repositoryOddsCalculationSettings1.NullText = "Select Settings";
this.repositoryOddsCalculationSettings1.PopupSizeable = false;
this.repositoryOddsCalculationSettings1.ValueMember = "ID";
For starters check whether the column name in your Grid datasource and the column in your grid control match. The match is case sensitive so name and Name are not same and hence can cause this issue. Secondly make sure the Grid datasource column datatype matches the value type of the LookUpEdit. If the LookupEdit is returning int and the Grid datasource column datatype is string, this alone can cause lots of headaches.

DataGrid: Dyanmically adding rows

I am new to windows application. I need to add rows in the DataGrid dynamically which has person data. when i do the following is see only the last person in the last row. i see rows populating but with no data. If i do a break on the first fetch i do get the right one. But something is wrong. Any ideas
foreach (var p in personList)
{
gvAdminSummary.Rows.Add(new DataGridViewRow());
gvAdminSummary.Rows[gvAdminSummary.Rows.Count-1].Cells[0].Value = p.FName;
gvAdminSummary.Rows[gvAdminSummary.Rows.Count - 1].Cells[1].Value = p.LName;
gvAdminSummary.Rows[gvAdminSummary.Rows.Count - 1].Cells[2].Value = p.PNo;
}
The DataGridRowView.Add method accepts string arrays:
gvAdminSummary.Rows.Add( { p.FName, p.LName, p.PNo });
Likely, though, there's a better solution for you in binding the grid directly to your person list.
This may not be the right approach. Create a BindingSource and bind a collection of your objects to it. Then bind the BindingSource to the Grid's data source. Make sure your objects implement INotifyPropertyChanged. This way, whenever, you add an object to the collection, or change a property within your object, it'll automatically reflect in the grid.
I don't know about DataGridView, but if you want to stick to inserting data into the control directly, why not use ListView instead? It has an API more suited to your current needs or way of doing things.
Either
gvAdminSummary.Datasource = persons;
gvAdminSummary.databind();
Or
foreach (var p in personList)
{
DataGridViewRow dr = new DataGridViewRow();
dr.cells.add(new datagridcell()) etc.. populate cells
gvAdminSummary.Rows.add(dr);
}

ICollectionView.SortDescriptions sort does not work if underlying DataTable has zero rows

We have a WPF app that has a DataGrid inside a ListView.
private DataTable table_;
We do a bunch or dynamic column generation ( depending on the report we are showing )
We then do the a query and fill the DataTable row by row, this query may or may not have data.( not the problem, an empty grid is expected )
We set the ListView's ItemsSource to the DefaultView of the DataTable.
lv.ItemsSource = table_.DefaultView;
We then (looking at the user's pass usage of the app, set the sort on the column)
Sort Method below:
private void Sort(string sortBy, ListSortDirection direction)
{
ICollectionView dataView = CollectionViewSource.GetDefaultView(lv.ItemsSource);
dataView.SortDescriptions.Clear();
var sd = new SortDescription(sortBy, direction);
dataView.SortDescriptions.Add(sd);
dataView.Refresh();
}
In the Zero DataTable rows scenario, the sort does not "hold"? and if we dynamically add rows they will not be in sorted order.
If the DataTable has at-least 1 row when the sort is applied, and we dynamically add rows to the DataTable, the rows com in sorted correctly.
I have built a standalone app that replicate this...
It is an annoyance and I can add a check to see if the DataTable was empty, and re-apply the sort...
Anyone know whats going on here, and am I doing something wrong?
FYI: What we based this off if comes from the MSDN as well: http://msdn.microsoft.com/en-us/library/ms745786.aspx
Update:
the sort not "holding" means, the ICollectionView.SortDescriptions has a SortDescription, but is not sorting the data as its added,
again only happens if there is no rows in the underlying DataTable if there are rows when the SortDescription is added, then everything works out fine~
Clearly this is a GUI bug. It would be nice to work around it on the GUI level not on the data level. Here is one suggestion.
DataTable table_ = new DataSet1().DataTable1;
ICollectionView dv_;
public MainWindow()
{
InitializeComponent();
dv_ = CollectionViewSource.GetDefaultView(table_);
dv_.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(dv_CollectionChanged);
lv.ItemsSource = dv_;
}
void dv_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add && table_.Rows.Count == 1 )
dv_.Refresh();
}

Categories

Resources