You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
        }
    }
}

问题根源与修正方案

核心问题

  1. Model类混淆:定义了空的CoffeeModel类,但实际带属性和通知实现的是Coffee类,ViewModel的集合用CoffeeModel作为元素类型,反序列化和绑定都指向空类,自然没有数据显示。
  2. ObservableCollection重复实例化:LoadCoffee方法里重新创建CoffeeList,导致之前的绑定引用失效。
  3. 属性命名与绑定路径:小写属性虽能绑定,但不符合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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 16:49:51