GUI / view没有注意到viewmodel中的更改。谁应该通知?

时间:2011-09-28 06:45:40

标签: silverlight silverlight-4.0 mvvm

我对Silverlight很新,并对通知机制有疑问。我的解决方案是像这样堆叠的MVVM应用程序:

VIEW 包含绑定到viewmodel中集合的RadGridView,该数据是一个entitycollection。 GridView的SelectedItem绑定到viewmodel中的相应属性。

视图模型 保存GridView绑定的以下属性并实现INotifyPropertyChanged。  •SelectList - 继承ObservableCollection的entitycollection。设置SelectList时,它会运行通知调用。 •SelectedItem - 也为其自己的属性实现INotifyPropertyChanged的实体。设置SelectedItem后,它将运行通知调用。

我的问题是,谁应该进行通知调用,以便GridView知道值已经改变了?有时,实体中的属性是以编程方式直接在viewmodel中设置的。至于现在,尽管属性正确地获取了新值,但GUI中没有发生任何事情。

问候,Clas

- 更新代码-------------------------

查看

<UserControl 
    xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
    x:Class="X.Y.Z.MonthReport.MonthReportView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot">
        <telerik:RadGridView x:Name="MonthReportGrid"
                             Grid.Row="1"
                             ItemsSource="{Binding SelectList}"
                             SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
                             AutoGenerateColumns="False">
            <telerik:RadGridView.Columns>
                <!-- The other columns have been cut out of this example -->
                <telerik:GridViewDataColumn DataMemberBinding="{Binding curDate, Mode=TwoWay, TargetNullValue=''}" DataFormatString="{} {0:d}" Header="Avläst datum" UniqueName="curDate" IsVisible="True" IsReadOnly="False">
                    <telerik:GridViewDataColumn.CellEditTemplate>
                        <DataTemplate>
                            <telerik:RadDateTimePicker SelectedValue="{Binding curDate, Mode=TwoWay, TargetNullValue=''}" InputMode="DatePicker" DateTimeWatermarkContent="ÅÅÅÅ-MM-DD" />
                        </DataTemplate>
                    </telerik:GridViewDataColumn.CellEditTemplate>
                </telerik:GridViewDataColumn>
                <telerik:GridViewDataColumn DataMemberBinding="{Binding curValue, Mode=TwoWay, TargetNullValue=''}" Header="Avläst värde" UniqueName="curValue" IsVisible="True" IsReadOnly="False" />
        </telerik:RadGridView>
    </Grid>
</UserControl>

查看.CS

using System;
using System.Collections.Generic;
using System.Windows.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Windows.Controls;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.GridView;


namespace X.Y.Z.MonthReport
{

    public partial class MonthReportView : UserControl, IMonthReportView
    {
        /// <summary>
        /// ViewModel attached to the View
        /// </summary>
        public IMonthReportViewModel Model
        {
            get {   return this.DataContext as IMonthReportViewModel; }
            set {   this.DataContext = value; }
        }

        public MonthReportView()
        {
            InitializeComponent();
            this.MonthReportGrid.CellEditEnded += new EventHandler<GridViewCellEditEndedEventArgs>(MonthReportGrid_OnCellEditEnded);
        }


        public void MonthReportGrid_OnCellEditEnded(object sender, GridViewCellEditEndedEventArgs e)
        {
            if (e.Cell.Column.UniqueName == "curValue")
            {
                // ...
                this.Model.SetAutomaticReadingDate();
            }

            if (e.Cell.Column.UniqueName == "curDate")
            {
                this.Model.UpdateAutomaticReadingDate();
            }
        }
    }
}

视图模型

using System;
using Microsoft.Practices.Prism.Events;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Prism.Commands;


namespace X.Y.Z.MonthReport
{
    public class MonthReportViewModel : ViewModel<IMonthReportView>, IMonthReportViewModel
    {
        private readonly IEventAggregator eventAggregator;
        private readonly IMonthReportService dataService;
        private readonly IMonthReportController dataController;


        private DateTime? _newReadingDate;
        public DateTime? NewReadingDate
        {
            get { return _newReadingDate; }
            set { _newReadingDate = value; }
        }

        //Holds the selected entity
        private MonthReportEntity _selectedItem;
        public MonthReportEntity SelectedItem
        {
            get { return _selectedItem; }
            set
            {
                if (_selectedItem != value)
                {
                    _selectedItem = value;
                    //The INotifyPropertyChanged implementation inherited from ViewModel-base.
                    Notify(() => this.SelectedItem);
                }
            }
        }

        //The entitycollection
        private MonthReportEntityCollection _selectList;
        public MonthReportEntityCollection SelectList
        {
            get { return _selectList; }
            set
            {
                if (_selectList != value)
                {
                    _selectList = value;
                    //The INotifyPropertyChanged implementation inherited from ViewModel-base.
                    Notify(() => this.SelectList);
                }
            }
        }

        public MonthReportViewModel(IMonthReportView view,
            IEventAggregator eventAggregator, IMonthReportService dataService, IMonthReportController dataController)
        {
            this.InitializeCommands();
            this.eventAggregator = eventAggregator;
            this.dataController = dataController;
            this.dataService = dataService;
            this.View = view;
            this.View.Model = this;

            dataService.onGetMonthReportComplete += new EventHandler<MonthReportEventArgs>(OnGetMonthReportComplete);
            dataService.onSaveMonthReportComplete += new EventHandler<MonthReportEventArgs>(OnSaveMonthReportComplete);

            InitializeData();
        }

        public void InitializeCommands()
        {
            // ...
        }

        public void InitializeData()
        {
            GetMonthReport();
        }

        //This function is not working as I want it to.
        //The gridview doesn't notice the new value.
        //If a user edits the grid row, he should not need to
        //add the date manually, Therefor I use this code snippet.
        public void SetAutomaticReadingDate()
        {
            if ((NewReadingDate.HasValue) && (!SelectedItem.curDate.HasValue))
            {
                SelectedItem.curDate = NewReadingDate;
                //The INotifyPropertyChanged implementation inherited from ViewModel-base.
                Notify(() => this.SelectedItem.curDate);
            }
        }

        public void GetMonthReport()
        {
            dataService.GetMonthReport();
        }

        public void SaveMonthReport()
        {
            dataService.SaveMonthReport(SelectList);            
        }

        void OnGetMonthReportComplete(object sender, MonthReportEventArgs e)
        {
            // ...
        }

        void OnSaveMonthReportComplete(object sender, MonthReportEventArgs e)
        {
            // ...       
        }

        #region ICleanable
        public override void Clean()
        {
            base.Clean();
        }
        #endregion
    }
}

2 个答案:

答案 0 :(得分:1)

如果你像这样进行绑定

<telerik:GridViewDataColumn DataMemberBinding="{Binding curValue, Mode=TwoWay, TargetNullValue=''}" Header="Avläst värde" UniqueName="curValue" IsVisible="True" IsReadOnly="False" />

你只需要查看绑定就知道你必须在哪里调用PropertyChanged并且绑定说:

属性“curValue”必须实现INotifyProperyChanged以获取视图通知。

  public void SetAutomaticReadingDate()
    {
        if ((NewReadingDate.HasValue) && (!SelectedItem.curDate.HasValue))
        {
            //this is enough if the class of SelectedItem implements INotifyPropertyChanged
            //and the curDate Poperty raise the event 
            SelectedItem.curDate = NewReadingDate;               
        }
    }

btw BAD代码样式命名属性curDate!它应该是CurDate,带有camlCase的属性会伤害我的眼睛:)

答案 1 :(得分:0)

您的“MonthReportEntityCollection”必须实现“INotifyCollectionChanged”接口,以允许向UI通知集合更改(项目添加/删除)。 您的“MonthReportEntity”必须实现“INotifyPropertyChanged”接口,以允许通知UI有关权限的属性更改。 其他东西看起来是正确的。