I'm looking to create a custom DataGrid such that users can attach notes to each cell using a popup input box. Currently I've created a CustomDataGrid class, inheriting from DataGrid, with a ContextMenu that has an option to add a note. When the user chooses to add a note, I find the selected cell, an input box is opened and returns the response, and I store it in a list of lists of strings, where each list of string represents a row. This doesn't work all the time, however, because sometimes no cell is selected, and I get an error message saying: 'Object reference not set to an instance of an object.'. I'm thinking of creating a CustomDataGridCell class, inheriting from DataGridCell, which has its own ContextMenu and note string. The question is, how would I make all cells in my CustomDataGrid a CustomDataGridCell? Is there a better way to do this?
Here is my current CustomDataGrid class:
public class CustomDataGrid : DataGrid
{
MenuItem miAddNote;
List<List<string>> notes;
public CustomDataGrid()
{
notes = new List<List<string>>();
miAddNote = new MenuItem();
miAddNote.Click += MiAddNote_Click;
miAddNote.Header = "Add a note";
this.ContextMenu = new ContextMenu();
this.ContextMenu.Items.Add(miAddNote);
}
private void MiAddNote_Click(object sender, RoutedEventArgs e)
{
try
{
int rowIndex = this.SelectedIndex;
int colIndex = this.SelectedCells[0].Column.DisplayIndex;
InputBox ib = new InputBox(notes[rowIndex][colIndex]);
if (ib.ShowDialog() == true)
{
notes[rowIndex][colIndex] = ib.Response;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
protected override void OnLoadingRow(DataGridRowEventArgs e)
{
base.OnLoadingRow(e);
int numColumns = this.Columns.Count;
List<string> newRow = new List<string>();
for (int i = 0; i < numColumns; ++i)
{
newRow.Add("");
}
notes.Add(newRow);
}
}
The question is, how would I make all cells in my CustomDataGrid a CustomDataGridCell?
There is no easy way to to this I am afraid. And it is not really necessary to create a custom cell type just to get rid of the exception.
Is there a better way to do this?
You should simply check whether there are any selected cells before trying to access any:
private void MiAddNote_Click(object sender, RoutedEventArgs e)
{
int rowIndex = this.SelectedIndex;
if (rowIndex != -1 && SelectedCells != null && SelectedCells.Count > 0)
{
int colIndex = this.SelectedCells[0].Column.DisplayIndex;
InputBox ib = new InputBox(notes[rowIndex][colIndex]);
if (ib.ShowDialog() == true)
{
notes[rowIndex][colIndex] = ib.Response;
}
}
}