I have a datagridview with multiple column and I had create a custom checkbox in one of the column header . Since I want to fix the checkbox header in the column when i scroll the bar, so i create 'scroll'event to handle it.
private void dataGridView1_Scroll(object sender, ScrollEventArgs e)
{
if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll)
{
chbx.Location = new Point(chbx.Location.X - (e.NewValue - e.OldValue), chbx.Location.Y);
}
if (chbx.Location.X < dataGridView1.Location.X)
{
chbx.Visible = false;
}
else
{
chbx.Visible = true;
}
}
It's works (Picture 1). However, when i click the refresh button(data in gridview refresh) and i scroll the bar again, it comes with the problem below(Picture2).
Picture 1
Picture 2.
private void btnRefresh_Click(object sender, EventArgs e)
{
dataGridView1.DataSource = null;
SetupDGV();
}
private void SetupDGV()
{
///.....
chbx = new CheckBox();
Point headerCellLocation = dataGridView1.GetCellDisplayRectangle(0, -1, true).Location;
chbx.Name = "enableCHBX";
chbx.Location = new Point(headerCellLocation.X + 60, headerCellLocation.Y + 8);
chbx.BackColor = Color.White;
chbx.Size = new Size(15, 15);
// Assign Click event to the Header CheckBox.
cbx.Click += new EventHandler(chbxEnable_Click);
dataGridView1.Controls.Add(chbx);
}
Any suggestion on this?
I have removed the dataGridView1_Scroll Event Handler.
Instead I have used the Paint event using: this.dataGridView1.Paint += this.Handle_Paint;
Inside the Paint Event Handler I have the following code:
private void Handle_Paint(object sender, PaintEventArgs e)
{
//// Get the header cell
var cell = this.dataGridView1.Columns[0].HeaderCell;
//// Get the Location
var headerCellLocation = dataGridView1.GetCellDisplayRectangle(0, -1, true).Location;
//// Get the Horizontal Scrolling Offset (if the User has scrolled)
var scrollOffset = this.dataGridView1.HorizontalScrollingOffset;
//// Get the Cell width (minus) the checkbox width (minus) any scrolling there is
var widthVal = cell.Size.Width - this.chbx.Size.Width - scrollOffset;
//// Get 1/4 of the Cells height (so the checkbox sits in the center)
var quarterCellHeight = cell.Size.Height / 4;
//// Calculate the new Location for the Checkbox
var newLocation = new Point(headerCellLocation.X + widthVal, headerCellLocation.Y + quarterCellHeight);
//// Update the Location
this.chbx.Location = newLocation;
}
I have also added the following if statement inside of the SetupDGV method:
if (this.dataGridView1.Controls.Contains(this.chbx))
{
this.dataGridView1.Controls.Remove(this.chbx); //// Remove so we don't have a duplicate
}
Which ensures we won't create a duplicate checkbox inside of the dataGridView when we refresh the Data for the grid.
Here is a quick little video of the result:
https://gyazo.com/e544b38b1ca065bb16e4f279fc5aa24e
Related
Custom treeview control added to datagridview does not show at front.
Tried treeView1.BringToFront(); but same result.
private void dataGridViewProblem_CellEnter(object sender, DataGridViewCellEventArgs e)
{
if (treeView1 != null)
{
treeView1.Visible = false;
}
if (e.RowIndex != -1 && e.ColumnIndex == dataGridViewProblem.Columns["Category"].Index)
{
dataGridViewProblem.Controls.Add(treeView1);
// It returns the retangular area that represents the Display area for a cell
Rectangle oRectangle = dataGridViewProblem.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, true);
//Setting area for DateTimePicker Control
treeView1.Size = new Size(oRectangle.Width, treeView1.Height);
// Setting Location
treeView1.Location = new Point(oRectangle.X, oRectangle.Y + oRectangle.Height);
treeView1.BringToFront();
treeView1.Visible = true;
}
}
in relation to the post UWP C# Add Button Dynamically and Organizing On StackPanel I have additional questions
how do I control these dynamically created button(s)' event? eg. button 1 to turns on LED 1, button 2 to turns on LED 2 etc.
how to selectively remove the button(s) and reorganize the remaining buttons with no empty spaces in between.
Thank you.
Update:
I have a routine to add the client with details such as client IP etc. from the client and to add and display them in a scrollviewer.
How do i link either the clientname or client ip to the dictionary?
private async void AddClientList()
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
ClientListUserControl clientListControl = new ClientListUserControl(this, new ClientList(clientName, receiveIP, DateTime.Now, receivePort, receiveService, receiveDEV, receiveSTS, receiveACT));
ClientList_Panel.Children.Add(clientListControl);
clientListControl.updateDisplay();
});
}
You can also use Tag property of Button to pass the parameter. This property is inherited from FrameworkElement, and generally it is used to get or set an arbitrary object value that can be used to store custom information about this object.
Please refer to following code.
private void ButtonCreateNewButton_Click(object sender, RoutedEventArgs e)
{
Button b = new Button();
b.Height = 30;
b.Width = 100;
b.VerticalAlignment = VerticalAlignment.Top;
b.HorizontalAlignment = HorizontalAlignment.Left;
b.Margin = new Thickness(6, 6, 6, 6);
b.Content = "Button " + buttonCounter;
b.Tag = "LED-" + buttonCounter;
b.Click += Button_Click;
....
buttonCounter++;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var btn = sender as Button;
var led = btn.Tag;
//use led_name as a parameter here, according with this variable to turn on the LED
TurnOnOffLed(led);
}
To your first question:
To handle this, you should introduce a dictionary, where the button is the key and your value is the client. So you can get the linked client in the ClickHandler.
public Dictionary<Button, object> clientDict = new Dictionary<Button, object>();
Note: Here the type of the client is object, because I don`t know what type you have!
You add the button inside of your AddButton routine. Again: I dont know where you get your client from, so I added the value null. Change this to fulfil your requirements. Then you add another ClickHandler and get the linked client:
b.Click += HandleButtonClick;
clientDict.Add(b, null);
private void HandleButtonClick(object sender, RoutedEventArgs e)
{
//Execute whatever you want from your client:
var client = clientDict[sender as Button];
}
To your second question:
You need to add a RemoveMethod, where you get the column and row of the button, which should be deleted. Afterwards you can manipulate all other buttons column and row property. To avoid, that a new added button is not aligned to the others, you need to change the add-process, to make the position of the new button depending on the number of elements in your dictionary. Here an example how the full code could look like:
public int buttonCounter = 1;
public Dictionary<Button, object> clientDict = new Dictionary<Button, object>();
private void RemoveBtn(Button button)
{
var row = Grid.GetRow(button);
var column = Grid.GetColumn(button);
//Rearange
foreach (var btn in clientDict.Keys)
{
var r = Grid.GetRow(btn);
var c = Grid.GetColumn(btn);
if (c > column || (c == column && r > row))
{
if (r != 0)
{
//Set the row new
Grid.SetRow(btn, r - 1);
}
else
{
//Need to set it to a new column
Grid.SetRow(btn, 3);
Grid.SetColumn(btn, c - 1);
}
}
}
myGrid.Children.Remove(button);
clientDict.Remove(button);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//Create the button
Button b = new Button();
b.Height = 30;
b.Width = 100;
b.VerticalAlignment = VerticalAlignment.Top;
b.HorizontalAlignment = HorizontalAlignment.Left;
b.Margin = new Thickness(20, 20, 0, 0);
b.Content = "Button " + buttonCounter;
b.Click += HandleButtonClick;
clientDict.Add(b, null);
//Calculate the place of the button
int column = (int)(clientDict.Count / 4);
int row = clientDict.Count % 4;
//Check if you need to add a columns
if (row == 0 && myGrid.ColumnDefinitions.Count <= column)
{
ColumnDefinition col = new ColumnDefinition();
col.Width = new GridLength(column, GridUnitType.Auto);
myGrid.ColumnDefinitions.Add(col);
}
//Add the button
myGrid.Children.Add(b);
Grid.SetColumn(b, column);
Grid.SetRow(b, row);
buttonCounter++;
}
private void HandleButtonClick(object sender, RoutedEventArgs e)
{
//Execute whatever you want from you handler:
var client = clientDict[sender as Button];
}
Note: The rearrange process is not performance optimized.
Header check box on selection select all the check boxes in the checkbox column. After selecting the header checkbox, when data refreshes, it is still displayed as marked on it.
I have the following code when clicking on Ok button, it loads data in the datagridview with header check box and all the check boxes in each rows. Now, select the header checkbox that selects all the check boxes in all the rows. Then, again clicking on Ok button, it reloads the data but the check mark on the header check box is still displaying instead of not checked.
private void buttonOk_Click(object sender, EventArgs e)
{
LoadDataGridView();
CheckBox ckBoxHeader = new CheckBox();
//Get the column header cell bounds
Rectangle rect = datagridview1.GetCellDisplayRectangle(0, -1, true);
rect.Y = 3;
//align header check box in the middle center at rect.X = 82
rect.X = (rect.Location.X + (rect.Width / 2)) - 10 ;
ckBoxHeader.Size = new Size(18, 18);
//Change the location of the CheckBox to make it stay on the header
ckBoxHeader.Location = rect.Location;
datagridview1.Columns[0].Frozen = true;
ckBoxHeader.CheckedChanged += ckBoxHeader_CheckedChanged;
//Add the CheckBox into the DataGridView
datagridview1.Controls.Add(ckBoxHeader);
}
private void ckBoxHeader_CheckedChanged(object sender, EventArgs e)
{
for (int j = 0; j <= datagridview1.RowCount - 1; j++)
{
datagridview1[0, j].Value = ((CheckBox)sender).Checked;
}
datagridview1.EndEdit();
}
It solved my issue of unselecting the header check box. The above code should be rewritten as follows in order to headerCheckBox.Checked = false; to be working:
Load Event Code -
private void Form1_Load(object sender, EventArgs e)
{
addHeaderCheckBox();
changeDataGridViewColumnReadonly();
datagridview1.Columns[0].Frozen = true;
}
Load datagridview method code -
private void LoadDataGridView()
{
DataTable dt = new DataTable();
string WhereClause = " WHERE NO LIKE '" + textBoxNumber.Text.ToString().Substring(0,12) + "%' AND (DATE_TIME_START BETWEEN " + General.BuildOraDateString(dateTimePickerStart.Value) + " AND " + General.BuildOraDateString(dateTimePickerEnd.Value) + ") AND STATUS_IND = 'ST' ";
dt = Unit.GetData(WhereClause);
this.datagridview1.Refresh();
this.datagridview1.DataSource = dt;
headerCheckBox.Checked = false;
headerCheckBox.MouseClick += new
MouseEventHandler(headerCheckBox_MouseClick);
datagridview1.CellValueChanged +=
new DataGridViewCellEventHandler(datagridview1_CellValueChanged);
datagridview1.CurrentCellDirtyStateChanged +=
new EventHandler(datagridview1_CurrentCellDirtyStateChanged);
datagridview1.CellPainting +=
new
DataGridViewCellPaintingEventHandler(datagridview1_CellPainting);
}
Ok button click event-
private void buttonOk_Click(object sender, EventArgs e)
{
LoadDataGridView();
totalCheckBoxes = dgvBaleDisposition.RowCount;
}
I have small problem. I want make program where I can drag generated labels between multiple FlowLayoutPanels. But last few days I have tried to make drag and drop working. I tried many tutorials, examples etc. but it is always something bit diferent and I am not able extract only basic code.
It is similar to this program but it is in Visual Basic and I need it in C#. I know it is maybe very simple, but I am newbie.
Thank you for help.
Real Drag&Drop ist most useful between applications and maybe also between Forms.
Assuming you want to drag Labels between FLPs on the same Form, the code below should get you going..
It takes two FlowLayoutPanels called FLP1 and FLP2 and starts by initializing them with a few Labels.
Note the three mouse events I add to each Label to emulate a Drag&Drop action!
private void Form1_Load(object sender, EventArgs e)
{
// create a few Label with varying Colors for testing..
fillFLP(FLP1, 88);
fillFLP(FLP2, 111);
}
void fillFLP(FlowLayoutPanel FLP, int cc)
{
for (int i = 0; i < 24; i++)
{
Label l = new Label();
// the next 3 lines optional and only are there for testing!
l.AutoSize = false;
l.Text = FLP.Name + " " + i.ToString("00");
l.BackColor = Color.FromArgb(255, cc * 2 - i, 255 - 5 * i, cc + 5 * i);
// add controls and set mouse events:
FLP.Controls.Add(l);
l.MouseDown += l_MouseDown;
l.MouseMove += l_MouseMove;
l.MouseUp += l_MouseUp;
}
}
// the currently moved Label:
Label mvLabel = null;
void l_MouseDown(object sender, MouseEventArgs e)
{
// keep reference
mvLabel = (Label)sender;
}
void l_MouseMove(object sender, MouseEventArgs e)
{
// if we are dragging a label:
if (mvLabel != null)
{
// mouse pos in window coords
Point mvPoint = this.PointToClient(Control.MousePosition);
// the label is still in the FLP, so we start the drg action:
if (mvLabel.Parent != this)
{
mvLabel.Parent = this;
mvLabel.Location = mvPoint;
mvLabel.BringToFront();
}
else
{
// we are already in the form, so we just move
mvLabel.Location = mvPoint;
}
}
}
void l_MouseUp(object sender, MouseEventArgs e)
{
// are we over a FLP? and if so which?
Point MP = Control.MousePosition;
FlowLayoutPanel FLP = null;
Point mLoc1 = FLP1.PointToClient(MP);
Point mLoc2 = FLP2.PointToClient(MP);
if (FLP1.ClientRectangle.Contains(mLoc1)) FLP = FLP1;
else if (FLP2.ClientRectangle.Contains(mLoc2)) FLP = FLP2;
else return; // no! nothing we can do..
// yes, now find out if we are over a label..
// ..or over an empty area
mvLabel.SendToBack();
Control cc = FLP.GetChildAtPoint(FLP.PointToClient(MP));
// if we are over the FLP we can insert at the beginning or the end:
// int mvIndex = 0; // to the beginning
int mvIndex = FLP.Controls.Count; // to the end
// we are over a Label, so we insert before it:
if (cc != null) mvIndex = FLP.Controls.IndexOf(cc);
// move the Label into the FLP
FLP.Controls.Add(mvLabel);
// move it to the right position:
FLP.Controls.SetChildIndex(mvLabel, mvIndex);
// let go of the reference
mvLabel = null;
}
This lets you drag and drop Lables to and fro between two FLPs and also within the FLPs by dropping onto Labels.
Note that you will need a few extra lines if you want to allow dropping between Labels and still position there..
Note : In WinForm
I facing problem in TableLayoutPanel. I adding and removing the control dynamicall using TableLauoutPanel. My problem is, if i remove the control in the middle (ie i added TextBox1, TextBox2 and TextBox3 and now i removed TextBox2) at this time other controls are not resized properlly. When the last control (ie TextBox3 ) is removed, its resizing properlly. I attached my code here. What is the problem?
///HERE tbl is the TableLayoutPanel
private void AddText_Click(object sender, EventArgs e)
{
TextBox txt = new TextBox();
txt.MouseDoubleClick += new MouseEventHandler(txt_MouseDoubleClick);
txt.Multiline = true;
txt.Dock = DockStyle.Fill; NEWADD(txt);
}
private void NEWADD(Control ctrl)
{
tbl.RowCount += 1;
tbl.RowStyles.Add(new RowStyle(SizeType.Percent, 100F / tbl.RowStyles.Count));
tbl.Controls.Add(ctrl, 0, tbl.RowStyles.Count - 1);
foreach (RowStyle row in tbl.RowStyles)
{
row.SizeType = SizeType.Percent;
row.Height = 100F / (tbl.RowStyles.Count);
}
}
private void RemoveControl(Control ctrl)
{
tbl.RowCount -= 1;
tbl.Controls.Remove(ctrl);
tbl.RowStyles.Clear();
for (int i = 0; i < tbl.Controls.Count; i++)
{
tbl.RowStyles.Add(new RowStyle(SizeType.Percent, 100F /( tbl.RowStyles.Count +1)));
}
foreach (RowStyle row in tbl.RowStyles)
{
row.SizeType = SizeType.Percent;
row.Height = 100F / (tbl.RowStyles.Count);
}
tbl.Refresh();
}
void txt_MouseDoubleClick(object sender, MouseEventArgs e)
{
RemoveControl(sender as Control);
}
Can't test it at the moment, but it looks like your problem is the logic for removing the row that the control is in.
tbl.RowCount -= 1
is always going to remove the last row. You need to move through each control that is in a row after the the you want to remove and shift your controls up one row. Maybe something like this...
foreach(Control control in tbl.Controls)
{
if(control.Row > controlToRemove.Row)
control.Row--;
}
Since it looks like you're also trying to dynamically create a new table row for each control, you might do a little better with a FlowLayoutPanel. You should be able to style it to get a similar effect and it will be able to handle "row creation" automatically.