Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF Binding ComboBox to my ViewModel

Tags:

c#

mvvm

wpf

xaml

I am trying to bind my ViewModel to my ComboBox. I have ViewModel class defined like this:

class ViewModel
{
    public ViewModel()
    {
        this.Car= "VW";
    }

    public string Car{ get; set; }
}

I set this ViewModel as DataContext in Window_Load like:

   private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        this.DataContext = new CarModel();
    }

Then in my xaml, I do this to bind my ComboBox to this ViewModel. I want to show the "VW" as selected by default in my ComboBox:

        <ComboBox Name="cbCar" SelectedItem="{Binding Car, UpdateSourceTrigger=PropertyChanged}">
            <ComboBoxItem Tag="Mazda">Mazda</ComboBoxItem>
            <ComboBoxItem Tag="VW">VW</ComboBoxItem>
            <ComboBoxItem Tag="Audi">Audi</ComboBoxItem>
        </ComboBox>

I have 2 questions:

  1. How do I set default value selected in Combo Box to "VW" (once form loads, it should show "VW" in combo box).
  2. Instead of setting ComboBoxItems like above in xaml, how to I set it in my ViewModel and then load these in ComboBox?

Thanks,

UPDATE: So far, I manage to implement this but I get error as below in the ViewModel c-tor:

namespace MyData
{
    class ViewModel
    {
        public ViewModel()
        {
            this.Make = "";
            this.Year = 1;

            this.DefaultCar = "VW"; //this is where I get error 'No string allowed'
        }

        public IEnumerable<Car> Cars
        {
            get
            {
                var cars = new Car[] { new Car{Model="Mazda"}, new Car{Model="VW"}, new Car{Model="Audi"} };
                DefaultCar = cars.FirstOrDefault(car => car.Model == "VW"); 
            }
        }

        public string Make { get; set; }
        public int Year { get; set; }
        public Car DefaultCar { get; set; }
    }

    class Car
    {
        public string Model { get; set; }
    }
}
like image 426
pixel Avatar asked Dec 16 '15 20:12

pixel


2 Answers

As you are going to implement MVVM it will be a lot better if you start to think in objects to represent Cars in your application:

    public class ViewModel
    {    
            public Car SelectedCar{ get; set; }
            public ObservableCollection<Car> Cars{ 
                get  {
                    var cars = new ObservableCollection(YOUR_DATA_STORE.Cars.ToList());
                    SelectedCar = cars.FirstOrDefault(car=>car.Model == "VW");
                    return cars;
                }
            }
    }
    
    public class Car 
    {
        public string Model {get;set;}
        public string Make { get; set; }
        public int Year { get; set; }
    }

Your Xaml:

<ComboBox SelectedItem="{Binding SelectedCar}", ItemsSource="{Binding Cars}" 
        UpdateSourceTrigger=PropertyChanged}"/>
like image 73
E-Bat Avatar answered Oct 20 '22 00:10

E-Bat


  1. Default Value: If you set viewModel.Car = "VW", then it should auto-select that item in the combo box. For this to work you will need to either implement INotifyPropertyChanged or set Car before you set DataContext.

INotifyPropertyChanged implementation might look like:

class ViewModel : INotifyPropertyChanged
{
    private string car;

    public ViewModel()
    {
        this.Car = "VW";
        this.Cars = new ObservableCollection<string>() { "Mazda", "VW", "Audi" };
    }

    public string Car
    {
        get
        {
            return this.car;
        }
        set
        {
            if (this.car != value)
            {
                this.car = value;
                OnPropertyChanged();
            }
        }
    }

    public ObservableCollection<string> Cars { get; }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. Bind ItemsSource and SelectedItem.

<ComboBox ItemsSource="{Binding Cars}"
          SelectedItem="{Binding Car, Mode=TwoWay}">
</ComboBox>

You can also set ComboBox.ItemTemplate if your source or view is more complex than just displaying a string:

    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}" />
        </DataTemplate>
    </ComboBox.ItemTemplate>

In the view model just add a list property:

public ObservableCollection<string> Cars { get; set; }

It doesn't have to be ObservableCollection but that type will auto-update the UI whenever you change the collection.

like image 33
FUR10N Avatar answered Oct 20 '22 01:10

FUR10N