5

現在最新かつ最高のバージョンのCaliburn.Micro(1.4.1)でWPFを使用しています。IWindowManager.ShowWindow(...)を使用して、新しいモードレスウィンドウを開きます。

private void OpenOrReactivateInfoView()
{
    if(this.infoViewModel == null)
    {
        this.infoViewModel = new InfoViewModel();
    }

    this.windowManager.ShowWindow(this.infoViewModel);
}

が呼び出されるたびに新しいウィンドウを開くのではなくOpenOrReactivateInfoView()、ウィンドウがまだ開いているかどうかを確認したいと思います。開いている場合は、既存のウィンドウがフォーカスを取り戻す必要があります。

これを解決するための優れたCalibrun.Micro-wayは何でしょうか?ビューモデルにウィンドウ(またはそれに関するUIElement)自体への参照を保持することは避けたいと思います。また、これは多くのモードレスダイアログで一般的な動作であるため、一般的な再利用可能な方法でこれを解決することをお勧めします。

Caliburn.Microには、これを実現する手段がすでに組み込まれていますか?

4

3 に答える 3

5

WindowManagerのソースコードは常に新しいウィンドウを作成するため、実際に新しいウィンドウを作成する場合は、WindowManager.ShowWindowメソッドのみを使用する必要があります。

最初に実行したいのは、次のようにビューモデルへの永続的な参照を保持することです。

private readonly InfoViewModel infoViewModel = new InfoViewModel();
private void OpenOrReactivateInfoView()
{
    this.windowManager.ShowWindow(this.infoViewModel);
}

次に、ビューモデルで、Focusまたは次のような任意のメソッドを作成します。

public void Focus()
{
    var window = GetView() as Window;
    if (window != null) window.Activate();
}

次に、OpenOrReactivateInfoView()メソッドに再度アクセスして、次のように少し調整します。

private void OpenOrReactivateInfoView()
{
    if (!this.infoViewModel.IsActive)
        this.windowManager.ShowWindow(this.infoViewModel);
    else
        this.infoViewModel.Focus();
}

この方法は私のために働いた。

于 2013-01-29T13:49:02.657 に答える
4

IViewAwareを実際に実装しなくてもウィンドウを追跡するためのかなり簡単な方法は、一緒に実行されるViewModelsとViewsへの弱参照のディクショナリを保持し、既存のウィンドウがあるかどうかを確認することです。WindowManager、サブクラス、または拡張機能のデコレータとして実装できます。

死んだWeakReferencesでさえパフォーマンスに影響を与えるほど十分なウィンドウを開くことを実際に計画していないと仮定すると、次のような単純なものでうまくいくはずです。長時間実行される場合は、ある種のクリーンアップを実装するのはそれほど難しいことではありません。

public class MyFancyWindowManager : WindowManager
{
    IDictionary<WeakReference, WeakReference> windows = new Dictionary<WeakReference, WeakReference>();

    public override void ShowWindow(object rootModel, object context = null, IDictionary<string, object> settings = null)
    {
        NavigationWindow navWindow = null;

        if (Application.Current != null && Application.Current.MainWindow != null)
        {
            navWindow = Application.Current.MainWindow as NavigationWindow;
        }

        if (navWindow != null)
        {
            var window = CreatePage(rootModel, context, settings);
            navWindow.Navigate(window);
        }
        else
        {
            var window = GetExistingWindow(rootModel);
            if (window == null)
            {
                window = CreateWindow(rootModel, false, context, settings);
                windows.Add(new WeakReference(rootModel), new WeakReference(window));
                window.Show();
            }
            else
            {
                window.Focus();
            }
        }

    }

    protected virtual Window GetExistingWindow(object model)
    {
        if(!windows.Any(d => d.Key.IsAlive && d.Key.Target == model))
            return null;

        var existingWindow = windows.Single(d => d.Key.Target == model).Value;
        return existingWindow.IsAlive ? existingWindow.Target as Window : null;
    }
}
于 2013-02-08T04:45:31.277 に答える
1

私はこの拡張メソッドを思いついた。それは動作しますが、私は特に満足していません、それはまだややハックです。

この拡張機能がモデルについて非常に多くの仮定をしなければならないことは明らかにデザインメルです(これらの厄介な例外も見られますか?)。

using System;
using System.Collections.Generic;
using Caliburn.Micro;

public static class WindowManagerExtensions
{
    /// <summary>
    /// Shows a non-modal window for the specified model or refocuses the exsiting window.  
    /// </summary>
    /// <remarks>
    /// If the model is already associated with a view and the view is a window that window will just be refocused
    /// and the parameter <paramref name="settings"/> is ignored.
    /// </remarks>
    public static void FocusOrShowWindow(this IWindowManager windowManager,
                                         object model,
                                         object context = null,
                                         IDictionary<string, object> settings = null)
    {
        var activate = model as IActivate;
        if (activate == null)
        {
            throw new ArgumentException(
                string.Format("An instance of type {0} is required", typeof (IActivate)), "model");
        }

        var viewAware = model as IViewAware;
        if (viewAware == null)
        {
            throw new ArgumentException(
                string.Format("An instance of type {0} is required", typeof (IViewAware)), "model");
        }

        if (!activate.IsActive)
        {
            windowManager.ShowWindow(model, context, settings);
            return;
        }

        var view = viewAware.GetView(context);
        if (view == null)
        {
            throw new InvalidOperationException("View aware that is active must have an attached view.");
        }

        var focus = view.GetType().GetMethod("Focus");
        if (focus == null)
        {
            throw new InvalidOperationException("Attached view requires to have a Focus method");
        }

        focus.Invoke(view, null);
    }
}
于 2013-01-29T15:40:25.313 に答える