Binding DataGrid Row Number to Property - c#

I have a DataGrid (named OperatorDataGrid) and the row number is set via the LoadingRow event:
private void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
e.Row.Header = (e.Row.GetIndex() + 1).ToString();
}
And the DataGrid itself is bound to an ObservableCollection<FilterRow> where FilterRow as a property called Index (not currently being used). The binding is done in the user control's constructor:
public AdvancedFilter()
{
InitializeComponent();
SetDefaults();
FilterRows.Add(new FilterRow());
OperatorDataGrid.ItemsSource = FilterRows;
}
What I can't figure out is how to bind the Row.Header value back to the model as items can constantly be added/removed. The LoadingRow method handles showing the number in the DataGrid but I can't get that value back into the object bound to that specific row since the header is not a specific column that is defined in the <DataGrid.Columns> section in the XAML. I did try the solution found here, however whenever I added a new row, the header cell would show Index is 0 for every row. Any suggestions would be appreciated.

You could simply set the source property yourself when you set the Header:
private void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
int rowNumber = e.Row.GetIndex() + 1;
e.Row.Header = rowNumber.ToString();
var dataObject = e.Row.DataContext as YourClass;
if (dataObject != null)
dataObject.RowNumber = rowNumber;
}
Then you know that the row number that you see in the view is synchronized with the property of the data object.
There is no way to bind directly to a method like GetIndex() in XAML which is why you handle the LoadingRow event in the first place.

Related

how to get the rows property in gridview of devxpress with a button to edit?

i have a gridview with devexpress my gridview contain a id ID="GriviewLV1" and i have a button in the row of the gridview to edit the record , in the event click of the button im trying give click in the button to edit but cannot get the property rows or something like that. im trying something like this but cannot do rows property because dont exist the rows property in grid view devexpress
button_Edit_click(object sender, EventArgs e)
{
foreach (GridViewRow row in GriviewLV1.Rows)
{
}
}
And for what exactly do you need row collection?
As far as I know, you can only manipulate with records (DataSource property object). Also it is possible to get selected row. Some my code examples with explanation:
private List<ImageSetMember> imageSets;
...
//assign collection as grid's DataSource.
//From now on any actions on imageSets object will be automatically reproduced
//as grid's row changes.
imageSetGridControl.DataSource = imageSets;
...
private void replaceButtonEdit_Click(object sender, System.EventArgs e)
{
//get focused row record's index at DataSource collection
int index = imageSetGridView.GetDataSourceRowIndex(imageSetGridView.FocusedRowHandle);
var selectedImage = imageSet[index].Image; //accessing to row's record
}

Bind a textbox to a datagridview row

I want to bind DataGridView Rows all from the same Column to a textbox, to make the text of that cell appear in that textbox when I click on cells from that Column. The problem is I can't use e.RowIndex. Is there any way to do this with properties or code?
You can use the TextBoxes DataBindings property. Something like...
textBox1.DataBindings.Add(new Binding("Text", GridDataSource, "ColumnOrPropertyName"));
If the grid does not have a data source, then you can wire up the grids SelectionChanged event and reference the grids CurrentRow property. Something like...
private void dataGridView1_SelectionChanged(object sender, EventArgs e) {
if (dataGridView1.CurrentRow != null) {
textBox1.Text = dataGridView1.CurrentRow.Cells["ColumnName"].Value.ToString();
}
}

ComboBox.Items.IndexOf returns -1

I have a ComboBox which is populated on Page Load event. Just after populating the ComboBox I call another method which returns a value that I want to make the default value of the ComboBox when Page loads. How can I change the selectedIndex to a value that is returned when I call another method?
XAML for ComboBox
<ComboBox Name="cboProductType" DisplayMemberPath="ProductTypeName" SelectedValuePath="ProductTypeID" SelectedIndex="0"/>
Page Load event:
void OnProductDetailLoad(object sender, RoutedEventArgs e)
{
GetServiceReference.Service1Client service = new GetServiceReference.Service1Client();
service.GetProductDetailsCompleted += service_GetProductDetailsCompleted;
service.GetProductTypeCompleted += service_GetProductTypeCompleted;
service.GetProductTypeAsync();
service.GetProductDetailsAsync(ProductId);
}
Populating ComboBox when Page Loads:
void service_GetProductTypeCompleted(object sender, GetProductTypeCompletedEventArgs e)
{
cboProductType.ItemsSource = e.Result;
}
Calling the other method which returns a particular ProductTypeName. I tried to get the index of that particular ProductTypeName but returns -1 always.
void service_GetProductDetailsCompleted(object sender, GetServiceReference.GetProductDetailsCompletedEventArgs e)
{
if (e.Result.Count != 0)
{
p.ProductID = e.Result[0].ProductID;
int index = cboProductType.Items.IndexOf(e.Result[0].ProductTypeName);
cboProductType.SelectedIndex = index;
}
Also is this a right approach for setting the SelectedIndex property?
Say I have following items loaded in ComboBox in following Index order:
Index DisplayMemberName(ProductTypeName)
0 Color
1 Size
2 Variant
3 N-size
and e.Result[0].ProductTypeName contains Variant so I now want SelectedIndex = 2 of ComboBox
I hope my question is clear
The SelectedIndex is only valid when you manually fill a combobox. If you are using the ItemsSource to fill the items in a combobox, you must define a SelectedValuePath which will then allows you to use the SelectedItem property to SET/GET the selected item. When using binding to a DataContext to bind the controls, the SelectedValuePath should be the property that links the Parent/Child together.

How to hide automatically generated columns in DataGrid?

I've automatically populated a DataGrid from a DataTable from a SQL server. I want the user to be able to add or remove which columns are visible. I originally tried this:
public void populateTaskTable(DataTable dt)
{
//add the whole datatable to the datagrid
dg.DataContext = dt.DefaultView;
dg.Columns[0].Visibility = Visibility.Collapsed;
}
For a corresponding xaml (I've tried both with and without the AutoGenerateColumns="True"
<DataGrid Name="dg" ItemsSource="{Binding}" AutoGenerateColumns="True"
<!-- <DataGrid.Columns></DataGrid.Columns> -->
</DataGrid>
Which resulted in a memory violation break. So then I did
MessageBox.Show(dg.Columns.Count());
to see if Columns was being populated, which it wasn't, it output a 0 even though I could see the columns in the program.
I found out from this previous stackoverflow question that "automatically generated columns are not added to the Columns index".
Then from this question I tried updating the DataGrid to get Columns populated like so
taskTable.UpdateLayout();
and
taskTable.Items.Refresh();
Which didn't do anything.
Is there a way to access the properties of an automatically generated DataGrid, or a way to add all of the columns of the DataGrid to the Columns component?
Thanks in advance.
Hook up the AutoGeneratingColumn event and hide the column over there.
dataGrid.AutoGeneratingColumn += dataGrid_AutoGeneratingColumn;
void dataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
e.Column.Visibility = Visibility.Collapsed;
}
You may need to conditionally hide the columns, you can use
private void DataGrid_OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
if (e.PropertyName == "YourProperty")
{
e.Column.Visibility = Visibility.Collapsed;
}
}
Or you can use AutoGeneratedColumns event. It will be fired when all the columns has been generated.
dataGrid.AutoGeneratedColumns += DataGrid1_AutoGeneratedColumns;
void DataGrid1_AutoGeneratedColumns(object sender, EventArgs e)
{
int columnsCount = DataGrid1.Columns.Count;
//You can access the columns here.
}
The link you referred says that Automatically generated columns are not added to the Columns collection. I just noticed that Auto generated columns are indeed added to the collection. It is poor answer that links to the documentation of System.Web.UI.WebControls.DataGrid which is very wrong.
My solution is to use a static method where you pass in the grid and list of column names like this:
public static void CollapseGridColumns(DataGrid grid, List<string> columnNames)
{
foreach (var column in grid.Columns)
{
foreach(string columnName in columnNames)
{
if (column.Header.ToString().ToLower() == columnName.ToLower())
{
column.Visibility = Visibility.Collapsed;
break;
}
}
}
}

How make a DataGridVewLinkColumn sort with the rest of the DataGridView

I populated a DataGridView with a DataTable as DataSource. This DataSource has a column with comments in it. I hide this column as part of the requirements and added a new DataGridVewLinkColumn that when is clicked the user will be able to see that comment.
My problem is when I sort by clicking on any of the headers from the DataGridView, all the DataGridViewLinkColumn links disappear. I have set the SortMode to Automatic in this LinkColumn but seems that I need to do something else because still as soon as I click on the headers from the other columns in the Grid the links disappear.
Any one knows how can I make sure that when the DataGridView is sorted the link column gets sorted accordingly?
Many thanks
OK I figure it out. The problem is because I used a DataTable as DataSource it was binded to the grid and there is no way to add an extra column to a grid source that is already binded and expect that it will bind with the source.
To solve this problem I just modified the data table. Add the extra column in the data table with the strings that will be the links in the DataGridView and populate the DataGridView programatically as recommended in http://msdn.microsoft.com/en-us/library/bxt3k60s(v=vs.90).aspx
Column Sort Modes in the Windows Forms DataGridView Control
When a DataGridView control containing both bound and unbound columns is sorted, the values in the unbound columns cannot be maintained automatically. To maintain these values, you must implement virtual mode by setting the VirtualMode property to true and handling the CellValueNeeded and CellValuePushed events.
This is a bit complicated, so the simplest solution would be to add an extra column into your DataTable.
I'll leave an example below for future reference.
The points are:
VirtualMode should be true.
CellValueNeeded should be handled properly to show the specified cell values.
ColumnHeaderMouseClick should be handled properly to sort by the unbound columns, and to show sort glyphs.
Note:
The DataGridView in this example is read-only to make things simple.
This example form contains:
A typed DataSet, that has DataTable1 with columns of ID(string), Comment(string):
private DataSet1 dataSet1;
A BindingSource:
private BindingSource dataTable1BindingSource;
.DataMember = "DataTable1";
.DataSource = this.dataSet1;
A DataGridView:
private DataGridView dataTable1DataGridView;
.DataSource = this.dataTable1BindingSource;
.VirtualMode = true;
.CellValueNeeded += this.dataTable1DataGridView_CellValueNeeded;
.ColumnHeaderMouseClick += this.dataTable1DataGridView_ColumnHeaderMouseClick;
.ReadOnly = true;
.AllowUserToAddRows = false;
.AllowUserToDeleteRows = false;
Its columns:
private DataGridViewTextBoxColumn iDDataGridViewTextBoxColumn; // bound column
private DataGridViewTextBoxColumn commentDataGridViewTextBoxColumn; // bound column
private DataGridViewLinkColumn linkColumn; // unbound column
.SortMode = DataGridViewColumnSortMode.Automatic;
And here goes the code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// Hold the link texts, in a dictinary
// keyed by ID (= unique key in DataTable1), to be bound to each row.
private SortedDictionary<string, string> _linkTexts
= new SortedDictionary<string, string>();
private void Form1_Load(object sender, EventArgs e)
{
// Bound data sample
this.dataSet1.DataTable1.AddDataTable1Row("1", "Comment1");
this.dataSet1.DataTable1.AddDataTable1Row("2", "Comment2");
this.dataSet1.DataTable1.AddDataTable1Row("3", "Comment3");
// Unbound data sample
this._linkTexts.Add("1", "linkA");
this._linkTexts.Add("2", "linkC");
this._linkTexts.Add("3", "linkB");
}
// Handles ColumnHeaderMouseClick to do custom sort.
private void dataTable1DataGridView_ColumnHeaderMouseClick(
object sender, DataGridViewCellMouseEventArgs e)
{
// When the unbound column header is clicked,
if (e.ColumnIndex == this.linkColumn.Index)
{
// Create a new DataView sorted by the link text
// with toggling the sort order.
DataView newView;
switch (this.linkColumn.HeaderCell.SortGlyphDirection)
{
case SortOrder.None:
case SortOrder.Descending:
this.linkColumn.HeaderCell.SortGlyphDirection
= SortOrder.Ascending;
newView = this.dataSet1.DataTable1
.OrderBy(row => this._linkTexts[row.ID])
.AsDataView();
break;
default:
this.linkColumn.HeaderCell.SortGlyphDirection
= SortOrder.Descending;
newView = this.dataSet1.DataTable1
.OrderByDescending(row => this._linkTexts[row.ID])
.AsDataView();
break;
}
// Set it as DataSource.
this.dataTable1BindingSource.DataSource = newView;
// Clear sort glyphs on the other column headers.
foreach (DataGridViewColumn col
in this.dataTable1DataGridView.Columns)
{
if (col != this.linkColumn)
col.HeaderCell.SortGlyphDirection = SortOrder.None;
}
}
// The bound column header is clicked,
else
{
// Sorting has done automatically.
// Reset the sort glyph on the unbound column.
this.linkColumn.HeaderCell.SortGlyphDirection = SortOrder.None;
}
}
// Handles CellValueNeeded to show cell values in virtual mode.
private void dataTable1DataGridView_CellValueNeeded(
object sender, DataGridViewCellValueEventArgs e)
{
// Extract the bound row from the current data view.
DataSet1.DataTable1Row row
= (this.dataTable1BindingSource[e.RowIndex] as DataRowView)
.Row as DataSet1.DataTable1Row;
// For the unbound column,
if (e.ColumnIndex == this.linkColumn.Index)
{
if (row.IsIDNull())
e.Value = DBNull.Value;
else
// get the value from the dictionary.
e.Value = this._linkTexts[row.ID];
}
// For the bound columns,
else
{
// get the value from the data source.
string propName = this.dataTable1DataGridView
.Columns[e.ColumnIndex].DataPropertyName;
e.Value = row[propName];
}
}
}

Categories