I am very confuse what is better approach to display child view and subscribe to its event on ReactiveUI WPF, so far I have 2 implementation that somehow works for my case:
Implementation 1:
public class ChildWindowView
{
public event EventHandler<Exception> Error;
public event EventHandler<bool> Closed;
internal void ShowSomeChild()
{
var vm = new SomeChildViewModel();
var view = new SomeChildView { DataContext = vm };
ChildWindowManager.Instance.Show(view, "Child Title");
Observable.FromEventPattern<Exception>
(h => vm.Error += h, h => vm.Error -= h)
.Subscribe(p => Error?.Invoke(p.Sender, p.EventArgs));
Observable.FromEventPattern<bool>
(h => vm.Close += h, h => vm.Close -= h)
.Subscribe(p => Close?.Invoke(p.Sender, p.EventArgs));
}
internal void ShowOtherChild() { /* Code committed */}
internal void ShowAnotherChild() { /* Code committed */}
}
public class MainViewModel
{
private readonly ChildWindowView child = new ChildWindowView();
public MainViewModel()
{
// this commmand executed several times during runtime
ShowSomeChild = ReactiveCommand.Create(() => child.ShowSomeChild());
// this commmand executed several times during runtime
ShowOtherChild = ReactiveCommand.Create(() => child.ShowOtherChild());
// this commmand executed several times during runtime
ShowAnotherChild = ReactiveCommand.Create(() => child.ShowAnotherChild());
// handle child view error message
Observable.FromEventPattern<Exception>
(h => child.Error += h, h => child.Error -= h)
.Subscribe(e => /* Error Handling */);
// do something when child closed
Observable.FromEventPattern<bool>
(h => child.Close += h, h => child.Close -= h)
.Subscribe(e => /* Do Something */);
}
}
As you see, on the first implementation ChildWindowView
subscribe to an event on the ChildViewModel
before invoking his own Event, this event then subscribed by MainViewModel
.
The advantage in this implementation is MainViewModel
only need to subscribe to child event once for any child, although ChildWindowView
will subscribe to ChildViewModel
every time ShowSomeChild()
is called.
Implementation 2:
public class ChildWindowView
{
public event EventHandler<Exception> Error;
public event EventHandler<bool> Closed;
internal void ShowSomeChild(SomeChildViewModel vm)
{
var view = new SomeChildView { DataContext = vm };
ChildWindowManager.Instance.Show(view, "Child Title");
}
internal void ShowOtherChild(OtherChildViewModel vm)
{
var view = new OtherChildView { DataContext = vm };
ChildWindowManager.Instance.Show(view, "Child Title");
}
internal void ShowAnotherChild(AnotherChildViewModel vm)
{
var view = new AnotherChildView { DataContext = vm };
ChildWindowManager.Instance.Show(view, "Child Title");
}
}
public class MainViewModel
{
private readonly ChildWindowView child = new ChildWindowView();
public MainViewModel()
{
// this commmand executed several times during runtime
ShowSomeChild = ReactiveCommand.Create(() =>
{
var vm = new SomeChildViewModel();
// handle child view error message
Observable.FromEventPattern<Exception>
(h => vm.Error += h, h => vm.Error -= h)
.Subscribe(e => /* Error Handling */);
// do something when child closed
Observable.FromEventPattern<bool>
(h => vm.Close += h, h => vm.Close -= h)
.Subscribe(e => /* Do Something */);
child.ShowSomeChild(vm)
});
// this commmand executed several times during runtime
ShowOtherChild = ReactiveCommand.Create(() =>
{
var vm = new OtherChildViewModel();
// handle child view error message
Observable.FromEventPattern<Exception>
(h => vm.Error += h, h => vm.Error -= h)
.Subscribe(e => /* Error Handling */);
// do something when child closed
Observable.FromEventPattern<bool>
(h => vm.Close += h, h => vm.Close -= h)
.Subscribe(e => /* Do Something */);
child.ShowOtherChild(vm)
});
// this commmand executed several times during runtime
ShowAnotherChild = ReactiveCommand.Create(() =>
{
var vm = new AnotherChildViewModel();
// handle child view error message
Observable.FromEventPattern<Exception>
(h => vm.Error += h, h => vm.Error -= h)
.Subscribe(e => /* Error Handling */);
// do something when child closed
Observable.FromEventPattern<bool>
(h => vm.Close += h, h => vm.Close -= h)
.Subscribe(e => /* Do Something */);
child.ShowAnotherChild(vm)
});
}
}
On the second implementation, I move child vm creation and event subscribtion to MainViewModel, but I lose central subscribtion that can handle all close event from any child.
And here is the ChildWindowManager
that used to display child view on both implementation
public class ChildWindowManager : ReactiveObject
{
public static ChildWindowManager Instance { get { return lazy.Value; } }
private static readonly Lazy<ChildWindowManager> lazy =
new Lazy<ChildWindowManager>(() => new ChildWindowManager());
[Reactive] public string Title { get; set; }
[Reactive] public bool IsOpen { get; set; }
[Reactive] public FrameworkElement XmlContent { get; set; }
ChildWindowManager ()
{
XmlContent = null;
}
public void Show(FrameworkElement content, string title)
{
XmlContent = content;
Title = title;
IsOpen = true;
}
public async void Close()
{
IsOpen = false;
XmlContent = null;
}
}
Or maybe someone have better solutions.