Giter VIP home page Giter VIP logo

runceel / reactiveproperty Goto Github PK

View Code? Open in Web Editor NEW
873.0 55.0 99.0 53.41 MB

ReactiveProperty provides MVVM and asynchronous support features under Reactive Extensions. Target frameworks are .NET 6+, .NET Framework 4.7.2 and .NET Standard 2.0.

License: MIT License

C# 96.42% Vim Snippet 1.51% Dockerfile 0.24% Shell 1.82% HTML 0.01%
reactiveproperty c-sharp xamarin uwp xaml mvvm wpf rx reative reactive-extensions

reactiveproperty's Introduction

Japanese

ReactiveProperty

ReactiveProperty provides MVVM and asynchronous support features under Reactive Extensions. Target framework is .NET 6.0+, .NET Framework 4.7.2 and .NET Standard 2.0.

Build and Release

ReactiveProperty overview

Note:

If you’re developing a new application, consider using R3 instead of ReactiveProperty. R3, redesigned by the original author, aligns with the current .NET ecosystem and offers most of the features found in ReactiveProperty.

GitHub - Cysharp/R3

Concept

ReactiveProperty is a very powerful and simple library.

Delay and Select

This sample app's ViewModel code is as below:

public class MainPageViewModel
{
    public ReactivePropertySlim<string> Input { get; }
    public ReadOnlyReactivePropertySlim<string> Output { get; }
    public MainPageViewModel()
    {
        Input = new ReactivePropertySlim<string>("");
        Output = Input
            .Delay(TimeSpan.FromSeconds(1))
            .Select(x => x.ToUpper())
            .ObserveOnDispatcher()
            .ToReadOnlyReactivePropertySlim();
    }
}

It is really simple and understandable (I think!). Because there are NOT any base classes and interfaces. Just has declarative code between Input property and Output property.

All steps are written in the "Getting Started" section in the ReactiveProperty documentation.

The concept of ReactiveProperty is simple that is a core class what name is ReactiveProperty[Slim], it is just a wrap class what has a value, and implements IObservable<T> and INotifyPropertyChanged, IObservable<T> is for connect change event of the property value to Rx LINQ method chane, INotifyPropertyChanged is for data binding system such as WPF, WinUI and MAUI.

And an important concept of ReactiveProperty is "Fun programing". ViewModel code with ReactiveProperty is very simple.

ViewModel's popular implementation:

public class AViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string _name;
    public string Name
    {
        get => _name;
        set
        {
            _name = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));

            // Update a command status
            DoSomethingCommand.RaiseCanExecuteChanged();
        }
    }

    private string _memo;
    public string Memo
    {
        get => _memo;
        set
        {
            _memo = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Memo)));

            // Update a command status
            DoSomethingCommand.RaiseCanExecuteChanged();
        }
    }

    // DelegateCommand is plane ICommand implementation.
    public DelegateCommand DoSomethingCommand { get; }

    public AViewModel()
    {
        DoSomethingCommand = new DelegateCommand(
            () => { ... },
            () => !string.IsNullOrEmpty(Name) && !string.IsNullOrEmpty(Memo)
        );
    }
}

Binding code:

<TextBlock Text="{Binding Name}">
<TextBlock Text="{Binding Memo}">

ViewModel's implementation using ReactiveProperty:

public class AViewModel
{
    public ValidatableReactiveProperty<string> Name { get; }
    public ValidatableReactiveProperty<string> Memo { get; }
    public ReactiveCommandSlim DoSomethingCommand { get; }

    public AViewModel()
    {
        Name = new ValidatableReactiveProperty<string>("", 
            x => string.IsNullOrEmpty(x) ? "Invalid value" : null);
        Memo = new ValidatableReactiveProperty<string>("",
            x => string.IsNullOrEmpty(x) ? "Invalid value" : null);
        DoSomethingCommand = new[]
            {
                Name.ObserveHasErrors,
                Memo.ObserveHasErrors,
            }
            .CombineLatestValuesAreAllFalse()
            .ToReactiveCommand()
            .WithSubscribe(() => { ... });
    }
}

Binding code:

<TextBlock Text="{Binding Name.Value}">
<TextBlock Text="{Binding Memo.Value}">

It's very simple.

ReactiveProperty doesn't provide base class by ViewModel, which means that ReactiveProperty can be used together with another MVVM libraries such as Prism, Microsoft.Toolkit.Mvvm and etc.

Documentation

ReactiveProperty documentation

NuGet packages

Package Id Version and downloads Description
ReactiveProperty The package includes all core features.
ReactiveProperty.Core The package includes minimum classes such as ReactivePropertySlim<T> and ReadOnlyReactivePropertySlim<T>. And this doesn't have any dependency even System.Reactive. If you don't need Rx features, then it fits.
ReactiveProperty.WPF The package includes EventToReactiveProperty and EventToReactiveCommand for WPF. This is for .NET 6 or later and .NET Framework 4.7.2 or later.
ReactiveProperty.Blazor The package includes validation support for EditForm component of Blazor with ReactiveProperty validation feature. This is for .NET 6.0 or later.

Following packages are maitanance phase.

Package Id Version and downloads Description
ReactiveProperty.UWP The package includes EventToReactiveProperty and EventToReactiveCommand for UWP.
ReactiveProperty.XamarinAndroid The package includes many extension methods to create IObservable from events for Xamarin.Android native.
ReactiveProperty.XamariniOS The package includes many extension methods to bind ReactiveProperty and ReactiveCommand to Xamarin.iOS native controls.

Support

I'm not watching StackOverflow and other forums to support ReactiveProperty, so please feel free to post questions at Github issues. I'm available Japanese(1st language) and English(2nd language).

If too many questions are posted, then I plan to separate posting place about feature requests, issues, questions.

Author info

Yoshifumi Kawai a.k.a. @neuecc is Founder/CEO/CTO of Cysharp, Inc in Tokyo, Japan. Awarded Microsoft MVP for Developer Technologies since April, 2011. He is an original owner of ReactiveProperty.

Takaaki Suzuki a.k.a. @xin9le software developer in Fukui, Japan. Awarded Microsoft MVP for Developer Technologies since July, 2012.

Kazuki Ota a.k.a. @okazuki software developer in Tokyo, Japan. Awarded Microsoft MVP for Windows Development since July 2011 to Feb 2017. Now, working at Microsoft Japan.

reactiveproperty's People

Contributors

100poisha avatar apocalypticoctopus avatar chrispulman avatar dependabot[bot] avatar hayer avatar iainholder avatar iseebi avatar jagapoko avatar llaughlin avatar meilcli avatar mgnslndh avatar mimtari avatar mlischka avatar neuecc avatar runceel avatar runceel-demo avatar ryo1988 avatar ryuix avatar s520 avatar shanon-hs avatar soi013 avatar tmori3y2 avatar xin9le avatar zbrianw avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

reactiveproperty's Issues

Do not trigger initial values for validation

Given this code:

public class AuthenticationViewModel : ViewModel, IDisposable
{
    [Required]
    public ReactiveProperty<string> EntryUsername { get; }

    public ReadOnlyReactiveProperty<string> EntryUsernameErrorMessage { get; }
    public AuthenticationViewModel()
    {
        EntryUsername = new ReactiveProperty<string>(initialValue: null)
            .SetValidateAttribute(() => EntryUsername);

        EntryUsernameErrorMessage = EntryUsername
            .ObserveErrorChanged
            .Select(x => x?.Cast<string>()?.FirstOrDefault())
            .ToReadOnlyReactiveProperty();
    }
}

When you open the page, validation is triggered and we can see the Required error message.
I can't find a way to delay initial validation to the first character entered by a user. Any ideas beside creating a new validation attribute?

Support debug symbol

こんにちは。NuGet Packageに.pdbファイルを追加することを検討していただけないでしょうか?

理由は、ステップインしてデバッグすることで、ReactivePropertyへの理解を深めるためです。
もちろん、自分でソースを落としてビルドすれば出来るのはわかっていますが、標準で配布されていれば「My Codeのみにステップイン」のチェックを外すだけでステップイン出来るので、かなり利用する側の負担が減ると思われます。

方法は2つあると思います。

nuget.orgで一緒に配布する方法は、基本は.nuspecの修正で出来ます。

ただし、ReactiveProperty.Platform.iOSはReleaseで.pdbが出力されていなかったので修正が必要です。

githubで間違ってForkボタンを押してしまったので、ついでに修正してパッケージの作成まで試してみました。

tmori3y2@cbd347a

では、良いお返事をお待ちしています。

PS.

Mono/Xamarinの素人でかなり悩んだので、一つ質問があります。

.dll.mdbがMono系のシンボルファイルのようですが、.pdbがあればパッケージをインストールしたMono/Xamarinのプロジェクトで.dll.mdbを生成してくれるのではないかと思うのですが、合っているでしょうか?

Insall error in Xamarin project

Xamarinプロジェクト(PCLプロジェクト)でver3.0.0 インストール時に下記エラーが発生しています。
ver2.9.0では問題ありません。

パッケージ 'System.ComponentModel.Annotations.4.1.0 : System.Runtime [4.1.0, )' はプロジェクト 'TestProject' に存在しません

プロジェクトは下記で作成したものです。
NewProject -> Visual C# -> Cross-Platform
Blank Xaml App (Xamarin.Forms.Portable)

複数ウィンドウでReactivePropertyを使うとスレッドの例外が発生する

いつもお世話になっております。
ReactivePropertyについて一つ質問があります。

UWPでワードやエクセルや付箋のように,全く同じウィンドウを複数開くことのできるアプリを作っているのですが,2つ目以降のウィンドウでモデルのプロパティに変化が生じるとThe application called an interface that was marshalled for a different thread.というお決まりの例外が発生してしまいます。

image

対策としてスケジューラにSynchronizationContextSchedulerを指定してみたら例外が発生しなくなりました。ですが,そもそもRxのスケジューラをよく分かっていないのでこれが正しい対処なのかも判断がつきません。また,仮にスケジューラが正しいとしても全てのプロパティにスケジューラを設定するのはおかしな感じがします。

this.Title = new ReactiveProperty<string>(
    raiseEventScheduler: new SynchronizationContextScheduler(SynchronizationContext.Current),
    initialValue: "");

再現プロジェクトを添付しますので,もしよければ見てやってください。

2つ目以降のウィンドウはタスクバーでアプリのアイコンを中クリックするなどで開いてください。

MultiWindowApp-master.zip

環境

  • Windows 10 1067
  • Visual Studio 2015
  • Prism.Unity
  • ReactiveProperty

Validation problem on DTO

HI i've strange error on validation:

If I have a ReactiveProperty<string> with validation:

TestString.SetValidateNotifyError(observable => string.IsNullOrEmpty(observable) ? "Error" : null);

XAML

<TextBox Text="{Binding TestString.Value ,Mode=TwoWay, ValidatesOnDataErrors=True,ValidatesOnExceptions=True , UpdateSourceTrigger=PropertyChanged, ValidatesOnNotifyDataErrors=True}" Width="500" >

Validation works:

image

But If I have a DTO (with INotifyPropertyChanged) not fire validation on Wpf:

public ReactiveProperty<EventoVenditaDto> CurrentItem { get; set; }
CurrentItem.SetValidateNotifyError(observable =>
            {
                return string.IsNullOrEmpty(observable.DesEventoVendita) ? "Error!!" : null;

            });

XAML:

<TextBox Text="{Binding CurrentItem.Value.DesEventoVendita ,Mode=TwoWay, ValidatesOnDataErrors=True, ValidatesOnExceptions=True , UpdateSourceTrigger=PropertyChanged, ValidatesOnNotifyDataErrors=True}" Width="500" >

image

Why?

Thanks!

Intellisense can't find ReactiveProperty Type

Dear Community,

the following problem appeared to me:

Error Image

I'm using Resharper and it seems it is not able to tell the generic type of the reactive property. Compiling this code works of course. If i look at the issue it's not showing "string" for the Value property but "???".
Can something be done about this. Of course it is not crititcal because the code can be compiled.

Nevertheless it's still not nice having errors popping up in the IDE.

Thank you very much

Throttle ReactiveCommand

Hi

I'm not sure if this was the right place to post but I have a question. How can I throttle/sample/... a ReactiveCommand? I want to implement the typical autocomplete feature but I'm bound to a MVVM pattern. So what I need to do is make sure the KeyUp event (bound to a ReactiveCommand) only fires when the user is done typing (Throttle with a TimeSpan) so I can query an API.

I can't seem to find something similar in the samples, the WP8.1 sample shows how to delay a result to a ReactiveProperty but not a ReactiveCommand. Any ideas or am I doing this completely wrong?

Thanks for your help!

Creating ReactiveCommands from Non-UI-Observables

When using ToReactiveCommand on a non-UI-Observable an InvalidOperationException is thrown since the Command may only be invalidated by the Dispatcher.

Using ObserveOnDispatcher() on the observable solves this issue, but the commands would be easier to use if ToReactiveCommand(..) would do this internally

ReactiveProperty doesn't notify on conversion errors

Dear Developers,

i have another problem with reactive property.
When i define a property this way:

var rp = new ReactiveProperty<int>(100);
rp.ObserveHasErrors.Subscribe(...)

The problem is that the observable doesn't inform me about conversion errors. If i bind rp to a textbox and enter "5Test" it obviously shows a convert error (in the ui) because "5Test" is no integer. Those errors are not sent to ObserveHasErrors observable as it seems.

Is this intended or an error?

Support for more complex async ReactiveCommands

Hello,
I had a problem for which I couldn't find a solution in your library. I want to perform an async task in my demo app.
The view-model:

public class ViewModel {
    public ReactiveProperty<string> FamilyName { get; private set; }
    public ReactiveCommand StoreUserCommand { get; private set; }
    public ReactiveProperty<string> Status { get; private;}
}

Storing a user takes a lot of time, so I want to perform this command asynchronous. So my ctor looks like this:

public ViewModel() {
    FamilyName = new ReactiveProperty<string>();
    Status = new ReactiveProperty<string>();

    StoreUserCommand = FamilyName
            .Select(s => !string.IsNullOrWhiteSpace(s) && s.Length > 5)
            .ToReactiveCommand();
    StoreUserCommand.Subscribe(async _=> {
        await Task.Delay(1000);//storing user take some time
        MessageBox.Show("Done");
    });
}

This solution makes the StoreUserCommand perform async, but it does not disable the button I bound it to. So I came up with this solution to initialize the command:

var isExceuting = new ReplaySubject<bool>(1);
isExceuting.OnNext(false);
StoreUserCommand = FamilyName
    .Select(s => !string.IsNullOrWhiteSpace(s) && s.Length > 5)
    .CombineLatest(isExceuting, (ce, ie) => ce && !ie)
    .ToReactiveCommand();

StoreUserCommand.Subscribe(async _ => {
    isExceuting.OnNext(true);
    await Task.Delay(1000);//storing user take some time
    isExceuting.OnNext(false);
    MessageBox.Show("Done");
});

As you can see, I have to to a lot of work, to simply do something async and prevent the user from doing this in parallel.
Now I have another problem. Some of the commands I use, have some preparation and wrap-up task that have to be done in the GUIs thread. An example: The command writes log messages that are visible in the GUI. These have to be cleared, before the new run.
I don't wanted to expand the last result above. On the one hand, there is lots of code that can be reused in similar situation, on the other hand there is already to much fluff code. It is hard to read. I simply wanted something like this:

StoreUserCommand = FamilyName
    .Select(s => !string.IsNullOrWhiteSpace(s) && s.Length > 5)
    .DoingAsync(() => {
        Thread.Sleep(1000);//storing a used takes a long time
        MessageBox.Show("Done");
    })
    .Prepare(() => Status.Value = "Started")//done in GUI thread
    .WrapUp(_ => Status.Value = "End") //done in GUI thread
    .ToAsyncReactiveCommand();

So I implemented something that used the builder pattern and some extension methods:

public class ReactiveCommandProperties<T> {
    private readonly IObservable<bool> _can_excecute;
    private readonly Func<T> _action_to_perform_async;
    private readonly IList<Action> _preparation_actions = new List<Action>();
    private readonly IList<Action<T>> _wrapup_actions = new List<Action<T>>();
    private bool _allow_concurent_runs;

    internal ReactiveCommandProperties(IObservable<bool> can_excecute, Func<T> action_to_perform_async) {
        _can_excecute = can_excecute;
        _action_to_perform_async = action_to_perform_async;
    }

    internal ReactiveCommandProperties<T> AddPreparation(Action preparation) {
        _preparation_actions.Add(preparation);

        return this;
    }

    internal ReactiveCommandProperties<T> AddWrapUp(Action<T> wrapup) {
        _wrapup_actions.Add(wrapup);

        return this;
    }

    internal ReactiveCommand Build(out IDisposable subscription) {
        var is_executing = new ReplaySubject<bool>(1);
        is_executing.OnNext(false);
        var command = _can_excecute.CombineLatest(is_executing, (ce, ie) => ce && !ie)
            .ToReactiveCommand();

        var preparations = _preparation_actions.ToArray();
        var wrapups = _wrapup_actions.ToArray();
        var block_concurent_calls = !_allow_concurent_runs;

        subscription = command.Subscribe(async _ => {
            if (block_concurent_calls)
                is_executing.OnNext(true);

            foreach (var action in preparations) {
                action();
            }

            var task = Task.Factory.StartNew(_action_to_perform_async);
            await task;

            foreach (var wrapup in wrapups) {
                wrapup(task.Result);
            }

            if(block_concurent_calls)
                is_executing.OnNext(false);
        });

        return command;
    }

    internal ReactiveCommandProperties<T> AllowConcurentRuns() {
        _allow_concurent_runs = true;

        return this;
    }  
}

public static class ReactiveCommandExtension {
    public static ReactiveCommandProperties<T> DoingAsync<T>(this IObservable<bool> canExecute, Func<T> action_to_perform_async) {
        return new ReactiveCommandProperties<T>(canExecute, action_to_perform_async);
    }

    public static ReactiveCommandProperties<Unit> DoingAsync(this IObservable<bool> canExecute, Action action_to_perform_async) {
        return new ReactiveCommandProperties<Unit>(canExecute, ()=>
        {
            action_to_perform_async();
            return Unit.Default;
        });
    }

    public static ReactiveCommandProperties<T> AllowConcurentCalls<T>(this ReactiveCommandProperties<T> properties) {
        return properties.AllowConcurentRuns();
    } 

    public static ReactiveCommandProperties<T> Prepare<T>(this ReactiveCommandProperties<T> properties, Action prepare) {
        return properties.AddPreparation(prepare);
    }

    public static ReactiveCommandProperties<T> WrapUp<T>(this ReactiveCommandProperties<T> properties, Action<T> wrapup) {
        return properties.AddWrapUp(wrapup);
    }

    public static ReactiveCommand ToAsyncReactiveCommand<T>(this ReactiveCommandProperties<T> properties) {
        IDisposable disposable;
        return properties.Build(out disposable);
    }
    public static ReactiveCommand ToAsyncReactiveCommand<T>(this ReactiveCommandProperties<T> properties, out IDisposable subscription) {
        return properties.Build(out subscription);
    }
}

This solution support:

  • Preventing the user from calling command multiple times by changing CanExcecute to false.
  • But optional allow used to call command multiple times concurrently.
  • Optionally adding Preparation tasks in GUI-thread.
  • Optionally adding Wrap-up tasks in GUI-thread.
  • An optional result from background task.
  • Separates WHAT is done from HOW its done.
  • Exposing internal created subscription to let consumer handle disposing, if he/she wish to.

The only thing that is not supported, is a custom scheduler.

.NET Core

Hello

Do you have any plans about .Net Core 2.0 ?

ReactiveProperty Android SetBinding does not support interfaces

Hi,

In an Android app, I've set all my ViewModels to use interfaces and my properties implements either IReadOnlyReactiveProperty or IReactiveProperty. But they cannot be used to call View.SetBinding().

If you want to allow my to collaborate, I can create a branch and implement it. Then I'll do a Pull Request.

Thanks

Update to System.Reactive v3.1.0

The project should be updated to System.Reactive.xxx version 3.1.0, in order to support newer projects.

Currently a project that references the new version of System.Reactive as well as ReactiveProperty gets an compile error.

Winforms data binding

Windows Forms で ReactiveProperty を使ったデータバインディングをしようとしています。

下記コードにて、
プロパティに文字列 "01" を設定したときに、ConvertBack で変換した値(int: 1)がモデルへ設定され、
Convert でまた変換された値(string: "1")が TextBox.Text へ設定されますが、
その直後に、TextBox.Text が元の値 "01" で上書きされてしまいます。

この上書きを抑制する方法はございますでしょうか?

また、TextBox.Text に文字列 "02" を設定したときに、
モデルを経て TextBox.Text に "2" が設定されるようには出来ますでしょうか?
※テストコードではTextChangedがトリガーですが、実際にはValidatingがトリガーになります。

よろしくお願いいたします。

モデル

        private class Model : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;

            private int intValue;

            public int IntValue
            {
                get { return this.intValue; }
                set
                {
                    Debug.WriteLine("Set Value:" + value);
                    if (this.intValue != value)
                    {
                        this.intValue = value;
                        var h = this.PropertyChanged;
                        if (h != null) h(this, new PropertyChangedEventArgs("IntValue"));
                    }
                }
            }
        }

テストコード

            var model = new Model();

            var stringProperty =
                model
                .ToReactivePropertyAsSynchronized(
                    m => m.IntValue,
                    convert: v => { Debug.WriteLine("Convert:" + v); return v.ToString(); },
                    convertBack: v => { Debug.WriteLine("ConvertBack:" + v); return int.Parse(v); });

            stringProperty.Subscribe(v => Debug.WriteLine("Subscribe:" + v));

            var tb = new System.Windows.Forms.TextBox();
            tb.TextChanged += (s, e) => Debug.WriteLine("TextChanged:" + tb.Text);

            stringProperty.BindTo(
                tb,
                t => t.Text,
                BindingMode.TwoWay,
                targetUpdateTrigger: Observable.FromEvent<EventHandler, EventArgs>(
                    h => (s, e) => h(e),
                    h => tb.TextChanged += h,
                    h => tb.TextChanged -= h)
                    .ToUnit());

            Debug.WriteLine("TextBox:" + tb.Text);

            Debug.WriteLine("StringProperty.Value change");
            stringProperty.Value = "01";

            Debug.WriteLine("TextBox.Text change");
            tb.Text = "02";

実行結果

Convert:0
ConvertBack:0
Set Value:0
Subscribe:0
TextChanged:0
TextBox:0

StringProperty.Value change
ConvertBack:01
Set Value:1
Convert:1
ConvertBack:1
Set Value:1
Subscribe:1
TextChanged:1
Subscribe:01
TextChanged:01

TextBox.Text change
TextChanged:02
ConvertBack:02
Set Value:2
Convert:2
ConvertBack:2
Set Value:2
Subscribe:2
Subscribe:02

ReactiveCommand Extension for constructor with Subscribe

Hi.

I wrote these code frequently.

DoSomeACommand = IsBusy
    .Select(x => !x)
    .ToReactiveCommand()
    .AddTo(this.Disposable);
DoSomeACommand.Subscribe(() => model.DoSome("A"));

DoSomeBCommand = IsBusy
...

I suppose there are 2 problems.

  • DoSomeACommand was repeated.
  • Constructor and Subscribe of DoSomeACommand were separated.

Therefore I wrote these Extension Method.

public static class ReactiveCommandEx
{
    public static ReactiveCommand WithSubscribe(this ReactiveCommand rcomm, Action onNext)
    {
        rcomm.Subscribe(onNext);
        return rcomm;
    }
}

How to use is this.

DoSomeACommand = IsBusy
    .Select(x => !x)
    .ToReactiveCommand()
    .WithSubscribe(() => model.DoSome("A"))
    .AddTo(this.Disposable);

So if I can add this method to ReactiveProperty, I will write pull-request with generic command ,test, and demo.

ObserverHasErrors in Subclasses

Hi,

i've a problem to get the following code up and running. The CommandButton (WPF) is always disabled.
It seems, that the ViewModel class doesn't catch the ObserveHasErrors changes from Customer class.

Customer.cs

namespace Application1
{
	public class Customer
	{
		[Required(ErrorMessage="Customer name is requried")]
		ReactiveProperty<string> CustomerName { get; }
		
		public Customer()
		{
			this.CustomerName = new ReactiveProperty<string>("").SetValidateAttribute(() => this.CustomerName);
		}
	}
}

ViewModel.cs

namespace Application1
{
	public class MyModel
	{
		ReactiveProperty<Customer> CustomerInfo { get; } = new ReactiveProperty<Customer>(new Customer());
		
		ReactiveCommand MyCommand { get; }
		
		public MyModel()
		{
			// this doesn't work, the button is always disabled
			this.MyCommand = new ReactiveCommand(this.CustomerInfo.ObserveHasErrors);
			
			// this doesn't work too, the button is always disabled
			// this.MyCommand = new ReactiveCommand(this.CustomerInfo.Value.CustomerName.ObserveHasErrors);
			
			this.MyCommand.Subscribe(() => MyCommandImpl());
		}
		
		private void MyCommandImpl()
		{
			// Do something
		}
	}
}

I hope someone can help me out.

regards

Enhancement: Observing Dependency Properties

It should be possible to convert an DependencyProperty to an Observable (and Reactive Property) in WPF und UWP projects.

The first step would be to get notifications when the property changes:

    public static class DependencyObjectExtensions
    {
        public static IObservable<EventArgs> Observe<T>(this T component, DependencyProperty dependencyProperty)
            where T:DependencyObject
        {
            return Observable.Create<EventArgs>(observer =>
            {
                EventHandler update = (sender, args) => observer.OnNext(args);
                var property = DependencyPropertyDescriptor.FromProperty(dependencyProperty, typeof(T));
                property.AddValueChanged(component, update);
                return Disposable.Create(() => property.RemoveValueChanged(component, update));
            });
        }
    }

I guess a similar approach could be used that additionally uses the SetValue(DependencyProperty, (object)T) and (T)GetValue(DependencyProperty) methods to wrap the DependencyProperty with an ReactiveProperty.

        public static ReactiveProperty<TValue> ToReactiveProperty<TDependencyObject, TValue>(this TDependencyObject component, DependencyProperty dependencyProperty)
            where TDependencyObject:DependencyObject
        {
            var initialValue = (TValue) component.GetValue(dependencyProperty);
            var property = new ReactiveProperty<TValue>(initialValue /* TODO: needs IScheduler and ReactivePropertyMode */);

            // subscribe to changes of the reactive property
            var changes = component.Observe(dependencyProperty);

            // TODO: needs to get disposed when ReactiveProperty gets disposed
            var subscription = changes.Subscribe(args => property.Value = (TValue)component.GetValue(dependencyProperty));
            
            return property;
        }
``

Thinking on IDisposables

Having a little misunderstanding on how do disposables work with reactive properties. Should we make each our ViewModel implement IDisposable interface and should we call .Dispose() method for each of our ReactiveProperties declared and used in our code? Or should we do it only in complicated scenarios when we want to stop observing events manually?

According to this page we should dispose our observables only if we create a subscription loop that should be stopped when ViewModel is no longer needed.

It would be nice if you could point out best practices on using IDisposables, cases when calling .Dispose() is necessary and when isn't, problems that may arise if we don't stop active subscriptions :)

Thanks, @runceel!

Making simpliest initialization less verbose

There may be some cases when properties should be initialized from a simple default value. False for IsLoading property, true for IsEmpty property and so on. To initialize my indicator properties I currently have to use this:

Query = new ReactiveProperty<string>(string.Empty);
IsGreeting = new ReactiveProperty<bool>(true);
IsLoading = new ReactiveProperty<bool>(false);
IsEmpty = new ReactiveProperty<bool>(false);

This is very nice, but seems to be quite verbose! :)

To simplify initialization static implicit operator magic can be used. For example, this code:

public class ReactiveProperty<TValue> 
{
    public static implicit operator ReactiveProperty<TValue>(TValue value) 
    {
        return new ReactiveProperty<TValue>(value);
    }
}

Will allow us to shorten our initializers directly to this:

Query = string.Empty;
IsGreeting = true;
IsLoading = false;
IsEmpty = false;

Or this (if we use ValueTuples and don't like many lines of code)

Query = string.Empty;
(IsGreeting, IsLoading, IsEmpty) = (true, false, false);

Nice!

Integration/merge with ReactiveIU

Hello! I'm taking a look to your project. I come from a very interesting project called ReactiveUI. The only problem with it is that it doesn't provide a handy way to handle validation.

Do you know that project? Maybe you could join efforts to merge both projects, since both of you attack almost the same problems. For instance, you also have a ReactiveCommand.

Please, take a look: https://github.com/reactiveui/ReactiveUI

Best regards!

Proposal: Mathematical Extensions

I wanted to do mathematical operations on reactive properties, so I wrote my own extension and wondering if it should be part of ReactiveProperty.

My use case looks something like this:

public class SomeGuiElementViewModel : IDisposable
{
    private IList<IDisposable> Subscriptions { get; } = new List<IDisposable>();

    // ordinary reactive properties 
    public ReactiveProperty<double> PosX { get; } 
        = new ReactiveProperty<double>(ReactivePropertyMode.DistinctUntilChanged);
    public ReactiveProperty<double> PosY { get; } 
        = new ReactiveProperty<double>(ReactivePropertyMode.DistinctUntilChanged);
    public ReactiveProperty<double> Width { get; } 
        = new ReactiveProperty<double>(ReactivePropertyMode.DistinctUntilChanged);
    public ReactiveProperty<double> Height { get; } 
        = new ReactiveProperty<double>(ReactivePropertyMode.DistinctUntilChanged);

    // calculated properties 
    public ReactiveProperty<double> Right { get; } 
    public ReactiveProperty<double> Bottom { get; } 
    public ReactiveProperty<double> MidX { get; }
    public ReactiveProperty<double> MidY { get; }

    public SomeGuiElementViewModel()
    {
         Right = PosX.Add(Width).ToReactiveProperty(mode: ReactivePropertyMode.DistinctUntilChanged);
         Subscriptions.Add(Right.Subscribe(right => Left = Update(Left, right - Width.Value)));

         Bottom = PosY.Add(Height).ToReactiveProperty(mode: ReactivePropertyMode.DistinctUntilChanged);
         Subscriptions.Add(Bottom.Subscribe(bottom => Top = Update(Top, bottom - Height.Value)));

         MidX = PosX.Add(Width.DivideBy(2d)).ToReactiveProperty(mode: ReactivePropertyMode.DistinctUntilChanged);
         Subscriptions.Add(MidX.Subscribe(midx => /* ... */));

         MidY = PosY.Add(Height.DivideBy(2d)).ToReactiveProperty(mode: ReactivePropertyMode.DistinctUntilChanged);
         Subscriptions.Add(MidY.Subscribe(midy => /* ... */));
    }

    // used to prevent endless updates because of harmonics
    private double Update(double originalValue, double newValue)
    {
        const double delta = 0.0001d;
        return (Math.Abs(original - newValue) > delta) ? newValue : oldValue;
    }

#region IDisposable
// dispose properties and subscriptions 
#endregion
}

Technically, this should work with any type that has the following shape:

public shape SNumber<T>
{
    static T operator +(T t1, T t2);
    static T operator -(T t1, T t2);
    static T operator *(T t1, T t2);
    static T operator /(T t1, T t2);
    static T operator %(T t1, T t2);
}

unfortunately, shapes are not implemented in C# yet, so I'm using an T4 template (
ReactiveExtensions.cs.tt) instead to cover at least the built-in types:

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<# var types = new []{ "float", "double", "int", "uint", "decimal", "long", "ulong" }; #>
using System.Reactive.Linq;

namespace System.Reactive.Extensions
{
    public static class ReactiveExtensions
    {
<# foreach(var type in types) { #>
        public static IObservable<<#= type #>> Add(this IObservable<<#= type #>> left, IObservable<<#= type #>> right)
        {
            return left.CombineLatest(right, (l, r) => l + r);
        }

        public static IObservable<<#= type #>> Substract(this IObservable<<#= type #>> left, IObservable<<#= type #>> right)
        {
            return left.CombineLatest(right, (l, r) => l - r);
        }

        public static IObservable<<#= type #>> MultiplyWith(this IObservable<<#= type #>> left, IObservable<<#= type #>> right)
        {
            return left.CombineLatest(right, (l, r) => l * r);
        }

        public static IObservable<<#= type #>> DivideBy(this IObservable<<#= type #>> left, IObservable<<#= type #>> right)
        {
            return left.CombineLatest(right, (l, r) => l / r);
        }

        public static IObservable<<#= type #>> Mod(this IObservable<<#= type #>> left, IObservable<<#= type #>> right)
        {
            return left.CombineLatest(right, (l, r) => l % r);
        }

        public static IObservable<<#= type #>> Add(this IObservable<<#= type #>> left, <#= type #> right)
        {
            return left.Select(l => l + right);
        }

        public static IObservable<<#= type #>> Substract(this IObservable<<#= type #>> left, <#= type #> right)
        {
            return left.Select(l => l - right);
        }

        public static IObservable<<#= type #>> MultiplyWith(this IObservable<<#= type #>> left, <#= type #> right)
        {
            return left.Select(l => l * right);
        }

        public static IObservable<<#= type #>> DivideBy(this IObservable<<#= type #>> left, <#= type #> right)
        {
            return left.Select(l => l / right);
        }

        public static IObservable<<#= type #>> Mod(this IObservable<<#= type #>> left, <#= type #> right)
        {
            return left.Select(l => l % right);
        }

        public static IObservable<<#= type #>> Add(this <#= type #> left, IObservable<<#= type #>> right)
        {
            return right.Select(r => left + r);
        }

        public static IObservable<<#= type #>> Substract(this <#= type #> left, IObservable<<#= type #>> right)
        {
            return right.Select(r => left - r);
        }

        public static IObservable<<#= type #>> MultiplyWith(this <#= type #> left, IObservable<<#= type #>> right)
        {
            return right.Select(r => left * r);
        }

        public static IObservable<<#= type #>> DivideBy(this <#= type #> left, IObservable<<#= type #>> right)
        {
            return right.Select(r => left / r);
        }

        public static IObservable<<#= type #>> Mod(this <#= type #> left, IObservable<<#= type #>> right)
        {
            return right.Select(r => left % r);
        }
<# } #>
    }
}

Update Reactive Extensions dependencies

Reactive Extensions changed their package names when they moved to the .NET Foundation, and then the unlisted all the old packages. This means that it's easy to wind up with the new packages and the old packages of Reactive Extensions installed when depending on both System.Reactive and on ReactiveProperty.

Here are the steps to reproduce:

  1. In Visual Studio, create a new console project
  2. Add a NuGet dependency on System.Reactive
  3. Add a NuGet dependency on Reactive Property
  4. You now have System.Reactive and Rx-Main style packages in your list of project references. This means that you have duplicate DLLs with identical namespaces and classes and everything.

Read more about it here.

The new Reactive Extensions is source compatible, so switching out the packages should not break anything.

Idea for another way of creating reactive stuff

I try to test everything and so I a little bit annoyed of the way reactive properties are created. More then a few times I wrote test that failed, because I simply forgot to include the correct IScheduler.

So I developed something I called IReactiveCretor. It can used in the following way:

    public class UserViewModel{
        public ReactiveProperty<bool> IsActive{get;}
        public ReactiveProperty<string> FamilyName {get;}
        public ReactiveProperty<string> Name {get;}
        public ReactiveProperty<DateTimeOffset> Age {get;}
        public ReactiveCommand DeleteUser {get; }

        ///in this scenario, each User object contains update about the same user
        public SomeViewModel(IObservable<User> user, IReactiveCreator observed){
            IsActive = observed.Propery(false); //automatically get uidispatcher
            FamilyName = user.Select(u => u.FamilyName).ToReactiveProperty(observed.OnDispatcher);
            Name = user.Select(u => u.Name).ToReactiveProperty(observed.OnDispatcher);
            NameOfUser = user
                .ObservedOn(observed.OnTaskScheduler) //push to background to do some heavy work
                .Select(CalculateAge)
                .ToReactiveProperty(observed.OnDispatcher);
            DeleteUser = observed.Command();
            DeleteUser.
               .Do(invokation => DeleteUserInDatebase())
               .Subscribe()
        }
        ...
    }

In my opinion this offers a more fluent API while creating reactive properties. My IReactiveCretor implementation uses a ITestSchedulerService that can be easily mocked in tests.

What do you think?

Missing Method exception on Xamarin.Android

I got the following exception when trying to run Reactive.Bindings.Helpers.FilteredReadOnlyObservableCollection.ToReadOnlyReactiveCollection either by invoking it or by using the extension method.

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.MissingMethodException: Method 'FilteredReadOnlyObservableCollection.ToReadOnlyReactiveCollection' not found.

The code is in a PCL, and I'm trying to run it on Xamarin.Android

validation limitations?

I'm wondering if there are some limitations in data validation. (A) While validation is happening, it is helpful to display a message letting the user know that an operation is in progress. Users may want to know if a long validation process ends in (B) error/exception or is (C) canceled so they can try again. Finally, (D) if validation is slower than the generation of values to validate, I think your code might notify listeners that error information has been updated, but the information that is published via INotifyDataErrorInfo may pertain to an older version of the property. All this makes me wonder if the validation function that is passed in to ReactiveProperty should work like this...

public enum ValidationProgress { Running, Completed, Faulted, Canceled }

public interface IValidationErrorInfo<T> {
    T Value { get; }
    ValidationProgress Progress { get; }
    IEnumerable Errors { get; }
    bool? HasErrors { get; }
    Exception Exception { get; }
}

public delegate IObservable<IValidationErrorInfo<T>> Validator<T>(IObservable<T> values);

In IValidationErrorInfo, HasErrors and Exception would be null if the progress is Running, Faulted, or Completed. You could automatically determine if ValidationProgress is Running - rather than relying on the validator function - as follows...

var latestValidationResults = Observable
    .CombineLatest(valuesToValidate, validator(valuesToValidate), 
        (v, r) => new { Value = v, Results = r });
var isValidating = latestValidationResults.Select(i => !Equals(i.Results.Value, i.Value));

Notice how this expression tests whether the validation results for a particular value match the current value stored in the property? This prevents you from publishing stale data. I would expect a ReactiveProperty instance to have a public member like what is shown below so other properties/code in your classes can inspect the current validation state.

IReadOnlyReactiveProperty<IValidationErrorInfo<T>> ValidationErrors { get; }

A similar expression would give you the most recent and relevant validation information to publish via INotifyDataErrorInfo. I'm not sure exactly how to map between IValidationErrorInfo and INotifyDataErrorInfo. Maybe you assume that if ValidationProgress is Canceled, Faulted, or Running, that HasErrors is true.

binding ReactiveProperty<string> in TextBox and inputting Korean character, there is an issue

I'm looking over and testing to decided to use your great solution in my work.
But, I found out an issue.

Binding ReactiveProperty in a TextBox for WPF and input Korean characters, there are some issues.

  1. After writing an Korean character, the cursor goes to begging of the TextBox.
  2. If one character is written in the TextBox, next input character is ignored. It is repeated continuosly.
  3. Input Korean charters continuously, the results are reversed.

The result of issues is below.

input issue

Code snippet is below.

<TextBox Text="{Binding KoreanMessage.Value, UpdateSourceTrigger=PropertyChanged}" />

I hope this issue will be fixed soon.
I really thank you for your passion on ReactiveProperty

DLL versions installed by NuGet is not updated from 1.0.0

We are using MSI based installer on Windows.
And MSI normally check the update of each exe/dll file by its associated version.
The problem is that RectiveProperty related DLLs have 1.0.0 for recent releases.

Do you have any plan to increment the version for future releases?

Update issues: Already defined assemblies

I just updated my projects to ReactiveProperty 4.1.1. However, I get some errors inside my test projects:

The type 'LocalScheduler' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Reactive.Core, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263'.

The type 'IScheduler' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Reactive.Interfaces, Version=3.0.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263'.

I tried to add those packages, but now the errors are:

The type 'IScheduler' exists in both 'System.Reactive.Interfaces, Version=3.0.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263' and 'System.Reactive, Version=4.0.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263'

The type 'ImmediateScheduler' exists in both 'System.Reactive.Core, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263' and 'System.Reactive, Version=4.0.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263'

I tried to:

  1. Close Visual Studio
  2. Delete packages folder
  3. Delete all bin/obj folders

Any ideas on what could be my issue?

Question regarding cleanup / Dispose

Hi,

Thanks for this great library!

I've just checked your examples and wonder how you clean up / unsubscribe from observables. Both ReactiveCommand and ReactiveProperty<T> implement the IDisposable interface. It is however not mentioned (or implemented) in any example.

I think the ToReactiveProperty<T>(this IObservable<T> source, ..) extension method requires the resulting property instance to be disposed - if not longer needed. Otherwise I would expect serious memleaks, if the application creates / destroys a lot of view models.

What do you think? Any best practices we should take into account?

Thanks,
Daniel

ReactivePropertySlim throws NotSupportedException when used in binding.

I'm developing a WPF application.
I tried using ReactivePropertySlim, and I noticed that it throw NotSupportedException when used in a binding.
An Exception is thrown at Reactive.Bindings.ReactivePropertySlim`1.System.ComponentModel.INotifyDataErrorInfo.add_ErrorsChanged(EventHandler`1 value).
For example, this occurs with the following code:

using System.Windows;
using Reactive.Bindings;

namespace WpfTest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new ViewModel();
        }
    }

    public class ViewModel
    {
        public ReactivePropertySlim<string> Slim { get; } = new ReactivePropertySlim<string>("test");
    }
}
<Window x:Class="WpfTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <TextBlock Text="{Binding Slim.Value}" />
</Window>

I found that I can avoid this issue by setting Binding.ValidatesOnNotifyDataErrors to false:

<Window x:Class="WpfTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <TextBlock Text="{Binding Slim.Value, ValidatesOnNotifyDataErrors=False}" />
</Window>

However it is verbose to set ValidatesOnNotifyDataErrors at every bindings.
It would be nice if you could change this behavior.

Add IGrouping implementation

Hello @runceel! Thanks for your great library.

Here is a short feature-request! While developing modern applications, both desktop and mobile ones, developers sometimes need to group elements in ListViews somehow and show group titles. Most XAML-based platforms are designed to provide support for grouping elements by using IGrouping<TKey, TValue> interface, so, often developers need to write their own implementations to let the UI know if a user has modified certain group of elements. The most commonly used implementation is the following:

public class ObservableGrouping<TKey, TValue> : ObservableCollection<TValue>, IGrouping<TKey, TValue>
{
    public ObservableGrouping(IGrouping<TKey, TValue> group) : base(grouping) => Key = group.Key;

    public ObservableGrouping(TKey key, IEnumerable<TValue> elements) : base(elements) => Key = key;

    public TKey Key { get; }
}

So, I think adding reactive IGrouping<,> implementation to the library could potentially make our lifes easier! I've created one, so please take a look, it's just a derived class from ReactiveCollection!

public class ReactiveGrouping<TKey, TValue> : ReactiveCollection<TValue>, IGrouping<TKey, TValue>
{
    public ReactiveGrouping(TKey key) => Key = key;

    public ReactiveGrouping(TKey key, IScheduler scheduler) : base(scheduler) => Key = key;

    public ReactiveGrouping(TKey key, IObservable<TValue> source) : base(source) => Key = key;

    public ReactiveGrouping(TKey key, IObservable<TValue> source, IScheduler scheduler) : base(source, scheduler) => Key = key;

    public ReactiveGrouping(IGrouping<TKey, TValue> group) : base(group.ToObservable()) => Key = group.Key;

    public TKey Key { get; }
}

Key is an immutable value during whole object lifetime here. Been thinking on making it an Observable<> too, but haven't really come across any cases where mutation of group titles in ListViews was desirable.

Thanks.

Easier way to get on IObservable<int> from CountNotifier

Hallo,
I'm using the CountNotifier in order count calls to a command as you suggest in my last issue #5.
For this purpose, I need to actual value stored in CountNotifier which I select in this way:

_callToCommandCounter = new CountNotifier();
_callToCommandCounter .Select(_ => _callToCommandCounter .Count > 0)

This works, but I prefer to have a possibility to observe the value directly. Something like this:

_callToCommandCounter.ObserveCount(count => count > 0);

What do you think?

ReactiveCommand.CanExecute should be more accessible

The three parts of this issue are:

  1. It would be nice to be able to override the CanExecute method (right now it's not virtual).
  2. It would be nice if there were constructors for ReactiveCommand that took a parameter of type Action<object>, which would provide the CanExecute functionality for that ReactiveCommand.
  3. There should probably be corresponding constructors for ReactiveCommand<T> that take a parameter of type Action<T>.

The reason for needing the original functionality of CanExecute is that it takes an object parameter, and there is no way to have similar functionality when specifying the IObservable<bool> canExecuteSource parameter to the ReactiveCommand constructor.

The reason I would like this added to ReactiveCommand rather than just using something like RelayCommand from MvvmLight is that it's really, really nice to be able to subscribe to commands.

Note: I'm not sure if this issue should be two separate issues; I'll be happy to split it out if that's agreed to be a better choice.

Idea for ReactiveProperty

Hi! I have an idea for the ReactiveProperty class, adding an Enabled and a Visible (bool) properties to the class, and that properties can be binded to the control binded to the Value property.

That's way there is not need to create separated properties (for example XXXXIsEnabled/XXXXIsVisible).

DependencyObject.ToReactiveProperty<T>(DependencyProperty) でTwoWayバインディングが動作しない

便利なライブラリの公開ありがとうございます。私的な開発で大変助かっております。

1点、ReactiveProperty 3.4.0で追加された、DependencyObjectの拡張メソッドの ToReactiveProperty についての質問があります。

ReactiveProperty 3.4.0をリリースしました - かずきのBlog@hatena

現象としましてはUserControlのTwoWayバインディングで、Dependency Propertyから生成したReactive Propertyからの変更が反映されないという状況です。質問としましては、この拡張メソッドは、仕様として Dependency Property => Reactive Property の単方向での変更しかサポートしてないのでしょうか?

ReactiveProperty/DependencyObjectExtensionsTest.cs at d935b7353937b3dcb20f3be1d0c4ab0b6d9b7ec7 · runceel/ReactiveProperty

上記のテストでも、Dependency Property => Reactive Property の単方向の更新のみ反映されるような仕様であるように見受けられます。

// テスト抜粋
            rp.Value = "homuhomu";
            rp.Value.Is("homuhomu");
            target.Name.Is("kimura");

今回、私のユースケースとしては Reactive Property => Dependency Property の変更の伝播、といいますか双方向の更新をさせたいのですが、正しい実装としてはどのように実装すればよいでしょうか?

// このように動作させたい
            rp.Value = "homuhomu";
            rp.Value.Is("homuhomu");
            target.Name.Is("homuhomu");

現状は以下のようにしてひとまず対処している状態です。(変更が循環してるような気がしますが、ひとまずは双方向の動作をしています)

var rp = target.ToReactiveProperty<string>(Person.NameProperty);
rp.Subscribe(x => target.Name = x );

ReactiveProperty should inherit from ReadOnlyReactiveProperty

It would be useful if the ReactiveProperty class inherited from the ReadOnlyReactiveProperty class. That way, we can have a private ReactiveProperty and a public ReadOnlyReactiveProperty with the same object as their value. This effectively lets us have private setters and public getters, but with a reactive property.

Example

// In this class we have an IsDirty boolean value that can change. We want
// it to be possible to change it from inside the class,
// but impossible to change it from outside the class except by actually
// changing one of the other properties.

public class MountainViewModel
{
    private ReactiveProperty<bool> _isDirty = new ReactiveProperty<bool>();

    // This is cleaner than having a line initializing
    // IsDirty in the constructor
    public ReadOnlyReactiveProperty<bool> IsDirty => _isDirty;

    public ReactiveProperty<string> Name { get; } = new ReactiveProperty<string>();

    public ReactiveProperty<double> HeightInMeters { get; } = new ReactiveProperty<double>();

    public MountainViewModel()
    {
        Name.Subscribe(_ => _isDirty.Value = true);
        HeightInMeters.Subscribe(_ => _isDirty.Value = true);
    }
}

// Example usage of MountainViewModel:

var mvm = new MountainViewModel();

// This line causes a compile error because IsDirty is a
// ReadOnlyReactiveProperty. This is good! We don't want people
// to manually set the dirty bit.
mvm.IsDirty.Value = true;

// The only way to change IsDirty to true is to actually change
// one of the other properties on the view model. This also is good!
mvm.Name = "Kilimanjaro";
Debug.Assert(mvm.IsDirty.Value);
// The assert passes because we changed the mountain's name

As it currently stands, we would have to make the class slightly less readable to accomplish the same effect:

public class MountainViewModel
{
    private ReactiveProperty<bool> _isDirty = new ReactiveProperty<bool>();

    public ReadOnlyReactiveProperty<bool> IsDirty { get; }

    public ReactiveProperty<string> Name { get; } = new ReactiveProperty<string>();

    public ReactiveProperty<double> HeightInMeters { get; } = new ReactiveProperty<double>();

    public MountainViewModel()
    {
        // This line is necessary because ReadOnlyReactiveProperty
        // is not a base class of ReactiveProperty.
        IsDirty = _isDirty.ToReadOnlyReactiveProperty(_isDirty.Value);

        Name.Subscribe(_ => _isDirty.Value = true);
        HeightInMeters.Subscribe(_ => _isDirty.Value = true);
    }
}

Thank you for your time!

EventToReactiveProeprty from Assembly "ReactiveProperty.NET45" is built with an older version of Blend SDK

This code results in an error when I'm using Blend 2015 and that's too bad because you can't use Blend to design WPF UI if you're using ReactiveProperty!

Here's the error message:
Type type 'EventToReactive' from assembly 'ReactiveProeprty.NET45' is built with older version of the Blend SDK, and is not supported in a Windows Presentation Framework 4 project.

coreInteractivity:Interaction.Triggers

        <coreInteractivity:EventTrigger 
                x:Name="DataCardIsLoaded"
                EventName="Loaded" 
                SourceName="UIProgramInfoData">

            <reactiveProperty:EventToReactiveProperty
                    x:Name="ReactOnLoaded" 
                    ReactiveProperty="{Binding ReactOnLoaded, UpdateSourceTrigger=PropertyChanged}" />

        </coreInteractivity:EventTrigger>

        <coreInteractivity:EventTrigger 
                x:Name="FieldLayoutReactor"
                EventName="FieldLayoutInitialized"
                SourceName="UIProgramInfoData">

            <reactiveProperty:EventToReactiveProperty 
                    x:Name="ReactOnInitialized"
                    IgnoreEventArgs="False"
                    ReactiveProperty="{Binding ReactOnInitialized, UpdateSourceTrigger=PropertyChanged}" />

        </coreInteractivity:EventTrigger>

    </coreInteractivity:Interaction.Triggers>

New namespace discussion

Motivation

Current name space is 'CodePlex.Reactive.Xxx'. But now, our project was moved to GitHub. It's ridiculous for us anymore. So, we are planning to change name space in ReactiveProperty version 2.

Help us

We are looking for some good ideas. Please tell us your idea :)

About usage of ToReactiveCommand()

I'm studying and run some examples on your site. It's very useful.
http://blog.okazuki.jp/entry/2015/02/22/212827

In the "Command at Reactive Property" section.
Yes, I could run your example.
Then, I've tried another type of ToReactiveCommand(), but my example doesn't work as expected.

What any problem in my source?
Buttons(Command1,2) doesn't change their appearance by CanExecuteChanged event.
But I can catch CanExecuteChanged event (Command1,2) every time boolSource.Value changes.

MainWindow.xaml

<Window.DataContext>
    <local:MainWindowViewModel></local:MainWindowViewModel>
</Window.DataContext>
<Grid>
    <StackPanel>
        <Button Content="Button1" Command="{Binding Command1}"/>
        <Button Content="Button2" Command="{Binding Command2}"/>
        <Button Content="Switch" Command="{Binding SwitchButton}"/>
    </StackPanel>
</Grid>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
}

public class MainWindowViewModel
{
    private ReactiveProperty<bool> boolSource { get; } = new ReactiveProperty<bool>(false);

    public ReactiveCommand Button1 { get; }
    public ReactiveCommand Button2 { get; }
    public ReactiveCommand SwitchButton { get; }
    public MainWindowViewModel()
    {
        Button1 = boolSource.ToReactiveCommand();            
        Button1.CanExecuteChanged += (s, e) => { System.Diagnostics.Debug.WriteLine("changed1"); };

        Button2 = new ReactiveCommand(boolSource);
        Button2.CanExecuteChanged += (s, e) => { System.Diagnostics.Debug.WriteLine("changed2"); };

        SwitchButton = new ReactiveCommand();
        SwitchButton.Subscribe(_ => { boolSource.Value = !boolSource.Value; });
    }
}

Thank you!

IsEnabled in ReactiveTimer

I tried to migrate DispatcherTimer to ReactiveTimer.
But, there is not IsEnabled Property in ReactiveTimer.

So, can I add the Property to ReactiveTimer?
If add, which is better?

  1. get only common Property
    bool IsEnabled {get;}

  2. ReactiveProperty
    ReaciveProperty<bool> IsEnabled {get;}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.