views:

1435

answers:

2

I have a class called IssuesView which implements INotifyPropertyChanged. This class holds an ObservableCollection<Issue> and exposes it as a DependencyProperty called Issues for consumption by Bindings. It is defined as below -

    public class IssuesView : DependencyObject, INotifyPropertyChanged
{
    public Issues Issues
    {
        get { return (Issues)GetValue(IssuesProperty); }
        set
        {
            SetValue(IssuesProperty, value);
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Issues"));
            }
        }
    }

    // Using a DependencyProperty as the backing store for Issues.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty IssuesProperty =
        DependencyProperty.Register("Issues", typeof(Issues), typeof(IssuesView), new UIPropertyMetadata(null));



    public IssuesView()
    {
        Refresh();
    }

    public void Refresh()
    {
        this.Issues = new Issues();
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

I have a test page declared like this -

<Page x:Class="Tracker.Pages.DEMO"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:cont="clr-namespace:Tracker.Controls"
Title="DEMO">
<StackPanel>
    <Button Click="Button_Click">Change</Button>
    <cont:IssueTimeline IssuesForTimeline="{Binding Source={StaticResource issuesView},Path = Issues}"/>
</StackPanel>

The IssuesView class is defined in Application.Resources.
Now in the event hadnler for the button i have this code -

private void Button_Click(object sender, RoutedEventArgs e)
    {
        IssuesView iv = Application.Current.FindResource("issuesView") as IssuesView;
        if (!once)
        {
            foreach (Issue i in iv.Issues)
            {
                i.DormantFor = new TimeSpan(30, 0, 0, 0);
                i.AssignedUserID = 12;
                i.Name = "MyName";
                i.Priority = Issue.Priorities.Critical;
                i.Status = Issue.Statuses.New;
                i.Summary = "NewSummary";
            }
            once = true;
        }
        else
        {
            iv.Refresh();
        }

once is a simple boolean to test mutation of the collection versus repopulation.

The first button click alters the collection's items and the UI is updated properly since the items implement INotifyPropertyChanged but the second click repopulates the collection but does not update the UI even though the event is not null and fires properly.

Why does the UI not update on the second click? How can i make it so that repopulating the collection will cause a UI update?

+1  A: 

First: there's no reason to implement INotifyProperty changed for DependencyProperties. DependencyProperties know when they change.

Second: I don't see an ObservableCollection in your code.

Third: it's not entirely clear to me (from the code you posted) where the issues you modify in the first click come from. I assume from another action, not posted here.

Am I correct if I assume that you want to clear the issues list with the second click (since I don't know what the Issues constructor does)?

Inferis
+1  A: 

You really need to simplify your repro. I can see several things wrong with it, but cannot help to solve your problem without seeing all of it. Here is my simple repro, which works just fine.

Window1.xaml:

<Window x:Name="_root" x:Class="CollectionRepro.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel DataContext="{Binding ElementName=_root}">
     <ItemsControl ItemsSource="{Binding Issues}"/>
     <Button x:Name="_addButton">Add</Button>
     <Button x:Name="_resetButton">Reset</Button>
    </StackPanel>
</Window>

Window1.xaml.cs:

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;

namespace CollectionRepro
{
    public partial class Window1 : Window
    {
     public static readonly DependencyProperty IssuesProperty = DependencyProperty.Register("Issues",
      typeof(ICollection<string>),
      typeof(Window1));

     public ICollection<string> Issues
     {
      get { return (ICollection<string>)GetValue(IssuesProperty); }
      set { SetValue(IssuesProperty, value); }
     }

     public Window1()
     {
      InitializeComponent();
      Reset();

      _addButton.Click +=new RoutedEventHandler(_addButton_Click);
      _resetButton.Click += new RoutedEventHandler(_resetButton_Click);
     }

     void  _resetButton_Click(object sender, RoutedEventArgs e)
     {
      Reset();
     }

     void  _addButton_Click(object sender, RoutedEventArgs e)
     {
      Issues.Add("Another issue");
     }

     private void Reset()
     {
      Issues = new ObservableCollection<string>();
     }
    }
}

HTH, Kent

Kent Boogaart