Binding a WPF ComboBox to a custom list
You set the DisplayMemberPath and the SelectedValuePath to "Name", so I assume that you have a class PhoneBookEntry with a public property Name.
Have you set the DataContext to your ConnectionViewModel object?
I copied you code and made some minor modifications, and it seems to work fine.
I can set the viewmodels PhoneBookEnty property and the selected item in the combobox changes, and I can change the selected item in the combobox and the view models PhoneBookEntry property is set correctly.
Here is my XAML content:
<Window x:Class="WpfApplication6.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<StackPanel>
<Button Click="Button_Click">asdf</Button>
<ComboBox ItemsSource="{Binding Path=PhonebookEntries}"
DisplayMemberPath="Name"
SelectedValuePath="Name"
SelectedValue="{Binding Path=PhonebookEntry}" />
</StackPanel>
</Grid>
</Window>
And here is my code-behind:
namespace WpfApplication6
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
ConnectionViewModel vm = new ConnectionViewModel();
DataContext = vm;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
((ConnectionViewModel)DataContext).PhonebookEntry = "test";
}
}
public class PhoneBookEntry
{
public string Name { get; set; }
public PhoneBookEntry(string name)
{
Name = name;
}
public override string ToString()
{
return Name;
}
}
public class ConnectionViewModel : INotifyPropertyChanged
{
public ConnectionViewModel()
{
IList<PhoneBookEntry> list = new List<PhoneBookEntry>();
list.Add(new PhoneBookEntry("test"));
list.Add(new PhoneBookEntry("test2"));
_phonebookEntries = new CollectionView(list);
}
private readonly CollectionView _phonebookEntries;
private string _phonebookEntry;
public CollectionView PhonebookEntries
{
get { return _phonebookEntries; }
}
public string PhonebookEntry
{
get { return _phonebookEntry; }
set
{
if (_phonebookEntry == value) return;
_phonebookEntry = value;
OnPropertyChanged("PhonebookEntry");
}
}
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
Edit: Geoffs second example does not seem to work, which seems a bit odd to me. If I change the PhonebookEntries property on the ConnectionViewModel to be of type ReadOnlyCollection, the TwoWay binding of the SelectedValue property on the combobox works fine.
Maybe there is an issue with the CollectionView? I noticed a warning in the output console:
System.Windows.Data Warning: 50 : Using CollectionView directly is not fully supported. The basic features work, although with some inefficiencies, but advanced features may encounter known bugs. Consider using a derived class to avoid these problems.
Edit2 (.NET 4.5): The content of the DropDownList can be based on ToString() and not of DisplayMemberPath, while DisplayMemberPath specifies the member for the selected and displayed item only.
How do I bind a WPF ComboBox to a List Objects in XAML?
Your problem is simple.
Change
public List<AccountManager> AccountManagers;
to this
public List<AccountManager> AccountManagers { get; set; }
and make sure that you have these in your MainWindow constructor
public MainWindow()
{
InitializeComponent();
//Setup Account managers here
DataContext = this;
}
you can only bind to properties not fields and you need to ensure the proper data context
Binding Custom Object to WPF Combobox
Refer the below code. You can use SelectedItem to get both the ID and Name in one SelectedObject. Get only ID using SelectedValue.
<ComboBox ItemsSource="{Binding Clinics}" DisplayMemberPath="ClinicName"
SelectedValuePath="ClinicId" SelectedValue="{Binding SelectedClinicId}"
SelectedItem="{Binding SelectedClinic}"/>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
class Clinic
{
public int ClinicId { get; set; }
public string ClinicName { get; set; }
}
class ViewModel
{
public ObservableCollection<Clinic> Clinics { get; set; }
public ViewModel()
{
Clinics = new ObservableCollection<Clinic>();
for (int i = 0; i < 10; i++)
{
Clinics.Add(new Clinic() { ClinicId=i+1,ClinicName="MyClinic"+(i+1) });
}
}
private int selectedClinicId;
public int SelectedClinicId
{
get { return selectedClinicId; }
set
{
selectedClinicId = value;
}
}
private Clinic selectedClinic;
public Clinic SelectedClinic
{
get { return selectedClinic; }
set
{
selectedClinic = value;
MessageBox.Show("ID:"+selectedClinic.ClinicId.ToString()+" "+"Name:"+selectedClinic.ClinicName);
}
}
}
Combobox binding itemsource to custom list and selecteditem to an instance of that list doesn't work
Is the SelectedItem
the exact same reference in memory as the item in the ItemsSource
?
By default, WPF will compare the SelectedItem
to the items in the ItemsSource
by reference, and if they're not the same reference in memory, it will return no matching item.
If you are unable to do this in your code, the most common workarounds are to either:
Bind the
SelectedValue
to a value type instead of a reference type, and set theSelectedValuePath
<ComboBox ItemsSource="{Binding Grades}"
SelectedValue="{Binding SelectedPerson.MyGrade.GradeId}"
SelectedValuePath="GradeId"
DisplayMemberPath="Name"/>Or override the
.Equals()
to ensure the two objects are considered equal when specific properties match, as opposed to being considered equal when the reference in memory matches.public override bool Equals(object obj)
{
if (obj == null || !(obj is Grade))
return false;
return ((Grade)obj).GradeId == this.GradeId);
}
WPF - Bind combobox to List of custom class objects
change
public class ComboboxItem
{
public string DisplayValue;
public string InternalValue;
}
to
public class ComboboxItem
{
public string DisplayValue {get;set;}
public string InternalValue {get;set;}
}
WPF Databinding combobox to a list string
Posting my comment back to mark the answer.
My DataContext was set, BUT it was set after InitializeComponent(). I thought that could be the problem. Then I realized that as I am binding through xaml, when the view loads, the binding happens to the property which is empty.
The property gets populated when the view is ready after its loaded (i.e on _presenter.OnViewReady()). Since it's not an observable collection nothing gets added to the combobox. Specifying it from my code behind works, because at that time the data exists in the property.
WPF: Binding a List class to a ComboBox
Here a simple example using the MVVM Pattern
XAML
<Window x:Class="Binding_a_List_to_a_ComboBox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid HorizontalAlignment="Left"
VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<ComboBox Grid.Column="0" Grid.Row="0" ItemsSource="{Binding SearchPointCollection , UpdateSourceTrigger=PropertyChanged}"
SelectedIndex="{Binding MySelectedIndex, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding MySelectedItem, UpdateSourceTrigger=PropertyChanged}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding Id}" Grid.Row="0"/>
<TextBlock Text="{Binding Name}" Grid.Row="1"/>
<TextBlock Text="{Binding Otherstuff}" Grid.Row="2"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button Content="Bind NOW" Grid.Column="0" Grid.Row="1" Click="Button_Click"/>
<TextBlock Text="{Binding MySelectedIndex, UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Grid.Row="0"/>
<Grid Grid.Column="1" Grid.Row="1"
DataContext="{Binding MySelectedItem, UpdateSourceTrigger=PropertyChanged}">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Id}" Grid.Column="0"/>
<TextBlock Text="{Binding Name}" Grid.Column="1"/>
<TextBlock Text="{Binding SomeValue}" Grid.Column="2"/>
</Grid>
</Grid>
Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using Import_Rates_Manager;
namespace Binding_a_List_to_a_ComboBox
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
DataContext = new coImportReader();
}
}
}
namespace Import_Rates_Manager
{
public class coImportReader : INotifyPropertyChanged
{
private List<coSearchPoint> myItemsSource;
private int mySelectedIndex;
private coSearchPoint mySelectedItem;
public List<coSearchPoint> SearchPointCollection
{
get { return myItemsSource; }
set
{
myItemsSource = value;
OnPropertyChanged("SearchPointCollection ");
}
}
public int MySelectedIndex
{
get { return mySelectedIndex; }
set
{
mySelectedIndex = value;
OnPropertyChanged("MySelectedIndex");
}
}
public coSearchPoint MySelectedItem
{
get { return mySelectedItem; }
set { mySelectedItem = value;
OnPropertyChanged("MySelectedItem");
}
}
#region cTor
public coImportReader()
{
myItemsSource = new List<coSearchPoint>();
myItemsSource.Add(new coSearchPoint { Name = "Name1" });
myItemsSource.Add(new coSearchPoint { Name = "Name2" });
myItemsSource.Add(new coSearchPoint { Name = "Name3" });
myItemsSource.Add(new coSearchPoint { Name = "Name4" });
myItemsSource.Add(new coSearchPoint { Name = "Name5" });
}
#endregion
#region INotifyPropertyChanged Member
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
public class coSearchPoint
{
public Guid Id { get; set; }
public String Name { get; set; }
public IRange FoundCell { get; set; }
public coSearchPoint()
{
Name = "";
Id = Guid.NewGuid();
FoundCell = null;
}
}
public interface IRange
{
string SomeValue { get; }
}
}
Here are 3 Classes:
MainWindow
which set VM as his DatacontextcoImportReader
the Class which presents your properties for your bindingscoSearchPoint
which is just a Container for your informationIRange
which is just an Interface
WPF bind comboBox to List string
You need to first set the DataContext
property of your MainWindow, which will provide a default source object for any Bindings where a source is not explictly set (by setting either Source, RelativeSource or ElementName).
The object held by the DataContext is typically called a view model.
Your view model should have a public property Statuses
which returns a List<string>
Then in XAML you can declare ItemsSource="{Binding Statuses}"
Statuses
may also be declared as ObservableCollection<string>
in case you want the UI to updated when elements are added or removed.
Related Topics
Visual Studio Publish Project into One Simple Installer
How to Get C# Enum Description from Value
Getting Servicestack to Retain Type Information
Why Response.Redirect Causes System.Threading.Threadabortexception
Using C#, How Does One Figure Out What Process Locked a File
Anyone Know a Good Workaround For the Lack of an Enum Generic Constraint
Use Linq to Get Items in One List≪≫, That Are Not in Another List≪≫
Asp.Net MVC: Custom Validation by Dataannotation
Difference Between Shadowing and Overriding in C#
How to Evaluate a C# Expression Dynamically
What's the Strangest Corner Case You'Ve Seen in C# or .Net
Deserializing Json to .Net Object Using Newtonsoft (Or Linq to Json Maybe)
Why and How to Avoid Event Handler Memory Leaks
Integer Summing Blues, Short += Short Problem