wm_
wm_

Reputation: 269

RelayCommand and WeakReference

I have the following:

public MainViewModel(IDataService dataService)
{
    _dataService = dataService;

    NotWorkingCommand = new RelayCommand(() => 
    dataService.GetData((item, error) =>
    {
        if (error != null)
        {
            // Report error here
            return;
        }
        WelcomeTitle = item.Title;
    }));
}

Can someone please explain why my RelayCommand would stop firing after a while? I suspect it has to do with WeakReference used in the RelayCommand but I have no experience with WeakReference. If I used _dataService.GetData instead, it will work.

Upvotes: 3

Views: 835

Answers (2)

Thomas
Thomas

Reputation: 558

marckm is not wrong here and the suggestion to use the class-level variable will work. But I would just like to clarify that the complete answer to this question should include a bit of info on "variable captures" in lambdas.

Before MVVMLight started to use weak references, the method-level variable dataService would by captured in the lambda expression. Normally, this variable would go out of scope once the method completes. Due to variable capture in the lambda, this would not happen here, which is why the body of the lambda would (always) work later on.

After MVVMLight moved to weak references, the code will initially work, but without the class-level variable (and assignment), the method-level variable will eventually be garbage collected, and the RelayCommand will then stop to work. Which is exactly what you saw here (six years ago - I know - but this question remains valid today).

Upvotes: 0

marckm
marckm

Reputation: 31

In your lambda expression, the dataService.GetData instruction won't work, because the scope of the variable dataService is only limited to the constructor.

Instead you should copy this reference to a backing field and call this instance instead. If think you were near the solution when you say it works by using _dataService.GetData.

private readonly IDataService _dataService;

public RelayCommand NotWorkingCommand { get; private set; }


public MainViewModel(IDataService dataService)
{
        _dataService = dataService;

        NotWorkingCommand = new RelayCommand(() =>
        _dataService.GetData((item, error) =>
        {
            if (error != null)
            {
                // Report error here
                return;
            }
            WelcomeTitle = item.Title;
        }));
    }

It seems that the delegate is correctly created because the reference exists when the relay command is created (in the scope of the ctor), but it can't be called at runtime because it cannot be evaluated correctly.

Upvotes: 2

Related Questions