Databinding and Add-Ins
There are many advantages to using the .NET Framework add-in technology to factor application logic and UI, including security isolation, discovery, activation, communication, lifetime management, and versioning.
WPF builds on the .NET Framework add-in technology to enable visual add-ins ie add-ins that provide UI for host applications to display. All that you need to do is define the contract to specify what types of things the host wants the add-in's UI to do. The end result for the user is that they see both host and add-in UI intermingled without knowing about the complex machinery underneath to make it work.
And, to some degree, developers might approach the development of add-ins the same way. For example, when a WPF host application displays a UI provided by an add-in, developers might intuitively expect features like data binding, commanding etc to just work. Features like this, though, need a little extra work to, err, get working because features like these weren't originally designed to work across the isolation boundary between host and add which is the space between the host's application domain and the add-ins application domain. (This use of application domains enables security isolation.)
The attached sample demonstrates how to implement host/add-in applications to support data binding. Specifically, the sample shows a host application that manages a data object (Person) and provides it to UI add-ins that either re-visualize the data or allow editing of the data, or both. Here's how the application looks at run time.
To understand the sample, you'll need to be familiar with .NET Framework and WPF add-in support. This SDK document provides a good starting point.
You'll need to play with the sample to see how it really works but the 10000' view is:
- There is one contract for the Add-In
- There is one contract for the Person data object
- The host instantiates the Person data object and binds some UI to it.
- The host activates and displays a UI provided by the add-in, to which the host passes the Person object. The add-in UI also binds to the Person object.
- When the host UI that is bound to the data object is updated, the changes are communicated to the add-in UIs that are also bound to the data object.
- When the editable add-in UI that is bound to the Person data object is updated, the changes are communicated back to the host.
To the host and add-in UIs, all they see is a Person data object that implements INotifyPropertyChanged which is the data binding interface that essentially ensures bound UI are updated when the data objects they are bound to are updated. The add-in pipeline to make this work is a little more involved, technically, but is the same as using INotifyPropertyChanged, in concept.
You'll find the best way to grok the sample is to download it and see it running.
Enjoy!
Comments
Anonymous
July 08, 2008
The comment has been removedAnonymous
July 09, 2008
The comment has been removedAnonymous
July 09, 2008
Hi Danny, Thanks for the feedback. Did that resolve your issue? Jim Galasyn Programming Writer Developer Division User Education Thank you for contacting the WPF team. By taking the time to write, you are helping us to improve the quality of our documentation and samples. Please accept our apologies for any inconvenience this may have caused you. This response is provided "AS IS" with no warranties, and confers no rights.Anonymous
July 09, 2008
Yes, Mostly. I've started a thread on the WPF forum with another question http://forums.msdn.microsoft.com/en/wpf/thread/2b2e0fe7-5dbb-4ac5-9fdf-f834ac144b81 Thanks, DannyAnonymous
May 14, 2009
Great sample -- but it shows the same issue I have with my AddIn framework. If I click on 'Load UI Addins' three times in your app, it throws the following exception. The same occurs for me if I open an AddIn eight times. I'm about to abandon AddIn framework because of it -- hoping you might have some insight. Many thanks! System.Runtime.InteropServices.COMException was unhandled by user code Message="Exception from HRESULT: 0x88980406" Source="PresentationCore" ErrorCode=-2003303418 StackTrace: at System.Windows.Media.Composition.DUCE.Channel.SyncFlush() at System.Windows.Media.MediaContext.CompleteRender() at System.Windows.Interop.HwndTarget.OnResize() at System.Windows.Interop.HwndTarget.HandleMessage(Int32 msg, IntPtr wparam, IntPtr lparam) at System.Windows.Interop.HwndSource.HwndTargetFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter) at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler) at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler) at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter) at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg) at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam) at MS.Win32.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam) at MS.Win32.HwndSubclass.DefWndProcWrapper(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam) at MS.Win32.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam) at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam) at MS.Win32.UnsafeNativeMethods.SetWindowPos(HandleRef hWnd, HandleRef hWndInsertAfter, Int32 x, Int32 y, Int32 cx, Int32 cy, Int32 flags) at System.Windows.Interop.HwndSource.Resize(Size newSize) at System.Windows.Interop.HwndSource.OnLayoutUpdated(Object obj, EventArgs args) at System.Windows.ContextLayoutManager.fireLayoutUpdateEvent() at System.Windows.ContextLayoutManager.UpdateLayout() at System.Windows.UIElement.UpdateLayout() at System.Windows.Interop.HwndSource.SetLayoutSize() at System.Windows.Interop.HwndSource.set_RootVisualInternal(Visual value) at System.Windows.Interop.HwndSource.set_RootVisual(Visual value) at System.AddIn.Pipeline.FrameworkElementAdapters.ViewToContractAdapter(FrameworkElement root) at AddInSideAdapters.AddIn_ViewToContractAddInSideAdapter.GetAddInUI(IPersonContract personContract) at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, Object server, Int32 methodPtr, Boolean fExecuteInContext, Object[]& outArgs) at System.Runtime.Remoting.Messaging.StackBuilderSink.PrivateProcessMessage(RuntimeMethodHandle md, Object[] args, Object server, Int32 methodPtr, Boolean fExecuteInContext, Object[]& outArgs) at System.Runtime.Remoting.Messaging.StackBuilderSink.SyncProcessMessage(IMessage msg, Int32 methodPtr, Boolean fExecuteInContext) InnerException: