简体   繁体   中英

Why wont UI update on RaisePropertyChanged?

I have a static IList which acts as a repository in a static class:

//static class Settings

public static IList RecentSearchedRepo = new ObservableCollection<object>();

and an IList located in another class which I bind my UI grid to :

//component class

private IList recentsearch = new ObservableCollection<object>();
public IList RecentSearch
{
    get
    {
        return recentsearch;
    }
    set
    {
        recentsearch = value;
        RaisePropertyChanged("RecentSearch");
    }
}

I add objects to RecentSearchedRepo :

RecentSearchedRepo.add(searchitem)

then set RecentSearch to the static list

RecentSearch = Settings.RecentSearchedRepo;

XAML snippet:

<GridLayout:RecentSearchGrid x:Name="recentSearchGrid" ItemsSource="{Binding RecentSearch}" />

snippet from RecentSearchGrid class which extends UserControl:

 public IList ItemsSource
 {
     get
     {
         return GetValue(ItemsSourceProperty) as IList;
     }
     set
     {
         SetValue(ItemsSourceProperty, value);
     }
}

private static readonly DependencyProperty ItemsSourceProperty =
                    DependencyProperty.Register("ItemsSource", typeof(IList), typeof(RecentSearchGrid), new PropertyMetadata(null, OnItemsSourcePropertyChanged));


private static void OnItemsSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
     RecentSearchGrid source = d as RecentSearchGrid;

     if (source != null)
     {
      source.setListforgrid(source.ItemsSource);
     }
}

The problem is when I add the first item to RecentSearchedRepo the UI is updated , but on every subsequent add the UI does not update.

Instead of:

RecentSearch = Settings.RecentSearchedRepo;

Try doing:

RecentSearch.Clear();
var freshData = Settings.RecentSearchedRepo;
if (freshData != null)
    foreach (var item in freshData)
        RecentSearch.Add(item);

You were killing the binding by reassigning the reference.

EDIT : After yours

You're doing it backwards: that OnItemsSourcePropertyChanged shouldn't be setting the source, it shouldn't be there at all actually.
You must bind, in RecentSearchGrid.xaml , to the ItemsSource dependency property declared in RecentSearchGrid.xaml.cs

I don't think that there's enough information here to answer your question. The following simple application mirrors the scenario that I see described in the question and it works as expected:

// MySettings.cs
public static class MySettings
{
    public static IList RecentSearchedRepo = new ObservableCollection<object>();
}

// MyVm.cs
public class MyVm : INotifyPropertyChanged
{
    private IList recentSearch = new ObservableCollection<object>();

    public event PropertyChangedEventHandler PropertyChanged;

    public MyVm()
    {
        this.RecentSearch = MySettings.RecentSearchedRepo;
    }

    public IList RecentSearch
    {
        get { return recentSearch; }
        set 
        { 
            recentSearch = value;
            this.RaisePropertyChanged("RecentSearch");
        }
    }

    private void RaisePropertyChanged(string p)
    {
        if (this.PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs(p));
    }
}

// MainWindow.xaml.cs
public partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();

        // Initialization as described in the question
        MySettings.RecentSearchedRepo.Add("SearchItem1");
        MySettings.RecentSearchedRepo.Add("SearchItem2");

        this.DataContext = new MyVm();
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        // Add a new item later
        MySettings.RecentSearchedRepo.Add("NewlyAddedSearchItem");
    }
}

// MainWindow.xaml
<Window x:Class="ScratchWpf.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <DockPanel>
        <Button DockPanel.Dock="Bottom" Content="Add new Search Item" Click="Button_Click_1" />
        <ListBox ItemsSource="{Binding RecentSearch}" />
    </DockPanel>
</Window>

I'm going to try putting on my psychic hat and ask if, perhaps, you are adding additional items to the wrong collection. Does the collection get recreated and placed at the binding after a single item is added, but later items are added to the original collection instead of the new one?

Given that you stated RecentSearchGrid is a UserControl, we can also infer that the implementation of ItemsSource may be a custom one rather than the standard one that would be inherited from an ItemsControl. It's possible that the RecentSearchGrid is breaking the binding incorrectly in there somehow.

I agree with Baboon. What is the purpose of OnItemsSourcePropertyChanged ? In a typical implementation, I wouldn't expect that to be there.

The problem may be as follow: OnItemsSourcePropertyChanged will not get called, if the instance does not change. From WPF point of view, when you RaisePropertyChangeEvent , but the instance of the bound collection does not change, PropertyChange handler will not be called at all.

Is Settings.RecentSearchedRepo the same instance through the lifetime of the app?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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