MVVM绑定问题:无法将ViewModel绑定到主窗口并展示数据
MVVM架构应用绑定问题:界面仅显示空文本框
我正在学习制作首个MVVM架构应用,却无法掌握如何将ViewModel绑定到MainWindow并在界面展示数据。我的JSON文件包含10个对象,但界面仅显示两行空文本框。以下是我的实现代码:
Model层代码
namespace MVVC.Model { public class CoffeeModel { } public class Coffee : INotifyPropertyChanged { [JsonProperty("coffee_type")] private string _type; [JsonProperty("price")] private double _price; [JsonProperty("roast_level")] private string _roast; [JsonProperty("origin_country")] private string _origin; public string type { get => _type; set { if (value != _type) { _type = value; RaisePropertyChanged("type"); } } } public double price { get => _price; set { if (value != _price) { _price = value; RaisePropertyChanged("price"); } } } public string roast { get => _roast; set { if(value != _roast) { _roast = value; RaisePropertyChanged("roast"); } } } public string origin { get =>_origin; set { if (_origin != value) { _origin = value; RaisePropertyChanged("origin"); } } } public event PropertyChangedEventHandler? PropertyChanged; private void RaisePropertyChanged(string property) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(property)); } } }
ViewModel层代码
namespace MVVC.ViewModel { public class CoffeeViewModel { public ObservableCollection<CoffeeModel> CoffeeList { get; set; } = new ObservableCollection<CoffeeModel>(); public void LoadCoffee() { CoffeeList=new ObservableCollection<CoffeeModel>(); string json = File.ReadAllText("CoffeeData.json"); var CoffeeModels = JsonConvert.DeserializeObject<List<CoffeeModel>>(json); foreach(var coffee in CoffeeModels) { CoffeeList.Add(coffee); } } } }
CoffeeView后台代码
namespace MVVC.Views { /// <summary> /// Interaction logic for CoffeeView.xaml /// </summary> public partial class CoffeeView : UserControl { public CoffeeView() { InitializeComponent(); } } }
我不确定是否应该在此处设置DataContext,且该文件的XAML无法查看,提示意外结束。
CoffeeView的XAML代码
<UserControl x:Class="MVVC.Views.CoffeeView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:MVVC.Views" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <Grid> <StackPanel HorizontalAlignment = "Left"> <ItemsControl ItemsSource = "{Binding Path = CoffeeList}" > <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel Orientation = "Horizontal"> <TextBox Text = "{Binding Path = type, Mode = TwoWay}" Width = "100" Margin = "3 5 3 5"/> <TextBox Text = "{Binding Path = price, Mode = TwoWay}" Width = "100" Margin = "0 5 3 5"/> <TextBlock Text = "{Binding Path = roast, Mode = OneWay}" Margin = "0 5 3 5"/> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </StackPanel> </Grid> </UserControl>
MainWindow后台代码
namespace MVVC { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void CoffeeViewControl_Loaded(object sender, RoutedEventArgs e) { MVVC.ViewModel.CoffeeViewModel coffeeViewModelObject= new ViewModel.CoffeeViewModel(); coffeeViewModelObject.LoadCoffee(); CoffeeViewControl.DataContext= coffeeViewModelObject; } } }
问题根源与修正方案
核心问题
- Model类混淆:定义了空的
CoffeeModel类,但实际带属性和通知实现的是Coffee类,ViewModel的集合用CoffeeModel作为元素类型,反序列化和绑定都指向空类,自然没有数据显示。 - ObservableCollection重复实例化:
LoadCoffee方法里重新创建CoffeeList,导致之前的绑定引用失效。 - 属性命名与绑定路径:小写属性虽能绑定,但不符合C#规范,且硬编码属性名容易出错。
分步修正
1. 修正Model类
删除空的CoffeeModel,把Coffee类重命名为CoffeeModel并保留所有实现,同时优化属性命名和通知方式:
namespace MVVC.Model { public class CoffeeModel : INotifyPropertyChanged { [JsonProperty("coffee_type")] private string _type; [JsonProperty("price")] private double _price; [JsonProperty("roast_level")] private string _roast; [JsonProperty("origin_country")] private string _origin; public string Type { get => _type; set { if (value != _type) { _type = value; RaisePropertyChanged(nameof(Type)); } } } public double Price { get => _price; set { if (value != _price) { _price = value; RaisePropertyChanged(nameof(Price)); } } } public string Roast { get => _roast; set { if(value != _roast) { _roast = value; RaisePropertyChanged(nameof(Roast)); } } } public string Origin { get =>_origin; set { if (_origin != value) { _origin = value; RaisePropertyChanged(nameof(Origin)); } } } public event PropertyChangedEventHandler? PropertyChanged; private void RaisePropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
2. 修正ViewModel
把集合设为只读,避免重复实例化,同时增加空值判断:
namespace MVVC.ViewModel { public class CoffeeViewModel { public ObservableCollection<CoffeeModel> CoffeeList { get; } = new ObservableCollection<CoffeeModel>(); public void LoadCoffee() { CoffeeList.Clear(); string json = File.ReadAllText("CoffeeData.json"); var coffeeModels = JsonConvert.DeserializeObject<List<CoffeeModel>>(json); if (coffeeModels == null) return; foreach(var coffee in coffeeModels) { CoffeeList.Add(coffee); } } } }
3. 修正XAML绑定路径
对应修改为大写开头的属性名,简化绑定语法:
<UserControl x:Class="MVVC.Views.CoffeeView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:MVVC.Views" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <Grid> <StackPanel HorizontalAlignment="Left"> <ItemsControl ItemsSource="{Binding CoffeeList}"> <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBox Text="{Binding Type, Mode=TwoWay}" Width="100" Margin="3 5 3 5"/> <TextBox Text="{Binding Price, Mode=TwoWay}" Width="100" Margin="0 5 3 5"/> <TextBlock Text="{Binding Roast, Mode=OneWay}" Margin="0 5 3 5"/> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </StackPanel> </Grid> </UserControl>
4. 优化DataContext设置
推荐在XAML中声明ViewModel,更符合MVVM规范:
在MainWindow的XAML中添加命名空间引用:
xmlns:vm="clr-namespace:MVVC.ViewModel"
然后设置资源并绑定DataContext:
<Window.Resources> <vm:CoffeeViewModel x:Key="CoffeeVM"/> </Window.Resources> <Grid> <local:CoffeeView DataContext="{StaticResource CoffeeVM}" Loaded="CoffeeViewControl_Loaded"/> </Grid>
修改MainWindow的Loaded事件:
private void CoffeeViewControl_Loaded(object sender, RoutedEventArgs e) { var vm = (CoffeeViewModel)CoffeeViewControl.DataContext; vm.LoadCoffee(); }
内容的提问来源于stack exchange,提问作者KrzysiekYESS
相关产品推荐
相关产品推荐

