I am teaching myself how to bind classes to XAML objects. I can't find anything on data within lists. Either that or I don't know the terminology very well. I want to make a combobox that is tied to the list, displaying the name of each Item in the Items list. How would I bind this to the combobox?
class Section
{
List<Item> Items = new List<Item>();
}
class Item
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
Try This,
<ComboBox ItemsSource="{Binding Items}" DisplayMemberPath="Name" />
Make your Items collection as a property.
public List<Item> Items { get; set;}
Section Class should be public and make it as your DataContext
Assuming Section is the current DataContext :
<ComboBox ItemsSource="{Binding Items}"
DisplayMemberPath="Name" />
Related
I'd like to get the selected Item of a ComboBox using the MVVM Pattern (beginner).
I've read that this could be achieved by binding the SelectedItem Property to a Property in the ViewModel.
XAML:
<ComboBox ItemsSource="{Binding RoomLockerLinkCollection}"
DisplayMemberPath="Room.Name"
SelectedItem="{Binding SelectedRoom}"/>
ViewModel:
public Room SelectedRoom { get; set; }
But it's not working - the only thing thats happening is a appearing red border around that ComboBox - in addition after selecting a new item in the ComboBox the "SelectedRoom" property in my VM is still null.
Edit 1 :
One short additional question:
The binding works fine - at least for the top "category". My Wrapper-Class also contains a list of lockers.
<ComboBox DataContext="{Binding SelectedItem, ElementName=_cmbRoomSelection}" ItemsSource=" {Binding LockerCollection}" DisplayMemberPath="Name" SelectedValue="{Binding SAVM.SelectedLocker, Mode=TwoWay}" />
When I check the type of the SelectedValue it's a "Locker" - fine.
But the SelectedLocker-Property in my VM stays null...
Additional, could s.o. explain when to use "SelectedItem" and "SelectedValue"? What's the difference? Setting the DataContext in the xaml code above can not be done by binding the SelectedValue...
Edit 2 (Solution) :
Okay, got it!
As I figured out I've reset my DataContext - now the Property SAVM of course could not be found.
Solution:
<ComboBox DataContext="{Binding SelectedItem, ElementName=_cmbRoomSelection}"
ItemsSource="{Binding LockerCollection}"
DisplayMemberPath="Name"
SelectedValue="{Binding SAVM.SelectedLocker **ElementName=_vStorage**, Mode=TwoWay}" />
The red box is an indication of a validation error from your Binding ,
The most common error would be that the BindingSource and the BindingTarget are not of the same type.
Use SelectedValue and SelectedValuePath to bind to your Room object.
CS :
public class Room
{
public string RoomName { get; set; }
}
public class RoomWrapper
{
public Room Room { get; set; }
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
public List<RoomWrapper> RoomWrappers
{
get
{
var list = new List<RoomWrapper>();
for (int i = 0; i < 10; i++)
{
list.Add(new RoomWrapper { Room = new Room { RoomName = "Room " + i } });
}
return list;
}
}
private Room selectedRoom;
public Room SelectedRoom
{
get { return selectedRoom; }
set
{
selectedRoom = value;
}
}
XAML :
<ComboBox ItemsSource="{Binding RoomWrappers}"
DisplayMemberPath="Room.RoomName"
SelectedValuePath="Room"
SelectedValue="{Binding SelectedRoom, Mode=TwoWay}" />
I have been trying to figure out the proper way to bind an ObservableCollection of a class to a ListBox with a TextBox DataTemplate. I've tried to implement the code in WPF binding: Set Listbox Item text color based on property but that hasn't gotten me very far as of yet. I'm new to WPF DataBinding, having at most programatically set the ItemsSource in simple cases.
I have this class
public class item
{
public string guid;
public bool found;
public bool newItem;
public Brush color;
}
and the following ObservableCollection
public ObservableCollection<item> _items;
public Window()
{
InitializeComponent();
_items = new ObservableCollection<item>();
}
Elsewhere in the code I add items to the collection via
_items.Add(new item() { guid = sdr.GetString(0), found = false, newItem = false, color = Brushes.Red });
Here's simplified XAML for the ListBox
<ListBox x:Name="ListBox_Items">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text=GUID_HERE Foreground=COLOR_HERE/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I've tried several different ways to get this to work properly, yet for none of them the ListBox is updating. Is anyone able to help point me in the right direction here?
Four things:
Your item class needs to use public properties:
public class item
{
public string guid { get; set; }
public bool found { get; set; }
public bool newItem { get; set; }
public Brush color { get; set; }
}
You need to set the ItemsSource to the collection, and set the current DataContext
public Window()
{
InitializeComponent();
DataContext = this;
_items = new ObservableCollection<item>();
ListBox_Items.ItemsSource = _items;
}
You need to update your DataTemplate to use the property names of your POCO
<ListBox x:Name="ListBox_Items">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding guid}" Foreground="{Binding color}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I think you forgot to bind your ListBox to collection itself.
Your XAML should look like:
<ListBox x:Name="ListBox_Items" ItemsSource="{Binding _items}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text=GUID_HERE Foreground=COLOR_HERE/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And if you want to change properties of items in your collection (and that changes to appear on UI) you should implement INotifyPropertyChanged (see more at MSDN) interface in "item" class.
I have a ListBox simplified to the following XAML
<ListBox ItemsSource="{Binding Properties}"
DisplayMemberPath="Name"
SelectedItem="SelectedProperty" />
and in my ViewModel:
private List<Property> propertyList;
private Property selectedProperty;
public List<Property> Properties
{
get
{
return propertyList;
}
set
{
propertyList = value;
NotifyPropertyChanged("Properties");
}
}
public Property SelectedProperty
{
get
{
return selectedProperty;
}
set
{
NotifyPropertyChanged("SelectedProperty");
selectedProperty= value;
}
}
My List box populates fine, but no matter what I try I cannot seem to get the SelectedProperty to update when I select an item in my list box. I have tried switching it all around to use ObservableCollection rather than List and adding an Event handler for CollectionChanged, but this has not worked.
I am sure I am missing something stupid, and cannot see the wood for the trees. I am reaching the end of my tether and need someone to step in and help.
You need to bind to the SelectedProperty:
<ListBox ItemsSource="{Binding Properties}"
DisplayMemberPath="Name"
SelectedItem="{Binding SelectedProperty}" />
I want my combobox item names and values to be taken from my List of course I don't want my view model to hold combobox items list.
I got a list a,b,c,d
public List<String> ComboList { get; set; }
...
ComboList = new List<String>();
ComboList.Add("A");
ComboList.Add("B");
ComboList.Add("C");
ComboList.Add("D");
and my ComboBox
<ComboBox Margin="29,40,0,526" Width="212" Height="35" Grid.Row="1" ItemsSource="{Binding Path=ComboList, Mode=OneTime}" SelectedValuePath="Key" DisplayMemberPath="Value"></ComboBox>
but it gives me a empty ComboBox ...
Remove the SelectedValuePath and DisplayMemberPath attributes. They are wrong.
You forget to do that just before the InitializeComponents into the code-behind :
public void MainWindow(){
this.Datacontext = this;
InitializeComponent()
}
Moreover you cannot bind the list directly, you better have to give an ObservableCollection.
This is an example :
public ObservableCollection<NetworkCard> NetworksCards { get { return m_aCards; } }
private ObservableCollection<NetworkCard> m_aCards = null;
m_aCards = new ObservableCollection<NetworkCard>(oHelper.ListNetworkCards());
Being a new to WPF/XAML/MVVM, I've got a question.
In my View, I have 2 listboxes, which derive from ItemsControl.
On my viewmodel, I'd like to expose 2 ItemsControl properties such that I can bind my listbox to this view model property... this way I can implement a command that, from the view model, lets me move the currently selected item from ListBox1 to ListBox2.
Imagine all the really cool stuff not shown the following snippets:
view model code:
public int MyStuff1SelectedIndex { get{...} set{...} }
public int MyStuff2SelectedIndex { get{...} set{...} }
public ItemsControl MyStuffItemsControl1 { set; private get; }
public ItemsControl MyStuffItemsControl2 { set; private set; }
view XAML:
<ListBox Name="x:MyStuffListBox1" SelectedIndex="{Binding MyStuff1SelectedIndex}.... />
<ListBox Name="x:MyStuffListBox2" SelectedIndex="{Binding MyStuff2SelectedIndex}...../>
given that, I want my viewmodel to be able to have a command which could move items from one list box to another, w/ code such as the following:
public void MoveItemCommandExecute(...)
{
var sourceItem = MyStuff1ItemsControl.MagicGetItemExtensionMehod(MyStuff1SelectedIndex);
MyStuff1ItemsControl.MagicRemoveItemExtensionMethod(MyStuff1SelectedIndex);
MyStuff2ItemsControl.MagicAddItemExtensionMethod(sourceItem);
}
so, basically, what would the binding XAML look like ? I am trying to set a property on the view model from the view...
thanks!
You'll want to rethink this approach. Typically, you would bind your two listboxes ItemsSource properties to two ObservableCollection<T> properties on your view model, where T is the type of object in your list.
<ListBox x:Name="MyStuffListBox1" ItemsSource="{Binding MyList1}" SelectedItem="{Binding SelectedList1Item}" />
<ListBox x:Name="MyStuffListBox2" ItemsSource="{Binding MyList2}" SelectedItem="{Binding SelectedList2Item}" />
Note: I would use x:Name in your XAML, rather than the Name attribute.
public ObservableCollection<Thing> MyList1 { get; set; }
public ObservableCollection<Thing> MyList2 { get; set; }
// these properties should raise property changed events (INotifyPropertyChanged)
public Thing SelectedList1Item { get {...} set {...} }
public Thing SelectedList2Item { get {...} set {...} }
// constructor
public MyViewModel()
{
// instantiate and populate lists
this.MyList1 = new ObservableCollection(this.service.GetThings());
this.MyList2 = new ObservableCollection(this.service.GetThings());
}
You can then format what is displayed in the lists using DisplayMemberPath or defining an ItemTemplate on each list.
You can swap items between the lists by using the standard Collection methods on the ObservableCollection type - http://msdn.microsoft.com/en-us/library/ms668604.aspx
You shouldn't be implementing controls in your view model. That makes it a view, not a model of a view. The properties on your view model should be ObservableCollection<T>, and you should be binding the ItemsSource of items controls to those properties.
If you do this, your XAML might look like this:
<ListBox ItemsSource="{Binding List1}" SelectedItem="{Binding SelectedItem1, Mode=TwoWay}"/>
<ListBox ItemsSource="{Binding List2}" SelectedItem="{Binding SelectedItem2, Mode=TwoWay}"/>
<Button Command="{Binding MoveItemFromList1ToList2Command}">Move</Button>
List1 and List2 are of type ObservableCollection<T>, SelectedItem1 and SelectedItem2 are of type T (whatever type you've decided T should be), and MoveItemFromList1ToList2Command is a RoutedCommand that has these two handlers defined:
public bool CanMoveItemFromList1ToList2
{
{ get { return SelectedItem1 != null; }
}
public void MoveItemFromList1ToList2()
{
List2.Add(SelectedItem1);
List1.Remove(SelectedItem1);
}
I'd have to test this code to be sure, but I don't think you need to bother with property-change notification in the MoveItemFromList1ToList2 method; when you remove the item from List1, the ObservableCollection will notify the ListBox that the item's been removed, and the ListBox will set SelectedItem to null, updating SelectedItem1 in the view model. (And, of course, that will make the code break if you remove it from the first collection before adding it to the second.)