Hide column in datagrid WPF - c#

I have a table in a database which I want to display in a WPF DataGrid. However I want to hide the first column. This column defines Id's for all items. I need the Id's for further actions, but I don't want to show it in the DataGrid. I've tried the code below, but I do get an error, on the last line, that the index has to be bigger than 0.
DbMainTable.ItemsSource = dataHandler.visibleDatabaseTable.DefaultView;
DbMainTable.Columns[0].Visibility = Visibility.Hidden;
If anyone can help me, let me know.

The problem is that when you are trying to set the visibility of the column it does not exist yet.
Try this:
In constructor:
DbMainTable.ItemsSource = dataHandler.visibleDatabaseTable.DefaultView;
DbMainTable.AutoGeneratedColumns += DbMainTable_OnAutoGeneratedColumns;
below:
private void DbMainTable_OnAutoGeneratedColumns(object? sender, EventArgs e)
{
DbMainTable.AutoGeneratedColumns -= DbMainTable_OnAutoGeneratedColumns;
DbMainTable.Columns[0].Visibility = Visibility.Hidden;
}

Could you provide more information about this issue? It is hard to guess what part of code is not working based on this.
But if I had to guess you use automatically generated columns and you try to hide this column before it is added to array of columns.
I event tried to do this with autogenerated columns and it gives me the same exception as you get.
To resolve this move this part of code somewhere where this datagrid (and its columns) is already loaded - for example to OnLoaded event handler in code behind
To achieve this:
in code behind add this method
private void DbMainTable_OnLoaded(object sender, RoutedEventArgs e)
{
DbMainTable.ItemsSource = dataHandler.visibleDatabaseTable.DefaultView;
DbMainTable.Columns[0].Visibility = Visibility.Hidden;
}
and in XAML:
<DataGrid x:Name="DbMainTable"
Loaded="DbMainTable_OnLoaded"
Grid.Column="0" />

If you need the id but don't want to see the column in the grid then I would think the simplest approach is not to add the column in the first place.
Work with the data which is in visibleDatabaseTable.
private void DbMainTable_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
if ((string)e.Column.Header == "Id")
{
e.Cancel = true;
}
}
On your datagrid:
<Datagrid .....
AutoGeneratingColumn="DbMainTable_AutoGeneratingColumn"/>

Related

How to deny rows deletion based on class property value? C# WPF

I want to deny deletion of a row in case some there is a property with specific value, for example if product type is Steel I would like to deny user from deleting that row..
I'm setting source to my datagrid like this:
dataGridSourceList = new ObservableCollection<DatabaseItems>(TempController.Instance.SelectItemsByUserId(Globals.CurrentUser.Id));
dtgMainItems.ItemsSource = dataGridSourceList;
I saw there is a property CanUserDeleteRows
And I've added this to definition of my datagrid in xaml but I'm not sure how to apply this properly..
CanUserDeleteRows="{Binding ElementName=dtgMainItems, Path=SelectedItem.IsDeleteEnabled}"
Any kind of help would be awesome
Thanks
You could handle the CommandManager.PreviewCanExecute attached event:
private void OnPreviewCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
if (e.Command == DataGrid.DeleteCommand)
{
DatabaseItems selectedItem = dtgMainItems.SelectedItem as DatabaseItems;
if (selectedItem != null && !selectedItem.IsDeleteEnabled)
e.Handled = true;
}
}
XAML:
<DataGrid x:Name="dtgMainItems" CommandManager.PreviewCanExecute="Grid_PreviewCanExecute" />

Remove column from child gridview

The parent of this grid is Project while the child is BOM. I've manage to display child grid using the following code.
private void gridView_MasterRowEmpty(object sender, DevExpress.XtraGrid.Views.Grid.MasterRowEmptyEventArgs e)
{
Project projects = (Project)gridView.GetRow(e.RowHandle);
e.IsEmpty = projects.BOMs.Count == 0;
}
private void gridView_MasterRowGetRelationCount(object sender, DevExpress.XtraGrid.Views.Grid.MasterRowGetRelationCountEventArgs e)
{
e.RelationCount = 1;
}
private void gridView_MasterRowGetRelationName(object sender, DevExpress.XtraGrid.Views.Grid.MasterRowGetRelationNameEventArgs e)
{
e.RelationName = "BOMs";
}
private void gridView_MasterRowGetChildList(object sender, DevExpress.XtraGrid.Views.Grid.MasterRowGetChildListEventArgs e)
{
Project projects = (Project)gridView.GetRow(e.RowHandle);
e.ChildList = new BindingSource(projects, "BOMs");
}
However, the code is showing me all the columns. I would like to hide some columns from the child which is BOM.
The only way I found was to use something like below
dataGridView1.Columns[index].Visible = false;
But where should I place the above code?
Updated Code
private void gridView_MasterRowExpanded(object sender, DevExpress.XtraGrid.Views.Grid.CustomMasterRowEventArgs e)
{
GridView gridView = sender as GridView;
GridView detailView = (GridView)gridView.GetDetailView(e.RowHandle, e.RelationIndex);
detailView.Columns["Column Name"].Visible = false;
}
To fulfill your need you must handle the Grid_MasterRowExpanded method in your GridControl :
private void Grid_MasterRowExpanded(System.Object sender, DevExpress.XtraGrid.Views.Grid.CustomMasterRowEventArgs e)
{
GridView view = sender;
GridView detail = view.GetDetailView(e.RowHandle, e.RelationIndex);
if (e.RowHandle == 0 | e.RowHandle == 1) {
if (detail.Name == "BOM") {
detail.Columns["Column Name"].Visible = false;
}
}
}
FYI, you can also do this at design-time, which is my favorite way to go. Within the gridView designer, you need to make sure you create a gridView for the master and child. Clicking "Retrieve Details" will do this. It will also blow away any columns you have already created, along with the layout, but the easy way around this is to save the layout as an XML, click "Retrieve Details" and then re-load the XML.
Here is what your designer will look like after you do that:
From here, you can click on each gridView (the master and child separately) and customize each -- change column widths, hide columns, DELETE columns (the data is still there but impossible for the UI to add to the grid), rearrange columns, etc.
And the best part -- no code.

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 to Add new Item to XAML Datagrid using Keyboard Tab press when last item is selected?

I have a pretty basic Datagrid XAML bound to a CollectionViewSource.
<DataGrid ItemsSource="{Binding Source={StaticResource EditingItemsCollectionViewSource}}"/>
And the Collection View Source is bound to an observable collection of very basic items with 3 numerical values. C# obviously.
I want to be able to add a new row (add a new item) at the bottom of this datagrid by pressing Tab on the keyboard when I am in the last cell of the last row.
Is this possible?
One possible solution is to programmatically set the property:
dataGrid.AllowUserToAddRows = true;
in order to implement "Add Row" functionality (provided that it was originally set to false, thus the new row was invisible). As per your task definition, it could be triggered by Tab key press (with any additional condition you may add):
private void dataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
try
{
if (e.Key == Key.Tab)
{
e.Handled = true;
// your code
}
}
catch{}
}
You may also want to set some default values for newly created row item by adding event handling procedure:
dataGrid.InitializingNewItem += new InitializingNewItemEventHandler(dataGrid_InitNewItem);
private void dataGrid_InitNewItem(object sender, InitializingNewItemEventArgs e)
{
// your code
}
Other sample implementations of adding row to WPF DataGrid could be found here: Wpf DataGrid Add new row
Also, pertinent to your description, you can add the item to the underlying ObservableCollection, so it will automatically appear in the DataGrid.
Hope this will help. Best regards,

How to activate combobox on first click (Datagridview)

In winforms, you need to click the combobox twice to properly activate it - the first time to focus it, the second time to actually get the dropdown list.
How do I change this behavior so that it activates on the very first click?
This is for DATAGRIDVIEW combobox.
I realize this is an old question, but I figured I would give my solution to anyone out there that may need to be able to do this.
While I couldn't find any answers to do exactly this... I did find an answer to a different question that helped me.
This is my solution:
private void datagridview_CellEnter(object sender, DataGridViewCellEventArgs e)
{
bool validClick = (e.RowIndex != -1 && e.ColumnIndex != -1); //Make sure the clicked row/column is valid.
var datagridview = sender as DataGridView;
// Check to make sure the cell clicked is the cell containing the combobox
if(datagridview.Columns[e.ColumnIndex] is DataGridViewComboBoxColumn && validClick)
{
datagridview.BeginEdit(true);
((ComboBox)datagridview.EditingControl).DroppedDown = true;
}
}
private void datagridview_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
datagridview.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
The above code must be tied into the CellEnter event of the datagridview.
I hope this helps!
edit: Added a column index check to prevent crashing when the entire row is selected.
Thanks, Up All Night for the above edit
edit2: Code is now to be tied to the CellEnter rather than the CellClick event.
Thanks, HaraldDutch for the above edit
edit3: Any changes will committed immediately, this will save you from clicking in another cell in order to update the current combobox cell.
Set the following on your DataGridView:
EditMode = EditOnEnter
This is probably the easiest solution and has been the workaround for many users here on SO when this question gets asked.
EDIT :
Per here do the following:
Set the Editmode:
EditMode = EditOnKeystrokeOrF2
Modify the EditingControlShowing event on the datagridview:
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
ComboBox ctl = e.Control as ComboBox;
ctl.Enter -= new EventHandler(ctl_Enter);
ctl.Enter += new EventHandler(ctl_Enter);
}
void ctl_Enter(object sender, EventArgs e)
{
(sender as ComboBox).DroppedDown = true;
}
This will get you your desired results. Let me know if that doesn't do it.
I changed only the EditMode property of the datagridview to EditOnEnter and it's working perfectly.
EditMode = EditOnEnter
If you set the entire grid to EditOnEnter, you can get some pretty funky activity when you are on a text column. Here's my solution, which should be self explanatory. If you did not know the column names, you could just check the cell type on mousemove.
Private Sub GridView_CellMouseMove(sender As Object, e As System.Windows.Forms.DataGridViewCellMouseEventArgs) Handles GridView.CellMouseMove
Select Case GridView.Columns(e.ColumnIndex).Name
Case "Ad_Edit", "Size_Caption", "Demo_Code"
GridView.EditMode = DataGridViewEditMode.EditOnEnter
Case Else
GridView.EditMode = DataGridViewEditMode.EditOnKeystrokeOrF2
End Select
End Sub
Set the DropDownStyle property of your combo box to DropDownList...
Perhaps old.. But make sure to set ReadOnly property to false, else the cell wont enter editmode and therefore the EditingControl returns null and casting DroppedDown = true will cast a NullReferencException.

Categories