2011-09-28 33 views
1

我對Silverlight頗爲陌生,並且對通知機制有疑問。我的解決方案是一個MVVM應用程序堆疊是這樣的:GUI /視圖不會注意視圖模型中的更改。誰應該通知?

VIEW包含綁定到視圖模型集合的RadGridView,該數據是entitycollection。 GridView的SelectedItem被綁定到viewmodel中的相應屬性。

視圖模型 存放低於在GridView被綁定到的屬性和實現INotifyPropertyChanged。 •SelectList - 繼承ObservableCollection的實體集合。當SelectList被設置時,它運行一個通知呼叫。 •SelectedItem - 爲其自身屬性還實現INotifyPropertyChanged的實體。當SelectedItem設置時,它運行一個通知調用。

我的問題是,誰應該進行通知調用,以便GridView知道值已更改?偶爾,實體中的一個屬性直接在視圖模型中以編程方式設置。就目前而言,雖然屬性正確獲取新值,但GUI中沒有任何事情發生。

問候,柯樂

- 使用代碼------------------------- UPDATE

VIEW

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

VIEW .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 
    } 
} 
+0

你是否在後臺線程中操作viewmodel?如果不是,請張貼一些代碼 – thumbmunkeys

回答

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

順便說一句不好的代碼風格名稱的屬性CURDATE!它應該是CurDate,帶有camlCase的屬性會傷害我的眼睛:)

+0

謝謝!它爲我解決了這個問題,但一開始並沒有解決。 INotifyPropertyChanged的實現在基礎實體中是不正確的,所以我也被困住了。 – Clas

0

您的「MonthReportEntityCollection」必須實現接口「INotifyCollectionChanged」以允許向UI通知有關集合更改(項目添加/刪除)的信息。 您的「MonthReportEntity」必須實現「INotifyPropertyChanged」接口,以便通知用戶界面關於物件屬性更改的信息。 其他東西看起來是正確的。

+0

該集合應該是一個ObservableCollection,它可以通知收集的變化,不需要創建一個新的集合。 – Aligned

+0

對齊,並不總是ObservableCollection提供足夠的功能(對於分頁支持,例如最好使用PagedCollectionView)。如果您需要任何帶有附加功能的自定義集合,則必須實施INotifyCollectionChanged以通知UI有關集合更改的信息。 毫無疑問,您可以從ObservableCollection繼承自定義集合。 – Andris

相關問題