Trouble with data binding for WindowsFormsHost ContextMenu

Beantwortet Trouble with data binding for WindowsFormsHost ContextMenu

  • 2012年4月27日 12:51
     
      コードあり

    I am hosting an ActiveX control in a WindowsFormHost and need to provide a ContextMenu.  I've been able to hardcode the menu in my XAML but I can't get data binding to work.  Here is a sample I wrote using the Windows Media Player ActiveX Control (Ignore the fact that it has it's own context menu, the real ActiveX control I'm using does not.)

    <Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    
        xmlns:ax="clr-namespace:AxWMPLib;assembly=AxInterop.WMPLib"
        xmlns:local="clr-namespace:AXSample"
        Title="MainWindow" Height="350" Width="525">
        <Window.DataContext>
            <local:MyViewModel/>
        </Window.DataContext>
        <Grid Name="grid1">
            <Grid.RowDefinitions>
                <RowDefinition Height="* "/>            
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Grid Grid.Row="0">
                <WindowsFormsHost>                
                    <!-- Hardcoding the menu items works
                    <WindowsFormsHost.ContextMenu>
                        <ContextMenu Name="mnuContext">
                            <MenuItem Header="HardcodedItemA" />
                            <MenuItem Header="HardcodedItemB" />
                        </ContextMenu>
                    </WindowsFormsHost.ContextMenu>
                    -->            
                    <!-- But the binding doesn't -->
                    <WindowsFormsHost.ContextMenu>
                        <ContextMenu Name="mnuContext" ItemsSource="{Binding MyMenuItems}">
                            <!-- If I set the DataContext directly on the ContextMenu it will work
                            but will not respond to changes                        
                            <ContextMenu.DataContext>
                                <local:MyViewModel/>
                            </ContextMenu.DataContext>                        
                            -->
                            <ContextMenu.ItemTemplate>
                                <DataTemplate>
                                    <MenuItem Header="{Binding MenuText}"/>
                                </DataTemplate>
                            </ContextMenu.ItemTemplate>
                        </ContextMenu>
                    </WindowsFormsHost.ContextMenu>                
                    <ax:AxWindowsMediaPlayer x:Name="axWmp"></ax:AxWindowsMediaPlayer>
                </WindowsFormsHost>
                
            </Grid>
            <Grid Grid.Row="1">           
                <Button Name="btnAdd">Add Context Menu Item
                    <Button.ContextMenu>
                        <!-- Note that the same context menu binding works for a simple Button -->
                        <ContextMenu Name="mnuButtonContext" ItemsSource="{Binding MyMenuItems}">
                            <ContextMenu.ItemTemplate>
                                <DataTemplate>
                                    <MenuItem Header="{Binding MenuText}"/>
                                </DataTemplate>
                            </ContextMenu.ItemTemplate>
                        </ContextMenu>
                    </Button.ContextMenu>
                </Button>
            </Grid>
        </Grid>
    </Window>

    Here is the code behind:

    Class MainWindow
        Public Sub New()
            ' This call is required by the designer.
            InitializeComponent()
            ' Add any initialization after the InitializeComponent() call.
            AddHandler axWmp.MouseDownEvent, AddressOf axWmp_MouseDown
        End Sub
        ' Open my context menu on the MouseDown
        Private Sub axWmp_MouseDown(ByVal sender As Object,
                                    ByVal e As AxWMPLib._WMPOCXEvents_MouseDownEvent)
            mnuContext.IsOpen = True
        End Sub
        ' Add a menu item to the ViewModel
        Private Sub btnAdd_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnAdd.Click
            Dim lobjViewModel As MyViewModel = CType(Me.DataContext, MyViewModel)
            lobjViewModel.AddMenuItem()
        End Sub
    End Class

    My ViewModel:

    Imports System.Collections.ObjectModel
    Public Class MyViewModel
        Private mcolMenuItems As ObservableCollection(Of MenuItem) = New ObservableCollection(Of MenuItem)
        Public Sub New()
            ' Add 1st menu item
            AddMenuItem()
        End Sub
        Public Sub AddMenuItem()
            Me.MyMenuItems.Add(New MenuItem With {.Header = "Item " & Me.MyMenuItems.Count.ToString})
        End Sub
        Public Property MyMenuItems() As ObservableCollection(Of MenuItem)
            Get
                Return mcolMenuItems
            End Get
            Set(ByVal value As ObservableCollection(Of MenuItem))
                mcolMenuItems = value
            End Set
        End Property
    End Class

    My observations:

    - The context menu on the Button works as I would expect.  It has 1 menu item initially.  After clicking the button to add another menu item, the context menu is updated properly.

    - The context menu on the ActiveX control is always empty.  If I explicitly set ContextMenu.DataContext for the WindowsFormHost ContextMenu, it will display a menu with the 1 item I added in the constructor of my ViewModel.  But even after adding additional menu items with the button, the context menu over the ActiveX control contains only 1 item.

    Is there any way to get the binding to work for the ActiveX control's ContextMenu without writing code-behind to keep it in sync?


    • 編集済み S T A N 2012年4月27日 12:53 Forgot to add question
    •  

すべての返信

  • 2012年4月30日 7:21
     
      コードあり
     Dim lobjViewModel As MyViewModel = CType(Me.DataContext, MyViewModel)

    Change to WindowsFormHost.DataContext

  • 2012年4月30日 12:44
     
      コードあり

    This did not seem to make any difference

    'Dim lobjViewModel As MyViewModel = CType(Me.DataContext, MyViewModel)
    Dim lobjViewModel As MyViewModel = CType(wfh.DataContext, MyViewModel)

  • 2012年5月1日 7:09
    モデレータ
     
     

    Hi STAN,

    You could set the DataContext Property to your ContextMenu, it will work, as the your last issue --> why your Item will not be added to the ContextMenu, it is caused by:

        private void btnAdd_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            MyViewModel lobjViewModel = (MyViewModel)this.DataContext;
            lobjViewModel.AddMenuItem();
        }

    If you change it to:

    private void btnAdd_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        MyViewModel lobjViewModel = (MyViewModel)mnuContext.DataContext;
        lobjViewModel.AddMenuItem();
    }

    Your code will work well.

    best regards,


    Sheldon _Xiao[MSFT]
    MSDN Community Support | Feedback to us
    Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

  • 2012年5月1日 15:17
     
     

    Thanks for your reply.  This did indeed cause my sample to work, although now the context menu on the button itself is no longer updated.  So my assumption is that now the DataContext for the ContextMenu and the Window are distinct.  Is there a way to change the sample so the ContextMenu and the rest of the Window share the same the DataContext?

  • 2012年5月2日 2:40
    モデレータ
     
     回答済み

    Hi STAN,

    I think you could not sync both DataContext with binding, because WPF ContextMenu is in a separate VisualTree, so you could not bind its DataContext.

    I suggest you could regist a DataContextChanged event handler, and then update the other by code.

    best regards,


    Sheldon _Xiao[MSFT]
    MSDN Community Support | Feedback to us
    Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • 回答としてマーク S T A N 2012年5月2日 12:43
    •  
  • 2012年5月2日 12:43
     
     

    Thanks, that confirms what I've seen.  I'll resolve it in code.