Binding a Wpf Combobox to a Custom List

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 the SelectedValuePath

    <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 Datacontext
  • coImportReader the Class which presents your properties for your bindings
  • coSearchPoint which is just a Container for your information
  • IRange 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



Leave a reply



Submit