C# WPF将组合框绑定到我的ViewModel

C# WPF将组合框绑定到我的ViewModel,c#,wpf,xaml,mvvm,C#,Wpf,Xaml,Mvvm,我正在尝试将ViewModel绑定到组合框。我有如下定义的ViewModel类: class ViewModel { public ViewModel() { this.Car= "VW"; } public string Car{ get; set; } } 我在Window_Load中将此ViewModel设置为DataContext,如下所示: private void Window_Loaded(object sender, Ro

我正在尝试将ViewModel绑定到组合框。我有如下定义的ViewModel类:

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

    public string Car{ get; set; }
}
我在Window_Load中将此ViewModel设置为DataContext,如下所示:

   private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        this.DataContext = new CarModel();
    }
然后在我的xaml中,我这样做是为了将我的组合框绑定到这个ViewModel。我想在我的组合框中显示默认选中的“VW”:

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

马自达
大众汽车
奥迪
我有两个问题:

  • 如何将组合框中选择的默认值设置为“VW”(表单加载后,组合框中应显示“VW”)
  • 如何在ViewModel中设置ComboBox项,然后将其加载到ComboBox中,而不是像上面那样在xaml中设置ComboBox项
  • 谢谢

    更新: 到目前为止,我成功地实现了这一点,但在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; }
        }
    }
    
    名称空间MyData
    {
    类视图模型
    {
    公共视图模型()
    {
    这个。Make=“”;
    本年=1年;
    this.DefaultCar=“VW”//这就是我得到错误“不允许字符串”的地方
    }
    公车
    {
    得到
    {
    var cars=新车[]{new Car{Model=“Mazda”},新车{Model=“VW”},新车{Model=“Audi”};
    DefaultCar=cars.FirstOrDefault(car=>car.Model==“VW”);
    }
    }
    公共字符串Make{get;set;}
    公共整数年{get;set;}
    公共汽车默认汽车{get;set;}
    }
    班车
    {
    公共字符串模型{get;set;}
    }
    }
    
  • 默认值: 如果设置了
    viewModel.Car=“VW”
    ,则它应该在组合框中自动选择该项。 为此,您需要在设置
    DataContext
    之前实现
    INotifyPropertyChanged
    或设置
    Car
  • INotifyPropertyChanged实现可能如下所示:

    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));
        }
    }
    
    如果源代码或视图比仅显示字符串更复杂,则还可以设置
    ComboBox.ItemTemplate

        <ComboBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}" />
            </DataTemplate>
        </ComboBox.ItemTemplate>
    
    
    
    在视图模型中,只需添加一个列表属性:

    public ObservableCollection<string> Cars { get; set; }
    
    公共可观测收集车{get;set;}
    

    它不一定非得是
    ObservableCollection
    ,但只要您更改集合,该类型将自动更新UI。

    当您要实现MVVM时,如果您开始考虑在应用程序中用对象来表示汽车,那会好得多:

        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; }
        }
    
    公共类视图模型
    {    
    公共汽车选定汽车{get;set;}
    公共可观测收集车{
    得到{
    var cars=新的ObservableCollection(您的_DATA_STORE.cars.ToList());
    SelectedCar=cars.first或default(car=>car.Model==“VW”);
    返回车辆;
    }
    }
    }
    公车
    {
    公共字符串模型{get;set;}
    公共字符串Make{get;set;}
    公共整数年{get;set;}
    }
    
    您的Xaml:

    <ComboBox SelectedItem="{Binding SelectedCar}", ItemsSource="{Binding Cars}" 
            UpdateSourceTrigger=PropertyChanged}"/>
    

    谢谢。你会怎么重写这行,我不明白它在做什么,因为“车”没有定义“SelectedCar=cars.FirstOrDefault(car=>car.Model==VW”);”?Thansk,@dbnex14,car变量表示cars集合中的每个项,之前不需要定义它。看看syntaxis汽车=>。这是lambda表达式。@dbnex14请查看lambda表达式的问题:我添加了更新。它在那条线上出错了。Thanks@dbnex14您正在定义字符串数组,而它应该是Car;)var cars=新车[]{new Car{Model=“Mazda”},新车{Model=“VW”},新车{Model=“Audi”},新车{Model=“BMW”},新车{Model=“Honda”};你在哪里设定汽车的价值观“马自达”、“大众”、“奥迪”?谢谢,我正在使用我的模型在表单上设置一些默认值。对不起,我是WPF的新手,只是想澄清为什么我需要这个。因此,当窗体打开时,默认情况下,这些值应该显示在我的控件中(在本例中是Car组合框,但我发布了带有两个其他控件的更新)。从新的更新中确定,Make和Year属性应该位于Car类中,而不是ViewModel中。DefaultCar应该分配给car的一个实例,而不是一个字符串,然后将其从ViewModel构造函数中删除。@E-Bat您是说ViewModel类应该只包含IEnumerable Cars,而其他所有内容都应该移动到car类吗?或者我应该从ViewModel C-TOR中删除它?在这种情况下,如何将DefaultCar分配给car的实例?它不是已经用上面的表达式赋值了吗?是否可以显示更改?dbnex14,在这种情况下,ViewModel应仅包含Cars和DefaultCar属性。DefaultCar可以在您从数据存储中获取车辆的瞬间分配。当您的视图加载并尝试解析其绑定时,将从您的视图中查询它们的Cars属性(由ComboBox中的ItemsSource属性触发)。此时,您可以在返回列表之前分配DefaultCar。请参阅下面的答案。顺便说一句,它应该是SelectedCar而不是DefaultCar,因为它是如何在SelectedItem绑定中定义的ComboBox@E-但我认为我的问题有误导性。因此,我将此标记为已回答,并创建了一个新的,以更好地解释我想要实现的目标。
    
    <ComboBox SelectedItem="{Binding SelectedCar}", ItemsSource="{Binding Cars}" 
            UpdateSourceTrigger=PropertyChanged}"/>