6

I have some ObservableCollections binded to some WPF controls and they work fine. And I have a feature where I completely replace these ObservableCollections through reassignment and filling them again, but after doing this, the WPF controls don't get updated.

Or is this binding connection only established at startup once, and then I should never reinitialize the ObservableCollections, but only change them?

EDIT:

public partial class MainWindow : Window
{
    ObservableCollection<EffectViewModel> effects;
    public ObservableCollection<EffectViewModel> Effects
    {
        get { return this.effects; }
        set
        {
            this.effects = value;
            this.RaisePropertyChanged ( "Effects" );
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    void RaisePropertyChanged ( string name )
    {
        var handler = this.PropertyChanged;
        if ( handler != null )
            handler ( this, new PropertyChangedEventArgs ( name ) );
    }
}

public void LoadEffects ( string path, string filename )
{
    //returns new ObservableCollection<EffectViewModel> ( );
    this.Effects = File.Load ( path, filename );
}

public class EffectViewModel
{
    public bool this [ EffectType type ]
    {
        get { return AllEffects.First ( e => e.Type == this.Type ).IsSupported; }
        set
        {
            AllEffects.First ( e => e.Type == this.Type ).IsSupported = value;
            this.RaisePropertyChanged ( "this" );
        }
    }

    #region Events

    public event PropertyChangedEventHandler PropertyChanged;
    void RaisePropertyChanged ( string name )
    {
        var handler = this.PropertyChanged;
        if ( handler != null )
            handler ( this, new PropertyChangedEventArgs ( name ) );
    }

    #endregion
}

EDIT2:

<Window x:Class="EffectWindow.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Title="Effect Display" Height="200" Width="700"
    <DockPanel VerticalAlignment="Stretch">

        <ListView
            ItemsSource="{Binding Effects}"
            AlternationCount="2"
            DockPanel.Dock="Top"
            HorizontalContentAlignment="Stretch">

            <ListView.View>
                <GridView>

                    <GridViewColumn
                        Width="70"
                        Header="GPU">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <CheckBox
                                    Margin="0"
                                    HorizontalAlignment="Center"
                                    IsChecked="{Binding [GPU], Mode=TwoWay}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>

                    <GridViewColumn
                        Width="70"
                        Header="CPU">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <CheckBox
                                    Margin="0"
                                    HorizontalAlignment="Center"
                                    IsChecked="{Binding [CPU], Mode=TwoWay}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>

                </GridView>
            </ListView.View>
        </ListView>

    </DockPanel>
</Window>
Joan Venge
  • 315,713
  • 212
  • 479
  • 689
  • did you raise a `PropertyChanged` event after you changed to a different collection? – BrokenGlass Mar 07 '11 at 20:05
  • No I didn't. How can I do that? I only use ObservableCollection MyItems =, so shouldn't this be raised by the ObservableCollection type itself? – Joan Venge Mar 07 '11 at 20:08
  • how would it, since you are creating a *new* collection and not changing the old one? – BrokenGlass Mar 07 '11 at 20:11
  • I know what you mean. I just didn't know how to squeeze in a propertychanged event in an auto property but Pavlo's answer helped me see that I need to use a normal property. – Joan Venge Mar 07 '11 at 20:19

3 Answers3

5

The object you are binding to should implement the INotifyPropertyChanged interface. Then, the bound collection property should raise PropertyChanged event in its setter. Something like this:

public ObservableCollection<MyObject> MyCollection
{
   get
   {
      return _myCollection;
   }
   set
   {
      _myCollection = value;
      RaisePropertyChanged("MyCollection");
   }
} 
Pavlo Glazkov
  • 20,498
  • 3
  • 58
  • 71
  • Thanks Pavlo, I tried what you said but it still doesn't work. To explain it, basically in my viewmodel, I have the index operator [] defined, and also implemented INotifyPropertyChanged on the viewmodel's index operator. this.RaisePropertyChanged ( "this" ); Not sure if I should use "this" as the parameter or something else or that it affects the binding? But also MyCollection is also defined like you showed. – Joan Venge Mar 07 '11 at 20:29
  • But from what I can see, implementing MyCollection like you did should be enough, right? Because then reassigning MyCollection should update all the properties binding to it, right? – Joan Venge Mar 07 '11 at 20:31
  • 1
    @Joan - The collection property should be enough. If it doesn't work, I suggest you edit your post to include relevant code of your view model and the XAML part where you set binding. This would help to diagnose the problem. – Pavlo Glazkov Mar 07 '11 at 20:35
  • 1
    @Joan - Please include also XAML that contains your binding that doesn't work. The code you provided looks OK, except this line: `this.RaisePropertyChanged ( "this" )` - this won't work, but judging from your description of the problem this should'n matter. – Pavlo Glazkov Mar 07 '11 at 20:59
  • Thanks Pavlo, will add xaml too. Btw what should I use instead of "this"? since it's the index operator. Do you know? – Joan Venge Mar 07 '11 at 21:04
  • I added the xaml Pavlo. Btw CPU and GPU are EffectType members which is an enum. – Joan Venge Mar 07 '11 at 21:08
  • 2
    @Joan - OK, now I see the problem. Your window doesn't inherit `INotifyPropertyChanged` interface (and the `EffectViewModel` too). But it should: `public partial class MainWindow : Window, INotifyPropertyChanged`. As for raising `PropertyChanged` event for the indexer property, specifying an empty string as a property name argument should work. – Pavlo Glazkov Mar 07 '11 at 21:18
  • Thanks Pavlo, it works now. You are the man. I would never think of implementing it on the Window class. But is this standard practice, I mean should I define these properties on the Window class or should I have another class that store MyCollection/Effects collection? Also like you said I didn't need to implement the raise event for the EffectViewModel's indexer property because I don't want to get an event for it, and it works like you said. – Joan Venge Mar 07 '11 at 21:29
  • 1
    @Joan - You are welcome :) As for implementing this stuff on the Window, topically no, you would not do it on the Window itself. Instead, you would create a view model for the main window that would expose these properties. Check out the FAQ about MVVM pattern for more information: http://stackoverflow.com/questions/1405739/mvvm-tutorial-from-start-to-finish. – Pavlo Glazkov Mar 07 '11 at 21:37
  • Thanks Pavlo, will check out your link now. It's these sort of things I just have to open my eyes. Like when you said I need a viewmodel for the mainwindow, I didn't think of this. Just thought viewmodel applied to types that represent the data, like my EffectViewModel but not to the Window itself. So how can I know if I need a viewmodel type for something? Is there a guideline? Is it described in the link? Then probably you don't need to answer. – Joan Venge Mar 07 '11 at 21:43
  • 1
    @Joan - Yeah, just check out the link :) Any MVVM tutorial will answer you questions. At very basic level, you will need a view model for every view of your application, rather than for data objects. Good luck with learning MVVM :) – Pavlo Glazkov Mar 07 '11 at 21:50
2

Try not to reassign, but clear and add new items.

Stecya
  • 22,896
  • 10
  • 72
  • 102
0

You’ll need to know the dependency object and dependency property where the binding was defined. Then you can use this line:

BindingOperations.GetBindingExpressionBase(dependencyObject, dependencyProperty).UpdateTarget();
OrahSoft
  • 783
  • 1
  • 5
  • 7