When a shortcut is pressed, a value is added to the list and passed to the listbox to add an item. However, if AddRange(RecentColors.ToArray() is used, not only new list items are added, but they are added continuously. If a new value is added to a list value, is there a way to add only that new value to the listbox?
private void mainForm_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.C)
{
RecentColors.Add(hexToRGB(hexcode.Text));
for(int i = 0; i < RecentColors.Count; i++)
{
color_list.Items.AddRange(RecentColors.ToArray());
}
}
}
Capture1
Capture2
When i add one item, i can't change the format that is already added..
The problem is that you has RecentColors with all items and each key press you add all items in the listbox. Try adding one element in RecentColors and also in the listbox:
var item = hexToRGB(hexcode.Text);
RecentColors.Add(item);
color_list.Items.Add(item);
UPDATE
Ok, first we are going to create a class for ListBox and ComboBox items.
public class ComboBoxItem
{
public bool Rgb { get; set; }
public override string ToString()
{
// Text to show in ComboBox
return this.Rgb ? "RGB" : "HTML";
}
}
public class ListBoxItem
{
public bool Rgb { get; set; }
public Color Color { get; set; }
public override string ToString()
{
// Text to show in ListBox
return this.Rgb ?
$"{this.Color.R},{this.Color.G},{this.Color.B}" :
$"{this.Color.R:X2}{this.Color.G:X2}{this.Color.B:X2}";
}
}
Each item in these controls will be an object of these classes. Add the items to the ComboBox:
this.comboBox1.Items.Add(new ComboBoxItem { Rgb = true });
this.comboBox1.Items.Add(new ComboBoxItem { Rgb = false });
When you need add items to ListBox:
this.listBox1.Items.Add(
new ListBoxItem { Rgb = true, Color = Color.Red });
Now, when you change between RGB and HTML in the ComboBox, you get the selected ComboBox item to know when show colors in RGB or in HTML. Then, iterate all ListBox items and set the RGB with this value. In this form, ListBox items will draw text in that mode. The ListBox doesn't know that your items has changes: you must force to redraw the items.
private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
var comboBoxItem = (ComboBoxItem)this.comboBox1.SelectedItem;
for (int i = 0; i < this.listBox1.Items.Count; i++)
{
var item = (ListBoxItem)this.listBox1.Items[i];
item.Rgb = comboBoxItem.Rgb;
// To force redraw
listBox1.Items[i] = listBox1.Items[i];
}
}
Here is the definition for AddRange:
Adds the elements of the specified collection to the end of the List<T>.
(source).
I could be misinterpreting what you're trying to do here, but you're adding the entire "RecentColors" sequence, every time your for loop is called.
Related
When I add an item into a listbox I also add a new line because I want there to be a blank line between each item added. When I remove a selected item I also want to remove the blank line I added otherwise I will end up getting 2 blank lines between each item this is the problem I am having so I thought if I could delete the selected item as well as the blank line above and below the selected item this would work. Is there a better approach to this?
ListBox1.Items.Remove(ListBox1.SelectedItem);
I have typed the items and differentiate what is the blank item and what is the value item. At the time of deleting I have the reference of both. It worked fine, see if it helps.
Here's an example:
Form:
private void Form1_Load(object sender, EventArgs e)
{
Data data = new Data { description = "Test1" };
listBox1.Items.Add(data);
data.BlankLine = new BlankItem();
listBox1.Items.Add(data.BlankLine);
data = new Data { description = "Test2" };
listBox1.Items.Add(data);
data.BlankLine = new BlankItem();
listBox1.Items.Add(data.BlankLine);
data = new Data { description = "Test3" };
listBox1.Items.Add(data);
data.BlankLine = new BlankItem();
listBox1.Items.Add(data.BlankLine);
data = new Data { description = "Test4" };
listBox1.Items.Add(data);
data.BlankLine = new BlankItem();
listBox1.Items.Add(data.BlankLine);
}
Event to delete the item on click:
private void listBox1_Click(object sender, EventArgs e)
{
if((listBox1.SelectedItem != null && listBox1.SelectedItem.GetType() != typeof(BlankItem)))
{
Data item = (Data)listBox1.SelectedItem;
listBox1.Items.Remove(item);
listBox1.Items.Remove(item.BlankLine);
}
}
Object Data
public class Data
{
public string description { get; set; }
public BlankItem BlankLine { get; set; }
public override string ToString()
{
return description;
}
}
Object BlankItem
public class BlankItem
{
public override string ToString()
{
return Environment.NewLine;
}
}
I wanted to try to implement the above functionality, but using a data-bound Listbox such that I make changes to the underlying list instead of the Listbox. If possible, use BindingList<T> instead of List<T> because it implements additional functionality specific to data binding.
The core is still the same, as each item added must also be followed by adding a string.Empty item. The same for removal, when an item is removed
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
var list = new BindingList<string>();
list.Add("ABC");
list.Add(string.Empty);
list.Add("GHK");
list.Add(string.Empty);
list.Add("OPQ");
listBox1.DataSource = list;
var binding = listBox1.BindingContext[list] as CurrencyManager;
listBox1.KeyDown += (s, ev) =>
{
if (ev.KeyData == Keys.Delete)
{
if (listBox1.SelectedItem != null && !listBox1.SelectedItem.Equals(string.Empty))
{
int index = listBox1.SelectedIndex;
if (index >= 0)
{
list.RemoveAt(index);
if (index < list.Count && list[index].Equals(string.Empty))
{
list.RemoveAt(index);
}
binding.Refresh();
}
}
}
if (ev.KeyData == Keys.Insert)
{
int index = listBox1.SelectedIndex;
if (index==-1 || list[index] == string.Empty)
{
index++;
}
list.Insert(index, "NEW " + (index + 1).ToString());
list.Insert(index+1, string.Empty);
}
};
}
}
press the [DEL] key to remove an item, and the [INS] key to add an item.
But I am not happy with this solution. I think there is a way to create a class that implements IListSource that you directly add/remove items and it creates a list with blanks in between automatically for binding.
I am trying to create a custom ComboBox in c# Winforms for using with custom Highlight color.
Found some examples from the internet and modified a little to keep my codes clean.But there is something wrong that i can not fix so i need your help.
here my custom ComboBox class:
using System.Drawing;
using System.Windows.Forms;
namespace TesTApp
{
class ThemedComboBox : ComboBox
{
protected Color _HighLightColor;
[System.ComponentModel.Description("High Light Color for selection"),
System.ComponentModel.Category("HighLight"),
System.ComponentModel.DefaultValue(typeof(Color), "Gray")]
public Color HighlightColor
{
get { return _HighLightColor; }
set
{
_HighLightColor = value;
Invalidate();
Update();
}
}
public ThemedComboBox()
{
InitializeComponent();
}
private void InitializeComponent()
{
this.DrawMode = DrawMode.OwnerDrawFixed;
HighlightColor = Color.FromArgb(255, 167, 36);
this.DrawItem += new DrawItemEventHandler(ComboBox_DrawItem);
}
void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index < 0)
return;
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
e.Graphics.FillRectangle(new SolidBrush(HighlightColor),
e.Bounds);
else
e.Graphics.FillRectangle(new SolidBrush(BackColor),
e.Bounds);
e.Graphics.DrawString(Items[e.Index].ToString(), e.Font,
new SolidBrush(ForeColor),
new Point(e.Bounds.X, e.Bounds.Y));
e.DrawFocusRectangle();
}
}
}
When i call the method for fill the ComboBox with List , DropDown does not display the names of items.
At first i created a class to fill the data
public class testItems
{
public string itemName { get; set; }
public int itemValue { get; set; }
}
And then i am calling the method that fills the ComboBox :
int maxItem = 5;
private void TestComboBox1()
{
List<testItems> _list = new List<testItems>();
for (int i = 0; i < maxItem; i++)
{
_list.Add(new testItems
{
itemName = "Item no: " + i.ToString(),
itemValue = i
});
}
themedComboBox1.DataSource = _list;
themedComboBox1.DisplayMember = "itemName";
themedComboBox1.ValueMember = "itemValue";
}
With this method , ComboBox DropDown does not display the name(DisplayMember) of items.
Then i have tried to fill ComboBox with a string array.With string array ComboBox displays the items but with this way i can not give values to items.
Here my method for fill the ComboBox with string array:
int maxItem = 5;
private void TestComboBox2()
{
string[] items = new string[maxItem];
for (int i = 0; i < maxItem; i++)
{
items[i] = "Item No : " + i;
}
themedComboBox2.DataSource = items;
}
All i want to have a custom ComboBox with custom Highlight color.Where am i doing wrong? Can you please help me to correct this?
The values you see "TestTApp.testItems" are actually generated in the virtual method Object.ToString(). If your sole issue is replacing these values, you can override that ToString method for your testItems class (which, by the way, I'd recommend naming TestItem)
See this:
public class testItems
{
public string itemName { get; set; }
public int itemValue { get; set; }
public override string ToString()
{
return itemName;
}
}
Working with lists and Combo boxes (not limited to combo boxes) is fairly simple, you don't have to worry about row numbers and column names as you have to do with general data sources. In fact, you don't even need to set the DisplayMember and DataMember.
Just notice that when working with this kind of approach, you work with values of type testItems, and not actually the type which you desired ValueMember to hold. For instance, calling themedComboBox1.SelectedValue returns an testItems object (and not an int).
Suppose, I created this DataGridView in design view.
Now, I need to add items to the ComboBox column pro grammatically and show the item with index = 0.
The following code does load a ComboBox.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.Rows.Add("1st Col", "2nd Col");
Column3.Items.Add("AAAA");
Column3.Items.Add("BBBB");
Column3.Items.Add("CCCC");
}
}
But, doesn't show 0-th item.
You could try:
private void Form1_Load(object sender, EventArgs e)
{
DataGridViewComboBoxColumn cmb = new DataGridViewComboBoxColumn();
cmb.Items.Add("AAAA");
cmb.Items.Add("BBBB");
cmb.Items.Add("CCCC");
dataGridView1.Rows.Add("1st Col", "2nd Col");
dataGridView1.Columns.Add(cmb);
}
You have to set current value for each cell in your column.
for (int i = 0; i < dataGridView.RowCount; i++)
dataGridView[3, i].Value = "AAAA";
I'm proposing you an alternative way the set the default/initial value of a DataGridViewComboBoxColumn, using a custom CellTemplate.
Assuming that (from the image shown), your ComboBox column is Column[2], you could assign it this custom CellTemplate, which can be initialized with a default value:
(Here, the default value is of type String, but you could make it generic if needed)
public class ComboBoxCell : DataGridViewComboBoxCell
{
private static string psDefaultValue;
public ComboBoxCell()
: base() { this.Value = psDefaultValue; }
public void DefaultValue(string Value)
{
psDefaultValue = Value;
this.Value = Value;
}
public override Type ValueType => typeof(String);
public override object DefaultNewRowValue => psDefaultValue;
}
When initializing a DataGridView, assign the custom CellTemplate to the DataGridViewComboBoxColumn:
ComboBoxCell ComboBoxCellTemplate = new ComboBoxCell();
dataGridView1.Columns[2].CellTemplate = ComboBoxCellTemplate;
Then, after filling in the ComboBox items list, define the default value and assign it using the custom DefaultValue() method of the CellTemplate:
((DataGridViewComboBoxColumn)dataGridView1
.Columns[2])
.Items.AddRange(new string[] { "Item1", "Item2", "Item3" });
((ComboBoxCell)dataGridView1.Columns[2]
.CellTemplate)
.DefaultValue(((DataGridViewComboBoxColumn)dataGridView1
.Columns[2]).Items[0].ToString());
After that, define the DatagridView DataSource. This way, for all new rows, the DataGridVieewComboBoxColumn will present the default value, the first item of the ComboBox in this case.
As the title suggests, I want to filter the values in a combobox according to what is written in a textbox. The combobox takes values from a list. I have tried AutoCompleteMode and AutoCompleteSource but it doesn't let me add any values to the combobox when I use these. The combobox holds values of a list of the following class.
class Groep
{
//Fields
private string naamGroep;
//Properties
public string NaamGroep
{
get { return this.naamGroep; }
set { naamGroep = NaamGroep; }
}
//Constructor
public Groep(string naam)
{
this.naamGroep = naam;
}
This is the list:
List<Groep> Groepen = new List<Groep>();
I have two textboxes. One to add items to the list and the other to filter the combobox.
Do it using a foreach loop
private void Button1_Click(object sender, EventArgs e)
{
ComboBox1.Items.Clear();
foreach (Groep g in Groepen.Where(g => g.NaamGroep.Contains(TextBox1.Text)))
ComboBox1.Items.Add(g.NaamGroep);
}
I have databound a listbox to a simple custom object collection. Next, I added a button to remove the selected item from the object collection. The problem is that when certain items are removed and the listbox is showing the vertical scroll bar, the scrollbar appears to reset to a new position, although what I really think is happening is that the control is repainting.
The folowing code sample demonstrates the problem. Add this code to a form, making sure that the vertical scrollbar appears. Select an item in the middle of the collection so that the scrollbar is centered and press the remove button. When the control repaints, the items and scrollbar are in a different position. I would like for the listbox to behave as it would with non-databound items. Am I better off not using databinding, or is there a solution that allows me to keep the contol bound?
Thanks.
public partial class Form1 : Form
{
private BindingList<ItemData> m_bList = new BindingList<ItemData>();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i < 50; i++)
{
m_bList.Add(new ItemData("Name " + i.ToString(), i));
}
this.listBox1.DisplayMember = "Name";
this.listBox1.DataSource = m_bList;
}
private void btnRemove_Click(object sender, EventArgs e)
{
m_bList.Remove(listBox1.SelectedItem as ItemData);
}
}
public class ItemData
{
public string Name { get; set; }
public int Position { get; set; }
public ItemData(string name, int position)
{
Name = name;
Position = position;
}
}
You need to preserve the TopIndex property of the listbox when removing the item. Preserving SelectedIndex does not stop the scrollbar from jumping. The code below does what I think you want.
private void btnRemove_Click(object sender,EventArgs e)
{
int topIndex = listBox1.TopIndex;
m_bList.Remove(listBox1.SelectedItem as ItemData);
if(listBox1.Items.Count>topIndex)
listBox1.TopIndex = topIndex;
}
I can think of one way to dampen the error (note this might not be the most accurate solution) . I just added a few things to the button click event. I am not sure if they solve your requirements completely since you would be the best judge of that, but nonetheless here you go.
private void btnRemove_Click(object sender, EventArgs e)
{
int s = listBox1.SelectedIndex;
m_bList.Remove(listBox1.SelectedItem as ItemData);
listBox1.Refresh();
listBox1.SelectedIndex = s;
}