8

WPFアプリケーションのインスタンスを保持するOfficeアドインを作成しました。ユーザーがアドインのボタンをクリックすると、次のようにしてさまざまなウィンドウを起動します。

MyViewModel viewModel = new MyViewModel(string infoFromOffice);
MyWindow view = new MyWindow();
view.DataContext = viewModel;

wpfApp.Run(view);

呼び出しの前にビューモデルを構築するwpfApp.Run()際に、後で現在のSynchronizationContextでprobelmsをヒットします。ここでの答えはその理由を説明しています。オフィスのアドインからWPFウィンドウを起動するためのより良い方法はありますか?

4

3 に答える 3

1

Officeアドインを作成したことはありませんが、他の種類の非WPFアプリケーション(Windowsフォーム、WPFビジュアルから.XPSファイルを生成するためのライブラリなど)でWPFウィンドウを使用しました。この質問で提案したアプローチを試すことができます。。WPFアプリを実行できるようにスレッドを構成する方法を示します。WPFアプリの生成されたアプリのコード( "App.gics")を見ると、次のように開始されているようです。

/// <summary>
    /// Application Entry Point.
    /// </summary>
    [System.STAThreadAttribute()]
    [System.Diagnostics.DebuggerNonUserCodeAttribute()]
    public static void Main() {
        WpfApplication1.App app = new WpfApplication1.App();
        app.InitializeComponent();
        app.Run();
    }

次のコードを使用して単体テストからアプリを起動しようとしましたが、うまく機能しました。

[TestMethod]
    public void TestMethod()
    {
        // The dispatcher thread
        var t = new Thread(() =>
        {
            var app = new App();
            // Corrects the error "System.IO.IOException: Assembly.GetEntryAssembly() returns null..."
            App.ResourceAssembly = app.GetType().Assembly;
            app.InitializeComponent();

            app.Run();
        });

        // Configure the thread
        t.SetApartmentState(ApartmentState.STA);
        t.Start();
        t.Join();
    }

編集

コードを見ると、SynchronizationContextに適したステートメントは、ViewModelの作成ではなくWindowインスタンスの作成であると思います(ViewModelがViewロジックを処理し、コントロールをインスタンス化しない限り、実行すべきではありません)。したがって、ウィンドウのインスタンス化をアプリのスレッドに移動してみることができます。このようなもの:

[TestMethod]
    public void TestMethod3()
    {
        // Creates the viewmodel with the necessary infomation wherever 
                    // you need to.
        MyViewModel viewModel = new MyViewModel(string infoFromOffice);

        // The dispatcher thread
        var t = new Thread(() =>
        {
            var app = new App();
            // Corrects the error "System.IO.IOException: Assembly.GetEntryAssembly() returns null..."
            App.ResourceAssembly = app.GetType().Assembly;
            app.InitializeComponent();

            // Creates the Window in the App's Thread and pass the information to it
            MyWindow view = new MyWindow();
            view.DataContext = viewModel;

            app.Run(view);
        });

        // Configure the thread
        t.SetApartmentState(ApartmentState.STA);
        t.Start();
        t.Join();
    }
于 2012-11-16T18:04:59.140 に答える
0

アーサーの回答は、問題が発生した理由を示すのに役立ちましたが、ビューモデルコンストラクターの呼び出しをの呼び出しの後に実行しながら、ホストアプリケーションからビューモデルにデータを渡す方法には実際には回答しませんでしたApp.Run()。それ以来、(非常に単純な)解決策を見つけました!興味のある方へ。

App.xaml.csの場合:

private string data;

public App(string infoFromOffice) {
    this.data = data;
}

protected override void OnStartup(StartupEventArgs e) {
    base.OnStartup(e);

    MyViewModel viewwModel = new MyViewModel(this.data);
    MyWindow view = new MyWindow();
    view.Show();
}

アプリを起動するとき:

App application = new App(infoFromOffice);
application.Run();

App.xamlで起動URIを削除する必要があることに注意してください。この非常に単純なソリューションを使用すると、アプリに情報を渡すことができますが、同時に、ビューモデルを「非WPF環境」で構築する必要がないため、ディスパッチャーなどを利用できます。

于 2012-12-07T15:55:01.633 に答える
0

これは、アプリケーションドメインを使用して、個別のアプリケーションドメインとUIスレッドでwpfアプリケーションを複数回開くバージョンです。これをオフィスのアドインで使用しました。スタートアップが呼び出されるたびに、新しいアプリケーションを取得します。wpfアプリが閉じられたときにスレッドがどれだけうまくシャットダウンするかを確認していません。

http://eprystupa.wordpress.com/2008/07/31/running-multiple-wpf-applications-in-the-same-process-using-appdomains/

パブリッククラスWpfHelper{

   public static void Startup()
    {
        var appDomainSetup = new AppDomainSetup()
        {
            ApplicationBase = Path.GetDirectoryName(typeof(WpfHelper).GetType().Assembly.Location)
        };

        AppDomain domain = AppDomain.CreateDomain(DateTime.Now.ToString(), null, appDomainSetup);

        CrossAppDomainDelegate action = () =>
        {
            Thread thread = new Thread(() =>
            {
                var app = new WpfApplication.App();

                WpfApplication.App.ResourceAssembly = app.GetType().Assembly;

                app.MainWindow = new WpfApplication.MainWindow();
                app.MainWindow.Show();
                app.Run();
            });

            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();

        };

        domain.DoCallBack(action);
    }

}

于 2013-12-21T06:02:04.177 に答える