I have a combobox inside a list where the items of the combo box are dynamic. They will be determined by the help of the selected item.
For example: If selected item is Item1 then combobox should contain Item1, Item2, Item3 but if selected item is Item2 then combo box should contain Item2, Item3, Item4
How to achieve the same by using binding..
Right now i am setting up two properties in my collection called SelectedValue and ListValues and binding them with my combobox but it only select first item of the list and leaving the rest one as it is.
Also, what is the order of execution of data binding as i want first Itemsource to call then selectedvalue should be set so that items will be selected.
Really appreciate for any help.
Here is my effort which works out but i am not sure if it's correct or not.
C#
public string SelectedValue
{
get
{
PropertyChanged.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs("Values"));
return _value;
}
set
{
if (value != null) //It will be null when binding of values happens
{
_value = value;
PropertyChanged.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs("Values"));
PropertyChanged.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs("SelectedValue"));
}
}
}
public IList<SomeType> Values
{
get
{
string status =_status;
return SomeFunctionToReturnValues(status);
}
}
XAML
<ComboBox SelectedValue="{Binding SelectedValue}" SelectedValuePath="Id" DisplayMemberPath="Text" Width="120" ItemsSource="{Binding Values,Mode=OneWay}"></ComboBox>
Please comment and Let me know if anyone can provide me better suggestion here.
You shold use ItemsSource property
<ComboBox SelectedItem="{Binding MyNum}" ItemsSource="{Binding Numbers}" Width="100" Height="30"/>
That bound to:
// Fills up combo box
public IEnumerable<int> Numbers
{
get
{
IEnumerable<int> temp = MyCollection.ToList();
return temp.SubArray(MyNum,MyCollection.count);
}
}
private int _myNum
public int MyNum
{
get
{
return _myNum;
}
set
{
_myNum = value;
OnPropertyChanged("MyNum");
}
}
When the SubArray is (Credit)
public static T[] SubArray<T>(this T[] data, int index, int length)
{
T[] result = new T[length];
Array.Copy(data, index, result, 0, length);
return result;
}
Related
Hi I am making an WPF application and have a problem with a listbox/listview, MVVM is implemented. I am creating a list of a class that is displayed on the listbox and I am editing the items through selecting an item in the listbox. The problem is when I am deleting an item it doesn't trigger onpropertychanged event to the UI, but is however working in the code, the values are right. When I close the window and reopens it then the list is updated, but not directly when the item is deleted, it never triggers onpropertychanged event for some reason.
It does work to just filter the quicknotelist like
quicknotelist = quicknotelist.where(x => x.id != selecteditem.id);
It works only once though and the UI updates however the selecteditem doesn't seem to work properly even though I am declaring
selecteditem = new quicknote() {*values*};
Part of relevant code, I am using INotifyPropertyChanged
private QuickNote selectedNote = new QuickNote(); // weeeeeee
public QuickNote SelectedNote
{
get
{
return selectedNote;
}
set
{
if (SelectedNote != null)
{
selectedNote = value;
OnPropertyChanged("SelectedNote");
EnableEditNoteBox = true;
}
}
}
private List<QuickNote> quickNoteList = new List<QuickNote>();
public List<QuickNote> QuickNoteList
{
get { return quickNoteList; }
set { quickNoteList = value; OnPropertyChanged("QuickNoteList"); }
}
here is the method that deletes the item
private void DeleteNote(object obj)
{
if (SelectedNote != null)
{
QuickNoteList.Remove(SelectedNote);
// I want this to trigger onpropertychanged without using myclasslist = newclasslist; since it messes up selecteditem to null.
}
}
heres the xaml part.
<ListBox
Width="713"
Height="230"
SelectedItem="{Binding SelectedNote, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
ItemsSource="{Binding QuickNoteList,BindsDirectlyToSource=True, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
DisplayMemberPath="Notes"
Foreground="Black"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.CanContentScroll="False"/>
I'd leave a comment if I could. You should lookup ObservableCollection. I think QuickNoteList should be of this type.
I have a ComboBox binded with an ObservableCollection. How can I do when user enter a text in the ComboBox, if item not in the list, the code automatically add a new item to the list?
<ComboBox Name="cbTypePLC"
Height="22"
ItemsSource="{StaticResource TypePLCList}"
SelectedItem="{Binding TypePLC}" IsReadOnly="False" IsEditable="True">
</ComboBox>
Bind Text property of your combo box to your view model item and then add to the bound collection there, like,
Text="{Binding UserEnteredItem, UpdateSourceTrigger=LostFocus}"
Change the UpdateSourceTrigger to LostFocus because default (PropertyChanged) will communicate each character change to your viewmodel.
// user entered value
private string mUserEnteredItem;
public string UserEnteredItem {
get {
return mUserEnteredItem;
}
set {
if (mUserEnteredItem != value) {
mUserEnteredItem = value;
TypePLCList.Add (mUserEnteredItem);
// maybe you want to set the selected item to user entered value
TypePLC = mUserEnteredItem;
}
}
}
// your selected item
private string mTypePLC;
public string TypePLC {
get {
return mTypePLC;
}
set {
if (mTypePLC != value) {
mTypePLC = value;
// notify change of TypePLC INPC
}
}
}
// your itemsource
public ObservableCollection <string> TypePLCList { set; private set;}
How can it be that SelectedItem is null and SelectedItems have an item selected?
Here's the screenshot from selection changed event:
My DataGrid:
<DataGrid SelectionChanged="CustomCmdDg_SelectionChanged" SelectedItem="{Binding CurrentX,Mode=TwoWay}" DataContext="{Binding MyViewModel}" x:Name="CustomCmdDg" ItemsSource="{Binding xList}" AutoGenerateColumns="False" GridLinesVisibility="Horizontal">
...
In my ViewModel:
xList= a list of class x (observable collection)
private x currentX;
public x CurrentX
{
get { return currentX; }
set
{
currentX = null;
NotifyPropertyChanged("CurrentX");
}
}
Purposely wanted that selected item will be null
If you set your currentitem to null you should first remove it from the collection, then it will be gone from the selected items:
Public ObservableCollection<x> xList
public x CurrentX
{
get { return currentX; }
set
{
xList.Remove(currentX)
currentX = null;
NotifyPropertyChanged("CurrentX");
}
}
Your observable list will update itself
If you need to be able to manipulate the SelectedItems collection you will have to provide a binding as well and peform the code required
Issue Summary
When using 2 cascading comboboxes, the child combobox does not select the current item, instead an empty item (I don't know where it comes from!) gets selected.
Issue Details
I have two comboboxes declared in xaml as given below. The two entities in play are StandardRack and RelayConfig
XAML:
<ComboBox ItemsSource="{Binding StandardRacks}" DisplayMemberPath="Name"
SelectedItem="{Binding StandardRack, Mode=TwoWay}" SelectedValuePath="Id"
<ComboBox ItemsSource="{Binding RelayConfigs}" DisplayMemberPath="DisplayName"
SelectedValue="{Binding DefaultRelayConfig, Mode=TwoWay}" SelectedValuePath="Id"
Here are the backing properties, and code to load comboboxes in ViewModel
ViewModel
private ObservableCollection<StandardRack> _standardRacks;
public ObservableCollection<StandardRack> StandardRacks {
get { return _standardRacks; }
set { _standardRacks = value; RaisePropertyChanged(() => StandardRacks); }
}
private StandardRack _standardRack;
public StandardRack StandardRack {
get { return _standardRack; }
set {
if (_standardRack != value) {
_standardRack = value;
LoadRelayConfigs();
RaisePropertyChanged(() => StandardRack);
}
}
}
private ObservableCollection<RelayConfig> _relayConfigs;
public ObservableCollection<RelayConfig> RelayConfigs {
get { return _relayConfigs; }
set { _relayConfigs = value; RaisePropertyChanged(() => RelayConfigs); }
}
private RelayConfig _defaultRelayConfig;
public RelayConfig DefaultRelayConfig {
get { return _defaultRelayConfig; }
set { _defaultRelayConfig = value; RaisePropertyChanged(() => DefaultRelayConfig); }
}
private void LoadRack() {
StandardRacks = new ObservableCollection<StandardRack>(
unitOfWork.StandardRackRepository.GetQueryable().Include(sr => sr.StandardRelay).ToList());
if (StandardRacks.Count > 0) {
StandardRack = Rack.StandardRack; //Set the current value of StandardRacks combobox
}
}
//Loads RelayConfigs Combobox based on Current Value of StandardRacks Combobox
private void LoadRelayConfigs() {
RelayConfigs = new ObservableCollection<RelayConfig>(
unitOfWork.RelayConfigRepository.GetQueryable()
.Where(rc => rc.StandardRelays.Any(srl => srl.Id == StandardRack.StandardRelay.Id)).ToList());
DefaultRelayConfig = Rack.DefaultRelayConfig; //Set Current Value of RelayConfigs Combobox. Does not work.
}
The above code loads both the comboboxes (StandardRacks and RelayConfigs) items properly. However the RelayConfigs selected value is not set to the one it is pointing to from XAML. Instead I get an empty item in the RelayConfigs Combobox as the current item.
Is the 'DefaultRelayConfig' part of the 'RelayConfigs' selection?
I have a List box that I want to display a list of objects, I am following the MVVM pattern and am finding it difficult to achieve what I want.
MainWindowView.xaml
<ListBox ItemsSource="{Binding Path=MyList}">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Path=Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
MainWindowViewModel.cs
private List<ListBoxItem> _myList = new List<ListBoxItem>();
public List<ListBoxItem> MyList
{
get { return _myList ; }
set
{
_myList = value;
OnPropertyChanged("MyList");
}
}
public SprintBacklogViewModel()
{
foreach(MyObject obj in MyObjects.MyObjectList)
{
ListBoxItem item = new ListBoxItem();
item.Content = obj;
MyList.Add(item);
}
}
MyList is getting updated correctly, but nothing is displaying in the window. (ItemsSource="{Binding Path=MyList}" also works, I tested with different data) I have not used an ItemTemplate before so any pointers are welcome. My understanding of it is that If I set it up correctly It will display the data in my objects.
eg:
<Label Content="{Binding Path=Name}"/>
there is a property in MyObject called Name, I want to display this as a label in my list
*EDIT
In my window I get a line of text - mynamespace.MyObject
MyList property in ViewModel is property of type ListBoxItem, it has property Name but it's not Name of MyObject. So you need to change your property in your ViewModel by
Replace
private List<ListBoxItem> _myList = new List<ListBoxItem>();
public List<ListBoxItem> MyList
{
get { return _myList ; }
set
{
_myList = value;
OnPropertyChanged("MyList");
}
}
with
private List<MyObject> _myList = new List<MyObject>();
public List<MyObject> MyList
{
get { return _myList ; }
set
{
_myList = value;
OnPropertyChanged("MyList");
}
}
Your list should not contain UI-Elements but data (you are data-binding), if you bind to a list of ListBoxItems the ListBox will disregard the ItemTemplate and just use the items as they fit the expected container for the ListBox. Containers will be generated automatically, you do not need to do that in your list.
If you add items to a collection at runtime the binding engine needs to be notified to update the changes, for this you should use an ObservableCollection or anything that implements INotifyCollectionChanged. (When doing so you further usually make the field readonly and only provide a getter) This is the reason why there are no items.