5
\$\begingroup\$

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.