【发布时间】:2014-11-05 14:03:30
【问题描述】:
在将 MVVM 与 WPF 结合使用方面,我有点初学者。我可以处理简单的事情,但我目前正在努力解决以下问题。
假设我有一个 TravelPlan 对象。 TravelPlan 有一个 Cities 对象(基本上是该计划将按特定顺序访问的所有城市的集合)。
城市使用动态控件呈现。它显示了可能城市的下拉框、加号 (+) 和减号 (-) 按钮。每当您按下 + 按钮时,都会出现一个新的空下拉列表供您选择。
我使用 TravelPlan 的视图模型和城市的单独视图模型创建了这个(见下文)。我添加了验证,以便您有选择一个城市。
public class CityViewModel : DataErrorInfoViewModel
{
private readonly IEnumerable<string> _availableCities;
private string _selectedCity;
public CityViewModel(IEnumerable<string> availableCities)
{
_availableCities = availableCities;
}
public string SelectedCity
{
get { return _selectedCity; }
set
{
_selectedCity = value;
RaisePropertyChanged(() => SelectedCity);
}
}
public IEnumerable<string> AvailableCities
{
get { return _availableCities; }
}
protected override bool Validate(string propertyName)
{
var isValid = base.Validate(propertyName);
if (MatchesProperty(() => SelectedCity, propertyName))
{
isValid = SelectedCity != null;
}
return isValid;
}
}
在 TravelPlan 视图模型中,我只使用 CityViewModel。
private ObservableCollection<CitiesViewModel> _cities;
在 TravelPlan 视图模型中,我还实现了 + / - 按钮。他们只需添加或删除城市视图模型。
这非常有效。
但是,我还想添加验证以查看所选城市的组合是否唯一(即,您不能两次选择同一个城市)。我无法将其添加到单个 CityViewModel 中,因为单个城市不知道所有其他选定的城市。
理想情况下,我想在自己的 ViewModel 中转换 CityViewModels 的 ObservableCollection。然后我可以将唯一验证添加到该特定视图模型。我相信我也可以将动态用户控件的逻辑移至该视图模型。
这将创建以下层次结构:TravelPlanViewModel - CitiesViewModels - CityViewmodel,其中每个视图模型都进行特定的验证。
这可能吗?是否推荐这样做?我想知道人们如何以 MVVM 方式解决这个特定的设计问题。 (我知道可以将唯一验证移动到 TravelPlan 视图模型中,但我想知道我描述的场景是否可行并且是一种常见做法)。
非常感谢代码示例!
【问题讨论】:
-
你是对的,如果你有多个城市供用户选择,你必须在比 cityViewModel 本身更高的级别实现验证规则。为此,您可能希望在视图中更高的下一个 XAML 层实现 ValidationRule。 WPF 将调用 ValidationRules 并自动为您生成结果。看看这门课msdn.microsoft.com/en-us/library/…
-
@user1522548,我知道这一点。但是我在哪里进行验证?进入 TravelPlanViewModel?还是创建一个单独的 CitiesViewModel 更好?
-
当然,我们还没有看到 CitesViewModel 或 TravelPlanViewModel 提供正确的建议。如前所述,您必须在位于 CityViewModel 位置的下一个容器中实现它。通常,正确的方法是在最接近需要的容器中进行。换句话说,如果您可以将其包含在层次结构中的较低位置,请不要将其置于顶层窗口层。我经常使用的技巧之一是创建实现组合行为的容器。按照您提到的顺序,我可能会创建一个 CitesViewModel,其中包含所需的所有 CityViewModel。
-
“遏制”或“偏好组合胜过继承”的力量非常有效!我使用这个概念的次数越多,我的应用程序就越好。所有你需要记住的是这个“是我正在处理的事物的一种类型或者它是否包含一种事物的类型。它包含一种事物的类型,只需将它作为属性放入,或者注入它通过构造函数。如果它是 - 那个东西的类型继承它。