Rows selection in GridControl DevExpress - c#

In DevExpress 13 GridControl.TableView with a dynamic list when a row is deleted the row selection doesn't dissapear. It remains on the row which replaced the deleted one. When the selected row is deleted, how can I make the row selection dissapear automatically too?
I tried to implement it through GridControl.BeginDataUpdate and GridControl.EndDataUpdate., dut it does not work.
private bool _isAlreadyLoaded = false;
private void GridControl_OnLoaded(object sender, RoutedEventArgs e)
{
if (ThisViewModel != null
&& _isAlreadyLoaded == false)
{
ThisViewModel.GettingNewRow += RefreshCommSessionsList;
_isAlreadyLoaded = true;
}
}
//InitializeDataList - method that getting List for GridControl.TableView
public void RefreshCommSessionsList()
{
App.Current.Dispatcher.Invoke(() =>
{
var a = GridControl.GetSelectedRowHandles();
int selectedRowHandle = -1;
if (a.Any())
{
selectedRowHandle = GridControl.View.FocusedRowHandle;
}
GridControl.BeginDataUpdate();
if (NewRowCount < 5 && ThisViewModel != null)
{
ThisViewModel.InitializeDataList();
TableView.DataControl.SelectItem(selectedRowHandle);
}
else
{
GridControl.RefreshData();
TableView.DataControl.SelectItem(selectedRowHandle);
}
GridControl.EndDataUpdate();
NewRowCount++;
});
}
Thank you!

You can use GridControl.CurrentItem property. If you set its value to null then the row selection will dissapear.
GridControl.CurrentItem = null;

To change the FocusedRow of a Grid, use the GridView!
So if your GridView is named the same as your GridControl it would go as follows,
GridView.FocusedRowChanged(null, null);
//Replace "GridView" with your GridView's name

Related

Custom column display text gets applied to cells it shouldn't

I got stuck while using the CustomColumnDisplayText Event. I am using this code:
private void gridView1_CustomColumnDisplayText(object sender, CustomColumnDisplayTextEventArgs e)
{
if (e.Column == colVehicle_FahrzeugartID && e.ListSourceRowIndex >= 0)
{
for (int i = 0; i < gridViewList.DataRowCount; i++)
{
object cellValue = gridViewList.GetRowCellValue(i, "Vehicle_FahrzeugartID");
this.clsFahrzeugart.ReadFromDb((int)cellValue);
if (this.clsFahrzeugart.Systemstatus == 11 && e.ListSourceRowIndex == i)
{
e.DisplayText = "Deleted...";
}
}
}
}
to display deleted if the value Systemstatus is 11 which stands for deleted in my database and everything works fine but if I am toggling my switch there are empty values in my column and some values are getting changed to deleted although they dont have the value 11.
This is how it looks if the Switch is toggled:
And this is how it should look like:
bool isOn = toggleSwitch1.EditValue is bool ? (bool)toggleSwitch1.EditValue : false;
if (isOn)
{
tbAutoBindingSource1.Filter = "Vehicle_Systemstatus = 1";
btn_UnDel.Visible = false;
}
else
{
tbAutoBindingSource1.Filter = "Vehicle_Systemstatus IS NOT NULL";
btn_UnDel.Visible = true;
}
Does somebody know how to fix this?
You do not need to traverse through all rows since this event is raised for an individual row. Since this event provides the e.ListDataSourceRowIndex property associated with a datasource row index, not a row handle, you need to use the GridView.GetListSourceRowCellValue method to access a cell value.
Refer to the Rows help topic to learn differences between datasource indexes and grid row handles.
private void gridView1_CustomColumnDisplayText(object sender, CustomColumnDisplayTextEventArgs e)
{
GridView view = sender as GridView;
if (e.Column == colVehicle_FahrzeugartID && e.ListSourceRowIndex >= 0)
{
object cellValue = view.GetListSourceRowCellValue(e.ListSourceRowIndex, "Vehicle_FahrzeugartID");
this.clsFahrzeugart.ReadFromDb((int)cellValue);
if (this.clsFahrzeugart.Systemstatus == 11)
e.DisplayText = "Deleted...";
}
}
You have several mistakes in your code.
0. Pointless cycle in event.
The CustomColumnDisplayText event are used to display text in currently processed cell. So, all you need is to get values according to that cell.
1. Wrong using of GetRowCellValue method.
You need to use RowHandle for GetRowCellValue. ListSourceRowIndex is wrong here. RowHandle and ListSourceRowIndex are not the same. You need to use GetRowHandle method to get RowHandle from ListSourceRowIndex.
Here is example:
private void gridView1_CustomColumnDisplayText(object sender, CustomColumnDisplayTextEventArgs e)
{
if (e.Column == colVehicle_FahrzeugartID && e.ListSourceRowIndex >= 0)
{
int rowHandle = gridViewList.GetRowHandle(e.ListSourceRowIndex);
object cellValue = gridViewList.GetRowCellValue(rowHandle, "Vehicle_FahrzeugartID");
this.clsFahrzeugart.ReadFromDb((int)cellValue);
if (this.clsFahrzeugart.Systemstatus == 11)
{
e.DisplayText = "Deleted...";
}
}
}

Custom cell merged

I need to display data in gridview with merged rows for some columns.
the original data from database like:
please help me to display gridview like:
for column transaksi merged by tgl
for column priority , price , creted by merged by transaksi
Using C#, how can I prepare a gridview for the format? Please help me.
I suggest you to go through documentation - Tutorial: Cell Merging
To implement custom cell merge use the GridView.CellMerge event
handler. First, check if the correct column is being processed. Then,
obtain display texts for the two cells being compared. Finally,
indicate that cells are to be merged if their display texts match. Set
the CellMergeEventArgs.Handled parameter to true to override the
grid's default processing for this column.
Example:
using DevExpress.XtraGrid.Views.Grid;
// ...
private void gridView1_CellMerge(object sender, DevExpress.XtraGrid.Views.Grid.CellMergeEventArgs e) {
GridView view = sender as GridView;
if(view == null) return;
if (e.Column == colCreatorID) {
string text1 = view.GetRowCellDisplayText(e.RowHandle1, colCreatorID);
string text2 = view.GetRowCellDisplayText(e.RowHandle2, colCreatorID);
e.Merge = (text1 == text2);
e.Handled = true;
}
}
Use your own conditions while processing a column. for example take transaksi 005, In this case check values of row 5 and 6 then compare column created by for equality depends upon your condition set the e.Merge to true.
I just picked response posted on this topic and added one line to achieve what you want.
bool IsTheSameCellValue(int column, int row)
{
// To compare only values on 1st and 2nd column (TGL, TRANSAKSI)
if (column > 1) return false;
DataGridViewCell cell1 = dataGridView[column, row];
DataGridViewCell cell2 = dataGridView[column, row - 1];
if (cell1.Value == null || cell2.Value == null)
{
return false;
}
return cell1.Value.ToString() == cell2.Value.ToString();
}
private void dataGridView_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
e.AdvancedBorderStyle.Bottom = DataGridViewAdvancedCellBorderStyle.None;
if (e.RowIndex < 1 || e.ColumnIndex < 0)
return;
if (IsTheSameCellValue(e.ColumnIndex, e.RowIndex))
{
e.AdvancedBorderStyle.Top = DataGridViewAdvancedCellBorderStyle.None;
}
else
{
e.AdvancedBorderStyle.Top = dataGridView.AdvancedCellBorderStyle.Top;
}
}
private void dataGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (e.RowIndex == 0)
return;
if (IsTheSameCellValue(e.ColumnIndex, e.RowIndex))
{
e.Value = "";
e.FormattingApplied = true;
}
}
However it's impossible to center text vertically in merged cells with this solution because it only erases the borders and not totally redraw the component.

How to set the DataGridView to not accept empty value?

I am using windows forms c# . Anyone knows how to set the DataGridView to not to accept empty value. because I do not want the user to insert empty values . Thank you
You can check value of cells on null or empty in your code:
foreach (DataGridViewRow dataRow in this.yourDataGridView.Rows)
{
for (int index = 0; index < dataRow.Cells.Count; index++)
{
if (dataRow.Cells[index].Value == null || dataRow.Cells[index].Value == System.DBNull.Value || string.IsNullOrEmpty(dataRow.Cells[index].Value.ToString()))
{
// here is your logic...
}
}
}
You can add CellValueChanged event to your dataGridView control
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value == null)
{
//Do something
}
}

Edit entire row in a DataGridView (not only one cell)

Could somebody advice how to do this?
Currently i have :
DataGridView with four columns - Text1 | Text2 | EditButton | SaveButton
When i click on the Text1 it becomes an editable field and i can
change its value
Then i try to edit Text2 but the click on this cell saves my changes in Text1
The issue is : when i try to edit second field (Text2) the first one (Text1) loses the focus, exits edit mode and saves changes that i made meanwhile i want to save all changes in a row simultaneously.
What i want to implement :
I press EditButton and all cells becomes editable so i can change value of any cell in a row
I change value of Text1, then value of Text2
And only when i press SaveButton it saves made changes
The question is : how to keep all cells in a row in edit mode until i press specific button?
Maybe you can use a custom DataGridView like this
public class CustomDGV : DataGridView
{
private object _cellValue;
private Dictionary<int, object[]> _pendingChanges;
public CustomDGV()
{
_pendingChanges = new Dictionary<int, object[]>();
}
protected override void OnCellBeginEdit(DataGridViewCellCancelEventArgs e)
{
// Save the value of the cell before edit
_cellValue = this[e.ColumnIndex, e.RowIndex].Value;
// If there's already a pending change for that cell, display the edited value
if (_pendingChanges.ContainsKey(e.RowIndex))
{
this[e.ColumnIndex, e.RowIndex].Value = _pendingChanges[e.RowIndex][e.ColumnIndex];
}
base.OnCellBeginEdit(e);
}
protected override void OnCellEndEdit(DataGridViewCellEventArgs e)
{
// Adds the edited value of the cell into a dictionary
if (!_pendingChanges.ContainsKey(e.RowIndex))
{
_pendingChanges.Add(e.RowIndex, new object[this.ColumnCount]);
}
_pendingChanges[e.RowIndex][e.ColumnIndex] = this[e.ColumnIndex, e.RowIndex].Value;
// Display the "old" value
this[e.ColumnIndex, e.RowIndex].Value = _cellValue;
}
public void SavePendingChanges(int rowIndex)
{
if (_pendingChanges.ContainsKey(rowIndex))
{
// Gets the pending changes for that row
var rowData = _pendingChanges[rowIndex];
// Update every cell that's been edited
for(int i = 0; i < rowData.Length; i++)
{
if (rowData[i] != null)
this[i, rowIndex].Value = rowData[i];
}
// Removes the pending changes from the dictionary once it's saved
_pendingChanges.Remove(rowIndex);
}
}
}
And on CellContentClick you can call SavePendingChanges()
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex > -1 && e.RowIndex > -1)
{
if (e.ColumnIndex == 3) // Save button
{
dataGridView1.SavePendingChanges(e.RowIndex);
}
}
}
Ok, i know it may look a bit messy but this seems to be simplest solution i could come up to - display TextBox over each read only cell when grid is going to edit mode :
public void DisplayEditors(DataGridView grid, DataGridViewRow row)
{
foreach (DataGridViewCell cell in row.Cells)
{
if (cell.ReadOnly == false)
{
var place = grid.GetCellDisplayRectangle(cell.ColumnIndex, cell.RowIndex, true);
var name = string.Format("EDITOR-{0}-{1}", cell.ColumnIndex, cell.RowIndex);
var editor = grid.Controls.Find(name, false).FirstOrDefault();
if (editor == null)
{
editor = new TextBox();
(editor as TextBox).Name = name;
grid.Controls.Add(editor);
}
else
{
editor.Show();
}
editor.Size = place.Size;
editor.Location = place.Location;
editor.Text = Convert.ToString(cell.Value);
}
}
}

Iterate through the columns of a Datagrid's ItemSource

I have a grid that needs to hide certain columns right after its data-bound. Here's my code so far:
private IEnumerable<DataGridColumn> GetDataGridColumns(DataGrid grid)
{
var itemsSource = grid.ItemsSource as IEnumerable;
if (null == itemsSource) yield return null;
foreach (var item in itemsSource)
{
var column = grid.ItemContainerGenerator.ContainerFromItem(item) as DataGridColumn;
if (null != column) yield return column;
}
}
private void LoadData()
{
GridMain.ItemsSource = (new VTAEEntities()).OrganizationInterfaces.ToList();
foreach (DataGridColumn Column in GetDataGridColumns(GridMain))
{
// Hiding columns
if (Column.Header as String != null) {
String tempHeader = Column.Header as String;
String[] unrequiredColumns = new String[] {
"Instances",
"Interfaces",
"Organizations",
"RegisteredCallerOnly"
};
if (unrequiredColumns.Contains(tempHeader)) {
Column.Visibility = System.Windows.Visibility.Hidden;
}
}
// Read-only columns
if (Column.Header as String != null)
{
String tempHeader = Column.Header as String;
String[] unrequiredColumns = new String[] {
"InstanceId",
"InterfaceId",
"OrganizationId"
};
if (unrequiredColumns.Contains(tempHeader))
{
Column.IsReadOnly = true;
}
}
}
}
All the unwanted columns + the columns I want to be read only are all there. Upon debugging, I realize that the GridMain.Columns is always 0 count. How do I iterate through the columns in an ItemSource?
wow, I think you're off road here.
the Itemcontainer is actually the Row in a WPF DG, not the column.
but you can achieve what you want a lot more easily:
foreach (var Column in GridMain.Columns)
{
// ...
}
also, I recommend you use Visibility.Collapsed instead of Visibility.Hidden in your case (otherwise the space will still be reserved)
as to why your Columns.Count = 0, I guess it is because when you actually run this code, your DG has not been rendered by WPF yet. So I would throw a GridMain.UpdateLayout() before looping through the Datagrid's Columns.
It might not be enough though. In this case you'd have to use this code:
UpdateLayout();
Action emptyDelegate = delegate() { };
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, emptyDelegate);
(to force an update)
otherwise, I suggest either you hide the columns on the fly using the AutoGeneratingColumn event handler in the DG, or you do the hiding AFTER the DG has been rendered using the DG's Loaded event
If you want to hide column than you can make use of
AutoGeneratingColumn
event of wpf grid that will might work for you to hide column.
private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
DataGridBoundColumn col = e.Column as DataGridBoundColumn;
//set visiblity by doing the code you wnat ..i.logic to hide column
if (col.Header.ToString().ToLower() == "id")
{
col.Visibility = System.Windows.Visibility.Hidden;
}
}

Categories

Resources