Alan Wayne
Alan Wayne

Reputation: 5384

Difficulty updating UI when contents of ObservableCollection is changed?

I have a combobox bound to an observablecollection as:

 <ComboBox 
        HorizontalAlignment="Left" Margin="586,51,0,0" VerticalAlignment="Top" Width="372" 
        SelectedItem="{Binding PrimaryInsurance.SelectedInsurance}"
        ItemsSource="{Binding PrimaryInsurance.AllPatientInsurance}" 
        ItemTemplate="{StaticResource InsuranceTemplate}" />

The observablecollection itself is defined as:

 private ObservableCollection<Insurance> _allPatientInsurance;
 public ObservableCollection<Insurance> AllPatientInsurance
    {
        get { return _allPatientInsurance; }
        set { if (_allPatientInsurance == value) return; _allPatientInsurance = value; OnPropertyChanged("AllPatientInsurance"); }
    }

Now Insurance encapsulates data downloaded from the database an adds INotifyPropertyChanged as:

 public string CompanyName
    {
        get { return insurance_View.Companyname; }
        set { if (insurance_View.Companyname == value) return; insurance_View.Companyname = value; OnPropertyChanged("CompanyName"); }
    }

Where insurance_View is the raw data record downloaded from the database.

All is good.

However, in an "UnDo" operation, I would like to replace the edited insurance_View record with its original record like:

 internal void UnDo()
    {
        insurance_View = (Insurance_View)pre_edit_Insurance_View.Clone();
    }

Although the edited version of insurance_View is correctly changed back to its original form, the display is not being updated. Futhermore, replacing the edited version of insurance with the original version of insurance in the ObservableCollection like:

  AllPatientInsurance.Remove(Old Insurance);
  AllPatientInsurance.Add(New Insurance);

Destroys all the bindings and displays a blank record.

So, what is the best way to update the display when the contents of Insurance is changed without destroying the Insurance Object? Is there a better way?

Edit #1. Just to be clear, I am trying to replace the data record within the Insurance object where it is the Insurance object that is bound to the display. I am not wanting to replace the entire collection being displayed. The only thing that comes to mind is to replace each value of the edited record with its original value, but this seems tedious so I am hoping for a better method.

Edit #2. Is there any way to trigger the Insurance setters when the encapsulated Insurance_View record is changed?

Edit #3. The insurance template:

        <!--DataTemplate for the Combobox Insurance List-->
    <DataTemplate x:Key="InsuranceTemplate">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="20" />
                <ColumnDefinition Width="120" />
                <ColumnDefinition Width="50" />
                <ColumnDefinition Width="14" />
                <ColumnDefinition Width="50" />
                <ColumnDefinition Width="60" />
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding XNotInEffect}"  Grid.Column="0" />
            <TextBlock Text="{Binding CompanyName}" Grid.Column="1"/>
            <TextBlock Text="{Binding EffectiveDateFrom}" Grid.Column="2"/>
            <TextBlock Text="--" Grid.Column="3" />
            <TextBlock Text="{Binding EffectiveDateTo}" Grid.Column="4" />
            <TextBlock Text="{Binding InsuranceType}" Grid.Column="5"/>
        </Grid>
    </DataTemplate>

Also, please note that simply removing then adding the same Insurance object results in its disappearance from the combobox drop down. Example:

    AllPatientInsurance.Remove(SelectedInsurance);
    AllPatientInsurance.Add(SelectedInsurance);

TIA

Upvotes: 1

Views: 98

Answers (3)

Alan Wayne
Alan Wayne

Reputation: 5384

This code does not work because the SelectedInsurance becomes null the moment it is removed from the collection:

 AllPatientInsurance.Remove(SelectedInsurance);
 AllPatientInsurance.Add(SelectedInsurance);

However, if a reference to the SelectedInsurance is kept then it can be added back as so:

 SelectedInsurance.Reset();
 var x = SelectedInsurance;
 AllPatientInsurance.Remove(SelectedInsurance);
 AllPatientInsurance.Add(x);
 SelectedInsurance = x;

Where Reset() is

 internal void Reset()
    {
        insurance_View = (Insurance_View)pre_edit_Insurance_View.Clone();
    }

and the last line sets the combobox back to the initially selected item.

So simple. :)

Upvotes: 0

whyloop
whyloop

Reputation: 46

I suppose your InsuranceTemplate has bindings to the Insurance' properties such as CompanyName and therefore listens to property changed events from the Insurance instance (the template's DataContext). So because the undo operation doesn't change the properties by calling the corresponding setters (but by changing the insurance_view) you have to manually trigger the property changed events (OnPropertyChanged("CompanyName") and so on) of every changed property after the undo operation to notify the view.

Upvotes: 1

Matthew Thurston
Matthew Thurston

Reputation: 760

Track the old insurance in its own observable collection. In your undo, you can assign the old collection to AllPatientInsurance, and let the property do the heavy lifting.

//initialize this elsewhere as appropriate
private ObservableCollection<Insurance> _oldPatientInsurance;

internal void UnDo()
{
    insurance_View = (Insurance_View)pre_edit_Insurance_View.Clone();
    AllPatientInsurance = _oldPatientInsurance;
}

Upvotes: 0

Related Questions