Introduction
In this article we will learn about ReactiveProperty and ReactiveCommand from ReactiveProperty.NET4 library. These are used to create Reactive properties and commands in XAML base applications while working with MVVM pattern. ReactiveProperty.NET4 library is built upon Reactive Extension for .NET. In this article, we will create a demo showing that how ReactiveProperty and ReactiveCommand help us in property and command binding by reducing number of lines of code and other overhead too.
Prerequisites: To understand this article, you should have basic understanding of Property binding and Commanding in WPF. If you are new to MVVM and Commanding binding in WPF, first have a look at this article.
Outlines
- What is Reactive Extension for .NET (Rx)
- What is ReactiveProperty
- What is ReactiveCommand
- Overview of Demo App
- Using Basic WPF Property and Command
- Using ReactiveProperty
- Using ReactiveCommand
What is Reactive Extension for .NET (Rx)
The Reactive Extensions (Rx) is a library which helps us in writing asynchronous and event-based programs. Rx uses LINQ syntax to write asynchronous and event handling queries or operations to achieve desired functionality. So whenever we are required to make multiple asynchronous calls and event based programming that is where Reactive Extensions (Rx) helps us. Reactive Extensions are available in multiple flavors like Rx for .NET 4.0, .NET 4.5, .NET 4.6, Windows Phone 8.0/8.1, Windows store app 8.1, Xamarin.iOS, Xamarin.Android. Apart from .Net Rx is also available for Java called RxJava, Rx fo jQuery called rxjs etc. For more learning about Rx visit Reactive Extensions.
What is ReactiveProperty
ReactiveProperty is a class which is used with MVVM framework while using ReactiveProperty.NET4 library. By default ReactiveProperty has implementation of INotifyPropertyChanged as well as IReactiveProperty<T>, IReactiveProperty, IHasErrors, IObservable<T>, IDisposable, INotifyDataErrorInfo, IReadOnlyReactiveProperty<T> and IReadOnlyReactiveProperty. So we use ReactiveProperty then we don’t need to implement INotifyPropertyChanged interface to achieve two way data binding. It provides more capabilities too as it implements various interfaces too. For more details on ReactiveProperty please visit this Codeplex page.
What is ReactiveCommand
ReactiveCommand is a class which is used with MVVM framework while using ReactiveProperty.NET4 library. It is used to achieve create command with Reactive capabilities. By default ReactiveCommand class is inherited from ReactiveCommand<T>. ReactiveCommand<T> implements ICommand, IObservable<T>, and IDisposable interface. So we use ReactiveCommand then we don’t need to implement ICommand interface.
Overview of Demo App
In demo application, main view is having three buttons called Using WPF Property and Command Demo, Using ReactiveProperty Demo and Using ReactiveCommand Demo. On each Button click associated view will open. All of three views are having similar layout and functionality is same to perform calculations. But implementations of all of three views are different to achieve the same functionality. There are fewer changes in UI XAML code but corresponding ViewModels are having major changes.
Every child view is having two TextBoxes to accept input values, one TextBlock to show output and four RadioButtons to perform specific calculation. Four RadioButtons are used to perform add, subtraction, multiply and divide operations. Calculation will be keep happening while changing the inputs based on checked RadionButton and result will be displayed output TextBlock. Quick overview of demo application is shown in below screenshot.
Using Basic WPF Property and Command
In previous article we were doing calculation on four kinds of Button clicks. On specified button click Calculated/result value is displayed in output TextBlock. But in this article we have removed buttons to perform operation. Instead of that we are using four RadionButtons.
Run the downloaded code and click on “Using WPF Property and Command Demo” button. Enter any numbers in TextBoxes then check any RadionButton. Result will be displayed in output TextBlock.
Layout code is written in UsingWpfPropertyCommandView.xaml file and it uses WpfPropertyCommandViewModel. WpfPropertyCommandViewModel containts properties and commands code needed for UsingWpfPropertyCommandView. WpfPropertyCommandViewModel is inherited from ViewModelBase class which is having implementation of INotifyPropertyChanged interface (To perform two way data binding for properties between View and ViewModel or vice versa). RelayCommand class is implementing ICommand interface to achieve commanding for RadionButton clicks. In case of any difficulty in understanding code for those two files please look in ICommand Interface in WPF article for detailed explanation.
Using ReactiveProperty
In this section we will learn how to use ReactiveProperty to achieve the same functionality as we have achieved in above section.
First let’s add required libraries. Required libraries can be added using "Manage NuGet Packages" as shown in below screenshot. It will add all required libraries for Reactive Extension for .NET.
To create layout in UsingReactivePropertyView.xaml, almost same XAML code will work which we have written in above section. Only two additional change we need to do. First change is, wherever there is property binding, in property names we have to add .Value so finally those names become like Add.Value. It is because ReactiveProperty exposes its value in that way. Second change is, on each RadioButton click, IsChecked property of RadionButtons is used to perform operations. IsChecked property of RadioButtons are bound with Add, Substract, Multiply and Divide properties of ReactivePropertyViewModel. Sample code as shown below.
<StackPanel Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="4" Margin="25,10,0,15" >
<Viewbox Height="30">
<StackPanel Orientation="Horizontal">
<RadioButton GroupName="RadioButtonGroup" Margin="25,0,0,0"
IsChecked="{Binding Add.Value, Mode=TwoWay}">Add</RadioButton>
<RadioButton GroupName="RadioButtonGroup" Margin="25,0,0,0"
IsChecked="{Binding Substract.Value, Mode=TwoWay}">Substract</RadioButton>
<RadioButton GroupName="RadioButtonGroup" Margin="25,0 ,0 ,0"
IsChecked="{Binding Multiply.Value, Mode=TwoWay}">Multiply</RadioButton>
<RadioButton GroupName="RadioButtonGroup" Margin="25,0,25,0"
IsChecked="{Binding Divide.Value, Mode=TwoWay}">Divide</RadioButton>
</StackPanel>
</Viewbox>
</StackPanel>
In above code, Add, Substract, Multiply and Divide property is bound with ReactiveProperty in ReactivePropertyViewModel. Whole code of ReactivePropertyViewModel is shown below.
Note: ReactivePropertyViewModel is not inhereated by ViewModelBase to achieve two way data binding.
public class ReactivePropertyViewModel : IDisposable
{
private bool isDisposed = false;
private readonly SerialDisposable firstValueSubscriptionDisposable
= new SerialDisposable();
private readonly SerialDisposable secondValueSubscriptionDisposable
= new SerialDisposable();
public ReactiveProperty<double?> FirstValue { get; private set; }
public ReactiveProperty<double?> SecondValue { get; private set; }
public ReactiveProperty<double?> Output { get; private set; }
public ReactiveProperty<bool> Add { get; private set; }
public ReactiveProperty<bool> Substract { get; private set; }
public ReactiveProperty<bool> Multiply { get; private set; }
public ReactiveProperty<bool> Divide { get; private set; }
public ReactivePropertyViewModel()
{
FirstValue = new ReactiveProperty<double?>();
SecondValue = new ReactiveProperty<double?>();
Output = new ReactiveProperty<double?>();
Add = new ReactiveProperty<bool>();
Substract = new ReactiveProperty<bool>();
Multiply = new ReactiveProperty<bool>();
Divide = new ReactiveProperty<bool>();
Add.Subscribe(x =>
{
if (x == true)
{
firstValueSubscriptionDisposable.Disposable
= FirstValue.Subscribe(y => add());
secondValueSubscriptionDisposable.Disposable
= SecondValue.Subscribe(y => add());
}
});
Substract.Subscribe(x =>
{
if (x == true)
{
firstValueSubscriptionDisposable.Disposable
= FirstValue.Subscribe(y => substract());
secondValueSubscriptionDisposable.Disposable
= SecondValue.Subscribe(y => substract());
}
});
Multiply.Subscribe(x =>
{
if (x == true)
{
firstValueSubscriptionDisposable.Disposable
= FirstValue.Subscribe(y => multiply());
secondValueSubscriptionDisposable.Disposable
= SecondValue.Subscribe(y => multiply());
}
});
Divide.Subscribe(x =>
{
if (x == true)
{
firstValueSubscriptionDisposable.Disposable
= FirstValue.Subscribe(y => divide());
secondValueSubscriptionDisposable.Disposable
= SecondValue.Subscribe(y => divide());
}
});
}
private void add()
{
Output.Value = FirstValue.Value + SecondValue.Value;
}
private void substract()
{
Output.Value = FirstValue.Value - SecondValue.Value;
}
private void multiply()
{
Output.Value = FirstValue.Value * SecondValue.Value;
}
private void divide()
{
Output.Value = FirstValue.Value / SecondValue.Value;
}
public void Dispose()
{
if (isDisposed) return;
isDisposed = true;
firstValueSubscriptionDisposable.Dispose();
secondValueSubscriptionDisposable.Dispose();
}
}
To avoid memory leaks we must clean up subscriptions of any observable as described here. In above code we are using SerialDisposable to dispose the subscriptions of ReactiveProperties. Reactive Core Library provides many such implementations of IDisposable interface under System.Reactive.Disposables namespace. For more details on Disposables, please have a look at this page of online book by Lee Campbell.
So above code of ReactivePropertyViewModel, is much better and concise that WpfPropertyCommandViewModel as per below points:
- In ReactivePropertyViewModel all subscription code is in one place while in WpfPropertyCommandViewModel we need to use set block of properties to notify changes and call method.
- In ReactivePropertyViewModel we do not need to create backing private field for properties.
- In ReactivePropertyViewModel code is much concise and self-explanatory.
- No need to create own implementation of ViewModelBase and RelayCommand.
Using ReactiveCommand
In this section we will learn how to use ReactiveCommand to achieve the same functionality as we achieved in above section. To create the layout all most same xaml code will work what we have written in above section. Only one change we need to do is, instead of using IsChecked property of RadioButton to perform a particular type of operation. In this section we will use a single command called "OperationCommand" in all of four RadioButton to perform a particular type of operation. Sample code as shown below:
<StackPanel Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="4" Margin="25,10,0,15" >
<Viewbox Height="30">
<StackPanel Orientation="Horizontal">
<RadioButton GroupName="RadioButtonGroup" Margin="25,0,0,0"
Command="{Binding OperationCommand}"
CommandParameter="{Binding Path=Content,
RelativeSource={RelativeSource Self}}">Add
</RadioButton>
<RadioButton GroupName="RadioButtonGroup" Margin="25,0,0,0"
Command="{Binding OperationCommand}"
CommandParameter="{Binding Path=Content,
RelativeSource={RelativeSource Self}}">Substract
</RadioButton>
<RadioButton GroupName="RadioButtonGroup" Margin="25,0,0,0"
Command="{Binding OperationCommand}"
CommandParameter="{Binding Path=Content,
RelativeSource={RelativeSource Self}}">Multiply
</RadioButton>
<RadioButton GroupName="RadioButtonGroup" Margin="25,0,25,0"
Command="{Binding OperationCommand}"
CommandParameter="{Binding Path=Content,
RelativeSource={RelativeSource Self}}">Divide
</RadioButton>
</StackPanel>
</Viewbox>
</StackPanel>
In above code OperationCommand is bound with ReactiveCommand of ReactiveCommandViewModel. Whenever any RadioButton will be checked OperationCommand will be executed. OperationCommand will subscribe specific operation and display result in output textblock.
public class ReactiveCommandViewModel : IDisposable
{
private bool isDisposed = false;
private readonly SerialDisposable firstValueSubscriptionDisposable
= new SerialDisposable();
private readonly SerialDisposable secondValueSubscriptionDisposable
= new SerialDisposable();
private readonly SingleAssignmentDisposable operationCommandSubscriptionDisposable
= new SingleAssignmentDisposable();
public ReactiveProperty<double?> FirstValue { get; private set; }
public ReactiveProperty<double?> SecondValue { get; private set; }
public ReactiveProperty<double?> Output { get; private set; }
public ReactiveCommand<string> OperationCommand { get; set; }
public ReactiveCommandViewModel()
{
FirstValue = new ReactiveProperty<double?>();
SecondValue = new ReactiveProperty<double?>();
Output = new ReactiveProperty<double?>();
OperationCommand = new ReactiveCommand<string>();
operationCommandSubscriptionDisposable.Disposable = OperationCommand.Subscribe(action =>
{
switch (action)
{
case "Add":
firstValueSubscriptionDisposable.Disposable
= FirstValue.Subscribe(x => add());
secondValueSubscriptionDisposable.Disposable
= SecondValue.Subscribe(x => add());
break;
case "Substract":
firstValueSubscriptionDisposable.Disposable
= FirstValue.Subscribe(y => substract());
secondValueSubscriptionDisposable.Disposable
= SecondValue.Subscribe(y => substract());
break;
case "Multiply":
firstValueSubscriptionDisposable.Disposable
= FirstValue.Subscribe(y => multiply());
secondValueSubscriptionDisposable.Disposable
= SecondValue.Subscribe(y => multiply());
break;
case "Divide":
firstValueSubscriptionDisposable.Disposable
= FirstValue.Subscribe(y => divide());
secondValueSubscriptionDisposable.Disposable
= SecondValue.Subscribe(y => divide());
break;
}
});
}
private void add()
{
Output.Value = FirstValue.Value + SecondValue.Value;
}
private void substract()
{
Output.Value = FirstValue.Value - SecondValue.Value;
}
private void multiply()
{
Output.Value = FirstValue.Value * SecondValue.Value;
}
private void divide()
{
Output.Value = FirstValue.Value / SecondValue.Value;
}
public void Dispose()
{
if (isDisposed) return;
isDisposed = true;
firstValueSubscriptionDisposable.Dispose();
secondValueSubscriptionDisposable.Dispose();
operationCommandSubscriptionDisposable.Dispose();
}
}
So using ReactiveCommand we need to write much less code in comparison to ReactivePropertyViewModel code.
Conclusion
In this article, we learned about ReactiveProperty and ReactiveCommand from ReactiveProperty.NET4 library. Hope it will help you to write better code while working with MVVM based WPF applications. Your comments/suggestions and queries are most welcome. Thanks.