Duplicate clicks on xx_Tap() happening in separate class - c#

The scenario:
I want to tap on a textblock and run a method to add that item to the cart.No, I don't prefer buttons to textblocks, thank you :)
The code (shoppingcart.cs)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading.Tasks;
namespace m_POS
{
public class shoppingcart
{
int cartnum;
int duplicate=0;
int num_of_items;
int counter=1;
List<item> items = new List<item>();
//constructor
public shoppingcart()
{
this.cartnum = counter;
counter += 1;
this.num_of_items = 0;
this.items = new List<item>();
init_items();
}
//return the item list of tapped/purchased items
public List<item> getitems(){
return this.items;
}
//returns the number of items tapped/purchased
public int get_num_of_items() { return this.num_of_items; }
// the method that adds a tapped-on item to the items list
public void additem(String itemx,String qty) {
for (int i = 0; i < item.pick_item.Count; i++)
{
if (itemx.Equals(item.pick_item[i].getname()))
{
item itm = new item(item.pick_item[i].getname(),
item.pick_item[i].getprice());
itm.addqty(Convert.ToInt16(qty));
this.items.Add(itm);
Debug.WriteLine("added to cart!!");
}
}
this.num_of_items += Convert.ToInt16(qty);
}
//used to test the additem() works. Everytime the class is run, this Rolex item will
//be the first to be added to the cart. ALWAYS. Funny thing is, it doesnt get
// duplicated.
private void init_items()
{
item itm12 = new item("Rolex", 4000);
//additem(itm12);
this.items.Add(itm12);
}
}
////////////////////////////////////////////////////////////////////////////////////////
public class item
{
String itemname;
int itemamount;
int itemqty = 0;
public static List<item> pick_item = new List<item>();
public static List<String> menu_food = new List<string> {
"Single Beef Burger",
"Double Beef Burger",
"Triple Beef Burger",
"Single Chicken Burger",
"Double Chicken Burger",
"Single Veggie Burger",
"1/2 Fries",
"Full Fries",
"Beef Steak",
"Mushroom",
"Steamed Rice",
"Rolex"};
public static List<String> menu_price = new List<String>{
"8000",
"17000",
"25000",
"12000",
"26500",
"7500",
"4000",
"6000",
"20000",
"25000",
"17500",
"4000"};
public item(string name, int amount)
{
this.itemamount = amount;
this.itemname = name;
this.itemqty = 1;
}
public static void init_menu()
{
for (int i = 0; i < get_menu().Count; i++)
{
item itm = new item(menu_food[i], Convert.ToInt32(menu_price[i]));
pick_item.Add(itm);
}
}
public void addqty(int qty) { this.itemqty = qty; }
public string getname() { return this.itemname; }
public int getprice() { return this.itemamount; }
public static int getpxbyname(string itemname) {
int ans=0;
for (int y = 0; y < pick_item.Count; y++) {
if (pick_item[y].itemname.ToString().Equals(itemname)) {
ans = pick_item[y].itemamount;
}
}
return ans;
}
public static List<String> get_menu() { return menu_food; }
public static List<String> get_price() { return menu_price; }
}
}
Where are the duplicates happening?
I'm getting the additem(string itemname,int itemqty) being run twice on every tap. Everything else is perfect, though.
What have I done before posting?
- Tested the Tap event and made sure it was only being fired ONCE per tap? Check.
- Tested the additem() method to make sure it works to being with? Check. I add a single item to the cart everytime the app is started. That item never gets duplicated.
Console Debug.WriteLine() shows
added to cart!!
added to cart!!
called method with System.Windows.Controls.TextBlock
The first two added to carts are from the method being called twice.
The next called method with System.Windows.Controls.TextBlock is from the debug i inserted just after calling this method from the Food.xaml.cs
Food.xaml.cs [part of it]
public Foods()
{
InitializeComponent();
item.init_menu();
populatemenu();
}
public void populatemenu()
{
List<String> display = item.get_menu();
for (int i = 0; i < display.Count; i++)
{
string tname = "tb" + i;
TextBlock tb = new TextBlock();
tb.Tap += new EventHandler<System.Windows.Input.GestureEventArgs>(tb_Click);
tb.Style = (Style)Resources["textblocker"];
tb.FontSize = 36;
tb.Text = display[i];
tb.Name = tname;
sp_lunch.Children.Add(tb);
}
}
private void tb_Click(object sender, RoutedEventArgs e)
{
tapped += 1;
selectqty(sender);
}
private void selectqty(object sender) {
Popup popup = new Popup();
popup.Height = 300;
popup.Width = 400;
popup.VerticalOffset = 100;
PopUpControl control = new PopUpControl();
popup.Child = control;
popup.IsOpen = true;
string qty="";
control.btnOK.Click += (s, args) =>
{
popup.IsOpen = false;
//pick input from the popup's textbox.
qty = control.tbx.Text;
if (qty == null||qty=="") { qty = "0"; }
//send clicked item to cart for addition
TextBlock clicked = ((TextBlock)sender);
string temp = clicked.Text;
Cart.cart_new.additem(temp, qty);
Debug.WriteLine("called method with "+sender.ToString());
tb_pamount_lunch.Text = Convert.ToString(Cart.cart_new.get_num_of_items());
//tb_pamount_lunch.Text = tapped.ToString();
MessageBox.Show(temp);
//update the dinner stackpanel to display the selected items
sp_dinner.Children.Clear();
List<item> display = Cart.cart_new.getitems();
for (int i = 0; i < display.Count; i++)
{
TextBlock tb1 = new TextBlock();
tb1.FontSize = 36;
tb1.Text = display[i].getname().ToString();
sp_dinner.Children.Add(tb1);
}
};
control.btnCancel.Click += (s, args) =>
{
//close popup when cancel is clicked
popup.IsOpen = false;
};
}
Any more info??
If there's some other class you'd want to take a look at, I'll gladly copy/paste it here or upload the whole project.zip :)

I think when you tab the thrid time, 3 items will be added.
(s, args) =>
{
popup.IsOpen = false;
//pick input from the popup's textbox.
qty = control.tbx.Text;
if (qty == null||qty=="") { qty = "0"; }
//send clicked item to cart for addition
TextBlock clicked = ((TextBlock)sender);
string temp = clicked.Text;
Cart.cart_new.additem(temp, qty);
Debug.WriteLine("called method with "+sender.ToString());
tb_pamount_lunch.Text = Convert.ToString(Cart.cart_new.get_num_of_items());
//tb_pamount_lunch.Text = tapped.ToString();
MessageBox.Show(temp);
//update the dinner stackpanel to display the selected items
sp_dinner.Children.Clear();
List<item> display = Cart.cart_new.getitems();
for (int i = 0; i < display.Count; i++)
{
TextBlock tb1 = new TextBlock();
tb1.FontSize = 36;
tb1.Text = display[i].getname().ToString();
sp_dinner.Children.Add(tb1);
}
};
control.btnCancel.Click += (s, args) =>
{
//close popup when cancel is clicked
popup.IsOpen = false;
};
This is because the control still exists and every time you call selectqty another action is added to the eventhandler list. And will be executed more than ones. You should only register the event ones. Like in your constructor.
Personal: You should register events to a button that within a subcontrol. Instead create a new event on the control and raise it there. This will give you the advantage to change the buttons or other controls (maybee you want short-cut keys in future) on that controls without altering you mainform.
example:
public class Form1 : Form
{
public Form1()
{
InitializeComponent();
control.btnOKClicked += Control_buttonOk;
control.btnCancelClicked += Control_buttonCancel;
}
private void Control_buttonOk(object sender, eventArgs e)
{
// implement code
}
private void Control_buttonCancel(object sender, eventArgs e)
{
// implement code
}
}
public class UserControl1: UserControl
{
public UserControl1()
{
InitializeComponent();
btnOK.Click += (sender, e) =>
{
if(btnOKClicked != null)
btnOKClicked(this, EventArgs.Empty);
};
btnCancel.Click += (sender, e) =>
{
if(btnCancelClicked!= null)
btnCancelClicked(this, EventArgs.Empty);
};
}
public event EventHandler btnOKClicked;
public event EventHandler btnCancelClicked;
}
This way you separate the functionallity/dependency of the layout of the control.
As i was writing this, i think you might look over here:
Form.ShowDialog Method http://msdn.microsoft.com/en-us/library/c7ykbedk.aspx This will handle the popup.IsOpen and will block your MainForm until it's closed. With a DialogResult you can read if the user pressed Ok or cancel.

Related

Create dynamically controls in columns inside a Panel

I have a panel where I create Labels and NumericUpDown fields dinamically like:
List<string> Labels = new List<string>();
public List<Label> DeliveryBreakdownLabelsModel = new List<Label>();
public List<NumericUpDown> DeliveryBreakdownNumericUpDownModel = new List<NumericUpDown>();
private void SetDeliveryBreakdownAmountForm_Load(object sender, EventArgs e)
{
var rModel = //List data from database
AddRow(rModel);
Arrange();
}
private void AddRow(IList<DeliveryBreakdownGetViewModel> rModel)
{
for (int i = 0; i < rModel.Count; i++)
{
Labels.Add(rModel[i].DesignGroupName);
var label = new Label
{
AutoSize = true, // make sure to enable AutoSize
Name = "label" + Labels.Count,
Text = rModel[i].DesignGroupName,
Location = new Point(12, YPos)
};
this.Controls.Add(label);
pnlDeliveryBreakdown.Controls.Add(label);
DeliveryBreakdownLabelsModel.Add(label);
var numericUpDown = new NumericUpDown
{
Name = "numericUpDown" + Labels.Count,
Text = rModel[i].ContractedAmount.ToString(),
Location = new Point(12, YPos),
Size = new Size(60, 19),
DecimalPlaces = 2,
Maximum = decimal.MaxValue
};
this.Controls.Add(numericUpDown);
this.Controls.Add(numericUpDown);
pnlDeliveryBreakdown.Controls.Add(numericUpDown);
DeliveryBreakdownNumericUpDownModel.Add(numericUpDown);
YPos += 25;
}
}
void Arrange()
{
// Determine the widest label sized by the AutoSize
var maxLabelX = 0;
for (int i = 0; i < Labels.Count; i++)
{
maxLabelX = Math.Max(maxLabelX, DeliveryBreakdownLabelsModel[i].Location.X + DeliveryBreakdownLabelsModel[i].Size.Width);
}
// Move all the text boxes a little to the right of the widest label
var maxNumericX = 0;
for (int i = 0; i < Labels.Count; i++)
{
maxNumericX = Math.Max(maxNumericX, DeliveryBreakdownNumericUpDownModel[i].Location.X + DeliveryBreakdownNumericUpDownModel[i].Size.Width);
DeliveryBreakdownNumericUpDownModel[i].Location = new Point(maxLabelX + 10, DeliveryBreakdownNumericUpDownModel[i].Location.Y);
}
//Set total wi
this.Width = maxNumericX + maxLabelX + 60;
}
So it looks like:
My question is, how can I modify my code in order to create more than one column. I want to do that because sometimes I can have alot of data so shows only in vertical may be a problem in future. Expected result: I.E
I suggest using a TableLayoutPanel with a UserControl that contains exactly one label and one numeric box.
Even in the designer, this looks neat.
All you have to do is expose the properties you want from the numeric box in your user control.
In the example above, I am using the following code:
// Fixed height user control
// Some code taken from: https://stackoverflow.com/a/4388922/380384
[Designer(typeof(MyControlDesigner))]
public partial class LabelNumeric : UserControl
{
public LabelNumeric()
{
InitializeComponent();
}
protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
{
base.SetBoundsCore(x, y, width, 24, specified);
}
[DefaultValue("Label")]
public string Caption
{
get => label1.Text;
set => label1.Text = value;
}
[DefaultValue(0)]
public decimal Value
{
get => numericUpDown1.Value;
set => numericUpDown1.Value =value;
}
[DefaultValue(0)]
public int DecimalPlaces
{
get => numericUpDown1.DecimalPlaces;
set => numericUpDown1.DecimalPlaces = value;
}
[DefaultValue(100)]
public decimal MaxValue
{
get => numericUpDown1.Maximum;
}
[DefaultValue(0)]
public decimal MinValue
{
get => numericUpDown1.Minimum;
}
}
internal class MyControlDesigner : ControlDesigner
{
MyControlDesigner()
{
base.AutoResizeHandles = true;
}
public override SelectionRules SelectionRules
{
get
{
return SelectionRules.LeftSizeable | SelectionRules.RightSizeable | SelectionRules.Moveable;
}
}
}
You can access all the controls from the tableLayoutPanel1.Controls property and check their position in the table like this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
foreach (var item in tableLayoutPanel1.Controls.OfType<LabelNumeric>())
{
var pos = tableLayoutPanel1.GetCellPosition(item);
item.Caption = $"Row{pos.Row}Col{pos.Column}";
}
}
}
So at runtime it is as follows:
The trick is to have one extra row on the bottom autosized, and all the other rows that contain the controls be of fixed height of 24pt.

What am I doing wrong in my custom event in Window Forms?

I'm working on a project that requires me to create items in one form, put them in a List in another and them insert them for display on a list view on a third. I have a custom event set up to add the items to their appropriate place but it doesn't work and I can't figure out why.
My UserInputForm is where the info is put in. I have a get/set method to pull the data from the fields. The declared EventHandler is in this form.
public partial class UserInputForm : Form
{
public UserInputForm()
{
InitializeComponent();
}
MainForm main;
public EventHandler AddNewItem;
public Items EachItem
{
get
{
Items newItem = new Items();
newItem.Name = nameBox.Text;
newItem.Month = monthBox.Text;
newItem.Day = dayBox.Value;
newItem.Senior = seniorCheckBox.Checked;
newItem.ImageIndex = monthBox.SelectedIndex;
return newItem;
}
set
{
nameBox.Text = value.Name;
monthBox.Text = value.Month;
dayBox.Value = value.Day;
seniorCheckBox.Checked = value.Senior;
}
}
private void AddItem (object sender, EventArgs e)
{
if (main == null)
{
main = new MainForm();
}
AddNewItem += main.AddNewItemHandler;
if (AddNewItem != null)
{
AddNewItem(this, new EventArgs());
}
EachItem = new Items();
}
}
In the Main, I have the event that adds the item to the list, calls a method to display the # of items in the list, and calls a method in the ListView Form to add it there.
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
List<Items> inputItems = new List<Items>();
UserInputForm newInput;
ListView list;
public void AddNewItemHandler(object sender, EventArgs e)
{
newInput = sender as UserInputForm;
Items newItem = newInput.EachItem;
inputItems.Add(newItem);
if (list == null)
{
list = new ListView();
}
list.AddToListView(newItem);
TotalInList();
}
private void OpenInputForm(object sender, EventArgs e)
{
newInput = new UserInputForm();
if (newInput.IsDisposed == true)
{
newInput = new UserInputForm();
}
newInput.Show();
OpenInputNum();
newInput.FormClosed += InputFormClosed;
}
private void OpenListView(object sender, EventArgs e)
{
if (Application.OpenForms.OfType<ListView>().Count<ListView>() == 1)
{
Application.OpenForms.OfType<ListView>().First().Close();
displayList.Checked = false;
}
else
{
if (list == null)
{
list = new ListView();
}
if (list.IsDisposed == true)
{
list = new ListView();
}
list.Show();
list.Load += ListOpened;
}
}
private void OpenInputNum()
{
string inputNum = $"{Application.OpenForms.OfType<UserInputForm>().Count<UserInputForm>()}";
openInputNumBox.Text = inputNum;
}
private void ListOpened(object sender, EventArgs e)
{
if (list == null)
{
list = new ListView();
}
if (list.IsDisposed == true)
{
list = new ListView();
}
list.AddToNewListView(inputItems);
}
public void TotalInList()
{
string listNum = $"{inputItems.Count()}";
itemListNumBox.Text = listNum;
}
}
The ListView Form has a method that adds all items at once when its opened or a single item when its already open. It changes the item to a ListViewItem and adds it to the list.
public partial class ListView : Form
{
public ListView()
{
InitializeComponent();
}
//list for listview
List<Items> toView;
public void AddToNewListView(List<Items> toListView)
{
toView = toListView;
ListViewItem addItem = new ListViewItem();
foreach (Items item in toView)
{
addItem.Text = item.ToString();
addItem.ImageIndex = item.ImageIndex;
addItem.Tag = item;
itemListView.Items.Add(addItem);
}
}
public void AddToListView(Items newItem)
{
ListViewItem addItem = new ListViewItem();
addItem.Text = newItem.ToString();
addItem.ImageIndex = newItem.ImageIndex;
addItem.Tag = newItem;
itemListView.Items.Add(addItem);
}
}
The problems I'm having are:
Though I follow the data and though it all seems to be there when needed, my ListView will not populate and neither will the count for the number of items in the main. Is there something wrong with my code?

How to create user control for displaying collection of other user controls in WinForms?

I need to create a user control MyTypeListControl to display collection of objects of type MyType using a user controls MyTypeDisplayControl instance for each of those objects.
So that I could
add instance of MyTypeListControl to my WinForm, then
load collection of MyType and
assign it to MyTypeListControl's DataSource.
In the result it should generate and show appropriate count of MyTypeDisplayControl instances in MyTypeListControl's instance.
In case if I needed to show list of properties - equivalent would be DataGrid with specific fields from MyType assigned to specific DataGrid's columns, but I want to view each MyType item as a user control - with more power for visual representation and functionality than DataGrid provides for it's rows.
Is that even possible?
I found this SO resource how to create My collection type, but this is only small part of the problem solution...
It is quite easy (if you know how) and doesn't take so much effort as you might think in the first place (at least for a simple implementation that handles collection of less then 100 items).
So at first lets create a MyType:
public class MyType
{
public static MyType Empty = new MyType(String.Empty, DateTime.MinValue);
public MyType(string myName, DateTime myBirthday)
{
MyName = myName;
MyBirthday = myBirthday;
}
public DateTime MyBirthday { get; private set; }
public string MyName { get; private set; }
}
At next we need a MyTypeControl:
public partial class MyTypeControl : UserControl
{
private MyType _MyType;
private Label labelBirthday;
private Label labelName;
private Label labelSeparator;
public MyTypeControl()
{
InitializeComponent();
}
public event EventHandler MyTypeChanged;
public MyType MyType
{
get { return _MyType; }
set
{
if (_MyType == value)
return;
_MyType = value ?? MyType.Empty;
OnMyTypeChanged(EventArgs.Empty);
}
}
protected virtual void OnMyTypeChanged(EventArgs eventArgs)
{
UpdateVisualization();
RaiseEvent(MyTypeChanged, eventArgs);
}
protected void UpdateVisualization()
{
SuspendLayout();
labelName.Text = _MyType.MyName;
labelBirthday.Text = _MyType.MyBirthday.ToString("F");
labelBirthday.Visible = _MyType.MyBirthday != DateTime.MinValue;
ResumeLayout();
}
private void InitializeComponent()
{
labelName = new Label();
labelBirthday = new Label();
labelSeparator = new Label();
SuspendLayout();
labelName.Dock = DockStyle.Top;
labelName.Location = new Point(0, 0);
labelName.TextAlign = ContentAlignment.MiddleCenter;
labelBirthday.Dock = DockStyle.Top;
labelBirthday.TextAlign = ContentAlignment.MiddleCenter;
labelSeparator.BorderStyle = BorderStyle.Fixed3D;
labelSeparator.Dock = DockStyle.Top;
labelSeparator.Size = new Size(150, 2);
Controls.Add(labelSeparator);
Controls.Add(labelBirthday);
Controls.Add(labelName);
MinimumSize = new Size(0, 48);
Name = "MyTypeControl";
Size = new Size(150, 48);
ResumeLayout(false);
}
private void RaiseEvent(EventHandler eventHandler, EventArgs eventArgs)
{
var temp = eventHandler;
if (temp != null)
temp(this, eventArgs);
}
}
Then comes our magically list control:
public class MyTypeListControl : UserControl
{
private ObservableCollection<MyType> _Items;
public MyTypeListControl()
{
AutoScroll = true;
_Items = new ObservableCollection<MyType>();
_Items.CollectionChanged += OnItemsCollectionChanged;
}
public Collection<MyType> Items
{
get { return _Items; }
}
private void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
UpdateVisualization();
}
private void UpdateVisualization()
{
SuspendLayout();
Controls.Clear();
foreach (var item in _Items)
{
var control = new MyTypeControl { MyType = item, Dock = DockStyle.Top };
Controls.Add(control);
Controls.SetChildIndex(control, 0);
}
ResumeLayout();
}
}
And now simply create the list control in your form or parent control and fill it with some meaningful values:
myTypeListControl.Items.Add(new MyType("Adam", DateTime.UtcNow.Add(-TimeSpan.FromDays(365 * 40))));
myTypeListControl.Items.Add(new MyType("Eva", DateTime.UtcNow.Add(-TimeSpan.FromDays(365 * 38))));

Implement jQuery Tag-it functionality in C# Win Form

I would like to implement a functionality similar to jQuery TagIt into C# windows forms.
Here is the link for jQuery - http://aehlke.github.com/tag-it/
I am thinking of creating a user control for this functionality.
Any help on how to go about this?
You're in luck, as there's already a container control called a FlowLayoutPanel that will get you 90% of the way there as a flowing tag host.
FlowLayoutPanel Class # MSDN
This control is available from the Toolbox in Visual Studio, so a good starting point would be to make a custom control based upon a FlowLayoutPanel, and another custom control to represent a tag based upon a Label or Checkbox, and update the drawing and behavior (in the case of a Label) to respond to clicks and to display the [x] to dismiss the tag.
Label Class # MSDN
CheckBox Class # MSDN
After making these two controls, you will need to do additional work to make your FlowLayoutPanel-derived control add/remove Label-based controls representing the state of the tags present.
Update: One thing I missed, a TextBox or other input field would need to be added in place to support adding new tags.
TextBox # MSDN
public class TagLayoutPanel : FlowLayoutPanel
{
//local variables/controls
private TextBox _entryBox;
private Dictionary<string,string> _currentTags;
//events
public delegate void TagsUpdatedHandler(TagEventArgs e);
public event TagsUpdatedHandler TagsUpdated;
//constructor(s)
public TagLayoutPanel()
{
Init();
}
public List<string> GetCurrentTags()
{
var lst = new List<string>();
if (_currentTags != null)
lst = _currentTags.Keys.ToList();
return lst;
}
private void Init()
{
_currentTags = new Dictionary<string, string>();
//Entry box
this.Padding = new Padding(3);
this.BackColor = Color.White;
_entryBox = new TextBox();
_entryBox.BackColor = Color.White;
_entryBox.BorderStyle = System.Windows.Forms.BorderStyle.None;
_entryBox.KeyUp += _entryBox_KeyUp;
this.Controls.Add(_entryBox);
}
private void _entryBox_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
var tag = _entryBox.Text;
if (!string.IsNullOrEmpty(tag))
{
this.AddTag(tag);
_entryBox.Text = String.Empty;
}
}
}
protected override void OnGotFocus(EventArgs e)
{
//Set focus to the textentry box.
base.OnGotFocus(e);
this._entryBox.Focus();
}
public void AddTag(string tag)
{
bool added = false;
if (!_currentTags.ContainsKey(tag))
{
_currentTags.Add(tag, tag);
added = true;
}
if(added)
{
Redraw();
Notify();
}
}
private void Notify()
{
if(TagsUpdated != null)
TagsUpdated(new TagEventArgs(GetCurrentTags().ToArray()));
}
public void Redraw()
{
this.Controls.Clear();
foreach (var tag in _currentTags.Keys)
{
DrawTag(tag);
}
AddEntry();
}
private void AddEntry()
{
this.Controls.Add(_entryBox);
_entryBox.Focus();
}
public void DrawTag(string tag)
{
var lbl = new Label();
lbl.MouseMove += lbl_MouseMove;
lbl.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
lbl.BackColor = Color.LightGray;
lbl.Name = "lbl_" + tag.Replace(" ", "");
lbl.ImageAlign = ContentAlignment.TopRight;
lbl.Text = tag;
lbl.Tag = tag;
lbl.Image = Resources.close_x; //Replace with your own image.
lbl.Click += lbl_Click;
this.Controls.Add(lbl);
}
private void lbl_Click(object sender, EventArgs e)
{
var lbl = (Label)sender;
bool removed = false;
foreach(var item in this.Controls)
{
if(item is Label)
{
if(((Label)item).Tag.ToString() == lbl.Tag.ToString())
{
_currentTags.Remove(lbl.Tag.ToString());
removed = true;
break;
}
}
}
if(removed)
{
Redraw();
Notify();
}
}
private void lbl_MouseMove(object sender, MouseEventArgs e)
{
var lbl = (Label)sender;
var startImgX = lbl.Width - 20;
var endImgY = lbl.Height - 15;
if (e.X >= startImgX && e.Y <= endImgY)
System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.Hand;
else
System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.Arrow;
}
}
public class TagEventArgs : EventArgs
{
public string[] Tags { get; private set; }
public TagEventArgs(string[] tags)
{
Tags = tags;
}
}

CheckedListBox with search function not checking correctly

I'm having strange issues with the check box control in C# .Net
My code below shows all logic that is required - _itemsChecked is a private dictionary containing all of the _fixtures and whether they are true or false (checked or un checked)
What I want is to be able to search my check list whilst retaining those which have been checked previously. If a checked item is included in the search results I want it to be checked.
The code nearly works! But for some reason boxes are randomly checked here and there, and it appears to work through debug but when the screen returns to the control it then hasn't worked.
Sure I'm missing something very simple.
My logic is:
DataSource includes those which match the typed search query,
Iterate through this list and check if the Guid is true in the dictionary.
If it is true then we set it as checked.
Hope I have provided adequate information.
Many thanks in advance.
private void searchTextBox_KeyUp(object sender, EventArgs e)
{
lst.DataSource = _fixtures
.OrderBy(f =>
f.Description)
.Where(f =>
f.Description.ToLower().Contains(searchFixturesTextBox.Text.ToLower()))
.ToList();
lst.DisplayMember = "Description";
for (var i = 0; i < lst.Items.Count; i++)
if(_itemsChecked.Contains(new KeyValuePair<Guid, bool>(((Fixture)lst.Items[i]).Guid, true)))
lst.SetItemChecked(i, true);
}
void lst_ItemCheck(object sender, ItemCheckEventArgs e)
{
var selectedItem = ((ListBox) sender).SelectedItem as Fixture;
if (selectedFixtureItem != null)
_itemsChecked[selectedItem.Guid] = e.CurrentValue == CheckState.Unchecked;
}
So I put this together from a few examples I found. The majority of the work came from How do I make a ListBox refresh its item text?
public class Employee
{
public string Name { get; set; }
public int Id { get; set; }
public bool IsChecked { get; set; }
public override string ToString()
{
return Name;
}
}
public partial class Form1 : Form
{
// Keep a bindable list of employees
private BindingList<Employee> _employees;
public Form1()
{
InitializeComponent();
// Load some fake employees on load
this.Load += new EventHandler(Form1_Load);
// Click once to trigger checkbox changes
checkedListBox1.CheckOnClick = true;
// Look for item check change events (to update there check property)
checkedListBox1.ItemCheck +=
new ItemCheckEventHandler(CheckedListBox_ItemCheck);
}
// Load some fake data
private void Form1_Load(object sender, EventArgs e)
{
_employees = new BindingList<Employee>();
for (int i = 0; i < 10; i++)
{
_employees.Add(new Employee()
{ Id = i, Name = "Employee " + i.ToString() });
}
// Display member doesnt seem to work, so using ToString override instead
//checkedListBox1.DisplayMember = "Name";
//checkedListBox1.ValueMember = "Name";
checkedListBox1.DataSource = _employees;
// Another example databind to show selection changes
txtId.DataBindings.Add("Text", _employees, "Id");
txtName.DataBindings.Add("Text", _employees, "Name");
}
// Item check changed, update the Employee IsChecked property
private void CheckedListBox_ItemCheck(object sender, ItemCheckEventArgs e)
{
CheckedListBox clb = sender as CheckedListBox;
if (clb != null)
{
Employee checked_employee = clb.Items[e.Index] as Employee;
if (checked_employee != null)
{
checked_employee.IsChecked = (e.NewValue == CheckState.Checked);
}
}
}
// Just a simple test that removes an item from the list, rebinds it
// and updates the selected values
private void btnChangeList_Click(object sender, EventArgs e)
{
_employees.RemoveAt(1);
checkedListBox1.DataSource = _employees;
for (var i = 0; i < checkedListBox1.Items.Count; i++)
{
Employee employee_to_check = checkedListBox1.Items[i] as Employee;
if (employee_to_check != null)
{
checkedListBox1.SetItemChecked(i, employee_to_check.IsChecked);
}
}
}
}

Categories