C# Winforms - bind textbox to array element from class - c#

I'm currently trying to bind an array element from a class to a text box without success.
class Test{
...
string[] toto = new string[]{"element1"};
}
Test test;
void form_load()
{
test = new Test();
textBox1.DataBinding.Add("Text", test, "toto(0)");
}
(I tried as discussed here : Winforms Databinding to element in array)
But I get :
System.ArgumentException: 'Cannot bind to the property or column
Requires(0) on the DataSource. Parameter name: dataMember'
If I bind it like this:
checkBox2.DataBindings.Add(new Binding("Checked", config.Requires[0], ""));
It works but I can't implement INotifyPropertyChanged for updating the form on change perform by the code.
Does anyone have any idea?
Edit: After binding, the form should be updated when the element of the array is updated.

Quite possibly there is a better way to do this, but what you could do is create an instance of BindingSource for each element in the array, set the BindingSource.Position property, then set that as the binding for the TextBox.
Edit: Made the Data Binding 2-way... changing the value in the control updates the object, changing the value from the object changes the control.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Test
{
public class Foo
{
public Foo()
{
Items = new BindingList<string>();
}
public IList<string> Items { get; private set; }
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
_dataSource.Items.Add("Value");
_dataSource.Items.Add("Value 2");
_dataSource.Items.Add("Value 3");
var frm = new Form();
var flp = new FlowLayoutPanel
{
Dock = DockStyle.Fill,
FlowDirection = FlowDirection.TopDown
};
for (int i = 0; i < _dataSource.Items.Count; i++)
{
var bs = new BindingSource(_dataSource, "Items");
bs.Position = i;
var tb = new TextBox();
tb.DataBindings.Add("Text", bs, "");
flp.Controls.Add(tb);
}
frm.Controls.Add(flp);
var btn = new Button()
{
Text = "Show Object's Values",
Dock = DockStyle.Bottom
};
btn.Click += btn_Click;
frm.Controls.Add(btn);
var btn2 = new Button()
{
Text = "Change Object's Values",
Dock = DockStyle.Bottom
};
btn2.Click += btn2_Click;
frm.Controls.Add(btn2);
Application.Run(frm);
}
static void btn_Click(object sender, EventArgs e)
{
MessageBox.Show(string.Join(Environment.NewLine, _dataSource.Items.ToArray()));
}
static void btn2_Click(object sender, EventArgs e)
{
var rng = new Random();
for (int i = 0; i < _dataSource.Items.Count; i++)
{
var b = new byte[8];
rng.NextBytes(b);
_dataSource.Items[i] = Convert.ToBase64String(b);
}
}
static Foo _dataSource = new Foo();
}
}

You could create a property as follows:
private string _element1;
public string Element1
{
get
{
return _element1;
}
set
{
element1 = value;
OnPropertyChanged(nameof(Element1));
}
}
Set it as: Element1 = config.Requires[0];
And then use it to set the TextBox as follows: checkBox2.DataBindings.Add(new Binding("Checked", Element1, ""));

Related

How to keep variable through an event?

I have a method to populate a combobox with some strings. At the end of the method I assign to the SelectedIndexChanged event. Here's how that method looks
public ComboBox PopulateComboBox()
{
Worksheet sheetWithTemplateNames = _iReader.GetWorksheetByName("Templates");
int lastRowOfTemplates = _iReader.GetLastRow(sheetWithTemplateNames);
var templateNames = _iHandler.GetTemplateNames(sheetWithTemplateNames, lastRowOfTemplates);
foreach (var template in templateNames)
{
Box.Items.Add(template);
}
Box.SelectedIndexChanged += Box_SelectedIndexChanged;
return Box;
}
and it works as I want to. My problem is that I need to use this templateNames list in the actual event and that's causing trouble. Here's how my event looks like now but ain't functioning.
private void Box_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox cmb = (ComboBox)sender;
var chosenObject = cmb.SelectedIndex;
MessageBox.Show(templateNames[chosenObject]);
}
but my list is now empty. It's instantiated in the constructor so I'd assume it'd keep it's state but that isn't the situation. Here's the top of the class
public class TemplateListCombobox
{
public ComboBox Box { get; set; }
private IDataReader _iReader;
private IDataHandler _iHandler;
private List<string> templateNames;
public TemplateListCombobox()
{
Box = new ComboBox();
_iReader = new DataReader();
_iHandler = new DataHandler();
templateNames = new List<string>();
}
}
so how could I possibly keep the state of my list through the event?
UPDATE:
MY class that calls this:
public static class GroupBoxHolder
{
private static GroupBox _thisGroupBox;
public static GroupBox GetGroupBox()
{
PopulateGroupBox();
return _thisGroupBox;
}
public static void PopulateGroupBox()
{
_thisGroupBox = new GroupBox();
TemplateListCombobox combo = new TemplateListCombobox();
ComboBox box = combo.GetComboBox();
_thisGroupBox.Controls.Add(box);
ConfigureGroupBox();
}
public static void ConfigureGroupBox()
{
_thisGroupBox.Location = new Point { X = 75, Y = 15 };
_thisGroupBox.Height = 150;
_thisGroupBox.Width = 400;
}
}
and my updated class
public class TemplateListCombobox
{
private ComboBox _box;
private readonly IDataReader _iReader;
private readonly IDataHandler _iHandler;
private readonly Worksheet _sheetWithTemplateNames;
public TemplateListCombobox()
{
_box = new ComboBox();
_iReader = new DataReader();
_iHandler = new DataHandler();
_sheetWithTemplateNames = _iReader.GetWorksheetByName("Templates");
PopulateComboBox();
}
public void PopulateComboBox()
{
int lastRowOfTemplates = _iReader.GetLastRow(_sheetWithTemplateNames);
var templateNames = _iHandler.GetTemplateNames(_sheetWithTemplateNames, lastRowOfTemplates);
foreach (var template in templateNames)
{
_box.Items.Add(template);
}
_box.SelectedIndexChanged += Box_SelectedIndexChanged;
}
public ComboBox GetComboBox()
{
return _box;
}
private void Box_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox cmb = (ComboBox)sender;
var chosenObject = cmb.SelectedItem.ToString();
var firstRowForTemplate = _iReader.GetFirstRowForTemplate(_sheetWithTemplateNames, chosenObject.ToString());
var attributes = _iReader.GetTemplateAttributes(_sheetWithTemplateNames, chosenObject, firstRowForTemplate);
}
}
A. Two lists?
var templateNames = creates a new local variable.
Do you want to set a member field instead? If so, remove var.
B. Read from comobox
Since the combo box contains the names read directly from it.
The flow of the code is something like the following:
var templateNames = _iHandler.GetTemplateNames(sheetWithTemplateNames, lastRowOfTemplates);
foreach (var template in templateNames)
{
Box.Items.Add(template);
}
... time passes
var chosenObject = cmb.SelectedIndex;
MessageBox.Show(templateNames[chosenObject]);
The combobox contains all the information you need. (You could use SelectedItem).
Note on two sources.
Since you're not clearing the combobox's items in the populate method, if it was called twice the combobox would gain new elements. That's not great but more importantly templateNames[chosenObject] would not work anymore because the combobox and the list would be out of sync.
In addition to the var templateNames mistake that doesn't cause the problem, you don't call PopulateComboBox in the code you provide, so the list is empty...
I don't understand why this method returns the Box since there is no parameter and it is a member field that you access directly in the code.
You only need to assign the event in the constructor, not each time you call the populate method that you need to call somewhere.
You should improve your class design because there is several clumsiness. For example, what is TemplateListCombobox without parent and how do you intend to use it? How are initialized _iReader and _iHandler? Do you need to keep templateNames? And so on...

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))));

How can I change label text in different class (C#)

Please, you can you help me, how can i change label text in diferent class?
Basic winform script:
public partial class buildEditor : Form
{
public buildEditor()
{
InitializeComponent();
Label maxSkillPoint = new Label();
maxSkillPoint.AutoSize = true;
maxSkillPoint.BackColor = System.Drawing.Color.Transparent;
maxSkillPoint.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
maxSkillPoint.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(193)))), ((int)(((byte)(196)))), ((int)(((byte)(181)))));
maxSkillPoint.Location = new System.Drawing.Point(528, 687);
maxSkillPoint.Name = "maxSkillPoint";
maxSkillPoint.Text = UniqueValue.spentSkillPoints.ToString();
maxSkillPoint.Size = new System.Drawing.Size(0, 20);
this.Controls.Add(maxSkillPoint);
}
public void maxSkillPoint_TextChanged(Form formInstance, string labelName)
{
// Get reference to the label
var label = formInstance.Controls.Find(labelName, true).FirstOrDefault();
if (null != label && label is Label)
{
(label as Label).Text = "test";
}
}
}
I created next class which will be change text for maxSkill text.
public class ChangeTextForMaxSkill()
{
Button button = new Button();
public ChangeTextForMaxSkill()
{
button.Click += new EventHandler(changeText);
}
private void changeText(object sender, EventArgs e)
{
// Get reference to the label
var buildEditor = new buildEditor();
buildEditor.maxSkillPoint_TextChanged(buildEditor, "maxSkillPoint");
}
}
I really thx for all answers.
I got it very simple:
Hand over the Label control in the constructor of your external class:
using System.Windows.Forms;
public class Yourclass{
private Label UpdateLabel;
public Yourclass (Label yourLabel)
{
this.UpdateLabel = yourlabel;
}
private void action()
{
//here is your update of the label
UpdateLabel.Text = "Your text";
}
}
In the form class, create an instance of "yourclass" and hand over the Label:
Yourclass cls = new Yourclass(Label1);
First of all your naming conventions do not follow standard practices. Both class and method names should use uppercase first letters of words, not camel case as you have done. I have used proper naming conventions in my answer.
You have to pass an instance of your BuildEditor* form to your ChangeTextForMaxSkill.ChangeText() function.
Next, the label object maxSkill is not a property of your BuildEditor class. Therefore, you'd need to actually find a reference to that control within the form since you're dynamically adding it.
public partial class BuildEditor : Form
{
public BuildEditor()
{
InitializeComponent();
Label maxSkill = new Label();
maxSkill.Name = "MaxSkil"; // need the ID to find it later (makes it easier)
maxSkill.Location = new Point(1, 1);
this.Controls.Add(maxSkill);
}
// This is just for testing; assumes you dragged a button from toolbox onto your
// BuildEditor form in the Form Designer
private void button1_Click(object sender, EventArgs e)
{
var changeTextForMaxSkill = new ChangeTextForMaxSkill();
changeTextForMaxSkill.ChangeText(this, "MaxSkil");
}
}
public class ChangeTextForMaxSkill
{
public void ChangeText(Form formInstance, string labelName)
{
// Get reference to the label
var label = formInstance.Controls.Find(labelName, true).FirstOrDefault();
if (null != label && label is Label)
{
(label as Label) .Text = "test";
}
}
}
If you want to test it, just add a button on your form and make the test in the button click handler:
private void button1_Click(object sender, EventArgs e)
{
var changeTextForMaxSkill = new ChangeTextForMaxSkill();
changeTextForMaxSkill.ChangeText(this, "MaxSkil");
}
I've tested and this works :)

Duplicate clicks on xx_Tap() happening in separate class

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.

Filtering a ListBox

I have a ListBox named lsbEntities. I want to filter it's items based on some selected radio button.
The code below is kind of pseudo, is their a better approach?
private List<string> _listBoxItemsToFilter;
private Thread tFilterEntityList;
enum EntityType
{
Vehicle,
Facility
}
private void FilterEntityList(EntityType entityType)
{
_listBoxItemsToFilter = new List<string>();
Dictionary<string,string> entitiesAndClassTypes;
List<string> listBoxItems = new List<string>();
for(int i = 0; i < lsbEntities.Count; i++)
{
//object listItem = lsbEntities.Items[i];
listBoxItems.Add(lsbEntities[i].ToString());
}
// get associated types
entityClassTypes = _controlFacade.GetClassTypes(listBoxItems);
foreach (KeyValuePair<string,string>
entityAndClass in entitiesAndClassTypes)
{
classType = entityAndClass.Value;
if(classType != entityType)
{
_listBoxItemsToFilter.Add(entityAndClass.Key);
}
}
RemoveFilterFromEntityListBox();
AddFilterToEntityListBox();
}
private void AddFilterToEntityListBox()
{
// DELEGATE NEEDED TO MODIFY LISTBOX FROM THREAD
foreach(string listBoxItem in _listBoxItemsToFilter)
{
if(lsbEntities.Contains(listBoxItem)
{
// REMOVE WITH DELEGATE
}
}
}
private void RemoveFilterFromEntityListBox()
{
// DELEGATE NEEDED TO MODIFY LISTBOX FROM THREAD
if(_listBoxItemsToFilter != null)
{
foreach(string listBoxItem in _listBoxItemsToFilter)
{
if(!lsbEntities.Contains(listBoxItem)
{
// REMOVE WITH DELEGATE
}
}
}
}
// EXAMPLE CALL WHEN CLICKING RADIO-BUTTON
private void rbVehicles_CheckedChanged(object sender, EventArgs e)
{
switch (rbVehicles.Checked)
{
case (true):
{
object entityType = (object)EntityType.Vehicle;
tFilterEntityList = new Thread(FilterEntityList(entityType));
tFilterEntityList.IsBackground = true;
tFilterEntityList.Start();
//FilterEntityList(EntityType.Vehicle);
break;
}
}
}
I have only included an example of selecting to filter everything but VehicleS. The same approach would be used for the Facility class, where the thread would be re-instantiated.
Here is a simple example showing one way to filter items in a ListBox. This could be improved by using a ListView or DataGridView in VirtualMode. It is very unclear to me what you are trying to do, so if this is not helpful I will remove it.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
public class Form1 : Form
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
List<Entity> items = new List<Entity>()
{
new Entity(EntityType.Vehicle, "Car"),
new Entity(EntityType.Vehicle, "Aeroplane"),
new Entity(EntityType.Vehicle, "Truck"),
new Entity(EntityType.Vehicle, "Bus"),
new Entity(EntityType.Facility, "Garage"),
new Entity(EntityType.Facility, "House"),
new Entity(EntityType.Facility, "Shack"),
};
ListBox listBox;
ComboBox comboBox;
public Form1()
{
Text = "Filtering Demo";
ClientSize = new Size(500, 320);
Controls.Add(listBox = new ListBox
{
Location = new Point(10, 10),
Size = new Size(200, 300),
});
Controls.Add(comboBox = new ComboBox
{
Location = new Point(230, 10),
DropDownStyle = ComboBoxStyle.DropDownList,
Items = { "All", EntityType.Vehicle, EntityType.Facility },
SelectedIndex = 0,
});
comboBox.SelectedIndexChanged += UpdateFilter;
UpdateFilter(comboBox, EventArgs.Empty);
}
void UpdateFilter(object sender, EventArgs e)
{
var filtered = items.Where((i) => comboBox.SelectedItem is string || (EntityType)comboBox.SelectedItem == i.EntityType);
listBox.DataSource = new BindingSource(filtered, "");
}
}
enum EntityType { Vehicle, Facility, }
class Entity : INotifyPropertyChanged
{
public string Name { get; private set; }
public EntityType EntityType { get; private set; }
public Entity(EntityType entityType, string name) { EntityType = entityType; Name = name; }
public override string ToString() { return Name ?? String.Empty; }
// Implementing INotifyPropertyChanged to eliminate (caught) BindingSource exceptions
public event PropertyChangedEventHandler PropertyChanged;
}

Categories