Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Launching WPF windows from an Office add in

I have created an office add-in that holds an instance of a WPF Application. When the user clicks buttons on the add-in, I launch different windows by doing the following:

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

wpfApp.Run(view);

In constructing view models before my call to wpfApp.Run() I hit probelms with the current SynchronizationContext later on. The answer here explains why. Is there a better way of launching WPF windows from an office add-in?

like image 673
Coder1095 Avatar asked Nov 16 '12 14:11

Coder1095


People also ask

Does office use WPF?

To answer the question you think you're asking, no, Office doesn't use WPF. Only Visual Studio uses it. WPF is definitely NOT a layer over Win32 (but it does use DirectX).

Is Microsoft still supporting WPF?

Microsoft has faith in WPF as a UI framework Net Core 3.0. This demonstrates that Microsoft still has faith in WPF as a user interface framework, and the company is still willing to invest in it by updating and integrating it with its new offerings.”

Are WPF applications cross-platform?

WPF draws its own controls and does not use built-in Win32 GUI components. The user interface is typically defined in XAML, an XML language. WPF even went cross-platform, in a sense, when Microsoft introduced Silverlight, cut-down WPF for embedding in web pages, and then later for Windows Phone.


1 Answers

I've never created an Office add-in, but I have used WPF windows in other kinds of non-WPF applications (Windows Forms, libraries to generate .XPS files from WPF visuals, etc). You could try the approach I suggested in this question.. It shows how to configure a thread so it will be able to run the WPF app. If you take a look on the generated app's code ("App.g.i.cs") of a WPF app, it seems it is started like this:

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

I tried launching an app from a unit test with the following code and it worked well:

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

EDIT

Looking at your code I believe that the statement sensible to the SynchronizationContext is the creation of the Window instance, not the creation of your ViewModel (unless your ViewModel deals with View logic and instantiates controls, something it shouldn't be doing). So you can try to move the instantiation of the Window to the thread of the App. Something like this:

[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();
    }
like image 118
Arthur Nunes Avatar answered Oct 04 '22 21:10

Arthur Nunes