I have a form on which are "listBox1" and "button1". I have two function. The second function adds checkboxes to listbox1 and the first function displays message box. But I don´t know how to write the first function.
Here I want to check which checkbox is checked and write a message:
private void button1_click(object sender, EventArgs e)
{
MessageBox.Show("radiobutton: " + rb[i].Text);
}
Here I create checkboxes: //it´s working
internal void loadSurveys()
{
WebClient client2 = new WebClient();
var json = client2.DownloadString("http://www.test.net/api/surveys/?api_key=123");
JObject data = JObject.Parse(json);
var example = JsonConvert.DeserializeObject<Example>(json);
int y = 5;
int i = 0;
RadioButton[] rb = new RadioButton[example.surveys.Length];
String chkBox_name = "";
String chkBox_text = "";
foreach (var survey in data["surveys"].Children())
{
rb[i] = new RadioButton();
rb[i].Location = new Point(5, y);
rb[i].Name = chkBox_name + survey["id"];
rb[i].Text = chkBox_text + survey["title"];
rb[i].AutoSize = true;
this.listBox1.Controls.Add(rb[i]);
y += 20;
i++;
}
}
You can go through listBox1.Controls and pick checked RadioButton
private void button1_click(object sender, EventArgs e)
{
var rb = this.listBox1.Controls.OfType<RadioButton>().SingleOrDefault(n => n.Checked);
if (rb != null)
MessageBox.Show("radiobutton: " + rb.Text);
}
since this is RadioButton there shouldn't be more then one checked
The first step, is to make the radiobutton array a variable on form level:
RadioButton[] rb
which is assigned inside loadSurveys
rb = new RadioButton[example.surveys.Length];
Then the array is accessible inside your button click
var rb = rb.FirstOrDefault(r=>r.Checked);
if(rb==null)
MessageBox.Show("No radiobutton was selected");
else
MessageBox.Show("radiobutton: " + rb[i].Text);
edit Just noticed you add the radiobuttons to a listbox. Is the listbox1 variable an actual listbox? The above will still work, but if the goal is to display a listbox of radiobuttons, you can custom paint the listbox and else use a normal panel instead of a listbox.
Either way, you can also do a firstordefault on the controls on the controls of the listbox1 variable (with OfType), but if you'd use a listbox, and fill its items, you could simply use SelectedIndexChanged
edit 2
Since I already had it, wanted to show a way to make your listbox a radiobutton box. You can make any existing listbox a radiobutton box with the following class:
public class RadioButtonBoxPainter:IDisposable
{
public readonly ListBox ListBox;
public RadioButtonBoxPainter(ListBox ListBox)
{
this.ListBox = ListBox;
ListBox.DrawMode = DrawMode.OwnerDrawFixed;
ListBox.DrawItem += ListBox_DrawItem;
}
void ListBox_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index == -1) return;
Rectangle r = e.Bounds;
r.Width=r.Height;
bool selected= (e.State & DrawItemState.Selected) > 0;
e.DrawBackground();
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
ControlPaint.DrawRadioButton(e.Graphics, r, selected ? ButtonState.Checked : ButtonState.Normal);
r.X = r.Right + 2;
r.Width = e.Bounds.Width - r.X;
string txt;
if (ListBox.Site != null && ListBox.Site.DesignMode && e.Index >= ListBox.Items.Count)
txt = ListBox.Name;
else
txt = ListBox.GetItemText(ListBox.Items[e.Index]);
using (var b = new SolidBrush(e.ForeColor))
e.Graphics.DrawString(txt, e.Font, b, r);
if (selected)
{
r = e.Bounds;
r.Width--; r.Height--;
e.Graphics.DrawRectangle(Pens.DarkBlue, r);
}
}
public void Dispose()
{
ListBox.DrawItem -= ListBox_DrawItem;
}
}
Example of a standard implementation:
public class RadioButtonBox:ListBox
{
public readonly RadioButtonBoxPainter Painter;
public RadioButtonBox()
{
Painter = new RadioButtonBoxPainter(this);
}
[DefaultValue(DrawMode.OwnerDrawFixed)]
public override DrawMode DrawMode
{
get{return base.DrawMode;}
set{base.DrawMode = value;}
}
}
The RadioButtonBox is a control I actually use a lot. Personally I find it a lot quicker in implementing then a load of separate radiobuttons.
In case you want to use it, and want an example how to implement it in your current code, leave a comment and I'll add one.
Related
I'm trying to do a drag and drop of multiple items between ListBox in windows forms. The problem I'm having is if I select multiple items holding the Shift key and try to drag and drop it without release the the key I get an error. Actually the SelectedIndices and SelectedItems just show 1 item, the one I clicked first, even though multiple items are highlighted in the ListBox.
I'm using SelectionMode = MultiExtended
void ZListBox_MouseMove(object sender, MouseEventArgs e)
{
if (isDraggingPoint.HasValue && e.Button == MouseButtons.Left && SelectedIndex >= 0)
{
var pointToClient = PointToClient(MousePosition);
if (isDraggingPoint.Value.Y != pointToClient.Y)
{
lastIndexItemOver = -1;
isDraggingPoint = null;
var dropResult = DoDragDrop(SelectedItems, DragDropEffects.Copy);
}
}
}
It seems that if I don't release the left mouse button before I do "DoDragDrop", the items aren't selected and also if I try to get the SelectedIndices from the other ListBox, the Count is the number of "selected items", but when I try to navigate the list, I get a IndexOutOfRangeException.
Is there any work around for it?
Sample code to reproduce the issue:
(To reproduce:
1- Select an item
2- Hold shift and click in another item, than without release shift and mouse button, drag this item (if you have a breakpoint inside the 'if', you'll see just 1 item on SelectedItems))
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Load += Form1_Load;
}
private void Form1_Load(object sender, EventArgs e)
{
var someList = new List<ListItemsTest>();
someList.Add(new ListItemsTest() { ID = 1, Name = "Name 1" });
someList.Add(new ListItemsTest() { ID = 2, Name = "Name 2" });
someList.Add(new ListItemsTest() { ID = 3, Name = "Name 3" });
someList.Add(new ListItemsTest() { ID = 4, Name = "Name 4" });
someList.Add(new ListItemsTest() { ID = 5, Name = "Name 5" });
listBox1.DisplayMember = "Name";
listBox1.ValueMember = "ID";
listBox1.DataSource = someList;
listBox1.SelectionMode = SelectionMode.MultiExtended;
listBox1.MouseMove += ListBox1_MouseMove;
listBox1.AllowDrop = true;
}
void ListBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && listBox1.SelectedIndex >= 0)
{
var dropResult = DoDragDrop(listBox1.SelectedItems, DragDropEffects.Copy);
}
}
public class ListItemsTest
{
public int ID { get; set; }
public string Name { get; set; }
}
}
Another example, in case you need to know what Items were selected in a ListBox, using the SHIFT key to create an extended selection, even if you don't need to initiate a Draq&Drop operation:
Using the data sample you provided in the question, a List.
In the example, a List<int> (lbSelectedIndexes) is used to keep track of what items are currently selected in the ListBox. This List is filled only when the selection is performed using the SHIFT key, or after a Drag&Drop operation is initiated. This can be useful to determine the type of selection.
In all other cases the List<int> is empty and the SelectedItems and SelectedIndices collections can be used to determine the items currently selected.
The SystemInformation.DragSize value is also used to determine if the drag operation should be initiated when the Mouse Pointer is moved while the Left Button is pressed.
When the Drag&Drop operation is started, a new DataObject is filled with ListBox Items corresponding to the current selection, no matter how the selection was performed.
The DragDropEffects is set to DragDropEffects.Copy.
Point lbMouseDownPosition = Point.Empty;
List<int> lbSelectedIndexes = new List<int>();
private void listBox1_MouseDown(object sender, MouseEventArgs e)
{
var lb = sender as ListBox;
lbMouseDownPosition = e.Location;
lbSelectedIndexes = new List<int>();
int idx = lb.IndexFromPoint(e.Location);
if (ModifierKeys == Keys.Shift && idx != lb.SelectedIndex) {
lbSelectedIndexes.AddRange(Enumerable.Range(
Math.Min(idx, lb.SelectedIndex),
Math.Abs((idx - lb.SelectedIndex)) + 1).ToArray());
}
}
private void listBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left &&
((Math.Abs(e.X - lbMouseDownPosition.X) > SystemInformation.DragSize.Width) ||
(Math.Abs(e.Y - lbMouseDownPosition.Y) > SystemInformation.DragSize.Height)))
{
var lb = sender as ListBox;
DataObject obj = new DataObject();
if (lbSelectedIndexes.Count == 0) {
lbSelectedIndexes = lb.SelectedIndices.OfType<int>().ToList();
}
List<object> selection = lb.Items.OfType<object>().Where((item, idx) =>
lbSelectedIndexes.IndexOf(idx) >= 0).ToList();
obj.SetData(typeof(IList<ListItemsTest>), selection);
lb.DoDragDrop(obj, DragDropEffects.Copy);
}
}
To test the results, drop another ListBox (listBox2, here) on the Form, set its AlloDrop property to true and subscribe to the DragEnter and DragDrop events.
When the Mouse Pointer enters the second ListBox client area, the DragDropEffects.Copy effect is triggered if the e.Data.GetDataPresent() method detects that the dragged object contains a List<ListItemsTest>.
If the Data format is accepted, the Data Object is transformed back to a List<ListItemsTest> - using the IDataObject.GetData() method - and set as the DataSource of listBox2.
private void listBox2_DragDrop(object sender, DragEventArgs e)
{
ListBox lb = sender as ListBox;
if (e.Data != null && e.Data.GetDataPresent(typeof(IList<ListItemsTest>))) {
lb.DisplayMember = "Name";
lb.ValueMember = "ID";
lb.DataSource = e.Data.GetData(typeof(IList<ListItemsTest>));
}
}
private void listBox2_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(IList<ListItemsTest>))) {
e.Effect = DragDropEffects.Copy;
}
}
I see the issue now. The funny thing is, pressing the Ctrl key to select items in the list works normal, but the Shift key doesn't. My solution would be to recreate your own SelectedItems collection:
void listBox1_MouseMove(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left && listBox1.SelectedItems.Count > 0) {
int mouseIndex = listBox1.IndexFromPoint(e.Location);
if (mouseIndex > -1) {
ListBox.SelectedObjectCollection x = new ListBox.SelectedObjectCollection(listBox1);
if (Control.ModifierKeys == Keys.Shift) {
int i1 = Math.Min(listBox1.SelectedIndex, mouseIndex);
int i2 = Math.Max(listBox1.SelectedIndex, mouseIndex);
for (int i = i1; i <= i2; ++i) {
x.Add(listBox1.Items[i]);
}
} else {
x = listBox1.SelectedItems;
}
var dropResult = DoDragDrop(x, DragDropEffects.Move);
}
}
}
Just to let you know I found another solution. If I set Capture = false in the MouseDown event, Items will work as expected and we don't need to do the manual selection.
Eg:
void ZListBox_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Capture = false;
}
}
Hope it helps!
I have a ListBox that I wanted to be drag and drop sortable, and also have extended multiselect. I was getting the same issue as the OP, where the selected items was bombing out when using shift+click to select the items. If I add in a check to make sure no modifier keys are pressed on mouse down before initiating the DoDragDrop, it solves the problem.
(this is a VB.net code snippet, but you get the idea)
Private Sub lbClasses_MouseDown(sender As Object, e As MouseEventArgs) Handles lbClasses.MouseDown
If e.Button = MouseButtons.Left AndAlso Control.ModifierKeys = 0 Then
If Not IsNothing(lbClasses.SelectedItem) Then
lbClasses.DoDragDrop(lbClasses.SelectedItem, DragDropEffects.Move)
End If
End If
End Sub
I want to show tooltip on ListBox, so in load form I have:
lstTech.DrawMode = DrawMode.OwnerDrawFixed;
var techListQuery = $"exec getTaskAssignableEmployeeList";
var techList = db.GetTableBySQL(techListQuery);
lstTech.DataSource = techList.ToList();
lstTech.DisplayMember = "Abbreviation";
lstTech.ValueMember = "EmpGuid";
Then in DrawItem method I have:
private void lstTech_DrawItem(object sender, DrawItemEventArgs e)
{
ListBox senderListBox = (ListBox)sender;
if (e.Index < 0)
{
return;
}
var item = ((DataRowView)senderListBox.Items[e.Index]);
var abbr = senderListBox.GetItemText(item["Abbreviation"]);
var name = senderListBox.GetItemText(item["Name"]);
e.DrawBackground();
using (SolidBrush br = new SolidBrush(e.ForeColor))
{
e.Graphics.DrawString(abbr, e.Font, br, e.Bounds);
}
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected )
{
ttTechs.Show(name, senderListBox, e.Bounds.Right, senderListBox.PointToClient(Cursor.Position).Y);
}
e.DrawFocusRectangle();
}
Then I want to disappear Tooltip on mouse leave like:
private void lstTech_MouseLeave(object sender, EventArgs e)
{
ListBox senderListBox = (ListBox)sender;
ttTechs.Hide(senderListBox);
}
So now Tooltip works, it appear when I clic on some item of list, problem is I don't want it on clic, I want it in Hover event. So I try:
private void lstTech_MouseHover(object sender, EventArgs e)
{
ListBox senderListBox = (ListBox)sender;
ttTechs.Show(senderListBox);
}
But it returns me an error:
No overload for method 'Show' takes 1 arguments
What am I doing wrong? what I need to display tooltip on hover event and remove from click event? Regards
Update
As answer below I change code to:
//Set tooltip as Global variable
ToolTip toolTip = new ToolTip();
//Create new method to assign Draw
private void SetToolTipText()
{
var content = string.Empty;
foreach (DataRowView list in lstTech.SelectedItems)
{
var techName = list[1].ToString();
content += techName + Environment.NewLine;
}
toolTip.SetToolTip(lstTech, content);
}
//Draw method
private void lstTech_DrawItem(object sender, DrawItemEventArgs e)
{
SetToolTipText();
}
Problem is list items are invisible, if I click in listbox Tooltip appears correctly but list is not displayed. If I remove lstTech.DrawMode = DrawMode.OwnerDrawVariable; from load_form listbox items appears again but tooltip stop working. What is going on there?
There's a ToolTip control in WinForms which you can make use of.
Let's say your list box contains a bunch of names, and I want to only display the first 3 letters of each name on the tool tip. So I would write a function to go through each item in the list box and filter the names and create a string, then set it to the tool tip.
private void SetToolTipText()
{
var content = string.Empty;
foreach (var item in listBox1.Items)
{
var first3 = item.ToString().Substring(0, 3);
content += first3 + Environment.NewLine;
}
toolTip.SetToolTip(listBox1, content);
}
Note that the toolTip is a global variable in my Form.
public partial class MainForm : Form
{
ToolTip toolTip = new ToolTip();
public MainForm()
{
InitializeComponent();
}
Next I would call that function in my DrawItem() event like so:
private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
{
SetToolTipText();
}
In your program, instead of taking the first 3 characters of the string, do whatever the filtering you do.
Hello I made a custom text box with an associated label.
and I have a custom Form.
when on a form if I drag drop my custom textbox from the toolbox and set it's properties I can see that it works. However what I would like to do is when I'm on my custom control where I have a TableLayoutPanel (with 3 rows)
on row index 1(mid row) I would like to add my custom controls programatically.
when I do this the text label is somewhere else then the textbox.
My Code and the Image to my problem is below:
MyCustomTextBox:
public class MyLbTextBox : TextBox
{
#region CustomProperties
private Label AssociatedLabel = new Label();
private string _myLbText;
public string MyTextLabel
{
get => _myLbText;
set
{
_myLbText = value;
AssociatedLabel.Text = _myLbText ?? _myBindingField;
Size s = TextRenderer.MeasureText(AssociatedLabel.Text, AssociatedLabel.Font);
AssociatedLabel.Location =
new Point(Location.X - s.Width - AssociatedLabel.Padding.Right, Location.Y);
var MyMargin = this.Margin;
MyMargin.Left = 100;
this.Margin = MyMargin;
}
}
#endregion
private string _myBindingField;
public string MyBindingField
{
get { return _myBindingField; }
set
{
_myBindingField = value;
}
}
private MyJoins.MyExpressions _myExpression;
public MyJoins.MyExpressions MyExpression
{
get => _myExpression;
set => _myExpression = value;
}
public MyLbTextBox()
{
_myExpression = MyJoins.MyExpressions.Equals;
ParentChanged += MyLbTextBox_ParentChanged;
LocationChanged += MyLbTextBox_LocationChanged;
Disposed += MyLbTextBox_Disposed;
}
private void MyLbTextBox_Disposed(object sender, EventArgs e)
{
AssociatedLabel.Dispose();
}
private void MyLbTextBox_LocationChanged(object sender, EventArgs e)
{
Size s = TextRenderer.MeasureText(AssociatedLabel.Text, AssociatedLabel.Font);
AssociatedLabel.Location =
new Point(Location.X - s.Width - AssociatedLabel.Padding.Right, Location.Y);
}
private void MyLbTextBox_ParentChanged(object sender, EventArgs e)
{
AutoAddAssociatedLabel();
}
private void AutoAddAssociatedLabel()
{
if (Parent == null) return;
AssociatedLabel.Padding = new Padding(3);
Size s = TextRenderer.MeasureText(AssociatedLabel.Text, AssociatedLabel.Font);
AssociatedLabel.Location =
new Point(Location.X - s.Width - AssociatedLabel.Padding.Right, Location.Y);
Parent.Controls.Add(AssociatedLabel);
}
}
By the way, this is how I add my controls:
after adding my controls through the property grid
this is how I set them on the screen
private void _mySearchFields_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (_mySearchFields == null) return;
foreach (var searchField in _mySearchFields)
{
if (MySearchFieldsPanel.Contains(searchField.MyControl)) continue;
MySearchFieldsPanel.Controls.Add(searchField.MyControl, 1, 0);
}
var myHeight = MySearchFieldsPanel.Controls.Cast<Control>().Sum(variable => variable.Height);
MyBdPanel.RowStyles[1].Height = myHeight + 40;
}
I appreciate any help
This line is a reason of all problems:
Parent.Controls.Add(AssociatedLabel);
This is bad idea if you are creating composite controls (composite = consisting from several real controls). That will cause layout problems you have experienced and more.
Instead consider either:
Utilize UserControl to create composition.
Create custom control (like you do) but without more controls. If you need label - draw it as text in OnPaint while allocating some space: fixed with margin, adjustable with some property or dynamic with measuring text.
I have one requirement to add three check box in a group box, and check-box must react as radio button i.e.,
1. one can check only one check-box at a time.
2. when user goes to check another check box, previous one automatically should be unchecked.
I also know that this is not a good approach to do this, and it's really confusing to non-technical or technical user but I also want to learn something new in this.
I went through lots of sites, but I didn't get any satisfactory solution. I hope I will get good one from you.
Moreover, There are simple three check box to indicate three things for selection respectively and one text box. If one checks anyone things then texbox shows the selected thing.
For example:- Check-box show C#,ASP.NET and MVC respectively.
If one select C# then text-box must show C#.
Thanks...
With Thanks and Regards,
Ravindra.
You can use radio button for this functionality.
I'd do it like this, assuming you use winforms:
public partial class Form1 : Form
{
private bool ignoreEvents = false;
public Form1()
{
InitializeComponent();
//set this handler to the events of all 3 checkboxes
checkBox1.CheckedChanged += radioCheckboxes_CheckedChanged;
checkBox2.CheckedChanged += radioCheckboxes_CheckedChanged;
checkBox3.CheckedChanged += radioCheckboxes_CheckedChanged;
}
private void radioCheckboxes_CheckedChanged(object sender, EventArgs e)
{
if (!ignoreEvents)
{
ignoreEvents = true; // otherwise the other checkboxes would react when i set the state programmatically
CheckBox current = sender as CheckBox;
if (current == checkBox1)
{
checkBox2.Checked = false;
checkBox3.Checked = false;
}
else if (current == checkBox2)
{
checkBox1.Checked = false;
checkBox3.Checked = false;
}
else
{
checkBox1.Checked = false;
checkBox2.Checked = false;
}
ignoreEvents = false;
}
}
}
With WPF I'd just use a style for a radiobutton so that it looks like a checkbox...
you can simply use another task like timer that updates every 50ms ,
so as to disable the check boxes you want to disable there ,
in your "checked changed event" only flag the controls ,
like for checkbox1 = flagdcheckbx = 1 ; and so on.
private async Task writeTimer()
{
if(ignoreEvents == true)
{
ignoreEvents = false;
switch(flagdcheckbx)
{
case 1:
checkBox2.Checked = false;
checkBox3.Checked = false;
break;
case 2:
checkBox1.Checked = false;
checkBox3.Checked = false;
break;
case 3:
checkBox1.Checked = false;
checkBox2.Checked = false;
break;
}
}
}
private void radioCheckboxes_CheckedChanged(object sender, EventArgs e)
{
CheckBox current = sender as CheckBox;
if (current == checkBox1)
{
if (current.checked)
{
ignoreEvents = true;
flagdcheckbx=1;
}
}
else if (current == checkBox2)
{
if (current.checked) // it should happen only when checked
{
ignoreEvents = true;
flagdcheckbx=2;
}
}
else
{
if (current.checked)
{
ignoreEvents = true;
flagdcheckbx=3;
}
}
}
I assume you know how to group RadioButton controls inside a container and you just look for the CheckBox appearance for your radio button groups.
As an option you can modify the RadioButtonList that I've shared in [this post] and add the CheckBox appearance to it. In the following picture you can see two RadioButtonList control, one with CheckBox appearance and the other with RadioButton appearance:
radioButtonList1.DataSource = Enum.GetValues(typeof(DayOfWeek));
radioButtonList1.Appearance = RadioButtonListAppearance.CheckBox;
radioButtonList2.DataSource = Enum.GetValues(typeof(DayOfWeek));
Here is the modified version of code to add Appearance property:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
public class RadioButtonList : ListBox
{
RadioButtonListAppearance appearance = RadioButtonListAppearance.RadioButton;
public RadioButtonListAppearance Appearance
{
get { return appearance; }
set { appearance = value; Invalidate(); }
}
Size s;
public RadioButtonList()
{
this.DrawMode = DrawMode.OwnerDrawFixed;
using (var g = Graphics.FromHwnd(IntPtr.Zero))
s = RadioButtonRenderer.GetGlyphSize(
Graphics.FromHwnd(IntPtr.Zero), RadioButtonState.CheckedNormal);
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
var text = (Items.Count > 0) ? GetItemText(Items[e.Index]) : Name;
Rectangle r = e.Bounds; Point p;
var flags = TextFormatFlags.Default | TextFormatFlags.NoPrefix;
var selected = (e.State & DrawItemState.Selected) == DrawItemState.Selected;
var state = selected ?
(Enabled ? RadioButtonState.CheckedNormal :
RadioButtonState.CheckedDisabled) :
(Enabled ? RadioButtonState.UncheckedNormal :
RadioButtonState.UncheckedDisabled);
if (RightToLeft == System.Windows.Forms.RightToLeft.Yes)
{
p = new Point(r.Right - r.Height + (ItemHeight - s.Width) / 2,
r.Top + (ItemHeight - s.Height) / 2);
r = new Rectangle(r.Left, r.Top, r.Width - r.Height, r.Height);
flags |= TextFormatFlags.RightToLeft | TextFormatFlags.Right;
}
else
{
p = new Point(r.Left + (ItemHeight - s.Width) / 2,
r.Top + (ItemHeight - s.Height) / 2);
r = new Rectangle(r.Left + r.Height, r.Top, r.Width - r.Height, r.Height);
}
var bc = selected ? (Enabled ? SystemColors.Highlight :
SystemColors.InactiveBorder) : BackColor;
var fc = selected ? (Enabled ? SystemColors.HighlightText :
SystemColors.GrayText) : ForeColor;
using (var b = new SolidBrush(bc))
e.Graphics.FillRectangle(b, e.Bounds);
if (appearance == RadioButtonListAppearance.RadioButton)
{
RadioButtonRenderer.DrawRadioButton(e.Graphics, p, state);
}
else if (appearance == RadioButtonListAppearance.CheckBox)
{
CheckBoxRenderer.DrawCheckBox(e.Graphics, p, (CheckBoxState)state);
}
else
{
throw new InvalidOperationException("Appearance is invalid.");
}
TextRenderer.DrawText(e.Graphics, text, Font, r, fc, bc, flags);
e.DrawFocusRectangle();
base.OnDrawItem(e);
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override SelectionMode SelectionMode
{
get { return System.Windows.Forms.SelectionMode.One; }
set { }
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override int ItemHeight
{
get { return (this.Font.Height + 2); }
set { }
}
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override DrawMode DrawMode
{
get { return base.DrawMode; }
set { base.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; }
}
}
public enum RadioButtonListAppearance
{
RadioButton,
CheckBox
}
Assuming you have a few CheckBox controls in a container like a GroupBox, In the load event of your form:
Find all CheckBox controls of the container
Set AutoCheck property of the CheckBox controls to false
Handle Click event of the CheckBox controls and in the event handler, set Checked property of clicked element to true and for rest, set it to false
Here is the code:
private void Form1_Load(object sender, EventArgs e)
{
var all = groupBox1.Controls.OfType<CheckBox>().ToList();
foreach (CheckBox c in all)
{
c.AutoCheck = false;
c.Click += (obj, args) =>
{
var ThisCheckBox = (CheckBox)obj;
foreach( CheckBox cc in all.Except(new[] { ThisCheckBox }))
cc.Checked = false;
ThisCheckBox.Checked = true;
};
}
}
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";
}