Basically I have the following code to bring up 3 different datagrid views depending on the button clicked.
public partial class ChooseDB : Form
{
private DataGridView doctorsDataGridView = new DataGridView();
private DataGridView patientsDataGridView = new DataGridView();
private DataGridView hospitalsDataGridView = new DataGridView();
public ChooseDB()
{
InitializeComponent();
}
public void buttonDoctorsDB_Click(object sender, EventArgs e)
{
doctorsDataGridView.DataSource = doctorsDataSet.Doctors;
doctorsDataGridView.Dock = DockStyle.Right;
if (Controls.Contains(patientsDataGridView))
Controls.Remove(patientsDataGridView);
if (Controls.Contains(hospitalsDataGridView))
Controls.Remove(hospitalsDataGridView);
this.Controls.Add(doctorsDataGridView);
}
public void buttonPatientsDB_Click(object sender, EventArgs e)
{
patientsDataGridView.DataSource = patientsDataSet.Patients;
patientsDataGridView.Dock = DockStyle.Right;
if (Controls.Contains(doctorsDataGridView))
Controls.Remove(doctorsDataGridView);
if (Controls.Contains(hospitalsDataGridView))
Controls.Remove(hospitalsDataGridView);
this.Controls.Add(patientsDataGridView);
}
public void buttonHospitalsDB_Click(object sender, EventArgs e)
{
hospitalsDataGridView.DataSource = hospitalsDataSet.Hospitals;
hospitalsDataGridView.Dock = DockStyle.Right;
if (Controls.Contains(patientsDataGridView))
Controls.Remove(patientsDataGridView);
if (Controls.Contains(doctorsDataGridView))
Controls.Remove(doctorsDataGridView);
this.Controls.Add(hospitalsDataGridView);
}
}
}
So far so good, but the table that it brings up is all "smooshed" to the right
I've checked up on autosizing but haven't found how to apply it to my code specifically.
I would like it to show all the columns, instead of just showing the first two and then giving a scrollbar at tha bootom.
I'm assuming here that autosizing is the right way to go, if not please set me on the right path.
Autosizing of a dataGridView should be on by default (and its probably set to 'displayed cells'. Does your first view of a dataGrid look fine (with all 3 columns showing up), but its subsequent views that appear scrunched?
In one of my applications, I handle the autosizing within the form1_load event.
private void Form1_Load(object sender, EventArgs e)
{
GetICD10();
FreezeBand(dataGridView1.Columns[0]); // Client requested to have ICD code column "frozen" by default
// Cannot seem to select both autosize and allow user to size in designer, so below is the "code around".
// Designer has autosize set to displayedcells.
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None; // Turn off autosize
dataGridView1.AllowUserToResizeRows = true; // Turn on letting user size columns
dataGridView1.AllowUserToOrderColumns = true;
// Create tooltip and populate it
var toolTip1 = new ToolTip { AutoPopDelay = 5000, InitialDelay = 1000, ReshowDelay = 500, ShowAlways = true };
toolTip1.SetToolTip(tbCode, "Enter an ICD code to search for");
toolTip1.SetToolTip(tbDescriptionLong, "Enter a description to search for");
}
Related
I am trying to develop a software for designing and generating batches of IDs for schools etc. On the design part, a user would be able to create any number of text fields, select them, drag them around and/or nudge them with the arrow keys and edit their properties like text, font, size, and location. What I am trying to achieve is a much simpler version of the Visual Studio form designer. Here is a screenshot of my UI
So far, I have created a User Control called 'UserLabel' that inherits the Label class (I like Label because I can set the background transparent). A new UserLabel can be created by clicking the 'Add Text' button and can be dragged around the picture box.
public partial class UserLabel : Label
{
private System.Drawing.Point StartPoint;
private bool IsMouseDown = false;
public UserLabel()
{
InitializeComponent();
this.Text = "New Item";
this.AutoSize = true;
this.BackColor = System.Drawing.Color.Transparent;
this.Font = new System.Drawing.Font("Arial", 12);
this.Location = new System.Drawing.Point(5, 5);
this.Size = new System.Drawing.Size(50, 20);
}
protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
IsMouseDown = true;
this.BringToFront();
StartPoint = e.Location;
}
}
protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
{
IsMouseDown = false;
}
protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e)
{
if (IsMouseDown)
{
this.Left = e.X + this.Left - StartPoint.X;
this.Top = e.Y + this.Top - StartPoint.Y;
}
}
}
But since Label is not selectable, I have no clue how to proceed from here. I have tried adding a BorderStyle when the item is selected (see below) to give visual cues to the user which item is selected. But this does not achieve anything as far as being able to edit the properties. And I couldn't even manage to remove the BorderSyle to indicate a loss of focus.
protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
IsMouseDown = true;
this.BringToFront();
StartPoint = e.Location;
this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
}
}
Can anyone please point me in the right direction as to how I can override the CanFocus property (or Selectable property, I have no clue) or any other suggestion on how to achieve this? I am also open to any other approach to achieve my goal.
NOTE: I have tried a different approach where there will be a set number of items that are hidden and can be set visible by user like this. But I don't like this as it is repetitive and even though 10 items seem plenty, I can never know if a user might need more than this.
You do not have to hide/show any static number of rows, it is a bad design choice. All you need is use a DataGridView and a Button to add rows to the DataGridView. This way users can type anything they want into your textboxes and select from combobox of the row whatever they want to choose, also use a submit button to push code to db/render it on ui wherever you want to. Sample code might look like this-
private void button1_Click(object sender, EventArgs e)
{
DataGridViewColumn dataGridViewColumn = new DataGridViewColumn(new DataGridViewTextBoxCell()) ;
this.dataGridView1.Columns.Add(dataGridViewColumn);
DataGridViewColumn dataGridViewColumn2 = new DataGridViewColumn(new DataGridViewComboBoxCell());
this.dataGridView1.Columns.Add(dataGridViewColumn2);
DataGridViewRow dataGridViewRow = new DataGridViewRow();
dataGridViewRow.Cells.Add(new DataGridViewTextBoxCell());
this.dataGridView1.Rows.Add(new DataGridViewRow());
}
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.
Here is what I am trying to accomplish:
I have two datagriddviews. Datagridview1 holds a list of urls. Datagridview2 is basically a bookmarking system. A user can right-click on a url in datagridview1 and select to favorite or "bookmark" it. That row will then be copied to datagridview2. The font on the row on datagridview1 will then become bolded to show that it has been favorited and added to datagridview2. How do I keep these two synced? For example if a user removes a favorite on datagridview2 it should become unbolded on datagridview1 as it is no longer a favorite. What is an efficient way to keep these 2 synced to each other since the indexes will be different? I Had through about just iterating through each row to see if the cell content strings were equal and then unbolding it based off that but that seems very inefficient. Any suggestions on how to accomplish this?
As a good option you can have a data source like a DataTable having and string Url and a bool Favorite column.
Then, bind the first grid to the data table as its DataSource.
Bind the second grid to a DataView that you created from your data table and set Favorite=true as its Filter.
Then handle RowPrePaint event of first DataGridView and set the font to be bold if the row has favorite=true, else set the font to be regular.
For add button and remove button, set the value of favorite column on data row behind the current row and then call EndEdit on data row.
Initialization
private void Form1_Load(object sender, EventArgs e)
{
//Create DataTable
var data = new DataTable();
data.Columns.Add("Url", typeof(string));
data.Columns.Add("Favorite", typeof(bool));
//Fill Data
data.Rows.Add("http://stackoverflow.com", true);
data.Rows.Add("http://bing.com", false);
data.Rows.Add("http://google.com", false);
//Set DataBidnings to allUrlsDGV
this.allUrlsDGV.DataSource = data;
//Set DataBidnings to favoriteUrlsDGV
var favoriteData = new DataView(data);
favoriteData.RowFilter = "Favorite=true";
this.favoriteUrlsDGV.DataSource = favoriteData;
}
RowPrePaint
private void allUrlsDGV_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
var f = e.InheritedRowStyle.Font;
var drv = (DataRowView)allUrlsDGV.Rows[e.RowIndex].DataBoundItem;
if (drv.Row.Field<bool>("Favorite") == true)
allUrlsDGV.Rows[e.RowIndex].DefaultCellStyle.Font = new Font(f, FontStyle.Bold);
else
allUrlsDGV.Rows[e.RowIndex].DefaultCellStyle.Font = new Font(f, FontStyle.Regular);
}
Add and Remove Buttons
private void AddButton_Click(object sender, EventArgs e)
{
if (allUrlsDGV.CurrentRow == null)
return;
var drv = (DataRowView)allUrlsDGV.CurrentRow.DataBoundItem;
drv.Row["Favorite"] = true;
drv.Row.EndEdit();
}
private void RemoveButton_Click(object sender, EventArgs e)
{
if (favoriteUrlsDGV.CurrentRow == null)
return;
var drv = (DataRowView)favoriteUrlsDGV.CurrentRow.DataBoundItem;
drv.Row["Favorite"] = false;
drv.Row.EndEdit();
}
I am trying to add different controls to cells in the same column. The drop down does not show and there is no visible setter:
private void AddBooleanDropDown(DataGridView grid, int row, KeyValuePair<string, string> kvp)
{
DataGridViewComboBoxCell dropDownCell = new DataGridViewComboBoxCell();
dropDownCell.DataSource = new string[] { "True", "False" };
grid.Rows[row].Cells["Value"] = dropDownCell;
}
Not sure if this will be helpful to you, but maybe an alternative method?
I wanted to be able to update an excel spreadsheet that I read into a DataGridView and give the user a few options. I used a ContextMenuStrip that would display on a MouseClick event.
It displays a small menu when you right click on a cell:
If it's not what you're looking for at all, sorry; just perhaps an alternate solution:
////////////////////////////////////////////////////////////////////////
//Change Priority Strip
////////////////////////////////////////////////////////////////////////
ContextMenuStrip changePriority = new ContextMenuStrip();
ToolStripMenuItem highPriority = new ToolStripMenuItem("High Priority");
changePriority.Items.Add(highPriority);
highPriority.Click += new EventHandler(changePriorityHighEvent);
ToolStripMenuItem normalPriority = new ToolStripMenuItem("Normal Priority");
changePriority.Items.Add(normalPriority);
normalPriority.Click += new EventHandler(changePriorityNormalEvent);
ToolStripMenuItem lowPriority = new ToolStripMenuItem("Low Priority");
changePriority.Items.Add(lowPriority);
lowPriority.Click += new EventHandler(changePriorityLowEvent);
////////////////////////////////////////////////////////////////////////
private void gridView_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Right) //On Right Click
{
DataGridView.HitTestInfo hit = gridView.HitTest(e.X, e.Y); //Get the clicked cell
if (e.RowIndex < 0) //If it's a header, ignore
return;
gridView.CurrentCell = gridView[e.ColumnIndex, e.RowIndex]; //Select the cell for future info
if (gridView.CurrentCell.ColumnIndex == 6) //If this is the priority column
{
changePriority.Show(Cursor.Position.X, Cursor.Position.Y); //Show the strip
}
}
}
private void changePriorityHighEvent(Object sender, EventArgs e) {
//make changes
}
private void changePriorityNormalEvent(Object sender, EventArgs e) {
//make changes
}
private void changePriorityLowEvent(Object sender, EventArgs e) {
//make changes
}
Here is very good MSDN Example.
The DataGridView control provides several column types, enabling your users to enter and edit values in a variety of ways. If these column types do not meet your data-entry needs, however, you can create your own column types with cells that host controls of your choosing. To do this, you must define classes that derive from DataGridViewColumn and DataGridViewCell. You must also define a class that derives from Control and implements the IDataGridViewEditingControl interface.
Not sure if you can change a specific cell in a grid unless it's the same type.
You could try adding a new column of combo boxes all with that data source
var newCol = new DataGridViewComboBoxColumn()
{
DataSource = new string[] { "True", "False" }
};
grid.Columns.Add(newCol);
also you might want to check that the int your passing in isn't greater than the number of rows.
I am very confused with what is happening here. I have a DataGridviewComboBoxColumn that I want to act like a combobox (clearly). I have the following code:
Code in designer.cs:
this.PurposeCol.DataPropertyName = "Purpose";
this.PurposeCol.DisplayStyle = System.Windows.Forms.DataGridViewComboBoxDisplayStyle.ComboBox;
this.PurposeCol.HeaderText = "Purpose";
this.PurposeCol.Name = "PurposeCol";
this.PurposeCol.Resizable = System.Windows.Forms.DataGridViewTriState.True;
this.PurposeCol.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
this.PurposeCol.Width = 78;
Constructor on form page:
PurposeCol.ReadOnly = false;
PurposeCol.DataSource = tripPurposeComboBox.Items; //Verified that this line fills the datasource with 14 items
PurposeCol.DisplayMember = "ItemText";
PurposeCol.ValueMember = "ItemValue";
The problem is that when I click it nothing happens. The text displayed is what I am expecting, and I can confirm that there are 14 items in the DataSource, but I cannot seem to get any other items to display. Is there a special setting that needs to be set before DataGridviewComboBoxColumn to act like a ComboBox?
You set the ReadOnly property to False for the column, but make sure the DataGridView.ReadOnly property is set to False too (it normally is by default).
dataGridView1.ReadOnly = false;
If it's set to True, it will override the ReadOnly property on your column, and you won't be able to open the drop-down.
To use it as editable combobox, you need to implement validating event for combobox cell while editing control showing
eg.
private void datagrid_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (datagrid.CurrentCell.ColumnIndex == 4)
{
if (e.Control.GetType() == typeof(DataGridViewComboBoxEditingControl))
{
DataGridViewComboBoxEditingControl cbo = e.Control as DataGridViewComboBoxEditingControl;
cbo.DropDownStyle = ComboBoxStyle.DropDown;
cbo.Validating += new CancelEventHandler(cbo_Validating);
cbo.SelectedIndexChanged += new EventHandler(SpacingComBox_SelectedIndexChanged);
}
}
}
and implement cbo_Validating and SpacingComBox_SelectedIndexChanged
void cbo_Validating(object sender, CancelEventArgs e) private void
SpacingComBox_SelectedIndexChanged(object sender, EventArgs e)