【问题标题】:ObservableCollection Bound from ViewModel Does Not Update View从 ViewModel 绑定的 ObservableCollection 不更新视图
【发布时间】:2013-08-13 06:45:30
【问题描述】:

我允许用户通过视图中的 ContextMenu 菜单项删除项目,我希望在视图中自动看到效果。到目前为止,视图中的项目一直存在,直到应用程序重新启动,在这种情况下,它不再可见。这对于认为该项目已从应用程序中完全删除的用户来说是非常混乱的。我的问题是,我做错了什么可以解决这个问题?

App.xaml.cs

//PictureRepository is a class that gathers pictures from IsolatedStorage
public static PictureRepository PictureList
    {
        get
        {
            return PictureRepository.Instance;
        }
    }

PictureRepository.cs

#region Constants

    public const string IsolatedStoragePath = "Pictures";

    #endregion

    #region Fields

    private readonly ObservableCollection<Picture> _pictures = new ObservableCollection<Picture>();

    #endregion

    #region Properties

    public ObservableCollection<Picture> Pictures
    {
        get { return _pictures; }
    }

    #endregion

    #region Singleton Pattern

    private PictureRepository()
    {
        LoadAllPicturesFromIsolatedStorage();
    }

    public static readonly PictureRepository Instance = new PictureRepository();

    #endregion

    /// <summary>        
    /// Saves to local storage
    /// This method gets two parameters: the captured picture instance and the name of the pictures folder in the isolated storage
    /// </summary>
    /// <param name="capturedPicture"></param>
    /// <param name="directory"></param>
    public void SaveToLocalStorage(CapturedPicture capturedPicture, string directory)
    {
        //call IsolatedStorageFile.GetUserStoreForApplication to get an isolated storage file
        var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
        //Call the IsolatedStorageFile.EnsureDirectory extension method located in the Common IsolatedStorageFileExtensions class to confirm that the pictures folder exists.
        isoFile.EnsureDirectory(directory);

        //Combine the pictures folder and captured picture file name and use this path to create a new file 
        string filePath = Path.Combine(directory, capturedPicture.FileName);
        using (var fileStream = isoFile.CreateFile(filePath))
        {
            using (var writer = new BinaryWriter(fileStream))
            {
                capturedPicture.Serialize(writer);
            }
        }
    }

    /// <summary>
    /// To load all saved pictures and add them to the pictures list page
    /// </summary>
    public CapturedPicture LoadFromLocalStorage(string fileName, string directory)
    {
        //To open the file, add a call to the IsolatedStorageFile.GetUserStoreForApplication
        var isoFile = IsolatedStorageFile.GetUserStoreForApplication();

        //Combine the directory and file name
        string filePath = Path.Combine(directory, fileName);
        //use the path to open the picture file from the isolated storage by using the IsolatedStorageFile.OpenFile method
        using (var fileStream = isoFile.OpenFile(filePath, FileMode.Open, FileAccess.Read))
        {
            //create a BinaryReader instance for deserializing the CapturedPicture instance
            using (var reader = new BinaryReader(fileStream))
            {
                var capturedPicture = new CapturedPicture();
                //create a new instance of the type CapturedPicture called CapturedPicture.Deserialize to deserialize the captured picture and return it
                capturedPicture.Deserialize(reader);
                return capturedPicture;
            }
        }
    }

    /// <summary>
    /// To load all the pictures at start time
    /// </summary>
    private void LoadAllPicturesFromIsolatedStorage()
    {
        //add call to the IsolatedStorageFile.GetUserStoreForApplication to open an isolated storage file
        var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
        //Call the IsolatedStorageFile.EnsureDirectory extension method located in the Common IsolatedStorageFileExtensions class to confirm that the pictures folder exists
        isoFile.EnsureDirectory(IsolatedStoragePath);

        //Call the IsolatedStorageFile.GetFileNames using the pictures directory and *.jpg as a filter to get all saved pictures
        var pictureFiles = isoFile.GetFileNames(Path.Combine(IsolatedStoragePath, "*.jpg"));
        //var pictureFiles = isoFile.GetFileNames(Path.Combine(IsolatedStoragePath, ""));

        //Iterate through all the picture files in the list and load each using the LoadFromLocalStorage you created earlier
        foreach (var pictureFile in pictureFiles)
        {
            var picture = LoadFromLocalStorage(pictureFile, IsolatedStoragePath);
            _pictures.Add(picture);
        }
    }

MainPage.xaml.cs

protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        //Recent is the ListBox in the view that is populated from the ObservableCollection
        if (Settings.AscendingSort.Value)
        {
            //Recent.ItemsSource = PictureRepository.Instance.Pictures.OrderBy(x => x.DateTaken);
            Recent.ItemsSource = App.PictureList.Pictures.OrderBy(x => x.DateTaken);
        }
        else
        {
            //Recent.ItemsSource = PictureRepository.Instance.Pictures.OrderByDescending(x => x.DateTaken);
            Recent.ItemsSource = App.PictureList.Pictures.OrderByDescending(x => x.DateTaken);
        }        
    }

//My attempt at deleting the item from both the View and IsolatedStorage
private void deleteContextMenuItem_Click(object sender, RoutedEventArgs e)
    {
        var listBoxItem = ((MenuItem)sender).DataContext as CapturedPicture;
        fileName = listBoxItem.FileName;

        if (fileName != null)
        {
            try
            {
                //Neither of the following remove the item from the View immediately
                App.PictureList.Pictures.Remove(listBoxItem);
                PictureRepository.Instance.Pictures.Remove(listBoxItem);


                    //To open the file, add a call to the IsolatedStorageFile.GetUserStoreForApplication
                    var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
                    //Combine the directory and file name
                    string filePath = Path.Combine(PictureRepository.IsolatedStoragePath, fileName);
                    isoFile.DeleteFile(filePath);
            }
            catch
            {
                MessageBoxResult r = MessageBox.Show("There was an error deleting the image.", "Notice", MessageBoxButton.OK);
                if (r == MessageBoxResult.OK)
                    return;
            }            
        }
    }

如您所见,我正在尝试从视图和独立存储中删除该项目。截至目前,从 IsolatedStorage 中的删除工作正常,但我似乎无法让视图自动更新?我必须等到应用程序重新启动并在 OnNavigatedTo 事件中重新填充 ListBox 才能看到任何更改。

【问题讨论】:

    标签: c# windows-phone-7 mvvm windows-phone-8 listbox


    【解决方案1】:

    问题是您正在将 IOrderedEnumerable 分配给 Recent.ItemSource 而不是 ObservableCollection。

    在 LoadAllPicturesFromIsolatedStorage() 中创建一个临时列表,您可以在其中添加从文件加载的数据,然后创建 ObservableCollection。

    PictureRepository.cs

    #region Constants
    
    public const string IsolatedStoragePath = "Pictures";
    
    #endregion
    
    #region Properties
    
    public ObservableCollection<Picture> Pictures
    {
        get; private set;
    }
    
    #endregion
    
    #region Singleton Pattern
    
    private PictureRepository()
    {
        LoadAllPicturesFromIsolatedStorage();
    }
    
    public static readonly PictureRepository Instance = new PictureRepository();
    
    #endregion
    
    /// <summary>        
    /// Saves to local storage
    /// This method gets two parameters: the captured picture instance and the name of the pictures folder in the isolated storage
    /// </summary>
    /// <param name="capturedPicture"></param>
    /// <param name="directory"></param>
    public void SaveToLocalStorage(CapturedPicture capturedPicture, string directory)
    {
        //call IsolatedStorageFile.GetUserStoreForApplication to get an isolated storage file
        var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
        //Call the IsolatedStorageFile.EnsureDirectory extension method located in the Common IsolatedStorageFileExtensions class to confirm that the pictures folder exists.
        isoFile.EnsureDirectory(directory);
    
        //Combine the pictures folder and captured picture file name and use this path to create a new file 
        string filePath = Path.Combine(directory, capturedPicture.FileName);
        using (var fileStream = isoFile.CreateFile(filePath))
        {
            using (var writer = new BinaryWriter(fileStream))
            {
                capturedPicture.Serialize(writer);
            }
        }
    }
    
    /// <summary>
    /// To load all saved pictures and add them to the pictures list page
    /// </summary>
    public CapturedPicture LoadFromLocalStorage(string fileName, string directory)
    {
        //To open the file, add a call to the IsolatedStorageFile.GetUserStoreForApplication
        var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
    
        //Combine the directory and file name
        string filePath = Path.Combine(directory, fileName);
        //use the path to open the picture file from the isolated storage by using the IsolatedStorageFile.OpenFile method
        using (var fileStream = isoFile.OpenFile(filePath, FileMode.Open, FileAccess.Read))
        {
            //create a BinaryReader instance for deserializing the CapturedPicture instance
            using (var reader = new BinaryReader(fileStream))
            {
                var capturedPicture = new CapturedPicture();
                //create a new instance of the type CapturedPicture called CapturedPicture.Deserialize to deserialize the captured picture and return it
                capturedPicture.Deserialize(reader);
                return capturedPicture;
            }
        }
    }
    
    /// <summary>
    /// To load all the pictures at start time
    /// </summary>
    private void LoadAllPicturesFromIsolatedStorage()
    {
        //add call to the IsolatedStorageFile.GetUserStoreForApplication to open an isolated storage file
        var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
        //Call the IsolatedStorageFile.EnsureDirectory extension method located in the Common IsolatedStorageFileExtensions class to confirm that the pictures folder exists
        isoFile.EnsureDirectory(IsolatedStoragePath);
    
        //Call the IsolatedStorageFile.GetFileNames using the pictures directory and *.jpg as a filter to get all saved pictures
        var pictureFiles = isoFile.GetFileNames(Path.Combine(IsolatedStoragePath, "*.jpg"));
        //var pictureFiles = isoFile.GetFileNames(Path.Combine(IsolatedStoragePath, ""));
    
        var pictures = new List<Picture>();
    
        //Iterate through all the picture files in the list and load each using the LoadFromLocalStorage you created earlier
        foreach (var pictureFile in pictureFiles)
        {
            var picture = LoadFromLocalStorage(pictureFile, IsolatedStoragePath);
            pictures.Add(picture);
        }
    
        Pictures = new ObservableCollection<Picture>(pictures.OrderBy(x => x.DateTaken));
    }
    

    在 MainPage.cs 上将 OnNavigatedTo 方法更改为:

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        //Recent is the ListBox in the view that is populated from the ObservableCollection
        //Recent.ItemsSource = PictureRepository.Instance.Pictures.OrderBy(x => x.DateTaken);
        Recent.ItemsSource = App.PictureList.Pictures;
    }
    

    【讨论】:

    • 我已经尝试过您的解决方案,它确实有效。但是,我唯一的问题是,在我的 MainPage.xaml OnNavigatedTo 事件中,我让用户选择是升序还是降序排序,我已经更新了我的原始问题以显示这一点。使用新解决方案,我将无法保留此功能?我尝试将我的If Else 检查放在按日期排序的LoadAllPicturesFromIsolatedStorage 事件中,但这在重新启动应用程序之前不会显示效果?
    • 你可以使用一个 CollectionViewSource 来包装你的 ObservableCollection。查看此链接以获取示例:babaandthepigman.wordpress.com/2011/07/03/… 然后您将能够即时过滤和排序您的收藏。
    猜你喜欢
    • 2021-01-24
    • 1970-01-01
    • 2013-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-07
    • 1970-01-01
    • 2012-12-16
    相关资源
    最近更新 更多