Wednesday, November 19, 2008   Search 
Links

 

Disciple
 Ask Dr. WPF Minimize
Author: Dr. WPF Created: 8/13/2007 5:15 PM
Do you have questions about Windows Presentation Foundation that might have broad appeal? Ask Dr. WPF!

Support Your Local Pub
By Dr. WPF on 8/29/2007 1:55 PM

Recently, one of my peers informed me that due to my lack of participation in the WPF community, I'm just not a good citizen.  I told him to go to h... well...  you get the gist.

I was feeling a twinge of guilt about this, so I decided to look up my most recent posts in the WPF... er... uh... "Avalon" community forums.  (Well that can't be good.)  Upon seeing the timestamps on those posts, I was feeling a slightly larger twinge of guilt.  Then I looked at the actual content...  WOW! 

How did we survive in a world without Grid?  Was there really once a native element called FlowPanel?  And the binding syntax... that's just wrong!  Okay, clearly it's been too long and I might just be a bad citizen.

Sidenote:  I was tempted to include some links to those posts, but they are all under the name I was using prior to joining the witness protection plan.  So in the interest of protecting my family, who desperately would like to distance themselves from my geekiness, I'm leaving those links out.

To ease my conscience, I've been hanging out in the WPF MSDN Forum for the last few days.  I've got to admit... this is a pretty cool place!  I plan to pop in here more frequently.  It's amazing how much the community has grown and what a wealth of knowledge is available now.  And the volume of activity completely blew me away.  If you haven't been there lately, stop being a bad citizen and check it out!

Comments (1)

Hosting Office in a WPF Application
By Dr. WPF on 8/24/2007 4:01 PM

Dear Dr. WPF,

Is it possible to host Microsoft Excel inside of a WPF application?  Do you have any sample code?

Sincerely,
Rob



Hi Rob,

It’s certainly possible to host a Microsoft Office application inside of a WPF application.  And just to prove it, I’m writing this entire post inside of Microsoft Word while it’s being hosted inside my WPF application.

WPF Hosting WordFeel free to download the code for this sample.  This sample will work for hosting Word, Excel, PowerPoint, or Visio documents.  It should host Project documents also, but I don’t have Project, so I couldn’t verify this.  And I should note that hosting Visio 2007 documents proved to be very flaky.  The Visio host crashed more often than not.  The other hosts seemed pretty stable.

You will need to install the DSO Framer control prior to running the sample.  More on that below...

So yes, it’s possible to host an Office application, but that doesn’t necessarily mean it’s easy!  There are definitely a lot of caveats, disclaimers, qualifiers, stipulations, and limitations (yep, even the thesaurus works in the hosted scenario!) when hosting any Win32-based window (a.k.a., an HWND) within a WPF app.  Most of these are documented in the SDK in topics like WPF Interoperation: ''Airspace'' and Window Regions Overview and Hosting a Microsoft Win32 Window in WPF.  In the latter article, special attention should be given to the sections entitled “Notable differences in output behavior” and “Notable differences in input behavior”.

Hosted Office applications come with a whole set of their own challenges (keeping the document focused, keeping application menus in sync with document menus, etc).  If you go down the path of hosting an Office app, you should expect some technical challenges and a potential steep learning curve, especially if you’re considering office automation.

There are code samples in the SDK that demonstrate how to host an ActiveX control inside your WPF application.  So if you can find a simple ActiveX wrapper for your Office application, then you’re all set, right?

Well, unfortunately it’s not that easy when it comes to hosting Office.  An Office application, like Excel, has much larger requirements for its host container.  The host must be an Active Document Container.  This container implements a number of COM interfaces above and beyond those found in a simple ActiveX host.

There are a couple of Active Document Containers readily available on most Windows machines:

1.     Internet Explorer

2.     the Windows Forms WebBrowser control

The simplest approach to hosting an Office application inside a managed application involves hosting the Windows Forms WebBrowser control and pointing it at an Office document.  If all you care about is simple hosting, this approach might work for you.

SIDEBAR: For the record, I should point out that there is also an unmanaged WebBrowser control (shdocvw.dll) that ships as part of Internet Explorer.  This control can be hosted in an unmanaged app (or even in a managed app using the instructions in this article, but why would you do that when there's already a managed control?).  Indeed, the Windows Forms WebBrowser control is just a managed wrapper around the Internet Explorer WebBrowser control.  As such, Internet Explorer must be installed for any solution that involves either WebBrowser control.

Usually, however, if you are hosting something like Excel, you need to automate the document (to load, save, or print it, invoke automation commands, etc).  The WebBrowser control does not give you much access to the document-related automation classes.  (For information on the Office automation classes, check out the vast Office Development documentation in the SDK.)  For this level of control, you need a better Active Document Container.  Unfortunately, Microsoft has not released any such “supported” container.  It would be great if they could put out a managed control that could serve as an Active Document Container.  But so far, the only thing they offer is an “unsupported” container in the form of an ActiveX control called DSO Framer control. 

The DSO Framer control was produced a few years back by the good folks in Microsoft Developer Support.  Although their name says it (“Support”, that is), they don’t do it (“Support”, that is) for this control.  The DSO Framer control (along with its source code… yes, you get the full source) is provided “as is”.  Microsoft doesn’t support it and Dr. WPF doesn’t support it either…  However, we both use it!

My sample of WPF hosting Word (illustrated above and available for download) is indeed built using the DSO Framer control.  It is an extremely simple implementation of a WPF application hosting an ActiveX control.  In this case, that ActiveX control just happens to be an Active Document Container.

NOTE:  I could not get the most recent version of the DSO Framer control (compiled as a 32-bit control) to run on my 64-bit Vista box.  It runs well on my 32-bit Vista installation.  On my x64 machine, the application complains that the control is not registered, even though I can verify and instantiate an instance just fine in OleView.  Not sure if this is a problem with the control or a configuration problem on my machine.  If others encounter the same problem, I’d love to hear about it.  Maybe someone in Microsoft Developer Support could try to reproduce this failure and look into a fix (hint, hint)…  Oh yeah… it’s not a supported control.  Maybe if I say “pretty please”.

Anyway, I hope you find this information and sample helpful!

Best regards,
Dr. WPF

 

Comments (20)

Can my value converter access the target of the binding?
By Dr. WPF on 8/18/2007 11:02 AM

Dear Dr. WPF,

In my application, I’m using a value converter to convert a GUID to a static resource.  The GUID is accessible in my DataTemplate through a binding like this:

<DataTemplate>
  <
Grid Height="Auto" Width="Auto">
    <
TextBlock Text="{Binding Path=ID}" />
  </
Grid>

</DataTemplate>

I would really like to use the GUID in a more dynamic way as a key into a resource dictionary. I imagine it would look something like this (although obviously this won’t work): 

<DataTemplate>
  <
Grid Height="Auto" Width="Auto">
    <
ContentControl 
        Content="{StaticResource {Binding Path=ID}}" />
  </
Grid>
</
DataTemplate>

I thought I might be able to use a binding along with a value converter that uses FindResource() to look up the static resource. Unfortunately, my value converter does not receive a reference to the object on which the binding is set. It only gets the bound value (the GUID) and the type of the target dependency property. In order to call FindResource(), I need a reference to the actual target dependency object.

Is there an easy way to do this in WPF?

Thanks for any help you can provide!

Sincerely,
Jim



Hi Jim,

Yes, it can be frustrating that your value converter does not receive a reference to the target dependency object for the binding. Value converters were designed to be more generic in nature, allowing them to be used in scenarios that might not involve bindings. As such, they have no knowledge of the binding itself or the object on which it is set. That said, there are actually many cases where a value converter might desire this kind of contextual information. 

Your scenario is a prime candidate for a multibinding and multivalue converter. With a multibinding, you can actually supply your own reference to the target dependency object using one of the bindings, as follows:

<DataTemplate>

  <Grid>

    <ContentControl>

      <ContentControl.Content>

        <MultiBinding Converter="{StaticResource MyConverter}">

          <MultiBinding.Bindings>

            <Binding RelativeSource="{RelativeSource Self}" />

            <Binding Path="ID" />

          </MultiBinding.Bindings>

        </MultiBinding>

      </ContentControl.Content>

    </ContentControl>

  </Grid>

</DataTemplate>

 

In this case, the converter class must implement the IMultiValueConverter interface so that it can be used with the multibinding. Since we have conveniently passed in a Self reference as the first binding, we now have a reference to the target dependency object in our converter. The converter’s Convert method might look something like the following:

public object Convert(object[] values, Type targetType,

    object parameter, CultureInfo culture)

{

  FrameworkElement targetObject = values[0] as FrameworkElement;

  if (targetObject == null)

  {

    return DependencyProperty.UnsetValue;

  }

  return targetObject.TryFindResource(values[1]);

}

 

I hope this helps!

Best regards,
Dr. WPF

Comments (1)

The Doctor Is In
By Dr. WPF on 8/13/2007 1:23 PM

Welcome to the online office of Dr. WPF.  This is my obligatory "Hello World" post.

I've managed (quite deliberately) to avoid the whole world of RSS for the past several years, as I really haven't had much to say that I would deem especially blogworthy.  But lately, I'm spending more and more time answering questions about WPF, so it occurs to me that some of my knowledge might actually qualify as marginally interesting to a few of you.

So here goes...

If you have questions about WPF that you think might have broad appeal, please drop me an email and I will do my best to answer them.  If the volume becomes very large, I reserve the right to become very selective.

And thanks in advance for your patience as I learn the ins and outs of this thing we call the blogosphere

Comments (1)


 Print   
Copyright 2007 by Dr. WPF   Terms Of Use  Privacy Statement