1

Similar to DataTable saved to Session state loses event handlers although the recommended solution there did not apply. I am not serializing Session data. Objects are being kept InProc.

I have a class called Application with these relevant bits:

public class Application {
    public event PropertyChangedEventHandler PropertyChanged;

    private Lazy<Asset> _asset;

    public String AssetId { get; set; }

    public Application() {
        RestoreEventHandlers(new StreamingContext());
    }

    [OnDeserialized]
    public void RestoreEventHandlers(StreamingContext context) {
        PropertyChanged += AssetId_PropertyChanged;
        PropertyChanged.Invoke(this, new PropertyChangedEventArgs("AssetId"));
    }

    private void AssetId_PropertyChanged(Object sender, PropertyChangedEventArgs e) {
        if (e.PropertyName == "AssetId")
            _asset = new Lazy<Asset>(() => new Asset(AssetId));
    }

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] String propertyName = null) {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

The goal is for _asset to get reset whenever the related AssetId property changes. I need to keep the AssetId and Asset records synchronized. I have verified that the event is called after an object is created the first time.

After an application is created I am putting it in Session like this:

HttpContext.Current.Session["CurrentApplication"] = application;

On subsequent requests I am getting it from Session like this:

var application = HttpContext.Current.Session["CurrentApplication"] as Application;

This is being called from a helper class which is why I need to use the static objects to get the current request context.

Later in the same method I have a line that does this, if the user has asked to change the asset on the application:

application.AssetId = assetId;

After this assignment the event handler is not invoked. If I write it this way instead it works as intended:

application.RestoreEventHandlers(new StreamingContext());
application.AssetId = assetId;

Something is causing my event handlers to become unbound. Any ideas?

Community
  • 1
  • 1
Yuck
  • 49,664
  • 13
  • 105
  • 135
  • 1
    The last 2 code snippets are the same, did you mean to put something else in the last one? – Rhumborl Sep 25 '14 at 13:10
  • @Rhumborl Yes, good catch. Sorry about that. I meant to show that if I am not explicitly calling `RestoreEventHandlers` then the event will not fire. I don't want to have to call that explicitly because the whole point is for client code to be blissfully unaware of that mechanism. – Yuck Sep 25 '14 at 13:15

1 Answers1

2

I may be way out here, but is the PropertyChanged event being invoked at all, other than in RestoreEventHandlers()? I had it in mind that you need to raise it manually inside the property - see example at http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged(v=vs.110).aspx

private string _assetId;

public string AssetId
{
    get
    {
        return _assetId;
    }
    set
    {
        _assetId = value;
        OnPropertyChanged();
    }
}

Of course you could just reset the _asset inside the property:

private string _assetId;

public string AssetId
{
    get
    {
        return _assetId;
    }
    set
    {
        _assetId = value;
        _asset = new Lazy<Asset>(() => new Asset(AssetId));
    }
}
Rhumborl
  • 16,349
  • 4
  • 39
  • 45