Problem in removing the controls dynamically - c#

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.

Related

C# checkbox header issue when scroll the bar

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

Shift listView tiles?

I have been attempting to understand the tiled listView in c#.net for weeks now with no succession.
I have shrunk my form's height/width (154x154) to the same tile size as the picture(s) (items with pictures) in my listView (which is docked in the form2); when my form2 is shown, you see item[0] in the listView...that is it! (which I want so far, so good!)
I have set the scrollable property to false to do away with both scrollbars (works perfectly fine so far...)
I have hooked both the left and right arrow keys GLOBALLY (which works as it has been thoroughly debugged) and when clicking the RIGHT arrow key, it should VERTICALLY bring up item[1], and so fourth.
The LEFT arrow key would bring up the previous item till it hits 0.
I have tried the following, but it does NOTHING.
private void HotkeyHandler(int i)
{
{
if (this.listView1.InvokeRequired)
{
SetHotkeyCallback p = new SetHotkeyCallback(HotkeyHandler);
this.Invoke(p, new object[] { i });
}
else
{
switch (i)
{
case 1:
listView1.View = View.List;
if (listView1.TopItem.Index > 0)
{
listView1.TopItem = listView1.Items[listView1.TopItem.Index - 1];
}
listView1.View = View.Tile;
break;
case 2:
listView1.View = View.List;
if (listView1.TopItem.Index < listView1.Items.Count)
{
listView1.TopItem = listView1.Items[listView1.TopItem.Index + 1];
}
listView1.View = View.Tile;
break;
}
}
}
}
Please help me, I been loosing my mind for weeks now.
EDIT: The switch within the function above does go off, I have debugged it; therefore, it is not the invoking that is the problem...
I don't think you can do it directly.
The way to get rid of the ScrollBars is indeed to set Scrollable = false;.
But that means what it says: Now the ListView will not scroll.
Here is a common workaround for many scrolling issues:
Place the Listview in a Panel and make it as large as needed to show all Items.
Then in order to scroll simply move the LV up and down:
private void prepare_Click_1(object sender, EventArgs e)
{
// we sit inside a Panel
listView1.Parent = panel1;
// initially they have the same size
listView1.Size = panel1.Size;
listView1.Location = Point.Empty;
// a few test items
for (int i = 0; i < 100; i++)
listView1.Items.Add("Item " + i);
// now grow the height to display all items:
int cols = listView1.Width / listView1.TileSize.Width;
listView1.Height = (listView1.Items.Count / cols) * listView1.TileSize.Height;
}
// moving the LV up looks like scrolling down..
private void scrollDown_Click(object sender, EventArgs e)
{
listView1.Top -= listView1.TileSize.Height;
if (listView1.Bottom < panel1.Height)
listView1.Top = -listView1.Height + panel1.Height;
}
// moving the LV down looks like scrolling up..
private void scrollUp_Click_1(object sender, EventArgs e)
{
listView1.Top += listView1.TileSize.Height;
if (listView1.Top > 0) listView1.Top = 0;
}

C# Drag and Drop labels within FlowLayoutPanels

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..

I created an array of pictureBoxes how can i register for an event to all the pictureBoxes?

The code:
pbs = new PictureBox[8];
for (int i = 0; i < pbs.Length; i++)
{
pbs[i] = new PictureBox();
pbs[i].MouseEnter += Form1_MouseEnter;
pbs[i].MouseLeave += Form1_MouseLeave;
pbs[i].Size = new Size(100, 100);
pbs[i].Margin = new Padding(0, 0, 0, 60);
pbs[i].Dock = DockStyle.Top;
pbs[i].SizeMode = PictureBoxSizeMode.StretchImage;
Panel p = i < 4 ? panel1 : panel2;
p.Controls.Add(pbs[i]);
pbs[i].BringToFront();
}
I did:
pbs[i].MouseEnter +=
And when i clicked TAB it did: Form1_MouseEnter
It's not what i wanted.
I want that when i move with the mouse over each of the pictureBoxes area it will do something.
One event for all the pictureBoxes.
If i moved over pictureBox1 do something...pictureBox2 the same...
How can i do it ? I don't want to create 8 events for each pictureBox but one enter event for all.
You need simply write
pbs[i].MouseEnter += globalMouseEnterEvent;
of course you need to have a globalMouseEnterEvent somewhere in your code
public void globalMouseEnterEvent(object sender, System.EventArgs e)
{
....
}
However, another piece of information is needed when your work with event shared between numerous controls. You need to recognize the control that triggers the event. The control instance is passed using the sender parameter that you can cast to your appropriate control type, but what is needed is to give a unique identifier to your control. Like setting the Tag or Name properties when you build the control
for (int i = 0; i < pbs.Length; i++)
{
.....
pbs[i].Tag = "PB" + i.ToString()
...
}
so in the MouseEnter code you could write
public void globalMouseEnterEvent(object sender, System.EventArgs e)
{
PictureBox p = sender as PictureBox;
if(p.Tag.ToString() == "PB1")
.....
else if ......
}
dont use form1_event , copy it's code and rename it
pbs[i].MouseEnter += yourEventName
it's enough
What you're doing is absolute correct, you attach the handler to the event of each control in
turn, so that the same handler works for every PictureBox.
I guess your problem is that the method VS creates is named Form1_MouseEnter. This is completely irrelevant, what determines what a method will handle is the += operator, not its name. Just try to run your original code and it will do what you want.
It seems to be a bug in the C# editor though, as it should have named the automatically generated handler something more appropriate, but anyway, you can rename the method afterwards to reflect its true meaning.
I've tried to apply the tips from the others to your code:
pbs = new PictureBox[8];
for (int i = 0; i < pbs.Length; i++)
{
pbs[i] = new PictureBox();
pbs[i].MouseEnter += Picturebox_MouseEnter;
pbs[i].MouseLeave += PictureBox_MouseLeave;
pbs[i].Name = string.Concat("PB", i); //Added to identify each picturebox
pbs[i].Size = new Size(100, 100);
pbs[i].Margin = new Padding(0, 0, 0, 60);
pbs[i].Dock = DockStyle.Top;
pbs[i].SizeMode = PictureBoxSizeMode.StretchImage;
Panel p = i < 4 ? panel1 : panel2;
p.Controls.Add(pbs[i]);
pbs[i].BringToFront();
}
And the handlers:
private void Picturebox_MouseEnter(object sender, EventArgs e)
{
PictureBox pb = sender as PictureBox;
if (pb != null)
{
if (pb.Name == "PB2")
{
//Do PB2 specific task
}
//Your code when mouse enters one of the pictureboxes
//Use Name property to determine wich one, if needed
}
}
private void PictureBox_MouseLeave(object sender, EventArgs e)
{
//Your code when mouse leaves one of the pictureboxes
//Use Name property to determine wich one, if needed
}

C#: How do you edit items and subitems in a listview?

How do you edit items and subitems in a listview? Let's say I have a listview with 3 columns,and subitems,
Car Brand | Car Name | Car Year
Ford | Mustang | 2000
Dodge | Charger | 2007
How would I Add items like that to listview and how would I edit let's say the Car Name on which ever row by index[] if I needed to edit at runtime at firing of an event?
If you're looking for "in-place" editing of a ListView's contents (specifically the subitems of a ListView in details view mode), you'll need to implement this yourself, or use a third-party control.
By default, the best you can achieve with a "standard" ListView is to set it's LabelEdit property to true to allow the user to edit the text of the first column of the ListView (assuming you want to allow a free-format text edit).
Some examples (including full source-code) of customized ListView's that allow "in-place" editing of sub-items are:
C# Editable ListView
In-place editing of ListView subitems
I use a hidden textbox to edit all the listview items/subitems. The only problem is that the textbox needs to disappear as soon as any event takes place outside the textbox and the listview doesn't trigger the scroll event so if you scroll the listview the textbox will still be visible.
To bypass this problem I created the Scroll event with this overrided listview.
Here is my code, I constantly reuse it so it might be help for someone:
ListViewItem.ListViewSubItem SelectedLSI;
private void listView2_MouseUp(object sender, MouseEventArgs e)
{
ListViewHitTestInfo i = listView2.HitTest(e.X, e.Y);
SelectedLSI = i.SubItem;
if (SelectedLSI == null)
return;
int border = 0;
switch (listView2.BorderStyle)
{
case BorderStyle.FixedSingle:
border = 1;
break;
case BorderStyle.Fixed3D:
border = 2;
break;
}
int CellWidth = SelectedLSI.Bounds.Width;
int CellHeight = SelectedLSI.Bounds.Height;
int CellLeft = border + listView2.Left + i.SubItem.Bounds.Left;
int CellTop =listView2.Top + i.SubItem.Bounds.Top;
// First Column
if (i.SubItem == i.Item.SubItems[0])
CellWidth = listView2.Columns[0].Width;
TxtEdit.Location = new Point(CellLeft, CellTop);
TxtEdit.Size = new Size(CellWidth, CellHeight);
TxtEdit.Visible = true;
TxtEdit.BringToFront();
TxtEdit.Text = i.SubItem.Text;
TxtEdit.Select();
TxtEdit.SelectAll();
}
private void listView2_MouseDown(object sender, MouseEventArgs e)
{
HideTextEditor();
}
private void listView2_Scroll(object sender, EventArgs e)
{
HideTextEditor();
}
private void TxtEdit_Leave(object sender, EventArgs e)
{
HideTextEditor();
}
private void TxtEdit_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return)
HideTextEditor();
}
private void HideTextEditor()
{
TxtEdit.Visible = false;
if (SelectedLSI != null)
SelectedLSI.Text = TxtEdit.Text;
SelectedLSI = null;
TxtEdit.Text = "";
}
Click the items in the list view.
Add a button that will edit the selected items.
Add the code
try
{
LSTDEDUCTION.SelectedItems[0].SubItems[1].Text = txtcarName.Text;
LSTDEDUCTION.SelectedItems[0].SubItems[0].Text = txtcarBrand.Text;
LSTDEDUCTION.SelectedItems[0].SubItems[2].Text = txtCarName.Text;
}
catch{}
Sorry, don't have enough rep, or would have commented on CraigTP's answer.
I found the solution from the 1st link - C# Editable ListView, quite easy to use. The general idea is to:
identify the SubItem that was selected and overlay a TextBox with the SubItem's text over the SubItem
give this TextBox focus
change SubItem's text to that of TextBox's when TextBox loses focus
What a workaround for a seemingly simple operation :-|
private void listView1_MouseDown(object sender, MouseEventArgs e)
{
li = listView1.GetItemAt(e.X, e.Y);
X = e.X;
Y = e.Y;
}
private void listView1_MouseUp(object sender, MouseEventArgs e)
{
int nStart = X;
int spos = 0;
int epos = listView1.Columns[1].Width;
for (int i = 0; i < listView1.Columns.Count; i++)
{
if (nStart > spos && nStart < epos)
{
subItemSelected = i;
break;
}
spos = epos;
epos += listView1.Columns[i].Width;
}
li.SubItems[subItemSelected].Text = "9";
}

Categories

Resources