Observable FromEventPattern when object rasing events is reinstantiated - system.reactive

I am trying to set up an observable in a class that will tick each time an event fires on a member.
public class FooService
{
private BarProvider _barProvider;
public IObservable<BarChangedEventArgs> BarChanged { get; }
public FooService()
{
BarChanged =
Observable
.FromEventPattern<BarChangedHandler, BarChangedEventArgs>(
h => _barProvider.Changed += h,
h => _barProvider.Changed -= h)
.Select(p => p.EventArgs);
}
public void OccursSomeTimeAfterFooServiceCreation
(
Func<BarProvider> barProviderFactory
)
{
_barProvider = barProviderFactory();
}
}
What I think I need to do is set up the event handler observable after assigning the new value of _barProvider in the OccursLater method, as this is a new event source. However, I believe setting BarChanged at this later point, after consumers may have already subscribed, will break those existing subscriptions.
I would like consumers of the FooService to be able to subscribe to BarChanged at any point, and see the observable as one stream of event args, regardless of how many times OccursSomeTimeAfterFooServiceCreation is called after the subscription is created.

If your Observable - creation depends on stuff that can change e.g. your barProvider, you should always retrieve those from other Observables and then utilize the Switch() operator.
To achieve this I utilized the BehaviorSubject.
public class FooService
{
public BehaviorSubject<BarProvider> _barProviderSubject = new BehaviorSubject<BarProvider>(null); //or initialize this subject with the barprovider of your choice
public IObservable<BarChangedEventArgs> BarChanged { get; }
public FooService()
{
var barChangedChanged = _barProviderSubject.Where(bP => bP != null).Select(bP =>
Observable.FromEventPattern<BarChangedHandler, BarChangedEventArgs>(
h => bP.Changed += h,
h => bP.Changed -= h)
.Select(p => p.EventArgs)
);
BarChanged = barChangedChanged.Switch();
}
public void OccursSomeTimeAfterFooServiceCreation
(
Func<BarProvider> barProviderFactory
)
{
_barProviderSubject.OnNext(barProviderFactory());
}
}

The problem is that you don't observe classes or variables. You observe instances.
If I understand it correctly, you want your subscribers to be oblivious of the fact that the observed instance changes.
Try something like this:
public class FooService
{
private BarProvider _barProvider;
private Subject<BarChangedEventArgs> subject = new Subject<BarChangedEventArgs>();
public IObservable<BarChangedEventArgs> BarChanged { get; } = subject.AsObservable();
public FooService()
{
}
public void OccursSomeTimeAfterFooServiceCreation
(
Func<BarProvider> barProviderFactory
)
{
_barProvider = barProviderFactory();
BarChanged =
Observable
.FromEventPattern<BarChangedHandler, BarChangedEventArgs>(
h => _barProvider.Changed += h,
h => _barProvider.Changed -= h)
.Select(p => p.EventArgs)
.Subscribe(subject);
}
}

Related

Reactive Extensions Throttle produce no results

Given this setup,
public static class NotifyPropertyChangedExtensions
{
public static IObservable<EventPattern<PropertyChangedEventArgs>> WhenPropertyChanged(this INotifyPropertyChanged source)
{
return Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
ev => source.PropertyChanged += ev,
ev => source.PropertyChanged -= ev);
}
}
public class Node : INotifyPropertyChanged
{
public bool IsChecked
{
get => _isChecked;
set
{
if (_isChecked != value)
{
_isChecked = value;
OnPropertyChanged();
}
}
}
}
nodes.Values.Select(node => node.WhenPropertyChanged())
.Merge()
.Where(x => x.EventArgs.PropertyName == "IsChecked")
.Throttle(TimeSpan.FromMilliseconds(200))
.Subscribe(x =>
{
// do somethings
});
why does this not fire any events when I call?
nodeX.IsChecked = true;
immediately after setting up the subscription but works afterwards?
You do realize that is the intended behavior of the Throttle operator:
only emit an item from an Observable if a particular timespan has passed without it emitting another item
(source)
So in your case, since you perform the Merge before applying the Throttle operator, an item is emitted after a change to IsChecked and then after 200 ms.

Dialog interaction requests using IObservable

I'm using reactive programming to build an MVVM app and am trying to figure out how my view model can raise a question and wait for a dialog to prompt the user for an answer.
For example, when the user clicks a Rename button I want a dialog to pop up that allows the user to change the text. My approach is for the view model to expose an IObservable<string> property. Code-behind in the View listens for emitted values and might display a UWP ContentDialog. If the user changes the text and clicks OK, code in that dialog would call ReportResult(string newText) on view model. I've got some code below to show how it works. Two questions:
Is this a reasonable approach for collecting information from the user?
Also, I've got two subtly different approaches for building this and don't know which is better.
interface IServiceRequest<TSource, TResult> : ISubject<TResult, TSource> { }
// Requests for information are just 'passed through' to listeners, if any.
class ServiceRequestA<TSource, TResult> : IServiceRequest<TSource, TResult>
{
IObservable<TSource> _requests;
Subject<TResult> _results = new Subject<TResult>();
public ServiceRequestA(IObservable<TSource> requests)
{
_requests = requests;
}
public IObservable<TResult> Results => _results;
public void OnCompleted() => _results.OnCompleted();
public void OnError(Exception error) => _results.OnError(error);
public void OnNext(TResult value) => _results.OnNext(value);
public IDisposable Subscribe(IObserver<TSource> observer) => _requests.Subscribe(observer);
}
// Requests for information are 'parked' inside the class even if there are no listeners
// This happens when InitiateRequest is called. Alternately, this class could implement
// IObserver<TSource>.
class ServiceRequestB<TSource, TResult> : IServiceRequest<TSource, TResult>
{
Subject<TSource> _requests = new Subject<TSource>();
Subject<TResult> _results = new Subject<TResult>();
public void InitiateRequest(TSource request) => _requests.OnNext(request);
public IObservable<TResult> Results => _results;
public void OnCompleted() => _results.OnCompleted();
public void OnError(Exception error) => _results.OnError(error);
public void OnNext(TResult value) => _results.OnNext(value);
public IDisposable Subscribe(IObserver<TSource> observer) => _requests.Subscribe(observer);
}
class MyViewModel
{
ServiceRequestA<string, int> _serviceA;
ServiceRequestB<string, int> _serviceB;
public MyViewModel()
{
IObservable<string> _words = new string[] { "apple", "banana" }.ToObservable();
_serviceA = new ServiceRequestA<string, int>(_words);
_serviceA
.Results
.Subscribe(i => Console.WriteLine($"The word is {i} characters long."));
WordSizeServiceRequest = _serviceA;
// Alternate approach using the other service implementation
_serviceB = new ServiceRequestB<string, int>();
IDisposable sub = _words.Subscribe(i => _serviceB.InitiateRequest(i)); // should dispose later
_serviceB
.Results
.Subscribe(i => Console.WriteLine($"The word is {i} characters long."));
WordSizeServiceRequest = _serviceB;
}
public IServiceRequest<string, int> WordSizeServiceRequest { get; set; }
// Code outside the view model, probably in the View code-behind, would do this:
// WordSizeServiceRequest.Select(w => w.Length).Subscribe(WordSizeServiceRequest);
}
Based on comments from Lee Campbell, here is a different approach. Maybe he'll like it better? I'm actually not sure how to build the IRenameDialog. Before it was just a bit of code-behind in the View.
public interface IRenameDialog
{
void StartRenameProcess(string original);
IObservable<string> CommitResult { get; }
}
public class SomeViewModel
{
ObservableCommand _rename = new ObservableCommand();
BehaviorSubject<string> _name = new BehaviorSubject<string>("");
public SomeViewModel(IRenameDialog renameDialog,string originalName)
{
_name.OnNext(originalName);
_rename = new ObservableCommand();
var whenClickRenameDisplayDialog =
_rename
.WithLatestFrom(_name, (_, n) => n)
.Subscribe(n => renameDialog.StartRenameProcess(n));
var whenRenameCompletesPrintIt =
renameDialog
.CommitResult
.Subscribe(n =>
{
_name.OnNext(n);
Console.WriteLine($"The new name is {n}");
};
var behaviors = new CompositeDisposable(whenClickRenameDisplayDialog, whenRenameCompletesPrintIt);
}
public ICommand RenameCommand => _rename;
}
Hmm.
The first block of code looks like a re-implementation of IObservable<T>, actually I think event worse ISubject<T>, so that raises alarm bells.
Then the MyViewModel class does other things like pass IObservable<string> as a parameter (Why?), create subscriptions (side effects) in the constructor, and expose a Service as a public property. You also metion having code in your view code behind, which is often a code-smell in MVVM too.
I would suggest reading up on MVVM (solved problem for 10yrs) and havnig a look at how other Client applications use Rx/Reactive programming with MVVM (solved problem for ~6yrs)
Lee shamed me into coming up with a better solution. The first and best turned out to be very simple. I pass into the constructor one of these:
public interface IConfirmationDialog
{
Task<bool> Show(string message);
}
Inside my view model, I can do something like this...
IConfirmationDialog dialog = null; // provided by constructor
_deleteCommand.Subscribe(async _ =>
{
var result = await dialog.Show("Want to delete?");
if (result==true)
{
// delete the file
}
});
Building a ConfirmationDialog wasn't hard. I just create one of these in the part of my code that creates view models and assigns them to views.
public class ConfirmationDialogHandler : IConfirmationDialog
{
public async Task<bool> Show(string message)
{
var dialog = new ConfirmationDialog(); // Is subclass of ContentDialog
dialog.Message = message;
var result = await dialog.ShowAsync();
return (result == ContentDialogResult.Primary);
}
}
So the solution above is pretty clean; dependencies my view model needs are provided in the constructor. Another approach similar to what Prism and ReactiveUI do is one where the ViewModel is constructed without the dependency it needs. Instead there is a bit of code-behind in the view to fill in that dependency. I don't need to have multiple handlers, so I just have this:
public interface IInteractionHandler<TInput, TOutput>
{
void SetHandler(Func<TInput, TOutput> handler);
void RemoveHandler();
}
public class InteractionBroker<TInput, TOutput> : IInteractionHandler<TInput, TOutput>
{
Func<TInput, TOutput> _handler;
public TOutput GetResponse(TInput input)
{
if (_handler == null) throw new InvalidOperationException("No handler has been defined.");
return _handler(input);
}
public void RemoveHandler() => _handler = null;
public void SetHandler(Func<TInput, TOutput> handler) => _handler = handler ?? throw new ArgumentNullException();
}
And then my ViewModel exposes a property like this:
public IInteractionHandler<string,Task<bool>> Delete { get; }
And handles the delete command like this:
_deleteCommand.Subscribe(async _ =>
{
bool shouldDelete = await _deleteInteractionBroker.GetResponse("some file name");
if (shouldDelete)
{
// delete the file
}
});

How to convert callbacks to Rx.Observable?

If an external library offers only to register a callback instead of an event, what is the best way to create an Observable from it?
If it where an event I could use Observable.FromEventPattern but in this case the only idea I have is to use a Subjectand queue events in it on each callback.
Is there any better way to do this?
Use Observable.Create. Here's an example:
void Main()
{
var target = new SampleCallbacker();
var actionB = new Action<int>(i => Console.WriteLine($"{i} * {i} = {i * i}."));
target.Register(actionB);
var observable = Observable.Create<int>(observer =>
{
var action = new Action<int>(i => observer.OnNext(i));
target.Register(action);
return () => target.Unregister(action);
});
var subscription = observable.Subscribe(i => Console.WriteLine($"From observable: {i} was fired."));
target.Fire(1);
target.Fire(2);
target.Fire(3);
Console.WriteLine("Unsusbscribing observable...");
subscription.Dispose();
target.Fire(4);
target.Fire(5);
}
class SampleCallbacker
{
private List<Action<int>> _actions = new List<System.Action<int>>();
public void Register(Action<int> action)
{
_actions.Add(action);
}
public void Unregister(Action<int> action)
{
while (_actions.Remove(action))
{} //loop remove
}
public void Fire(int i)
{
foreach (var action in _actions)
{
action(i);
}
}
}

How can I create an Rx observable which stops publishing events when the last observer unsubscribes?

I'll create an observable (through a variety of means) and return it to interested parties, but when they're done listening, I'd like to tear down the observable so it doesn't continue consuming resources. Another way to think of it as creating topics in a pub sub system. When no one is subscribed to a topic any more, you don't want to hold the topic and its filtering around anymore.
Rx already has an operator to suit your needs - well two actually - Publish & RefCount.
Here's how to use them:
IObservable xs = ...
var rxs = xs.Publish().RefCount();
var sub1 = rxs.Subscribe(x => { });
var sub2 = rxs.Subscribe(x => { });
//later
sub1.Dispose();
//later
sub2.Dispose();
//The underlying subscription to `xs` is now disposed of.
Simple.
If I have understood your question you want to create the observable such that when all subscribers have disposed their subscription i.e there is no more subscriber, then you want to execute a clean up function which will stop the observable from production further values.
If this is what you want then you can do something like below:
//Wrap a disposable
public class WrapDisposable : IDisposable
{
IDisposable disp;
Action act;
public WrapDisposable(IDisposable _disp, Action _act)
{
disp = _disp;
act = _act;
}
void IDisposable.Dispose()
{
act();
disp.Dispose();
}
}
//Observable that we want to clean up after all subs are done
public static IObservable<long> GenerateObs(out Action cleanup)
{
cleanup = () =>
{
Console.WriteLine("All subscribers are done. Do clean up");
};
return Observable.Interval(TimeSpan.FromSeconds(1));
}
//Wrap the observable
public static IObservable<T> WrapToClean<T>(IObservable<T> obs, Action onAllDone)
{
int count = 0;
return Observable.CreateWithDisposable<T>(ob =>
{
var disp = obs.Subscribe(ob);
Interlocked.Increment(ref count);
return new WrapDisposable(disp,() =>
{
if (Interlocked.Decrement(ref count) == 0)
{
onAllDone();
}
});
});
}
//Usage example:
Action cleanup;
var obs = GenerateObs(out cleanup);
var newObs = WrapToClean(obs, cleanup);
newObs.Take(6).Subscribe(Console.WriteLine);
newObs.Take(5).Subscribe(Console.WriteLine);

Reactive Extension in msword

I am wondering if it is possible to use Reactive Extensions in Word. I have seen this where Jeff shows how to wire up a workbook open event in excel http://social.msdn.microsoft.com/Forums/en/rx/thread/5ace45b1-778b-4ddd-b2ab-d5c8a1659f5f.
I wondering if I could do the same sort of thing in word.
I have got this far....
public static class ApplicationExtensions
{
public static IObservable<Word.Document> DocumentBeforeSaveAsObservable(this Word.Application application)
{
return Observable.Create<Word.Document>(observer =>
{
Word.ApplicationEvents4_DocumentBeforeSaveEventHandler handler = observer.OnNext;
application.DocumentBeforeSave += handler;
return () => application.DocumentBeforeSave -= handler;
});
}
}
but I receive the error No overload for 'OnNext' matches delegate 'Microsoft.Office.Interop.Word.ApplicationEvents4_DocumentBeforeSaveEventHandler
Can anyone point me in the right direction.
Regards
Mike
Your problem is an issue of delegate signatures.
IObserver<T>.OnNext is defined as void (T value)
whereas ApplicationEvents4_DocumentBeforeSaveEventHandler is defined as void (Document doc, ref bool SaveAsUI, ref bool Cancel)
If you only need to emit the Document (and not the other details, like making it cancelable), you can do something like this:
public static IObservable<Word.Document> DocumentBeforeSaveAsObservable(
this Word.Application application)
{
return Observable.Create<Word.Document>(observer =>
{
Word.ApplicationEvents4_DocumentBeforeSaveEventHandler handler =
(doc, ref saveAsUI, ref cancel) => observer.OnNext(doc);
application.DocumentBeforeSave += handler;
return () => application.DocumentBeforeSave -= handler;
});
}
If you do require all the data, you'll need to create a wrapper class of some kind an IObservable sequence can only emit a single type:
public class DocumentBeforeSaveEventArgs : CancelEventArgs
{
public Document Document { get; private set; }
public bool SaveAsUI { get; private set; }
public DocumentBeforeSaveEventArgs(Document document, bool saveAsUI)
{
this.Document = document;
this.SaveAsUI = saveAsUI;
}
}
And then you can use it like so:
public static IObservable<Word.Document> DocumentBeforeSaveAsObservable(
this Word.Application application)
{
return Observable.Create<Word.Document>(observer =>
{
Word.ApplicationEvents4_DocumentBeforeSaveEventHandler handler =
(doc, ref saveAsUI, ref cancel) =>
{
var args = new DocumentBeforeSaveEventArgs(doc, saveAsUI);
observer.OnNext(args);
cancel = args.Cancel;
};
application.DocumentBeforeSave += handler;
return () => application.DocumentBeforeSave -= handler;
});
}