3

I have a textbox bound to a view model with the following XAML:

<TextBox x:Name="usrTxt" Text="{Binding UserID, UpdateSourceTrigger=PropertyChanged}" 
    Margin="0,0,0,10" TextWrapping="Wrap" Height="50"
    VerticalAlignment="Bottom" ToolTip="User ID" FontSize="29.333" 
    VerticalContentAlignment="Center" Padding="15,0" TabIndex="0">
      <TextBox.InputBindings>
        <KeyBinding Key="Return" Command="{Binding EntrCommand}"/>
      </TextBox.InputBindings>
</TextBox>

I'm trying to create a ReactiveCommand in my view model that will trigger whenever the KeyBinding event in the view is fired. I'm positive that I have the syntax wrong for this, but I'm not sure what I need to do to fix it after looking at the docs. Here's my relevant view model code:

class MainViewModel : ReactiveObject
{
      private DbContext dbCtx;

      public MainViewModel()
      {
          dbCtx = new DbContext(Properties.Settings.Default.DbString);

          EnterCmd = this.WhenAny(x => x.UserID, x => x.Value)
                .Where(x => !String.IsNullOrWhiteSpace(x))
                .Do(_ => IsLoading = true);

          EnterCmd.Subscribe(x =>
          {
                Console.WriteLine(x);
                IsLoading = false;
          });
      }

      public ReactiveCommand EnterCmd { get; private set; }

      ...
}

An obvious problem is that WhenAny returns System.IObservable<string> where as EnterCmd expects type ReactiveUI.ReactiveCommand. Another problem I noticed is that I can't declare EnterCmd with a getter and setter because I got the error 'ReactiveCommand': static types cannot be used as parameters. Any help would be appreciated.

John
  • 3,296
  • 2
  • 24
  • 36
  • Command="{Binding EntrCommand} it must be a typo..pls edit this – shreesha Aug 06 '15 at 13:31
  • @shreesha It's not a typo. I assumed that `{Binding EntrCommand}` would map to that property I have in my view model called `EntrCommand`. That may not be the correct way to do this, though. – John Aug 06 '15 at 13:33

2 Answers2

4

Proper syntax for RxUI command:

    public ReactiveCommand<object> EnterCmd { get; private set; }
    ObservableAsPropertyHelper<bool> _isLoading;
    public bool IsLoading { get { return _isLoading.Value; } }

    public MainViewModel()
    {
        EnterCmd = ReactiveCommand.Create(
            this.WhenAny(x => x.UserID, x => x.Value)
                .Select(x => !String.IsNullOrWhiteSpace(x)));

        EnterCmd.IsExecuting.ToProperty(this, x => x.IsLoading, out _isLoading);

        EnterCmd.Subscribe(x =>
        {
            Console.WriteLine(x);
        });

ReactiveCommand is a static helper class (factory methods mostly), the real type is the generic version of it.

Gluck
  • 2,933
  • 16
  • 28
  • This looks great. My only other issue then is how to convert `` in my view so that when I press enter, that command subscription is triggered. Any ideas? – John Aug 06 '15 at 14:40
  • I should probably give more detail... `Console.WriteLine(x)` actually IS being called when I press enter, as expected, but the value is empty. How do I access the actual string from `x`? I tried `x.Value` but that doesn't seem to be a valid option. – John Aug 06 '15 at 14:44
  • You should access it from the VM, relying on the command parameter isn't [recommended](http://reactiveui.readthedocs.org/en/latest/concepts/commands/). In your case `Console.WriteLine(UserID)` – Gluck Aug 06 '15 at 14:58
0

Use such reactiveCommand then:

public class ReactiveCommand : ICommand, IObservable<object>
{
    private bool _canExecute = true;
    private readonly Subject<object> _execute = new Subject<object>();

    public ReactiveCommand(IObservable<bool> canExecute = null)
    {
        if (canExecute != null)
        {
            canExecute.Subscribe(x => this._canExecute = x);
        }
    }

    public bool CanExecute(object parameter)
    {
        return this._canExecute;
    }

    public void Execute(object parameter)
    {
        this._execute.OnNext(parameter);
    }

    public event EventHandler CanExecuteChanged;

    public IDisposable Subscribe(IObserver<object> observer)
    {
        return this._execute.Subscribe(observer);
    }
}
Immons
  • 257
  • 1
  • 11
  • Thanks for the response. Do you have any example of how I can implement this into my current codebase? I'm not sure how to do so based on the example you gave. – John Aug 06 '15 at 13:40