datagridView edits - c#

I have a datagridview that is bound to a SQLite database. Now, I wish to modify some fields in the datagridview.
There are 4 TEXT columns - Timestamp, Message, Type , Hash.
Now I find a row, I want to right click it.. And it should have to option - "include" .. So, when i click include in the context menu, the Type column of my DGV should change to "include" from whatever it previously was... (I don't want it be enabled to edit.. I just want it to change within the program) How do i get the index where I have clicked and access that particular cell to modify it??

This code does what you want:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
BindingList<User> users = new BindingList<User>();
users.Add(new User(){Name = "Fred", Included = "False", Title="Mr"});
users.Add(new User(){Name = "Sue", Included = "False", Title="Dr"});
users.Add(new User(){Name = "Jack", Included = "False", Title="Mr"});
dataGridView1.DataSource = users;
}
private void dataGridView1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
DataGridView.HitTestInfo hit = dataGridView1.HitTest(e.X, e.Y);
if (hit.rowIndex >= 0)
{
dataGridView1.ClearSelection();
dataGridView1.Rows[hit.RowIndex].Selected = true;
contextMenuStrip1.Show(this.dataGridView1, new Point(e.X, e.Y));
}
}
}
private void includeToolStripMenuItem_Click_1(object sender, EventArgs e)
{
// Included was the name of the column to change in my example code,
// you could also use the index of the column if you know it.
dataGridView1.SelectedRows[0].Cells["Included"].Value = "Included";
}
}
public class User
{
public string Name { get; set; }
public string Title { get; set; }
public string Included { get; set; }
}
I couldn't think of a better method of informing the context menu which row was selected than actually using the selected row property of the DataGridView - you could also store this in a class level field, but I don't think that is quite as tidy.

private void dataGridView_DoubleClick(object sender, EventArgs e)
{
var grid = (DataGridView)sender;
var point = grid.PointToClient(Cursor.Position);
var hit = grid.HitTest(p.X, p.Y);
MessageBox.Show(string.Format("{0} / {1}", hit.ColumnIndex, hit.RowIndex));
}
Code is not compile tested, but in theory this should do the job.
dataGridView.Rows[rowIndex].Cells[cellIndex].Value = "something";

Related

How to get value of Row Double-Click Row in gridView

I have a DevExpress gridView I want to get value of Row in Double-Click Row in gridView. I tried a lot but there error
Error CS1061 'GridView' does not contain a definition for 'CalcHitInfo' and no accessible extension method 'CalcHitInfo' accepting a first argument of type 'GridView' could be found (are you missing a using directive or an assembly reference?)
as well
How to handle clicks on row's cells?
How to i put value of Row in New window?
private void gridView2_DoubleClick_1(object sender, EventArgs e)
{
try
{
DXMouseEventArgs ea = e as DXMouseEventArgs;
GridView view = sender as GridView;
GridHitInfo info = view.CalcHitInfo(ea.Location);
if (info.InRow || info.InRowCell)
{
string colCaption = info.Column == null ? "N/A" : info.Column.GetCaption();
MessageBox.Show(string.Format("DoubleClick on row: {0}, column: {1}.", info.RowHandle, colCaption));
}
}
catch (Exception) { }
}
Your question is How to get value of Row Double-Click Row in GridView (DevExpress).
Referencing DevExpress.Win.Design 22.1.6 NuGet I was able to reproduce your issue using a minimal form and I believe the problem is coming from sender as GridView which seems to evaluate null (because the sender is GridControl and evidently is not a compatible reference per the as operator documentation).
When I cast the objects correctly, everything seems to work.
private void gridView2_DoubleClick_1(object? sender, EventArgs e)
{
if (
(sender is GridControl control) &&
(control.MainView is GridView gridView) &&
(e is DXMouseEventArgs args))
{
var hittest = gridView.CalcHitInfo(args.Location);
// BTW don't block the double-click event to do this.
BeginInvoke(() =>
{
MessageBox.Show(
text: Animals[hittest.RowHandle].ToString(),
caption: $"DoubleClick on row: {hittest.RowHandle}, column: {hittest.Column.GetCaption()}"
);
});
}
}
My minimal reproducible example uses this code to set up the DevExpress.XtraGrid.GridControl.
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
gridControl.DataSource = Animals;
Animals.Add(new Animal { Name = "Luna", Kind = Kind.Cat });
Animals.Add(new Animal { Name = "Daisy", Kind = Kind.Dog});
gridControl.DoubleClick += onGridControlDoubleClick;
var view = (GridView)gridControl.MainView;
view.OptionsBehavior.Editable = false;
view.Appearance.FocusedCell.BackColor = Color.CadetBlue;
view.Appearance.FocusedCell.ForeColor = Color.White;
}
private void onGridControlDoubleClick(object? sender, EventArgs e)
{
if (
(sender is GridControl control) &&
(control.MainView is GridView gridView) &&
(e is DXMouseEventArgs args))
{
var hittest = gridView.CalcHitInfo(args.Location);
// BTW don't block the double-click event to do this.
BeginInvoke(() =>
{
MessageBox.Show(
text: Animals[hittest.RowHandle].ToString(),
caption: $"DoubleClick on row: {hittest.RowHandle}, column: {hittest.Column.GetCaption()}"
);
});
}
}
public BindingList<Animal> Animals { get; } = new BindingList<Animal>();
}
public enum Kind
{
Other,
Cat,
Dog,
}
public class Animal
{
[Display(AutoGenerateField = false)]
public string ID { get; set; } = Guid.NewGuid().ToString().Substring(0,8);
public string? Name { get; set; }
public Kind Kind { get; set; }
public override string ToString() => $"{Name} ({Kind})";
}

Make auto generated column readonly in DataGridView

I have a DataGridView whose DataSource is a DataTable with five columns. If I attempt to access a column's ReadOnly property, like so:
datagridview.Columns[1].ReadOnly = true;
It throws a NullReferenceExcpetion.
I understand this is due to how the framework manages its auto generated columns, as noted by the answer to this question.
My question is: How do I make a column(s) readonly when the data source is auto generated?
Can't really say why it's not working, but a simple test with this code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.AutoGenerateColumns = true;
dataGridView1.DataSource = GenerateData();
dataGridView1.Columns[0].ReadOnly = true;
}
private List<DataSourceTest> GenerateData()
{
return new List<DataSourceTest>()
{
new DataSourceTest(1, "A"),
new DataSourceTest(2, "B"),
new DataSourceTest(3, "C"),
new DataSourceTest(4, "D"),
new DataSourceTest(5, "E"),
new DataSourceTest(6, "F"),
};
}
}
public class DataSourceTest
{
public DataSourceTest(int id, string name) { ID = id; Name = name; }
public int ID { get; set; }
public string Name { get; set; }
}
and making the gridview EditMode set to EditOnEnter so we can easily check if it's readonly or not, shows that it does the job well.
But if you still have issues, the best bet is to use an event, and the closest event for your question is the DataBindingComplete that will fire after the binding is done, so on that time, you will have full access to all your columns as they already bind to the gridview object.
double click on the event in the GridView control and add your readonly setter:
private void dataGridView1_DataBindingComplete(
object sender, DataGridViewBindingCompleteEventArgs e)
{
dataGridView1.Columns[0].ReadOnly = true;
}
In true TEK fashion, I figured out a solution to my own question:
To do this, you need to make use of the ColumnAdded event
datagridview.ColumnAdded += dataGridView_ColumnAdded;
Then in the event, you can check a column by name:
private void dataGridView_ColumnAdded(object sender, DataGridViewColumnEventArgs e)
{
if (e.Column is DataGridViewColumn)
{
DataGridViewColumn column = e.Column as DataGridViewColumn;
column.ReadOnly = true;
if (column.Name == "first_name")
{
column.ReadOnly = false;
}
}
}
Make column read-only when column has been generated
private void Form1_Load(object sender, EventArgs e)
{
List<Student> allStudent = new List<Student>();
for (int i = 0; i < 10; i++)
{
allStudent.Add(new Student { Name = "Student" + i, Roll = i + 1 });
}
dataGridView1.AutoGenerateColumns = true;
dataGridView1.DataSource = allStudent;
//Edited to show column count
MessageBox.Show("Column count is " + dataGridView1.Columns.Count);
foreach (DataGridViewColumn column in dataGridView1.Columns)
{
column.ReadOnly = true;
}
}
public partial class Student
{
public string Name { get; set; }
public int Roll { get; set; }
}

Creating Dynamic Tables in ASP.NET via button onclick event

Here are my requirements:
I have a dropdown list and text box (appName and profile).
I want to take the values from the dropdown and text box and add them to a table (or a control like gridview that renders into a
table)
At some point I want to be able to loop through the table and submit the values to a db.
My problem:
The postback caused by the onClick even is casing the table to only show the last value entered, and doesn't retain any of the previous
values.
Notes:
I tried to work arond this using a datalist bound to a datagrid, but no luck.
Code:
protected void addAppButton_Click(object sender, EventArgs e)
{
DropDownList appList = (DropDownList)newEntryFV.FindControl("appList");
TextBox profileTextBox = (TextBox)newEntryFV.FindControl("profileTextBox");
addAppsToTable(appList.SelectedValue.ToString(), profileTextBox.Text.ToString());
}
private void addAppsToTable(string appName, string profileName)
{
Table appsTable = (Table)newEntryFV.FindControl("appTable");
TableRow newRow = new TableRow();
TableCell appNameCell = new TableCell();
TableCell profileCell = new TableCell();
appNameCell.Text = appName;
profileCell.Text = profileName;
newRow.Cells.Add(appNameCell);
newRow.Cells.Add(profileCell);
appsTable.Rows.Add(newRow);
}
Code that solved my problem:
[Serializable]
public class securityApps
{
public string secAppID { get; set; }
public string secAppName { get; set; }
public string secProfile { get; set; }
}
protected void Page_Load(object sender, EventArgs e)
{
BindApps();
}
protected void addAppButton_Click(object sender, EventArgs e)
{
DropDownList appList = (DropDownList)newEntryFV.FindControl("appList");
TextBox profileTextBox = (TextBox)newEntryFV.FindControl("profileTextBox");
addAppsToListVS(appList.SelectedValue.ToString(), appList.SelectedItem.Text.ToString(), profileTextBox.Text.ToString());
BindApps();
}
private void addAppsToListVS(string appID, string appName, string profile)
{
securityApps secApp = new securityApps();
secApp.secAppID = appID;
secApp.secAppName = appName;
secApp.secProfile = profile;
((List<securityApps>)ViewState["appsListVS"]).Add(secApp);
}
// Binds apps to Grid View
private void BindApps()
{
GridView appsListGV = (GridView)newEntryFV.FindControl("appsListGV");
if (ViewState["appsListVS"] != null)
{
appsListGV.DataSource = (List<securityApps>)ViewState["appsListVS"];
appsListGV.DataBind();
}
else
{
List<securityApps> appsListVS = new List<securityApps>();
ViewState["appsListVS"] = appsListVS;
}
}
How about storing a List of objects (they could even be simple key value pairs) in the ViewState. You can use that data as the DataSource for a GridView. I think that's the simplest way to go. If you need more details, let me know.
Edits-- Your solution above looks good-- I might just make it a little easier by setting up a property for your ViewState values..
List<securityApps> AppsListVS{
get
{
if(ViewState["AppListVS"] == null
this.AppListVS = new List(securityApps)();
return (List<securityApps>)ViewState["AppListVS"];
}
set
{
ViewState["AppListVS"] = value;
}
}

Adding DataGridView columns programmatically

I have a DataGridView filled with productinformation. The datagridview has totally 50 columns but the users don't always need all the columns, I want to help them to be able to choose which columns to show and which ones not to show.
One solution that I would like to programm is that when the user right clicks on the columns they can choose from a list that pops up choose which columns to show and which ones not to shos. Just like the image below.
How can I do that. I would really appreciate any help.
You can achieve this using the WinForms ContextMenuStrip and the Visible property of DataGridView columns.
Here is some example code that does what you want:
namespace WindowsFormsApplication4
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
BindingList<User> users = new BindingList<User>{
new User{Name = "John", Address="Home Street", Title="Mr."},
new User{Name = "Sally", Address="Home Street", Title="Mrs."}
};
contextMenuStrip1.AutoClose = true;
contextMenuStrip1.Closing += new ToolStripDropDownClosingEventHandler(contextMenuStrip1_Closing);
dataGridView1.DataSource = users;
dataGridView1.DataBindingComplete += new DataGridViewBindingCompleteEventHandler(dataGridView1_DataBindingComplete);
}
void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
foreach (DataGridViewColumn gridViewColumn in this.dataGridView1.Columns)
{
ToolStripMenuItem item = new ToolStripMenuItem();
item.Name = gridViewColumn.Name;
item.Text = gridViewColumn.Name;
item.Checked = true;
item.CheckOnClick = true;
item.CheckedChanged += new EventHandler(item_CheckedChanged);
contextMenuStrip1.Items.Add(item);
}
foreach (DataGridViewColumn gridViewColumn in this.dataGridView1.Columns)
{
gridViewColumn.HeaderCell.ContextMenuStrip = contextMenuStrip1;
}
}
void item_CheckedChanged(object sender, EventArgs e)
{
ToolStripMenuItem item = sender as ToolStripMenuItem;
if (item != null)
{
dataGridView1.Columns[item.Name].Visible = item.Checked;
}
}
void contextMenuStrip1_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
if (e.CloseReason == ToolStripDropDownCloseReason.ItemClicked)
{
e.Cancel = true;
}
}
}
public class User
{
public string Name { get; set; }
public string Address { get; set; }
public string Title { get; set; }
}
}
The User class there is just so the example compiles, providing something to bind my DataGridView to.
I've also added some code that allows users to click more than one column at a time (by checking the close reason on closing and cancelling if it was an item select). This is actually a little borderline in terms of diverting from standard UI behaviour in my opinion - it is usually better to stick with standard behaviour, but I included since it is (I think) useful in this scenario.
Also, it is generally tidier to put this sort of customisation into a new control that inherits from DataGridView.

WPF - Changing Column Name on Data Bound DataGrid

Basically I'm using the ItemSource property of the datagrid to bind a generic list to my datagrid. However I'd really like to change the headings, I tried the following but I get a runtime exception:
dgtest.Columns[1].Header = "edited";
I used the AutoGeneratingColumn event and an Attribute to set my column names.
First create an attribute class...
public class ColumnNameAttribute : System.Attribute
{
public ColumnNameAttribute(string Name) { this.Name = Name; }
public string Name { get; set; }
}
Then I decorate my data class members with the new attribute...
public class Test
{
[ColumnName("User Name")]
public string Name { get; set; }
[ColumnName("User Id")]
public string UserID { get; set; }
}
Then I write my AutoGeneratingColumn event handler...
void dgPrimaryGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
var desc = e.PropertyDescriptor as PropertyDescriptor;
var att = desc.Attributes[typeof(ColumnNameAttribute)] as ColumnNameAttribute;
if(att != null)
{
e.Column.Header = att.Name;
}
}
... and attach it to my grid and test...
dgPrimaryGrid.AutoGeneratingColumn += dgPrimaryGrid_AutoGeneratingColumn;
var data = new object[]
{
new Test() { Name = "Joe", UserID = "1" }
};
dgPrimaryGrid.ItemsSource = data;
Here is what it looks like. Notice that the column names are not the property names (the default behavior).
This approach is a little more work, but it's nice to have the column heading defined at the same place as the bound column. You can reorder your columns without having to go to other places to fix c the column names.
You can change it on the ItemDataBound event:
public void yourDataGrid_OnItemDataBound(object s, DataGridItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Header)
{
// Change the cell index to the column index you want... I just used 0
e.Item.Cells[0].Text = "Text you want in header.";
}
}
If the grid is already bound you should be able to do:
yourDataGrid.Columns[0].Header = "Text you want in header.";
You are probably getting an error because you are trying to change the text before it is bound.
AutoGeneratedColumns event on wpf for change column name
datagrid1.AutoGeneratedColumns += datagrid1_AutoGeneratedColumns;
void datagrid1_AutoGeneratedColumns(object sender, EventArgs e)
{
datagrid1.Columns[0].Header = "New Column Name";
}
1) Switch off the automatic column generation and generate your data grid columns in the program code:
DataGridTextColumn TempColumn;
MyDataGrid.AutoGenerateColumns = false;
TempColumn = new DataGridTextColumn();
TempColumn.Header = "DisplayName0";
TempColumn.Binding = new Binding("BindingName0");
MyDataGrid.Columns.Add(TempColumn);
TempColumn = new DataGridTextColumn();
TempColumn.Header = "DisplayName1";
TempColumn.Binding = new Binding("BindingName1");
MyDataGrid.Columns.Add(TempColumn);
Then "BindigName0" is the internal binding name of column 0 and "DisplayName0" is the name that the user will see.
2) If you want to use the automatic column generation instead then the display names of the columns can be set in the "AutoGeneratingColumn" event:
MyDataGrid.AutoGeneratingColumn += MyDataGrid_AutoGeneratingColumn;
...
private void MyDataGrid_AutoGeneratingColumn(object sender,
DataGridAutoGeneratingColumnEventArgs e)
{
DataGridBoundColumn TempColumn;
string BindingName;
if (e.Column is DataGridBoundColumn)
{
TempColumn = e.Column as DataGridBoundColumn;
BindingName = (TempColumn.Binding as Binding).Path.Path;
if (BindingName == "BindingName0")
{
TempColumn.Header = "DisplayName0";
}
else if (BindingName == "BindingName1")
{
TempColumn.Header = "DisplayName1";
}
}
}

Categories

Resources