Archive for August, 2007

Support Your Local Pub

Wednesday, August 29th, 2007

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!

Hosting Office in a WPF Application

Friday, August 24th, 2007

note 

Updated on December 17, 2009

The approach described in this article for hosting office documents in WPF is no longer supported.  Microsoft has recently pulled the DSO Framer control from its knowledge base.  🙁

Please contact Microsoft Developer Support directly if you have questions regarding this decision.

 If a new supported solution for hosting Microsoft Office applications within WPF becomes available, I will try to post a sample.

Cheers,
Dr. WPF


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”.

FIX: Several people have advised that compiling the WPF application to specifically target the x86 platform (rather than “Any CPU”) fixes the above load issue on x64.  Thanks to all for this fix!  😀

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

Best regards,
Dr. WPF

Can my value converter access the target of the binding?

Saturday, August 18th, 2007

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

The Doctor Is In

Monday, August 13th, 2007

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.  🙂