【问题标题】:How to get View to update when the ViewModel gets changed当 ViewModel 改变时如何让 View 更新
【发布时间】:2019-05-09 13:45:00
【问题描述】:

我正在构建一个 WPF 应用程序来管理存储在 SharePoint 列表中的学生数据库。我是使用 MVVM 的新手,并且已经阅读了一些教程。我已经成功地创建了一个视图和模型,并设法将它绑定到一个数据网格控件。我想做的是根据组合框的输出更新视图中的数据。

这是我的模型:

using System.ComponentModel;

namespace StudentManagement.Model
{
public class Student : INotifyPropertyChanged
{
    private string _Title;
    private string _FullName;

    public string Title
    {
        get { return _Title; }
        set
        {
            if (_Title != value)
            {
                _Title = value;
                RaisePropertyChanged("Title");
            }
        }
    }

    public string FullName
    {
        get { return _FullName; }
        set
        {
            if (_FullName != value)
            {
                _FullName = value;
                RaisePropertyChanged("FullName");
            }

        }

    }



    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string property)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    } 
  }
}

这是视图模型:

using System.Collections.ObjectModel;
using StudentManagement.Model;
using SP = Microsoft.SharePoint.Client;
using StudentManagement.publicClasses;

namespace StudentManagement.ViewModel
{
    public class StudentViewModel
    {
        public ObservableCollection<Student> Students { get; set; }

        public void LoadStudents(string query)
        {


           ObservableCollection<Student> _students = new 
        ObservableCollection<Student>();

        SP.ClientContext ctx = clientContext._clientContext;

        SP.CamlQuery qry = new SP.CamlQuery();
        qry.ViewXml = query;
        SP.ListItemCollection splStudents = 
 ctx.Web.Lists.GetByTitle("Students").GetItems(qry);
        ctx.Load(splStudents);
        ctx.ExecuteQuery();

        foreach (SP.ListItem s in splStudents)
        {
            _students.Add(new Student { Title = (string)s["Title"], FullName = (string)s["FullName"] });
        }
        Students = _students;

        }
    }
}

这是我的 XAML

<UserControl x:Class="StudentManagement.Views.StudentsView"
             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" 
             mc:Ignorable="d" 
  
             xmlns:local="clr-namespace:StudentManagement.Views" >


    <Grid>

        <StackPanel HorizontalAlignment="Left" Width="200" >
            <TextBox Name="txtSearch" AcceptsReturn="True" ></TextBox>
            <ComboBox Name="cmbStatus"  SelectionChanged="cmbStatus_SelectionChanged" SelectedIndex="0">
                <ComboBoxItem>Active</ComboBoxItem>
                <ComboBoxItem>Inquiring</ComboBoxItem>
                <ComboBoxItem>Inactive</ComboBoxItem>
                <ComboBoxItem>Monitoring</ComboBoxItem>
            </ComboBox>
            <DataGrid Name="dgStudentList" ItemsSource="{Binding Path=Students}" AutoGenerateColumns="False">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Name" Binding="{Binding Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="100"/>
                    <DataGridTextColumn Header="Parent" Binding="{Binding FullName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="100" />
                </DataGrid.Columns>
            </DataGrid>
        </StackPanel>
    </Grid>
</UserControl>

...以及视图背后的代码:

using System.Windows.Controls;
using StudentManagement.ViewModel;

namespace StudentManagement.Views
{
    /// <summary>
    /// Interaction logic for StudentsView.xaml
    /// </summary>
    public partial class StudentsView : UserControl
    {
        private StudentViewModel _viewModel = new 
StudentViewModel();

    public StudentsView()
    {
            InitializeComponent();
            DataContext = _viewModel;
        }

        private void cmbStatus_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            string combotext = ((sender as ComboBox).SelectedItem as ComboBoxItem).Content as string;   
            string qry = @"<View>  
                        <Query> 
                            <Where><Eq><FieldRef Name='Current_x0020_Status' /><Value Type='Choice'>" + combotext + @"</Value></Eq></Where> 
                        </Query> 
                       </View>";

            _viewModel.LoadStudents(qry);

        }
    }
}

就目前而言,学生在加载时加载到数据网格中就好了。当事件 cmbStatus_SelectionChanged 触发时,我已经完成了测试,我可以看到 LoadStudents 函数触发并返回正确数量的条目,但数据网格上没有任何更新。

我确定这是一个菜鸟错误,我错过了一些基本的东西,但这个是我的头脑,我很感激任何指导。

【问题讨论】:

  • 创建学生列表后,不要使用新列表重新创建。只需删除现有元素。
  • StudentViewModel 不应命名为 *viewmodel,除非它正确实现了 INotifyPropertyChanged

标签: c# wpf mvvm


【解决方案1】:

由于StudentViewModel.LoadStudents() 更改了Students 属性的值,视图模型需要通知视图这已更改。您可以通过让StudentViewModel 实现INotifyPropertyChanged 来做到这一点(就像Student 一样)。 DataGrid 将订阅 PropertyChanged 事件,并在该事件触发时更新其内容。

【讨论】:

  • 事实证明我需要两者都做。实施 INPC 使其工作,并清除集合(如@MathivananKP 的回答)使其工作速度显着加快。
【解决方案2】:

如果 ComboBox 的选择发生变化,您每次都在初始化学生集合。

ObservableCollection<Student> _students = new ObservableCollection<Student>();

您不应该对 ViewModel 中的绑定集合执行此操作。您可以像这样清除收藏并添加新项目。

public class StudentViewModel
{
    public ObservableCollection<Student> Students { get; set; } = new ObservableCollection<Student>();

    public void LoadStudents(string query)
    {
        Students.Clear();

        SP.ClientContext ctx = clientContext._clientContext;

        SP.CamlQuery qry = new SP.CamlQuery();
        qry.ViewXml = query;
        SP.ListItemCollection splStudents =  ctx.Web.Lists.GetByTitle("Students").GetItems(qry);
        ctx.Load(splStudents);
        ctx.ExecuteQuery();

        foreach (SP.ListItem s in splStudents)
        {
            Students.Add(new Student { Title = (string)s["Title"], FullName = (string)s["FullName"] });
        }
    }
}

【讨论】:

  • 好答案。我还敦促从Students 中省略设置器set;,因此不再可能在没有通知的情况下替换集合。最后,我认为 StudentViewModel 仍然应该对所有属性执行完整的 INPC 实现,因为它具有绑定的属性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-06
  • 2021-08-13
  • 2015-05-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多