DataView.Table is not obeying DataView.Sort rules - c#

I have a DataView called FubarView, which was created by a call to our database. The columns are Label, Value, RawName & PhoneNumber. After creation of the DataView, I added a sort order to the DataView with...
this.FubarView.Sort = "RawName, Value"
I then (amongst other irrelevant stuff like setting DisplayMember, etc.) bound it to my WinForms ComboBox...
cmbDefault.DataSource = this.FubarView;
This worked perfectly, with the ComboBox, displaying sorted information as intended. HOWEVER, when at a later point I tried to look at FubarView using the SelectedIndex from my ComboBox...
phoneNumber = this.FubarView.Table.Rows[cmbDefault.SelectedIndex]["PhoneNumber"]
...it would return the wrong value, as if FubarView went and sorted itself by Value again! How do you fix this?

This is because you are sorting a view on the table, not the actual table. So if you access the Table trough DataView.Table you get your original data.
If you want to access the sorted rows you should access them trough the DataView.

I wouldn't work with indexes, I would use IDs instead.

Related

Correct way to bind a GridLookUpEdit to a XtraGridColumn

I want to do the following:
I have an XtraGrid (short Grid) on top of an Dialog to choose e.g. offers.
A offer has a dealer from a list of all dealers.
'offer' and 'dealer' are XPO Objects.
In the lower part there is a GridLookUpEdit (short LookUp)
Maybe I'm totally in a wrong way, because we used another data mapper before, but I'm completly stuck.
I have defined an XPCollection which is bound to the Grid and another XPCollection bound to the LookUp.
If I select a row in the Grid, values of Lookups which are not XPO-objects get changed according to the selected row.
As soon as the LookUp contains an XPO Object nothing is displayed. Session of all XPCollections are the same.
If i click in the LookUp, a list of all Dealers is shown.
If i select an entry I do the following:
Order order = gridView.GetRow(gridView.FocusedRowHandle); => shows an order
Dealer actDealer = this.gridLookUpEditDealer.EditValue as Dealer; => shows a Dealer
order.Dealer = actDealer; => lets the selected value vanish.
this.gridLookUpEditDealer.EditValue stays the same, but is no longer displayed.
The DataBinging of the LookUp is:
this.gridLookUpEditDealer.DataBindings.Add(new System.Windows.Forms.Binding("EditValue", this.mainGrid, "Dealer", true));
this.gridLookUpEditDealer.Properties.DataSource = this.dealers; // dealers = XPCollection
If i try:
this.gridLookUpEditDealer.EditValue = current.Dealer;
The LookUpEdit shows the value, but also "Value not valid"
I think the root cause is something that maybe the value in the Grid is not correctly bound as value in the LookUp. But what would be a correct way?
I think the problem is, that you directly binding the whole Dealer. Set up your GridLookUpEdit as described in DevExpress Documentation.
So you should do following for your LookupEdit:
Set the LookupEdit.ValueMember = "DealerId";
Bound the EditValue to this DealerId.
Set the LookupEdit.DisplayMember = "Name"; //Or sth. you like to show
Set your LookupEdit.DataSource = YourDealer-List
With something like this you get your DealerObject back:
Dealer dealer = GridLookUpEdit.Properties.GetRowByKeyValue(lookUpEdit.EditValue) as Dealer;
Because the EditValue will be your DealerId now. Further notice that you can use repositoryGridLookupEdit directly in your Offer Grid. So you don't need more then one Grid to show your information in a usable manner. Each offer is able to has a own Dealer-Column which holds a dealer. The repositoryLookupEdit allows you to edit the dealer within the Grid.
I hope this will help you. If not clarify your problem, i will assist you ;)
Just another way to achieve the same result. With XPO, if you change the binding code as shown below, the GridLookUpEdit will update the order.Dealer property automatically.
this.gridLookUpEditDealer.DataBindings.Add(new System.Windows.Forms.Binding("EditValue", this.mainGrid, "Dealer!", true));
I only added the exclamation sign behind the property name and can now remove this code:
Order order = gridView.GetRow(gridView.FocusedRowHandle); => shows an order
Dealer actDealer = this.gridLookUpEditDealer.EditValue as Dealer; => shows a Dealer
order.Dealer = actDealer; => lets the selected value vanish.
This feature was introduced specially for look-up editors and is described in this article: Property Descriptors.

How to keep "schema" of datagridview after DataSource refresh

I have 2 DataGridViews, it´s a kind of MasterDetail tables. I have a problem with Detail DataGridView called "dgw". It´s DataSource is datatable, dgw.DataSource=DataTable;. In code I do some work with columns like change names, add some columns, dgw.Columns.Add(NewColumn); change type of column, make some columns not visible etc.
Problem is, that when I set DataSource of dgw again, which is always when the row is changed in Master DataGridView, all my work with columns in dgw is gone and I see "ugly" columns without any changes I made to them.
This is how I refresh DataSource of dgw, code is called on every change of row in MasterDataGridView.
dgw.DataSource = typeof(DataTable);
dgw.DataSource = GetVCVDataSource(dataTable);
I found some solution and I thought that 1st line should do the work but I probably did not get the idea. Before it was dgw.DataSource = null;, I used that to turn off events that happened during datasource assignment.
I believe that there must be some easy solution but I can not work it out.
Thank you for any advice.
I suspect the first line in there is hurting you; the following would be more appropriate:
xx.DataSource = null;
xx.DataSource = GetVCVDataSource(dataTable);
Which will rebind without having to worry about a different type in the middle.
Also, at some point earlier (once only):
xx.AutoGenerateColumns = false;

Why can't I retrieve deleted DevExpress Grid rows?

I'm trying to get a list of rows deleted by pressing the '-' button in a Devexpress Grid widget as depicted here.
However, doing the following does not return any results
DataView delrows = new DataView(myTableAdapter.DataView.Table);
delrows.RowStateFilter = DataViewRowState.Deleted;
What am I doing wrong?
edit: Filtering on Added and Modified rows works fine.
instead of doing as you do now try this:
myTableAdapter.DataView.RowStateFilter = DataViewRowState.Deleted;
of course it's not easy to guess without knowing better your data binding architecture...
Considering that your DevExpress grid is binded to a DataTable (either with or without a DataView):
You can retrieve the deleted rows by using the Select() method of the DataTable. This is not a linq method.
table.Select(null, null, DataViewRowState.Deleted);
The rest of the rows can be retrieved by using
table.Select(null, null, DataViewRowState.CurrentRows);
Just be aware that a row that is added then deleted will not have the deleted flag, but will instead be removed from the rows collection. Such rows would also have a RowState of Detached.

DataGridView Custom Sorting With Datasource

In my C# .NET application, I have a DataGridView. The grid's DataSource is a BindingSource, and the BindSource is bound to a filtered DataView of a DataTable that is requeried from SQL frequently.
I can already sort columns in the grid, but the sort is always done alphabetically on the string version of whatever data value is showing in the cells. I have some fields that display a name, but need to be ordered by a specific value instead of alphabetically. I also have a field that can either be a number or the word "Unknown". I need to be able to customize the logic behind the sort.
I know I can't use the grid's SortCompare event because I am using a bound DataSource. I have tried creating columns that display a custom class that derive from IComparable, but sorting on that column still always sorts alphabetically instead of using my Compare() method.
I found one possible solution that involves keeping a hidden DataGridViewColumn that stores a number for sorting on, and using the grid's ColumnHeaderMouseClick event to force it to sort on that hidden "sort" column when the user clicks on the "display" column. However, the column header's "sort glyph" (the little up/down arrow icon that shows up on the sorted column) won't shot up because the actual sorted column is hidden. I have tried manually setting the column's HeaderCell.SortedGlyphDirection property, but the icon will always be hidden if the BindingSource's sort is not for that column.
I'm pretty sure I could get this working if, instead of a DataView of a DataTable, I used a sortable List of a custom wrapper objects I create for each data row, but I don't want to resort to that if possible. But if that's my only option, that's what I'll do.

Different Value Member, same control

Edit 1
I believe my problem stems from the following. The function that fills the dropdown portion sets the Display Member to the CountyName. Then when I try and set the SelectedText or EditValue, as has been suggested, that function only returns the CountyID which it try's to match to something in the DropDown list DisplayMember. I need it to match it to something in the ValueMember list.
Using the following I got it to work but it is a HACK and I'd greatly appreciate finding a real solution.
lkuResidenceCounty.ItemIndex = Convert.ToInt32(row["ResidencyCountyID"].ToString());
Original Post
I have a lookup box(DevExpress) on a member form that I fill the possible values in from the DB with this code -->
lkuResidenceCounty.Properties.DataSource = ConnectBLL.BLL.Person.CountyList();
lkuResidenceCounty.Properties.PopulateColumns();
lkuResidenceCounty.Properties.DisplayMember = "CountyName";
lkuResidenceCounty.Properties.ValueMember = "CountyID";
lkuResidenceCounty.Properties.Columns[0].Visible = false;
lkuResidenceCounty.Properties.Columns[2].Visible = false;
lkuResidenceCounty.Properties.Columns[3].Visible = false;
This works just fine as the CountyName is displayed as expected.
However, When I try and load an existing member's value for this field using the below, which is part of a function that takes a row from the DataSet -->
lkuResidenceCounty.Properties.ValueMember = row["ResidencyCountyID"].ToString();
I get a blank box. I have stepped through the code and the correct ID is being returned for the member.
Unfortunately the stored procedure to fill the dropdown options pulls from a Maintenance Table with the columns "CountyName" & "CountyID". So that is correct. Unfortunately, the stored procedure to load a specific person's current county pulls from the Person Table where there is a column called "ResidencyCountyID". It is so named because there is also a "ResponsibilityCountyID" column.
I need a way for them both to coexist, any solutions?
Thanks!
DisplayMember and ValueMember are used to populate the control with the list of selectable values. To set the selected value of a populated LookUpEdit control, set its EditValue property:
lkuResidenceCounty.EditValue = row["ResidencyCountyID"].ToString();
In response to your edit: According to the documentation:
The currently selected row determines values for the editor's edit value and display text. The value for BaseEdit.EditValue is obtained from the RepositoryItemLookUpEditBase.ValueMember field, while the text to display in the edit box is obtained from the RepositoryItemLookUpEditBase.DisplayMember field of the selected row.
When you change BaseEdit.EditValue,
the editor locates and selects the row
whose
RepositoryItemLookUpEditBase.ValueMember
field contains the new value. The text
in the edit box is changed to reflect
the newly selected row.
I don't use these controls but it sounds to me that it shouldn't be working as you described. I think the ToString() is the problem because EditValue accepts an object so it's probably expecting an int for the value. Try:
lkuResidenceCounty.EditValue = (int)row["ResidencyCountyID"];
The ValueMember property tells the list what field to pull from when setting the Value property. Once you've set the ValueMember to "CountyID", then when the list is Databound, it will set all the list items' value properties to their respect objects' CountyID fields.
Hence, you should not do:
lkuResidenceCounty.Properties.ValueMember = row["ResidencyCountyID"].ToString();
but rather
lkuResidenceCounty.Properties.ValueMember = "CountyID";
was perfectly fine, as long as you've correctly identified the field you're trying to databind. Once the list get's databound you should see the results you're expecting.
However, after looking at your code, it seems that you're mismatching your field. In one place you're using ResidencyCountyID and in another you're using CountyID. That is most likely your source of confusion. Figure out what the actual field name is and make sure you set the ValueMember to that.
UPDATE
After reading your comment, what your looking for is the SelectedValue property. The SelectedValue property tells the list to force the selected value to whatever input you give it.
Essentially you have two things going on here. ValueMember tells the list what to use as the value from your data source, and SelectedValue which tells the list what the currently selected value should be.
Why is it that you need the same LookUpEdit to have two value members? Is it being used standalone or in a grid? If standalone, you could swap out the two repository editors depending on the current row. But, are there more than 2 possible values for the ValueMember? That would also complicate things.
UPDATE
Looking at your edit, I think I understand what's going on a little more. So, you don't wish to change your ValueMember (which refers to a data column), but rather to change the value of the editor? If so, then you should definitely use EditValue (not SelectedText, which I don't believe is meant to be set), and assign it to row["value_field"] like so:
lkuResidenceCounty.EditValue = row["ResidencyCountyID"];
What happens when you do that?

Categories

Resources