I am trying to bind several ListBoxs to a List. When a ListBox on one form is updated, I want it to update the other ListBox, too.
The problem I am running into is that it doesn't seem to update the view on the ListBox when I update the underlying List. If I look at the ListBox.Items in debug, I can see that all the items I add are there, but are not being displayed. Additionally, when I open another form that displays the List on a ListBox, it does correctly display whatever items had already been added.
private List<String> _list;
public Form1()
{
InitializeComponent();
_list = StaticInstanceOfList.GetInstance();
listbox1.DataSource = _list;
}
public void AddStringToList(string value)
{
if (!_list.Contains(value))
{
_list.Add(value);
}
}
Try to use a BindingList<T> to store your items and then assign this list to both listboxes via the DataSource property.
Use a bindingSource and bind both listBoxes to that.
Related
My UI has a ListBox which is bound to a Collection. Right now this happens to be an ObservableCollection
My objective is to add objects to this Collection via the UI, and have the ListBox dynamically update, all while maintaining a sorted Collection.
I am aware that there is some SortedView that I can use in WPF. But that is not what I want - I need the actual Collection to remain sorted because my business logic requires a sorted collection.
One way that I thought of, is to create my own Collection class which uses a SortedList internally, and implements the INotifyCollectionChanged interface and produces NotifyCollectionChangedEventArgs event when the internal list changes. Sounds like a lot of work!
Is there a simple solution that I've missed?
Depending on your exact needs, the simplest approach is to keep your ObservableCollection, but wrap in in a new property of type ICollectionView:
public class MyViewModel {
private CollectionViewSource _collectionViewSource;
public ICollectionView MyCollectionView => _collectionViewSource.View;
public MyViewModel(ObservableCollection<MyDataItem> dataItems) {
_collectionViewSource = new CollectionViewSource() { Items = dataItems };
//Add sorting here using _collectionViewSource.SortDescriptions.Add(...)
}
You can use the wrapper property to extract a sorted list as needed.
Okay so I ended up inheriting from ObservableCollection, and overriding the Add() method.
This did the trick for me. Now my list is always sorted, and the ObservableCollection is the one that Notifies the UI of changes.
public class MyCollection : ObservableCollection<Int32>
{
public new void Add(Int32 x)
{
base.Add(x);
var oldList = new ObservableCollection<Int32>(this.OrderBy(c=>c));
Clear();
foreach(var i in oldList)
{
base.Add(i);
}
}
}
I'm a beginner with C#, any feedback on the code is appreciated.
I have a class that contains a property that is an enum:
public RaTypes RaBucket1Type { get; set; }
My enum is:
public enum RaTypes
{
Red,
Yellow
}
I was able to bind a form's combobox data-source to the enum so that when I click on the drop-down, I see the enumerations:
cmbBucket1Type.DataSource = Enum.GetValues(typeof(RaTypes));
When I load the form, I would like to populate the combo-box with the existing value. I have tried the following:
cmbBucket1Type.DisplayMember = "TradeType";
cmbBucket1Type.ValueMember = "TradeEnumID";
cmbBucket1Type.SelectedValue = EditedAlgorithm.RaBucket1Type;
But this did not work.
Also, I'm not sure I have implemented the ValueChanged event handler correctly either:
EditedAlgorithm.RaBucket1Type = (RaTypes)((ComboBox)sender).SelectedItem;
Can someone help me understand:
How to set the combobox to current value, and
How to handle the event handler so I can set the property to whatever was selected?
Thanks
-Ed
UPDATES
I have tried
cmbBucket1Type.SelectedIndex = cmbBucket1Type.FindString(EditedAlgorithm.RaBucket1Type.ToString());
and
cmbBucket1Type.SelectedItem = EditedAlgorithm.RaBucket1Type;
Neither works.
I think you're using the terminology a little differently than normal, which makes it difficult to understand.
Normally, the terms Add, Populate, and Select are used to mean the following:
Add - Add an item to the existing set of items in the combo box.
Populate - Initialize the combo box with a set of items.
Select (Display) - Choose one among many items in the combo box as the selected item. Normally this item will be displayed in the combo box visible area.
Having cleared that up, I assume following is what you want to do.
Initially populate the ComboBox with a set of values. In your case, values of RaType Enum.
Create an instance of your class which contains the property mentioned. Since you didn't name that class I'll simply name it SomeClass.
Initialize the RaBucket1Type property of the said class instance with an enum value of your choice. I'll initialize it to Yellow.
Have the ComboBox select the said value at start up.
After Form_Load, at any given time, if the user changes the value of the ComboBox, have the change reflected in your class instance property.
For that, I would do something like this:
public partial class MainForm : Form
{
// Your class instance.
private SomeClass InstanceOfSomeClass = null;
public MainForm()
{
InitializeComponent();
// Initialize the RaBucket1Type property with Yellow.
InstanceOfSomeClass = new SomeClass(RaTypes.Yellow);
// Populating the ComboBox
comboBox1.DataSource = Enum.GetValues(typeof(RaTypes));
}
// At selected index changed event
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
// Get the selected value.
var selected = comboBox1.SelectedValue;
// Change the `RaBucket1Type` value of the class instance according to the user choice.
InstanceOfSomeClass.RaBucket1Type = (RaTypes)selected;
}
private void MainForm_Load(object sender, EventArgs e)
{
// At form load time, set the `SelectedItem` of the `ComboBox` to the value of `RaBucket1Type` of your class instance.
// Since we initialized it to `Yellow`, the `ComboBox` will show `Yellow` as the selected item at load time.
if (InstanceOfSomeClass != null)
{
comboBox1.SelectedItem = InstanceOfSomeClass.RaBucket1Type;
}
}
}
public enum RaTypes
{
Red,
Yellow
}
public class SomeClass
{
public RaTypes RaBucket1Type { get; set; }
public SomeClass(RaTypes raTypes) { RaBucket1Type = raTypes; }
}
Please do keep in mind this is a basic example to show you how to handle the situation and not a complete finished code. You'll need to do a bunch of error checks to make sure class instances and selected items are not null etc.
I FOUND MY ANSWER:
I had the SelectedIndexChanged event pointing to my event handler which means that when I "added" items to the ComboBox using:
comboBox1.DataSource = Enum.GetValues(typeof(RaTypes));
it was triggering the event handler, and resetting my class property. My event handler was this:
var selectedValue = cmbBucket1Type.SelectedValue;
So the simple solution was to:
Remove the hard-coded event handler from the Visual Studio GUI.
Add the following event handler in code AFTER I assign the DataSource
bucketType1.SelectedIndexChanged += BucketTypeChanged;
This worked.
THANK YOU ALL FOR HELPING!!
-Ed
You can set the selectedValue like this:
cmbBucket1Type.SelectedValue = EditedAlgorithm.RaBucket1Type;
And you can handle the selected value when the combo change like this:
private void cmbBucket1Type_SelectedValueChanged(object sender, EventArgs e)
{
var selectedValue = cmbBucket1Type.SelectedValue;
}
I have a string array which contains filenames. a number of filenames vary depending on what endusers select. I would like know how to populate the string array onto combobox. Thanks for your help in advance,
Your requirement is simple. Create an ObservableCollection<string> named Items and fill it with your filenames:
public ObservableCollection<string> Items
{
get { return items; }
set { items = value; NotifyPropertyChanged("Items"); } }
}
Make sure that you implement the INotifyPropertyChanged Interface correctly in the class that has the property. Next, simply data bind this property to the ComboBox.ItemsSource property in XAML:
<ComboBox ItemsSource="{Binding Items}" />
Finally, ensure that you have set the DataContext of the control with the XAML to an instance of the class with the property:
Either:
DataContext = this; // if properties are defined in code behind
Or:
DataContext = new ClassWithProperty();
Here a simple way to achieve this
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
string[] files = new string[]{};
ObservableCollection<string> observableCollection = new ObservableCollection<string>(files);
comboBox1.ItemsSource = observableCollection;
}
}
If you have your full array of filenames, you may want to try something like this:
for(int i = 0; i < myStringArray.Length; i++)
{
ComboBox1.Items.Add(myStringArray[i]);
}
This should add all of the filenames into the combobox ComboBox1.
I'm using Prism in WPF.
I was watching the Prism starter kit, and it has a ICollectionView. In that collection, I need to add the object selected in it. What object (or collection) should I use to add objects?
I mean in the image, I have two listbox, in the first one I've got a readonly collection and the second one is a list where can add or remove objects.
Your List should be bound to an ICollectionView that wraps an ObservableCollection. When you add, you add to this Observable collection.
I.e
private readonly ObservableCollection<Stock> listToAddTo;
public ICollectionView List2 { get; private set; }
Constructor
listToAddTo = new ObservableCollection<Stock>();
List2 = CollectionViewSource.GetDefaultView(listToAddTo);
Where List2 is what is bound to
I have a custom control that has an Items property. I Have applied an EditorAttribute with a UITypeEditor of type CollectionEditor.
Collection Type:
[Serializable]
[Editor(typeof(CollectionEditor), typeof(UITypeEditor))]
public class ListItemsCollection : CollectionBase
{
// methods
}
Property Declaration In The Control:
private new ListItemsCollection _Items;
[Editor(typeof(CollectionEditor), typeof(UITypeEditor))]
public new ListItemsCollection Items
{
get
{
return _Items;
}
set
{
_Items = value;
// do other UI changes
}
}
Problem:
When I drop this control to the designer surface, I am able to add items to the Items property using the PropertyGrid. But, the when I click the Ok button of the CollectionEditor the setter of the Items property is not getting called.
AFAIK when a value is returned from the EditValue method of a UITypeEditor class the setter block of the property is supposed to be called.
This is driving me insane. I even tried adding Event's to the ListItemsCollection, so that when Items are added, I can whatever I want with the control's ui.
This is not supposed to be hard. What am I doing wrong?
I try to reprodeuce your situation: using following code, I get a message box showing whenever I edit the list from VS property window. Beware that you have to create the list by yourself. If you don't create it, VS create a temp list which you can edit from property window, but does not set your property to this list (so your setter will never be called)
public UserControl1()
{
InitializeComponent();
list = new BindingList<ListViewItem>();
list.ListChanged += new ListChangedEventHandler(list_ListChanged);
}
void list_ListChanged(object sender, ListChangedEventArgs e)
{
MessageBox.Show(e.ListChangedType.ToString());
}
private BindingList<ListViewItem> list;
public BindingList<ListViewItem> List1
{
get { return list; }
}
Collection properties should be read-only. It's the collection that is retrieved through the getter, and adjusted. The setter never enters into it, because that would mean setting a new collection.