在viewmodel和view之间使用MVVM的Wpf datacontext绑定

我刚刚开始学习MVVM,这里似乎是一个基本的问题,但我花了一整天时间试图弄明白。

我有一个解决方案,包含3个项目,一个用于Model,一个用于ViewModel,另一个用于View。 Model包含一个具有2个Text和CheckStatus属性的类。

ViewModel有一个名为listOfItems的列表,它有三个项目,每个项目都包含Model中的这两个属性。

View里面有一个listView,里面有一个CheckBox。 将CheckBox内容绑定到属性Text的正确方法是什么?

这是模型

using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace TheModel { public class CheckBoxListModel : INotifyPropertyChanged { private string text; public string Text { get { return text; } set { text = value; RaiseChanged("Text"); } } private bool checkStatus; public bool CheckStatus { get { return checkStatus; } set { checkStatus = value; RaiseChanged("CheckStatus"); } } private void RaiseChanged(string propName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propName)); } } public event PropertyChangedEventHandler PropertyChanged; } } 

这是视图模型

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Collections.ObjectModel; using TheModel; namespace TheViewModel { public class TheViewModel { public List ListOfItems { get; set; } public TheViewModelClass() { ListOfItems = new List { new CheckBoxListModel { CheckStatus = false, Text = "Item 1", }, new CheckBoxListModel { CheckStatus = false, Text = "Item 2", }, new CheckBoxListModel { CheckStatus = false, Text = "Item 3", } }; } public static implicit operator List(TheViewModelClass v) { throw new NotImplementedException(); } } } 

这是View XAML

           

这是View背后的代码,我知道我不应该在这里有什么东西,但那个部分应该去哪里?

 using System.Windows; using System.Windows.Controls; using System.Collections.Generic; using System.ComponentModel; using System.Windows.Controls.Primitives; using System.Windows.Media; using System; using System.Text; using TheViewModel; namespace TheView.Styles { public partial class ListViewDatabaseStyle : UserControl { public ListViewDatabaseStyle() { InitializeComponent(); } public List selectedNames = new List(); private void CheckBox_Click(object sender, RoutedEventArgs e) { var ChkBox = sender as CheckBox; var item = ChkBox.Content; bool isChecked = ChkBox.IsChecked.HasValue ? ChkBox.IsChecked.Value : false; if (isChecked) selectedNames.Add(item.ToString()); else selectedNames.Remove(item.ToString()); } } } 

首先。 设置项目的依赖关系。 ViewModel必须具有访问View和Model的权限。 (View和Model项目不必引用其他项目。)如果我是你,我会创建一个StartUp Project来将控件转移到ViewModel。 这个“StartUp”项目应该是WPF,所有其他项目应该是“类库”,但不要忘记添加项目所需的引用(例如,为您的视图项目创建usercontrols的system.xaml。)

项目依赖项: – StartUp – > ViewModel; – ViewModel – >查看; – ViewModel – > Model; (我应该为接口创建另一个项目,这只是我的变态。)

启动项目 :现在你的启动(WPF)项目应该包含在(app.xaml.cs)中:

 protected override void OnStartup(StartupEventArgs e) { // delete the startupuri tag from your app.xaml base.OnStartup(e); //this MainViewModel from your ViewModel project MainWindow = new MainWindow(new MainViewModel()); } 

启动wpf项目中唯一的一件事(Window)(显示你的UserControls)。

MainWindow.xaml内容:

    

(和xaml.cs)

  public partial class MainWindow : Window { public MainWindow(INotifyPropertyChanged ViewModel) { InitializeComponent(); this.DataContext = ViewModel; this.Show(); } } 

这就是你所有的StartUp WPF项目。 通过这种方式,我们将控件提供给您的ViewModel项目。

(好吧,它只是一个额外的,但我应该做一个“ViewService”来处理我的UserControls)

用于查找所有View的界面以及View与ViewModel的匹配。

 public interface IControlView { INotifyPropertyChanged ViewModel { get; set; } } 

我创建了一个单例来存储我的视图和我的视图模型。 (您可以跳过此部分。)我在Model项目中定义了这个。

  public class ViewService where T : IControlView { private readonly List cache; public delegate void ShowDelegate(T ResultView); public event ShowDelegate Show; public void ShowControl(INotifyPropertyChanged ViewModel) { if (Show != null) Show(GetView(ViewModel)); } #region Singleton private static ViewService instance; public static ViewService GetContainer { get { if (instance == null) { instance = new ViewService(); } return instance; } } private ViewService() { cache = new List(); var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(s => s.GetTypes()).Where(r => typeof(T).IsAssignableFrom(r) && !r.IsInterface && !r.IsAbstract && !r.IsEnum); foreach (Type type in types) { cache.Add(new WeakReference((T)Activator.CreateInstance(type))); } } #endregion private T GetView(INotifyPropertyChanged ViewModel) { T target = default(T); foreach (var wRef in cache) { if (wRef.IsAlive && wRef.Target.GetType().IsEquivalentTo(typeof(Z))) { target = (T)wRef.Target; break; } } if(target==null) target = (T)Activator.CreateInstance(typeof(Z)); if(ViewModel != null) target.ViewModel = ViewModel; return target; } } 

现在,您已经有了一个“服务”,可以在ViewModel的主窗口中显示您的UserControl:

 public class MainViewModel : INotifyPropertyChanged { private IControlView _control; public IControlView Control { get { return _control; } set { _control = value; OnPropertyChanged(); } } public MainViewModel() { //Subscribe for the ViewService event: ViewService.GetContainer.Show += ShowControl; // in this way, here is how to set a user control to the window. ViewService.GetContainer.ShowControl(new TheViewModel(yourDependencyItems)); //you can call this anywhere in your viewmodel project. For example inside a command too. } public void ShowControl(IControlView ControlView) { Control = ControlView; } //implement INotifyPropertyChanged... protected void OnPropertyChanged([CallerMemberName] string name = "propertyName") { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(name)); } } public event PropertyChangedEventHandler PropertyChanged; } 

如果您不想使用此“ViewService”。 只需创建一个UserControl实例,将View的DataContext与ViewModel匹配,并将此视图提供给Control属性。 这是您的ViewModel列表(仍在ViewMoldel项目中。)

 public class TheViewModel { private readonly ObservableCollection listOfItems; public ObservableCollection ListOfItems { get { return listOfItems; } } public ICommand SaveCheckedItemsText{ get{ return new RelayCommand(CollectNamesOfSelectedElements);} } public IEnumerable GetSelectedElements { get { return listOfItems.Where(item=>item.CheckStatus); } } public TheViewModel(IList dependencyItems) { listOfItems= new ObservableCollection(dependencyItems); } //here is your list... private List selectedNames //use this... private void CollectNamesOfSelectedElements() { selectedNames = new List(); foreach(ISelectable item in GetSelectedElements) { //you should override the ToString in your model if you want to do this... selectedNames.Add(item.ToString()); } } } 

RelayCommand文章

查看:(保留所有用户控件。)

在您的UserControl(xaml)中:

            

这里的接口是xaml.cs代码(用于UserControls):

 public partial class ListViewDatabaseStyle : UserControl, IControlView { public ListViewDatabaseStyle () { InitializeComponent(); } public INotifyPropertyChanged ViewModel { get { return (INotifyPropertyChanged)DataContext; } set { DataContext = value; } } } 

最后一个是与您的模型的Model项目:

  public interface ISelectable { bool CheckStatus { get; set; } } public class CheckBoxListModel : INotifyPropertyChanged, ISelectable { private string text; public string Text { get { return text; } set { text = value; RaiseChanged("Text"); } } private bool checkStatus; public bool CheckStatus { get { return checkStatus; } set { checkStatus = value; RaiseChanged("CheckStatus"); } } private void RaiseChanged(string propName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propName)); } } public event PropertyChangedEventHandler PropertyChanged; } } 

请原谅我的英语语法错误,希望你理解我的post。