几个小时以来,我一直被以下问题所困扰:
我是WPF的新手,尤其是MVVM。我有三个不同的类(Car
,Motorcycle
,Truck
)具有不同的性质。您可以在Combobox
中选择车辆。下面是我的Car
-Class的一个例子:
public class Car
{
public int Axes { get; set; }
public int Seats { get; set; }
public int Doors { get; set; }
public VehicleProperties.Car.Type Type { get; set; }
public int MaxWeight { get; set; }
public Fuel Fuel { get; set; }
public double ConsumptionPer100km { get; set; }
public bool Childseat { get; set; }
public string Brand { get; set; }
public string Model { get; set; }
public int FirstRegistration { get; set; }
public int Mileage { get; set; }
public Transmission Transmission { get; set; }
public int Power { get; set; }
public bool Tempomat { get; set; }
public SolidColorBrush Color { get; set; }
public int PollutionClass { get; set; }
public int EnvironmentalBadge { get; set; }
}
Motorcycle
-Class:
public class Motorcycle
{
public string Brand { get; set; }
public string Model { get; set; }
public Fuel Fuel { get; set; }
public VehicleProperties.Motorcycle.Type Type { get; set; }
public int Power { get; set; }
public int FirstRegistration { get; set; }
public int Mileage { get; set; }
public DriveType DriveType { get; set; }
public Transmission Transmission { get; set; }
public int CubicCapacity { get; set; }
public int PollutionClass { get; set; }
public Brush Color { get; set; }
public int ConsumptionPer100km { get; set; }
}
Truck
-Class:
public class Truck
{
public VehicleProperties.Truck.Type Type { get; set; }
public string Brand { get; set; }
public string Model { get; set; }
public int Mileage { get; set; }
public int Power { get; set; }
public Fuel Fuel { get; set; }
public Transmission Transmission { get; set; }
public int Axes { get; set; }
public int MaxWeight { get; set; }
public bool Tempomat { get; set; }
public SolidColorBrush Color { get; set; }
public int PollutionClass { get; set; }
public string WheelFormula { get; set; }
public int ConsumptionBadge { get; set; }
}
我必须创建一个窗口,您可以根据您选择的车辆创建新车辆。我首先考虑寻找类的属性,并在XAML中动态地检查DataType
的Markup-Extension
,但它不起作用,因为输出始终是string
。最重要的是:即使我让它工作,我将如何动态绑定它们?
现在,我正在为每个类设计3个网格,将它们绑定到变量,并将Visibility
-属性绑定到三个bool
s。有没有更有效的解决办法?我觉得这样做不对。
您应该使用DataTemplate
为每种车辆类型创建不同的视图,例如Car
。我们的想法是根据所选车辆数据类型显示DataTemplate
。由于您将每个DataTemplate
定义为隐式模板(没有x:Key指令),因此模板将自动应用(按数据类型)。
在下面的示例中,所选择的数据类型公开为绑定到ContentControl
的MainViewModel.NewVehicle
属性。然后,ContentControl
将自动应用适当的DataTemplate
。DataTemplate
的DataContext
和Car
一样是当前的数据类型。这就是为什么你可以很容易地将模板的UI元素绑定到新实例。
每当您从ComboBox
中选择一个类别时,MainViewModel
将创建所选车辆类型的新空实例并将其分配给MainViewModel.NewVehicle
属性。在你通过DataTemplate
提供的UI编辑完新车之后,你就可以处理完成的MainViewModel.NewVehicle
了。
接口IVehicleProvider
旨在消除switch
或多个if
,以确定要创建的实际车辆类型。它是由IVehicle接口实现的,而每个车辆类型都必须实现这个接口。
解决方案的关键部分是使用DataTemplate
(参见数据模板概述)为了创建三个个人编辑视图和IVehicleProvider
消除开关类型。
MainWindow.xaml
<Window>
<Window.DataContext>
<MainViewModel />
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type local:Car}">
<TextBlock Text="{Binding VehicleType}" Background="Green" />
</DataTemplate>
<DataTemplate DataType="{x:Type local:MotoryCycle}">
<TextBlock Text="{Binding VehicleType}" Background="Yellow" />
</DataTemplate>
<DataTemplate DataType="{x:Type local:Truck}">
<TextBlock Text="{Binding VehicleType}" Background="Red" />
</DataTemplate>
</Window.Resources>
<StackPanel>
<ComboBox ItemsSource="{Binding VehicleCategories}"
DisplayMemberPath="VehicleType"
SelectedItem="{Binding SelectedVehicleProvider}" />
<!-- Display the DataTemplate of the current type returned by NewVehicle -->
<ContentControl Content="{Binding NewVehicle}" />
<StackPanel>
</Window>
MainViewModel.cs
class MainViewModel : INotifyPropertyChanged
{
public MainViewModel()
{
this.VehicleCategories = new List<IVehicle>
{
new Car(),
new Truck(),
new MotoryCycle()
};
}
private void OnSelectedvehicleCategoryChanged()
=> this.NewVehicle = this.SelectedVehicleCategoryProvider.CreateEmpty();
public List<IVehicle> VehicleCategories { get; }
// The new vehicle, ready for edit in a view provided by a DataTemplate.
private IVehicle newVehicle;
public IVehicle NewVehicle
{
get => this.newVehicle;
set
{
this.newVehicle = value;
OnPropertyChanged();
}
}
private IVehicleProvider selectedVehicleCategoryProvider;
public IVehicleProvider SelectedVehicleCategoryProvider
{
get => this.selectedVehicleCategory;
set
{
this.selectedVehicleCategory = value;
OnSelectedvehicleCategoryChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
=> this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
VehicleType.cs
public enum VehicleType
{
Default = 0,
Car,
Truck,
Motorcycle
}
IVehicle.cs
public interface IVehicle : IVehicleProvider
{
VehicleType VehicleType { get; }
}
IVehicleProvider.cs
public interface IVehicleProvider
{
IVehicle CreateEmpty();
}
Car.cs
public class Car : IVehicle
{
public VehicleType VehicleType => VehicleType.Car;
public IVehicle CreateEmpty() => new Car();
// Properties of Car
}
Truck.cs
public class Truck : IVehicle
{
public VehicleType VehicleType => VehicleType.Truck;
public IVehicle CreateEmpty() => new Truck();
// Properties of Truck
}
MotoryCycle.cs
public class MotoryCycle : IVehicle
{
public VehicleType VehicleType => VehicleType.Motorcycle;
public IVehicle CreateEmpty() => new MotoryCycle();
// Properties of MotoryCycle
}