我遇到了一个问题,因为我有一个视图,其中所有控件都是在运行时创建的。
我正在尝试将它们中的每一个绑定到我的viewmodel,但我认为我的方法可能不对。
我们将以组合框为例。
我的模型包含数据:
public class ModelToContainTheData
{
public string BuildType { get; set; }
public string Section { get; set; }
public string QuestionID { get; set; }
public string Values { get; set; }
public int Selectable { get; set; }
public DateTime Changed { get; set; }
public string User { get; set; }
}
然后我创建了这个模型的数组,将以下方法绑定到ComboBox.SelectionChanged
private void ComboboxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var box = sender as ComboBox;
foreach(ModelToContainTheDatamodel in currentSettingsModel)
{
if(model != null)
if(model.QuestionID == box.Name)
{
model.Changed = DateTime.Now;
model.Values = box.SelectedValue.ToString();
model.User = "wc_set";
}
}
}
我想要做的是将数组绑定到viewmodel。有没有正确的方法来做到这一点,还是我需要完全改变我的approch?
我认为ObservableCollection可能是要走的路,但我无法弄清楚我是如何绑定它的。
答案 0 :(得分:4)
你的例子中有一些混乱。我建议熟悉MVVM模式,然后回到实际问题。 MVVM的主要思想(我认为你的目标是MVVM,因为你在谈论模型,视图和ViewModel)是为了解耦视图和模型。在MVVM中要避免订阅UI事件(如SelectionChanged
)。
您正在紧密地耦合UI和模型,尤其是通过将模型属性与UI控件属性(model.QuestionID == box.Name
)匹配。
我将简要解释一下以MVVM方式解决问题的一般概念:
您的模型需要全面了解您应用的域名世界中发生的事情。你有问题等等,所有这些都需要在域逻辑中表示,也称为业务逻辑。你有几堂课。我只是根据我对你的代码所理解的内容做了些什么,不知道它是否与你想要的东西相符......
// Model for an answer ('Value' in your question
public class Answer { ... }
// Model for a question containing possible answers and the actual answer
public class Question
{
private Answer _answer;
public List<Answer> PossibleAnswers { get; set; }
public Answer Answer { get; set; }
public DateTime Changed { get; set; }
public Question()
{
// Acquire the values from wherever
PossibleAnswers = ...;
}
}
请注意,该模型完全是独立的,这意味着它对ViewModel或View一无所知。
现在,您为此模型创建一个ViewModel,它将以一种视图可以绑定到您想要显示的数据的方式公开属性。在最简单的情况下,您只需转发模型的属性。使用实现INotifyPropertyChanged
的适当基类。有很多MVVM框架,比如MVVMLight:
public class QuestionViewModel : NotifyingObject
{
public Question Model { get; private set; }
public List<AnswerViewModel> PossibleAnswers
{
get { return _possibleAnswers; }
}
public DateTime Changed
{
get { return Model.Changed; }
public AnswerViewModel Answer
{
get { return _answer; }
set
{
_answer = value;
// Set properties on your model which are effected
_model.Answer = _answer.Model;
_model.Changed = DateTime.Now;
// Raise property changed events. They are needed
// to update the UI
RaisePropertyChanged("Answer");
RaisePropertyChanged("Date");
}
}
public QuestionViewModel(Question model)
{
Model = model;
_possibleAnswers = Model.Answers.Select(a => new AnswerViewModel(a));
}
}
public class AnswerViewModel { ... }
如您所见,ViewModel 了解模型,并将其自身值的变化传递给模型。但同样, ViewModel并没有关于View 的任何内容。
View使用WPF魔法绑定到ViewModel。您只需确保将View的DataContext
设置为ViewModel。有很多方法可以实现这一点,MVVMLight等MVVM框架也提供了这样做的方法。我只会在这里展示用法。假设你有ComboBox:
<ComboBox ItemsSource="{Binding PossibleAnswers}"
SelectedItem="{Binding Answer}" />
就是这样。 WPF负责其余部分。
在更复杂的场景中,您的模型上的集合可以主动更改,即不仅由UI中的用户而且还有其他原因,它会变得更复杂一些。然后,您需要同步模型和ViewModel上的集合。
这是你最终会遇到的更高级的东西。如果你到达那里,这个答案可能对你有帮助:
SO Answer on Collections on Model and ViewModels
这个答案起初可能有点压倒性,所以我建议使用网络上众多非常好的资源之一挖掘MVVM。使用我的答案作为指导,为您的实际问题找到解决方案。如果您在MVVM教程的帮助下理解了这个答案,那么您将适合以适当的MVVM方式解决您的问题。
编辑:关于动态创建UI元素
在WPF和MVVM中,您所描述的动态控件创建是一个非常自然的概念。基本思想是使用绑定到ViewModelItems集合的ItemsControl
并使用DataTemplate
来指定每个ViewModel的呈现方式。没有限制,每个项目都可以在复杂的控件中呈现,并且可以通过'ItemsControl的ItemsPanel
属性指定布局。在深入了解MVVM时,事情会变得清晰,而你的场景是MVVM解决的常见问题。只要留意WPF ItemsControl
以及你可以用它做什么......