This question is locked. New answers and comments are not allowed.
Hello,
I'm stuck with a problem that I can't solve although spending hours of googling for tips on the web. It's a MVVM application where the
viewmodel has a list of entities and an implementation of INotifyPropertyChanged. The view uses RadGridView to display the entities.
The problem occurs when I'm setting a property in one of the entities in the code of the viewmodel. The property gets the value correctly but the GUI doesn't update. I'm thankful for any help I can get, have been spending hours trying to solve this wiht no success. For code excerpts, se below.
Regards, Clas
VIEW
VIEWMODEL
VIEWMODEL BASE CLASS
I'm stuck with a problem that I can't solve although spending hours of googling for tips on the web. It's a MVVM application where the
viewmodel has a list of entities and an implementation of INotifyPropertyChanged. The view uses RadGridView to display the entities.
The problem occurs when I'm setting a property in one of the entities in the code of the viewmodel. The property gets the value correctly but the GUI doesn't update. I'm thankful for any help I can get, have been spending hours trying to solve this wiht no success. For code excerpts, se below.
Regards, Clas
VIEW
<UserControl xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" x:Class="X.Y.Z.MonthReport.MonthReportView" 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" Background="White"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <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>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.BeginningEdit += new EventHandler<GridViewBeginningEditRoutedEventArgs>(MonthReportGrid_OnBeginningEdit); this.MonthReportGrid.CellEditEnded += new EventHandler<GridViewCellEditEndedEventArgs>(MonthReportGrid_OnCellEditEnded); this.MonthReportGrid.SelectionChanged += new EventHandler<SelectionChangeEventArgs>(MonthReportGrid_OnSelectionChanged); } void MonthReportGrid_OnBeginningEdit(object sender, GridViewBeginningEditRoutedEventArgs e) { // ... } 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(); } } public void MonthReportGrid_OnSelectionChanged(object sender, SelectionChangeEventArgs e) { // ... } }}VIEWMODEL
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 bool isLoading; public bool IsLoading { get { return isLoading; } set { if (isLoading != value) { isLoading = value; Notify(() => this.IsLoading); } } } private DateTime? _newReadingDate; public DateTime? NewReadingDate { get { return _newReadingDate; } set { _newReadingDate = value; } } private MonthReportEntity _selectedItem; public MonthReportEntity SelectedItem { get { return _selectedItem; } set { if (_selectedItem != value) { _selectedItem = value; Notify(() => this.SelectedItem); } } } private MonthReportEntityCollection _selectList; public MonthReportEntityCollection SelectList { get { return _selectList; } set { if (_selectList != value) { _selectList = value; 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.IsLoading = true; } public void GetMonthReport() { dataService.GetMonthReport(); } public void SaveMonthReport() { dataService.SaveMonthReport(SelectList); } public void UpdateAutomaticReadingDate() { if (SelectedItem.curDate.HasValue) NewReadingDate = SelectedItem.curDate; } public void SetAutomaticReadingDate() { if ((NewReadingDate.HasValue) && (!SelectedItem.curDate.HasValue)) { SelectedItem.curDate = NewReadingDate; Notify(() => this.SelectedItem.curDate); } } void OnGetMonthReportComplete(object sender, MonthReportEventArgs e) { if (!e.HasError) this.SelectList = e.MonthReportData; else { this.SelectList = null; eventAggregator.GetEvent<ErrorEvent>().Publish(new ErrorEvent { Message = e.Error.ToString(), ExceptionObj = e.Error }); } this.IsLoading = false; } void OnSaveMonthReportComplete(object sender, MonthReportEventArgs e) { if (!e.HasError) { // Is it really necessary to re-set the SelectList with the same data again? //this.SelectList = e.MonthReportData; eventAggregator.GetEvent<MessageShowEvent>().Publish(new MessageShowEvent { MessageTitle = "Bekräftelse", Message = "Månadsrapporteringen sparades." }); } else { this.SelectList = null; eventAggregator.GetEvent<ErrorEvent>().Publish(new ErrorEvent { Message = e.Error.ToString(), ExceptionObj = e.Error }); } this.IsLoading = false; } #region ICleanable public override void Clean() { base.Clean(); //Remove existing references, for example eventhandlers added in constructor //Unsubscribe to subscribed events. } #endregion }}VIEWMODEL BASE CLASS
using System;using System.ComponentModel;using System.Linq.Expressions;using System.Windows;using System.Windows.Threading;using X.Y.Z.Common.Extensions;namespace X.Y.Z.Common{ public class ViewModel<TView> : ViewModel { public TView View { get; protected set; } public override void Clean() { base.Clean(); if (View is FrameworkElement) { FrameworkElement element = View as FrameworkElement; element.RemoveFromParentPanel(); } } } public class ViewModel : INotifyPropertyChanged, IDisposable, ICleanable { public ViewModel() { } public void Notify<TValue>(Expression<Func<TValue>> propertySelector) { if (PropertyChanged != null) { var memberExpression = propertySelector.Body as MemberExpression; if (memberExpression != null) { NotifyPropertyChanged(memberExpression.Member.Name); } } } public event PropertyChangedEventHandler PropertyChanged = delegate { }; protected void NotifyPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = this.PropertyChanged; if (handler != null) { var e = new PropertyChangedEventArgs(propertyName); handler(this, e); } } public void Dispose() { this.Clean(); } public virtual void Clean() { }#if DEBUG ~ViewModel() { string msg = string.Format("{0} ({1}) Finalized", this.GetType().Name, this.GetHashCode()); System.Diagnostics.Debug.WriteLine(msg); }#endif }}