0
votes

I have recently started learning reactive extensions and not an expert on Rx. However, I am changing a previously written application into Reactive UI. But, when I wanted to change a RelayCommand to ReactiveCommand<Unit, Unit>, I faced this error:

System.NotSupportedException: 'Index expressions are only supported with constants. My RelayCommand was defined as bellow:

DownloadCmd = new RelayCommand(async x=> await DownloadSubtitle(), CheckYoutubeLink);

I changed it with a Reactive Command as follow:

var can = this.WhenAnyObservable(x=>Observable.Return(x.CheckYoutubeLink()));
DownloadCmd = ReactiveCommand.CreateFromTask(_ => DownloadSubtitle(),can);

Unfortunately, it does not work. In other words, my question is how to use a function (Func) for "canExecute" parameters or something that behaves like functions. By the way, I do not prefer to use Properties instead of functions since I have to write many properties for my commands. I have checked this link: ReactiveUI: Using CanExecute with a ReactiveCommand however, it cannot help me a lot.

1
Please provide more code, how CheckYoutubeLink method looks like, what return type do you have? What declaration DownloadSubtitle has?Lukasz Szczygielek
@icn: The ReactiveUI implementation obviously depends on how CheckYoutubeLink is currently implemented and how and when you raise the CanExecuteChanged method of your RelayCommand?mm8
"Observable.Return(x.CheckYoutubeLink())" will check the link only once, pipe the result through the observable, and then complete. I agree wit Hostel and mm8 that more information is required but I guess that there is link property of similar in you application that can change. So you need to create a reactive property like "IsLinkValid" instead of your check method and update it whenever the link changes. On this property you can then build an observable using WhenAnyValue that you can use for "can".Đøharrrck
@Hostel, Đøharrrck predicted my code correctly, and his answer is about "CheckYoutubeLink()" is close to my implementaion.icn

1 Answers

2
votes

Based on the assumption that I made in my comment, a solution could look like this:

    public ViewModel()
    {
        this
            .WhenAnyValue(x => x.CurrentLink)
            .Subscribe(_ => CheckYoutubeLink());

        var can = this
            .WhenAnyValue(x => x.IsLinkValid);

        DownloadCmd = ReactiveCommand.CreateFromTask(_ => DownloadSubtitle(), can);
    }


    public ICommand DownloadCmd { get; private set; }

    [Reactive]
    public string CurrentLink { get; set; }

    [Reactive]
    public bool IsLinkValid { get; set; }

    private Task<object> DownloadSubtitle()
    {
        // your logic here
    }

    private void CheckYoutubeLink()
    {
        // your logic here
        IsLinkValid = CurrentLink != null && CurrentLink.Contains("youtube");
    }

As I said, I don't know what your application looks like but you just have to call CheckYoutubeLink whenever you set the link.