Cannot display item in combobox from ObservableCollection - c#

I've this combobox:
<ComboBox x:Name="notification_mode" ItemsSource="{Binding NotificationMode}"
DisplayMemberPath="Text"/>
in my model I've created a class that add also the value to comboboxitem:
public class ComboboxItem
{
public string Text { get; set; }
public object Value { get; set; }
public override string ToString()
{
return Text;
}
}
so in my viewmodel I've created an observableCollection that store all the items:
private ObservableCollection<Models.ComboboxItem> _notificationMode = new ObservableCollection<Models.ComboboxItem>();
public ObservableCollection<Models.ComboboxItem> NotificationMode
{
get
{
return _notificationMode;
}
set
{
Models.ComboboxItem item = new Models.ComboboxItem();
item.Text = "Con sonoro";
item.Value = 0;
_notificationMode.Add(item);
}
}
The problem's that in the combobox item isn't displayed nothing. Why happen this?

This is the standard Property declaration
public ObservableCollection<Models.ComboboxItem> NotificationMode
{
get
{
return _notificationMode;
}
set
{
_notificationMode = value;
OnPropertyChanged("NotificationMode");
}
}
You can initialize the above defined property in the ViewModel constructor
public YourViewModel()
{
Models.ComboboxItem item = new Models.ComboboxItem();
item.Text = "Con sonoro";
item.Value = 0;
_notificationMode.Add(item);
}

Related

How to remove items from listbox

i tried to remove item from listbox using MultiExtended as selection mode
this is my code
im using this snippet code for getid from listbox
private int getid(int index)
{
int.TryParse(lb_ItemList.Items[lb_ItemList.SelectedIndices[index]].ToString().Split('-')[0], out index);
return index;
}
and this code im using for remove index from listbox
for (int i = lb_ItemList.Items.Count - 1; i > -1; i--)
{
lb_ItemList.Items.RemoveAt(lb_ItemList.SelectedIndices[getid(i)]);
}
but for any reason it doesn't work... any suggestion? thanks
I assume you need to copy the content of lb_ItemList.SelectedIndices before you start remove items out of lb_ItemList because every call to Remove(...) will update the content of lb_ItemList.SelectedIndices
You only need remove by index and SelectedIndices has the index:
for (int i = lb_ItemList.SelectedIndices.Count - 1; i > -1; i--)
{
var index = lb_ItemList.SelectedIndices[i];
lb_ItemList.Items.RemoveAt(index);
}
You don't need your Id to remove selected items.
If you need work with you class in the Items, I recomended you create an Item class:
public class YourItem
{
public YourItem()
{
}
public YourItem(int id, string name)
{
this.Id = id;
this.Name = name;
}
public int Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
return $"{this.Id} - {this.Name}";
}
}
Then, you add your items to the ListBox:
this.lb_ItemList.Items.Add(new YourItem(1, "A"));
this.lb_ItemList.Items.Add(new YourItem(2, "B"));
this.lb_ItemList.Items.Add(new YourItem(3, "C"));
this.lb_ItemList.Items.Add(new YourItem(4, "D"));
The text of each item is that you return in ToString method of YourItem. For example "1 - A" for the first item.
And, when you are working with the ListBox, simply cast to your class:
var item = (YourItem)this.lb_ItemList.Items[1];
var id = item.Id;
var name = item.Name;
If you class is big, you can use your Item as a wrapper:
public class YourClass
{
public int Id { get; set; }
public string Name { get; set; }
// Other properties, methods...
}
public class YourItem
{
private YourClass _item;
public YourItem(YourClass obj)
{
this._item = obj;
}
public int Id
{
get { return this._item.Id}
set { this._item.Id = value; }
}
public string Name
{
get { return this._item.Name}
set { this._item.Name = value; }
}
public override string ToString()
{
return $"{this.Id} - {this.Name}";
}
}
Your class maybe have lost of information but for your item, you only expose Id and Name, for example.

Select item from combo box WPF from view model in C# WPF

I have the following view model:
public sealed class FileViewModel : AbstractPropNotifier
{
private string _path;
private CategoryViewModel _category;
public string Path
{
get
{
return _path;
}
set
{
_path = value;
OnPropertyChanged(nameof(Path));
OnPropertyChanged(nameof(Title));
}
}
public string Title => System.IO.Path.GetFileNameWithoutExtension(Path);
public CategoryViewModel Category
{
get
{
return _category;
}
set
{
_category = value;
OnPropertyChanged(nameof(Category));
}
}
}
and Category view model:
public sealed class CategoryViewModel : IEquatable<CategoryViewModel>
{
public string Title { get; set; }
public EMyEnum Value { get; set; }
public bool Equals(CategoryViewModel other)
{
return Title.Equals(other.Title) && Value == other.Value;
}
public static CategoryViewModel From(EMyEnum eCat)
{
return new CategoryViewModel
{
Title = eCat.DescriptionAttr(),
Value = eCat
};
}
}
I set data context to my view model like:
public sealed class MainViewModel
{
public MainViewModel()
{
Files = new ObservableCollection<FileViewModel>();
Categories = GetCategories();
}
public ObservableCollection<FileViewModel> Files { get; set; }
public CategoryViewModel[] Categories { get; set; }
private CategoryViewModel[] GetCategories()
{
var enums = Enum.GetValues(typeof(EMyEnum));
var list = new List<CategoryViewModel>();
foreach (var en in enums)
{
EMyEnum cat = (EMyEnum)en;
list.Add(CategoryViewModel.From(cat));
}
return list.ToArray();
}
}
and
_model = new MainViewModel();
DataContext = _model;
and XAML:
<Window.Resources>
<CollectionViewSource x:Key="Categories" Source="{Binding Categories}"/>
</Window.Resources>
and in DataGrid element
<DataGridComboBoxColumn SelectedItemBinding="{Binding Category}" ItemsSource="{Binding Source={StaticResource Categories}}" Header="Category" Width="2*" DisplayMemberPath="Title"/>
The dropdown is populated correctly but cannot select automatically from dropdown a specific Category, means the Category column from Datagrid is empty.
I expected to select automatically from dropdown with correspondent Category...
Where is my mistake ? I tried with SelectedItemBinding and SelectedValueBinding but same issue. Nothing selected from dropdown.
To be clear:
For a file, I set a category but nothing is selected:
But dropdown has items:
There are probably different instances of CategoryViewModels in your MainViewModel compared to the ones in the FileViewModels.
You should either override Equals and GetHashCode in your CategoryViewModel class or make sure that you set the Category property of each FileViewModel to a CategoryViewModel that's actually present in the CategoryViewModel[] array of the MainViewModel.

Picker itemlist and index update

I'm working on my fist app with Xamarin Forms and I'm struggling with a piece of code for a while now without making it work. Would be thankful if someone could give me a helping hand.
I have two pickers, picker1 and picker2, which have their Items and SelectedIndex properties logically connected to each other. A change in picker2 SelectedIndex causes an update of the Items and the SelectedIndex properties of the picker1 view. I have created a custom picker class which holds a bindable property for the items source to make the view pickers Items properties update accordingly to the viewmodel.
class BindablePicker : Picker
{
public static BindableProperty ItemsSourceProperty =
BindableProperty.Create<BindablePicker, IEnumerable>(o => o.ItemsSource, default(IEnumerable), propertyChanged: OnItemsSourceChanged);
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
private static void OnItemsSourceChanged(BindableObject bindable, IEnumerable oldvalue, IEnumerable newvalue)
{
var picker = bindable as BindablePicker;
picker.Items.Clear();
if (newvalue != null)
{
foreach (var item in newvalue)
{
picker.Items.Add(item.ToString());
}
}
}
}
The creation and binding of the view objects in the content page:
BindablePicker Level1Picker = new BindablePicker { Title = "Select" };
Level1Layout.Children.Add(Level1Picker);
Level1Picker.SetBinding(BindablePicker.ItemsSourceProperty, "Level1Items");
Level1Picker.SetBinding(BindablePicker.SelectedIndexProperty, "Level1Index");
BindablePicker Level2Picker = new BindablePicker { Title = "Select" };
Level2Layout.Children.Add(Level2Picker);
Level2Picker.SetBinding(BindablePicker.ItemsSourceProperty, "Level2Items");
Level2Picker.SetBinding(BindablePicker.SelectedIndexProperty, "Level2Index");
and finally the view model:
class EducationLevelViewModel1 : BaseViewModel
{
public EducationLevelViewModel1(Criterion educationLevel)
{
this.EducationLevel = educationLevel;
}
Criterion EducationLevel { get; set; }
string level1Choice;
string Level1Choice
{
get { return level1Choice ?? (EducationLevel._Filters[0]._RelevanceType.ToString()); }
set { level1Choice = value; }
}
List<string> level1Items;
public List<string> Level1Items
{
get { return level1Items ?? (level1Items = GetLevel1List()); }
set
{
level1Items = value;
OnPropertyChanged();
}
}
int level1Index = 0;
public int Level1Index
{
get { return level1Index; }
set
{
level1Index = value;
OnPropertyChanged();
}
}
void UpdateLevel1List()
{
Level1Choice = Level1Items[Level1Index];
Level1Items = GetLevel1List();
Level1Index =Level1Items.FindIndex(x => x == Level1Choice);
}
List<string> GetLevel1List()
{
if (Level2Items[(int)Level2Index] == Criterion.Filter.RelevanceType.Inadequacy.ToString())
{
return InadequacyItems;
}
else {
return AllPickerItems;
}
}
string level2Choice;
public string Level2Choice
{
get { return level2Choice ?? (EducationLevel._Filters[1]._RelevanceType.ToString()); }
set { level2Choice = value; }
}
List<string> level2Items;
public List<string> Level2Items
{
get { return level2Items ?? (level2Items = GetLevel2List()); }
set
{
level2Items = value;
OnPropertyChanged();
}
}
int level2Index = 0;
public int Level2Index
{
get { return level2Index; }
set
{
level2Index = value;
UpdateLevel1List();
OnPropertyChanged();
}
}
}
}
As you see, my viewmodel implements the BaseViewModel class which in turn implements the INotifyPropertyChanged. The logic in the vm is that a certain selectedindex in picker2 is triggering an update of the picker1 itemlist and selectedIndex. I'm doing this in the UpdateLevel1List(). Note the saving of the string selection so I can set the same selection of picker1 in the new list, otherwise I set it to index 0.
void UpdateLevel1List()
{
Level1Choice = Level1Items[Level1Index];
Level1Items = GetLevel1List();
Level1Index = Level1Items.FindIndex(x => x == Level1Choice) == -1 ? 0 : Level1Items.FindIndex(x => x == Level1Choice);
}
The problem:
So the actual update of the picker1 itemlist updated in the view accordingly the vm logic. But the new index is NOT, it is set to the default(-1). The app later crashes when i change the picker2 back to it's default selection.
I hope I made my self clear on what I'm trying to achieve here.

Dynamic combobox list databinding in C# WinForms

Have read a lot this resource and really like it, but now i met problem which i can't neither resolve by myself nor find similar solution.
I'm using C# winforms and linqtosql.
In my userforms I use additional view-class to bind list for comboboxes to let users be able to get and use a name-list of objects while being forbidden to get a whole object itself. (This is not question whether it is a good practice, no matter.)
For example(this is not real code, just for look):
ORM classes:
public class Contract
{
public string ID { get; set; }
public string Name { get; set; }
public Contractor Contractor { get; set; }
public string ContractorID { get; set; }
}
public class Contractor
{
public string ID { get; set; }
public string Name { get; set; }
public string Phone { get; set; }
}
This is additional view-class which is mapping for sqlserver view Contractor_List (SELECT c.ID, c.Name FROM Contractors c)
public class Contractor_List
{
public string ID { get; set; }
public string Name { get; set; }
}
UserForm:
public class ContractForm : Form
{
void Init()
{
TextBox nameBox = new TextBox();
ComboBox contractorBox = new ComboBox();
BindingSource contractSource = new BindingSource();
contractSource.DataSource = typeof (Contract);
nameBox.DataBindings.Add("Text", contractSource, "Name", false, DataSourceUpdateMode.OnValidation);
contractorBox.DataBindings.Add("SelectedValue", contractSource, "ContractorID", false, DataSourceUpdateMode.OnValidation);
BindingSource contractorListSource = new BindingSource();
contractorListSource.DataSource = typeof (Contractor_List);
contractorBox.DisplayMember = "Name";
contractorBox.ValueMember = "ID";
}
}
OK.
My idea is to load contractorBox.DataSource (it’s binding source) when contractorBox.SelectedValue is set.
I found that SelectedValue is not overridable, so I decided to inherit combobox and to create in it a new property called “ID” and do following stuff instead
In form:
contractorBox.DataBindings.Add("ID", contractSource, "ContractorID");
In Control (this is real code):
object _id;
bool _listInitialized;
public object ID
{
get
{
return _id;
}
set
{
if (!_listInitialized)
{
var bindingSource = DataSource as BindingSource;
if (bindingSource != null)
{
var t = (bindingSource.DataSource as Type);
var rst = … //Getting List
if (rst!=null)
{
bindingSource.DataSource = rst;
_listInitialized = true;
SelectedValueChanged += delegate {
if (SelectedValue != ID)
{
ID = SelectedValue;
}
};
}
}
}
else
{
_id = value;
if (SelectedValue != ID)
{
SelectedValue = value;
}
}
}
}
So, this code works fine. I can load form, Contract object and list of contractors and get right contractor name in combobox.
But. I have problem with backing Binding of “ID” property. When contractor in combobox is changed Contract object doesn’t update (neither ContractorID, no Contractor Itself) while ID, SelectedValue and SelectedItem of combobox change properly.
Why? What have I do to make this working.
Hah. So Simple Solution.
public new object SelectedValue
{
get
{
return base.SelectedValue;
}
set
{
if (!DesignMode)
{
if (!_listInitialized)
{
var bindingSource = DataSource as BindingSource;
if (bindingSource != null)
{
var t = (bindingSource.DataSource as Type);
var rst = ...///how you get your type list
if (rst != null)
{
bindingSource.DataSource = rst;
_listInitialized = true;
}
}
}
else
{
base.SelectedValue = value;
}
}
}
}
May be will be helpful for someone.

Change data with buttonclick - MVVM

I have a ListView with an List<List<enum>> property and i have a View that shows each bool as button.
I want to cycle through the bound enum when someone clicks on the button. The problem is I cant use a normal click because it would be outside of my ViewModel.
Edit:
I have the class TruthTable that has 2 DynTable:
public sealed class Column<T>
{
public Column()
{
ColumnData = new List<T>();
ColumnHeader = "";
}
...
public List<T> ColumnData { get; set; }
public string ColumnHeader { get; set; }
}
public sealed class DynTable<T>
{
public DynTable()
{
Columns = new List<Column<T>>();
}
...
public List<Column<T>> Columns { get; set; }
}
public sealed class TruthTable
{
public TruthTable()
{
input = new DynTable<bool>();
results = new DynTable<BoolState>();
}
...
private DynTable<bool> input;
private DynTable<BoolState> results;
public DynTable<bool> Input { get { return input; } set { input = value; } }
public DynTable<BoolState> Results { get { return results; }}
}
public enum BoolState
{
False = 0,
True = 1,
DontCare = 2
}
And i have a ViewModel for the TruthTable. I dont think that the I have to show the code for the ViewModel because its just a TruthTable property. I hope thats enough code to understand my problem ._.

Categories