简体   繁体   English

使用MVVM Light在ObservableCollection上的UI上更新项目

[英]Updating items at UI on an ObservableCollection using MVVM Light

So I have an ObservableCollection<Term> on a view model, with Term items having some data properties. 所以我在视图模型上有一个ObservableCollection<Term> ,其中Term项具有一些数据属性。

Term class: Term班:

using SQLite;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Neomilano.Model
{
    public class Term
    {
        public int ID { get; set; }

        public string Name { get; set; }

        public DateTimeOffset TermStart { get; set; }

        public DateTimeOffset TermEnd { get; set; }

        public string DurationText 
        {
            get 
            {
                return "from " + TermStart.Date.ToString("MMMM d, yyyy") + " to " + TermEnd.Date.ToString("MMMM d, yyyy");
            }        
        }

        public Term()
        {
        }
    }
}

This is the ViewModel in question that has the ObservableCollection ( ProjectBaseViewModel implements MVVM Light's ViewModelBase and has few properties that I don't think is necessary here): 这是有问题的具有ObservableCollection的ViewModelBaseProjectBaseViewModel实现了MVVM Light的ViewModelBase并且具有一些我认为不需要的属性):

using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Threading;
using Microsoft.Practices.ServiceLocation;
using Neomilano.Model;
using Neomilano.Services;
using SQLite;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Windows.Foundation;


namespace Neomilano.ViewModel
{
    public partial class TermsViewModel : ProjectBaseViewModel
    {

        public IDialogService DialogService
        {
            get { return ServiceLocator.Current.GetInstance<IDialogService>(); }
        }

#region properties
        private ObservableCollection<Term> _terms;
        public ObservableCollection<Term> Terms {
            get { return this._terms; }
            private set { Set(() => Terms, ref _terms, value); }
        }
#endregion

#region commands

        private RelayCommand<int> _deleteTermCommand;
        public RelayCommand<int> DeleteTermCommand
        {
            get 
            {
                return _deleteTermCommand ??
                    (_deleteTermCommand = new RelayCommand<int>(async id => {
                        var t = "Are you sure you want to delete this term?";
                        var c = "This cannot be undone.";
                        var ct = "delete";
                        bool deleteConfirmed = await DialogService.ShowConfirmationDialogAsync(t, c, ct);

                        if (deleteConfirmed == true)
                            await ExecuteDeleteTermAsync(id);
                    }));
            }
        }

#endregion

        public TermsViewModel()
        {
            if (IsInDesignMode)
            {
                List<Term> t = new List<Term>();

                t.Add(new Term() { ID=1, Name = "Sample Term 1", TermStart = DateTimeOffset.Parse("October 1, 2013"), TermEnd = DateTimeOffset.Parse("December 17, 2013") });
                t.Add(new Term() { ID=2, Name="Sample Term 2", TermStart=DateTimeOffset.Parse("January 1, 2014"), TermEnd=DateTimeOffset.Parse("April 30, 2014") });

                Terms = new ObservableCollection<Term>(t);
            }

        }

        /// <summary>
        /// Gets the list of Terms from the database and adds it to the Terms property of the ViewModel.
        /// </summary>
        /// <returns></returns>
        public async Task GetTermsListAsync()
        {
            IsProgressEnabled = true;

            List<Term> list = new List<Term>();
            await Task.Run(() =>
            {
                using (var db = new SQLiteConnection(app.DBFileName))
                {
                    list = db.Table<Term>().ToList<Term>();
                    db.Close();
                }
            });
            Terms = new ObservableCollection<Term>(list);

            IsProgressEnabled = false;
        }

        /// <summary>
        /// Returns the term ID of the selected term from the view.
        /// </summary>
        /// <param name="clickedItem"></param>
        /// <returns></returns>
        public Term ReturnSelectedTerm(object clickedItem)
        {
            return (Term)clickedItem;
        }

        public async Task ExecuteDeleteTermAsync(int termId)
        {
            IsProgressEnabled = true;

            Term t = new Term();
            await Task.Run(() =>
            {
                using (var db = new SQLiteConnection(app.DBFileName))
                {
                    var q = db.Table<Term>().Where(tr => tr.ID.Equals(termId));
                    t = q.First<Term>();

                    db.Delete<Term>(termId);
                    db.Close();
                }
            });

            var target = Terms.Single<Term>(tr => tr.ID.Equals(termId));
            Terms.Remove(target);

            IsProgressEnabled = false;
        }
    }
}

THE ISSUE: Sure, adding and removing terms from another page work well. 问题:当然,在另一个页面中添加和删除术语会很好。 When the Term items get updated, however, only the title gets updated. 但是,当Term项更新时,仅标题会更新。

Here's what's on the view: 这是视图上的内容:

            <ListView 
                x:Name="TermsListView"
                ItemsSource="{Binding Terms}" 
                IsItemClickEnabled="True"
                ItemClick="OnTermItemClick">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Holding="OnTermItemHold">
                            <FlyoutBase.AttachedFlyout>
                                <MenuFlyout x:Name="TermItemContextMenu">
                                    <MenuFlyoutItem Text="edit" Command="{Binding TermsViewModel.NavigateToFormCommand, Mode=OneWay, Source={StaticResource Locator}}" CommandParameter="{Binding}" />
                                    <MenuFlyoutItem Text="delete" Command="{Binding TermsViewModel.DeleteTermCommand, Mode=OneWay, Source={StaticResource Locator}}" CommandParameter="{Binding ID}" />
                                </MenuFlyout>
                            </FlyoutBase.AttachedFlyout>
                            <TextBlock Text="{Binding Name}"  Style="{ThemeResource ListViewItemTextBlockStyle}"/>
                            <TextBlock Text="{Binding DurationText}" Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}"/>
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>

Term.DurationText does not update when the two date values have changed. 当两个日期值更改时, Term.DurationText不会更新。 If the edit page is to be seen however, the change is reflected in the DatePickers. 但是,如果要查看编辑页面,则更改将反映在DatePickers中。

Is there any way that I can make DurationText update accordingly through Binding in such a way that it works with an implementation using MVVM Light ? 有什么方法可以通过Binding使DurationText更新, 使其可以与使用MVVM Light的实现一起使用

I have tried this but the error says: 我已经尝试过了,但是错误提示:

The type 'Neomilano.Model.Term' cannot be used as type parameter 'T' in the generic type or method 'Neomilano.Common.ItemsChangeObservableCollection'. 类型“ Neomilano.Model.Term”不能用作通用类型或方法“ Neomilano.Common.ItemsChangeObservableCollection”中的类型参数“ T”。 There is no implicit reference conversion from 'Neomilano.Model.Term' to 'System.ComponentModel.INotifyPropertyChanged'. 从“ Neomilano.Model.Term”到“ System.ComponentModel.INotifyPropertyChanged”没有隐式引用转换。

Project specs: * This is a WinRT app * It's a universal Windows App, but I'm working on Windows Phone first right now. 项目规格:*这是WinRT应用程序*这是通用的Windows应用程序,但是我现在首先在Windows Phone上工作。 I think this doesn't matter because of the convergence bet. 我认为这没关系,因为会合赌注。 WinRT and WinPRT, but who knows this might be the problem * As I have mentioned, I'm using MVVM Light(libraries only). WinRT和WinPRT,但谁知道这可能是问题所在*如前所述,我正在使用MVVM Light(仅库)。

So, in general, how can I update the contents of an item of an ObservableCollection in WinRT using MVVM Light ? 因此,总的来说, 如何使用MVVM Light更新WinRT中ObservableCollection项的内容

Thank you for your help! 谢谢您的帮助!

You don't need anything in the linked article, you simply need Term to impllement INotifyPropertyChanged . 链接文章中不需要任何内容​​,只需要使用Term即可实现INotifyPropertyChanged ObservableCollection<T> only notifies the ListView bound to it that the content of the collection has changed, ie it notifies add, remove, move, replace, reset etc. It doesn't monitor the items within the collection for changes. ObservableCollection<T>仅通知绑定到它的ListView集合的内容已更改,即,它通知添加,删除,移动,替换,重置等。它不会监视集合中的项是否发生更改。

In this case, you can make Term derive from ViewModelBase , as this contains an implementation of INotifyPropertyChanged . 在这种情况下,您可以使TermViewModelBase派生,因为它包含INotifyPropertyChanged的实现。

An example is below. 下面是一个示例。 Note how the setter for TermStart also raises a change event for DurationText , as this property is dependent. 请注意, TermStart的设置程序还如何引发DurationText的change事件,因为此属性是依赖的。

public class Term : ViewModelBase
{
    private int _id;
    private string _name;
    private DateTimeOffset _termStart;
    private DateTimeOffset _termEnd;

    public int Id
    {
        get { return _id; }
        set
        {
            if (value == _id) return;
            _id = value;
            RaisePropertyChanged("Id");
        }
    }

    public string Name
    {
        get { return _name; }
        set
        {
            if (value == _name) return;
            _name = value;
            RaisePropertyChanged("Name");
        }
    }

    public DateTimeOffset TermStart
    {
        get { return _termStart; }
        set
        {
            if (value.Equals(_termStart)) return;
            _termStart = value;
            RaisePropertyChanged("TermStart");
            RaisePropertyChanged("DurationText");
        }
    }

    public DateTimeOffset TermEnd
    {
        get { return _termEnd; }
        set
        {
            if (value.Equals(_termEnd)) return;
            _termEnd = value;
            RaisePropertyChanged("TermEnd");
            RaisePropertyChanged("DurationText");
        }
    }

    public string DurationText
    {
        get { return "from " + TermStart.Date.ToString("MMMM d, yyyy") + " to " + TermEnd.Date.ToString("MMMM d, yyyy"); }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM