Reactive Extension in msword - ms-word

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;
});
}

Related

Subscribe to Close, but close only if item was saved

My scenario:
In an MVVM pattern, the view should be closed when a command is executed on ViewModel, but only if the item was successfully saved.
The View looks like:
public class CentreUpdateWindow : ReactiveWindow<CentreUpdateViewModel>
{
public CentreUpdateWindow()
{
this.InitializeComponent();
this.WhenActivated(d =>
d(ViewModel!.SubmitCommand.Subscribe(CloseIfSuccessfullySaved))
);
}
private void CloseIfSaved(Centre? obj)
{
if (ViewModel!.SuccessfullySaved)
Close(obj);
}
// ...
And the ViewModel:
public class CentreUpdateViewModel : ViewModelBase, IId
{
// ...
public ReactiveCommand<Unit, dtoo.Centre?> SubmitCommand { get; }
private bool _SuccessfullySaved;
public bool SuccessfullySaved
{
get { return _SuccessfullySaved; }
protected set { this.RaiseAndSetIfChanged(ref _SuccessfullySaved, value); }
}
The question:
The code works fine, but I'm not comfortable with the if (ViewModel!.SuccessfullySaved). I guess should be a way to write subscribe expression more accurate.
Is there a more elegant way to Subscribe on WhenActivated more "reactiveuistic" ?
public CentreUpdateWindow()
{
this.InitializeComponent();
this.WhenActivated(d =>
d(
ViewModel
.WhenAnyValue(x => x.SuccessfullySaved)
.CombineLatest(ViewModel!.SubmitCommand,
(saved, obj) => (saved, obj))
.Where(s => s.saved)
.Select(s => s.obj)
.Subscribe(Close)
));
}

Rx.Net: Chaining subscribers - alternative approach?

How can I re-write this code so that I don't have to chain Subscribers like below? Reason for asking is, this style will limit in an observable depending on another observable due to the style of the code, it can get confusing.
var results = myService
.GetData(accountId) // returns IObservable
.Subscribe(data =>
{
new MyWork().Execute(data) // returns IObservable
.Subscribe(result =>
{
myResults.Add(result);
WriteLine($"Result Id: {result.Id}");
WriteLine($"Result Status: {result.Pass}");
});
});
Added after 1st reply from Peter Bons
Below is the code for MyWork class that has the Execute Method
public class MyWork
{
public virtual IObservable<MyResult> Execute(MyData data)
{
MyResult result = null;
return IsMatch(data)
.Do(isMatch =>
{
if (isMatch)
{
result = new MyResult(1, true);
}
})
.Select(_ => result);
}
public IObservable<bool> IsMatch(MyData data)
{
return true;
}
}
It's really quite simple.
var results =
myService
.GetData(accountId)
.SelectMany(data => new MyWork().Execute(data))
.Subscribe(result =>
{
myResults.Add(result);
Console.WriteLine($"Result Id: {result.Id}");
Console.WriteLine($"Result Status: {result.Pass}");
});
If ever you are subscribing within a subscription then you are doing something wrong. Keep that in mind. There is almost always a way to make it a pure query with a single subscription.
Just to help out with testing, here's the code required to make this a Minimal, Complete, and Verifiable example.
public static class myService
{
public static IObservable<MyData> GetData(int x)
=> Observable.Return(new MyData());
}
public class MyWork
{
public virtual IObservable<MyResult> Execute(MyData data)
{
MyResult result = null;
return IsMatch(data)
.Do(isMatch =>
{
if (isMatch)
{
result = new MyResult() { Id = 1, Pass = true};
}
})
.Select(_ => result);
}
public IObservable<bool> IsMatch(MyData data)
{
return Observable.Return(true);
}
}
public class MyResult
{
public int Id;
public bool Pass;
}
public class MyData { }

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);
}
}
}

Observable.FromEvent, cannot get signatures right

I'm trying to create an IObservable from the following event:
public delegate bool Handle<in T>(T obj, Foo foo);
event Handle<Bar> Finance;
Any suggestions on how to properly create the observable?
Note, neither Foo nor Bar is based on EventArgs
Thanks!
You can try something like:
public class Test
{
public delegate void Handle<in T>(T obj, Foo foo);
public event Handle<Bar> Finance;
}
public static class TestEx
{
static IObservable<Tuple<Bar, Foo>> WhenFinanceChanged(this Test t)
{
return Observable.Create<Tuple<Bar, Foo>>(observer =>
{
Test.Handle<Bar> handler = (obj, foo) => observer.OnNext(Tuple.Create<Bar, Foo>(obj, foo));
t.Finance += handler;
return Disposable.Create(() => t.Finance -= handler);
});
}
}