【问题标题】:WPF Binding ComboBox to my ViewModelWPF 将 ComboBox 绑定到我的 ViewModel
【发布时间】:2015-12-16 20:04:26
【问题描述】:

我正在尝试将我的 ViewModel 绑定到我的 ComboBox。我有这样定义的 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 中,我这样做是为了将我的 ComboBox 绑定到这个 ViewModel。我想在我的 ComboBox 中显示默认选择的“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>

我有两个问题:

  1. 如何将 Combo Box 中选择的默认值设置为“VW”(表单加载后,组合框中应显示“VW”)。
  2. 如何在我的 ViewModel 中设置它而不是像上面那样在 xaml 中设置 ComboBoxItems,然后将它们加载到 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; }
    }
}

【问题讨论】:

  • 好的,从您的新更新开始,Make 和 Year 属性应该存在于 Car 类中,而不是 ViewModel 中。 DefaultCar 应该分配给 car 的实例,而不是字符串,然后将其从 ViewModel 构造函数中删除。
  • @E-Bat 你是说 ViewModel CLASS 应该只包含 IEnumerable Cars 而其他所有东西都应该移动到 Car CLASS 中?或者我应该从 ViewModel C-TOR 中删除它?在这种情况下,如何将 DefaultCar 分配给汽车实例?不是已经用上面的表达式赋值了吗?请问可以显示更改吗?
  • dbnex14,在这种情况下,ViewModel 应该只包含 Cars 和 DefaultCar 属性。可以在您从数据存储中获取 Cars 的那一刻分配 DefaultCar。当您的 View 加载并尝试解析其绑定时,将从您的 View 中查询 Cars 属性(由 ComboBox 中的 ItemsSource 属性触发)。然后此时您可以在返回列表之前分配 DefaultCar。请参阅下面的答案。
  • 顺便说一句,它应该是 SelectedCar 而不是 DefaultCar,因为它是在 ComboBox 的 SelectedItem 绑定中定义的
  • @E-Bat 我认为我的问题具有误导性。因此,我将其标记为已回答并在stackoverflow.com/questions/34326241/wpf-how-to-bind-combobox 创建了一个新的,它更好地解释了我想要实现的目标。

标签: c# wpf xaml mvvm


【解决方案1】:

当您要实现 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; }
    }

您的 Xaml:

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

【讨论】:

  • 谢谢。您将如何重写这一行,我不明白它在做什么,因为“汽车”没有在任何地方定义“SelectedCar = cars.FirstOrDefault(car=>car.Model == "VW");”?谢谢,
  • @dbnex14,car变量代表汽车集合中的每一项,之前不需要定义。查看语法 car=>。这是 lambda 表达式。
  • @dbnex14 请看这个问题的 lambda 表达式:stackoverflow.com/questions/3970219/c-sharp-lambda
  • 我添加了更新。它在那条线上出错。谢谢
  • @dbnex14 您正在定义一个字符串数组,它应该是一个 Car 数组;) var cars = new Car[] { new Car { Model = "Mazda"}, new Car { Model ="VW"},新车 {Model = "Audi"},新车 { Model = "BMW"},新车 { Model = "Honda"} };
【解决方案2】:
  1. 默认值: 如果您设置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));
    }
}

2。 绑定ItemsSourceSelectedItem

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

如果您的源或视图比仅显示字符串更复杂,您还可以设置ComboBox.ItemTemplate

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

在视图模型中只需添加一个列表属性:

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

它不必是 ObservableCollection,但该类型会在您更改集合时自动更新 UI。

【讨论】:

  • 您在哪里将汽车设置为它们的值“马自达”、“大众”、“奥迪”?谢谢
  • 我正在使用我的模型在表单上设置一些默认值。抱歉,我是 WPF 的新手,只是想澄清我为什么需要这个。因此,当表单打开时,这些值应该默认显示在我的控件中(在本例中是 Car 组合框,但我发布了带有其他几个控件的更新)。
猜你喜欢
  • 2011-06-25
  • 1970-01-01
  • 2013-09-13
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 1970-01-01
  • 1970-01-01
  • 2021-10-18
相关资源
最近更新 更多