Reputation: 14192
Is there a way to use a label function for the the Items placed in a combo box?
Currently it uses the ToString()
to get the label. As an example say you have a ComboBox
that is backed by a list objects of type Person
:
namespace WpfApplication1 {
public class Person {
public string fname { get; set; }
public string mname { get; set; }
public string lname { get; set; }
public Person(string fname, string mname, string lname) {
this.fname = fname;
this.mname = mname;
this.lname = lname;
}
public override string ToString() {
return this.lname +", " + this.fname + " "+ this.mname;
}
}
}
But now you want to the text for each person to be just this fname + " "+ this.mname[0]+" "+this.lname
in some places. Ideally I would like to be able to add a method to the backing XAML cs file like:
public string GetLabel(Person item) {
return item.fname + " " + item.mname[0] + " " + item.lname;
}
and then somehow point it the ComboBox at the method in the cs file.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="100" Width="250">
<Grid>
<ComboBox x:Name="items" Height="22" Width="200" ItemsSource="{Binding}"/>
</Grid>
</Window>
MainWindow.xaml.cs
using System.Collections.Generic;
using System.Windows;
namespace WpfApplication1 {
public partial class MainWindow : Window {
public List<Person> persons { get; set; }
public MainWindow() {
InitializeComponent();
this.persons = new List<Person>();
persons.Add(new Person("First", "Middle", "Last"));
persons.Add(new Person("John", "Jacob", "Jingleheimer"));
persons.Add(new Person("First", "Middle", "Last"));
this.items.DataContext = this.persons;
}
public string GetLabel(Person item) {
return item.fname + " " + item.mname[0] + " " + item.lname;
}
}
}
Upvotes: 1
Views: 277
Reputation: 1840
You should look at using a ViewModel to make this much more straight forward, but if you want to do what you are asking you could just make another property on your Person
class that you bind up to on your ComboBox.
public class Person
{
public string fname { get; set; }
public string mname { get; set; }
public string lname { get; set; }
public string FullName
{
get
{
return item.fname + " " + item.mname[0] + " " + item.lname;
}
}
public Person(string fname, string mname, string lname)
{
this.fname = fname;
this.mname = mname;
this.lname = lname;
}
}
Then you can just use this XAML:
<ComboBox x:Name="items" Height="22" Width="200" ItemsSource="{Binding} DisplayMemberPath="FullName"/>
Again I suggest you learn more about MVVM.
I Hope this helps.
Edit
Ok, you asked if I could show you how to do it using MVVM, so here it goes.
First we have our Person
class which is our model (I renamed properties and added an Id field because I could)
public class Person
{
public Guid Id { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public Person()
{
Id = Guid.NewGuid();
}
public Person(string firstName, string middleName, string lastName)
{
Id = Guid.NewGuid();
FirstName = firstName;
MiddleName = middleName;
LastName = lastName;
}
}
Notice that I didn't pollute my model with the FullName property as this is purely for display, so we will put it in a ViewModel.
Here is the PersonViewModel
(note the ViewModelBase in this case is just a base class that implements INotifyPropertyChanged
):
public class PersonViewModel : ViewModelBase
{
private Person person { get; set; }
public Guid Id { get { return person.Id; } }
public String FirstName
{
get { return person.FirstName; }
set
{
if (person.FirstName != value)
{
person.FirstName = value;
RaisePropertyChanged("FirstName");
}
}
}
public string MiddleName
{
get { return person.MiddleName; }
set
{
if (person.MiddleName != value)
{
person.MiddleName = value;
RaisePropertyChanged("MiddleName");
}
}
}
public string LastName
{
get { return person.LastName; }
set
{
if (person.LastName != value)
{
person.LastName = value;
RaisePropertyChanged("LastName");
}
}
}
public string FullName { get { return LastName + ", " + FirstName + " " + MiddleName; } }
public PersonViewModel()
{
person = new Person();
}
public PersonViewModel(Person inPerson)
{
person = inPerson;
}
}
It basically wraps our Person Class with Properties that are Raising PropertyChanged notifications (needed if you want to update the screen when a property changes). It also adds the new FullName
property.
Next we have a MainViewModel because I don't want to put code into the Code Behind page of the MainWindow. It just declares our List<PersonViewModel>
and populates it.
public class MainViewModel : ViewModelBase
{
public List<PersonViewModel> People { get; set; }
public MainViewModel()
{
// Get the people list from your data provider (in this case returns IEnumerable<Person>)
var peopleList = DataProvider.GetPeople();
// Wrap each person in a PersonViewModel to make them more UI friendly
People = peopleList.Select(p => new PersonViewModel(p)).ToList();
}
}
Finally, we have our MainWindow with the ComboBox
on it.
<Window x:Class="MVVM_Sample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:MVVM_Sample.ViewModels"
Title="MainWindow" Height="350" Width="525"
DataContext="{DynamicResource ViewModel}">
<Window.Resources>
<vm:MainViewModel x:Key="ViewModel" />
</Window.Resources>
<Grid>
<ComboBox ItemsSource="{Binding People}" DisplayMemberPath="FullName" SelectedValuePath="Id" Height="22" Width="200" />
</Grid>
</Window>
Notice that I declare an instance of MainViewModel
in the Resources and set it to the DataContext
of the Window. This makes my Binding statements look to the MainViewModel for the values.
I know this seems a bit long winded for such a simple example, but it makes much more sense when things start to get complicated and it helps keep the needed separation of concerns. Both MVVM and XAML are awesome tools, but there is a learning curve.
Upvotes: 1