簡體   English   中英

命令綁定在上下文相關菜單上不起作用?

[英]Command Binding not working on a context sensitive menu?

我有一個用戶控件(例如:UserCtrlClass),其中有一個樹形視圖

我有View模型(例如:OBJViewModel)類,用於表示樹視圖上的實際項目/數據顯示

接下來,我有一個樹視圖模型(例如:TreeViewModel),它具有OBJViewModel對象的列表

現在,在用戶控件文件背后的代碼中,我實例化了樹視圖模型類並將其設置為用戶控件類的數據上下文。

我需要一個上下文相關菜單,僅當我右鍵單擊樹中的特定項目時才需要顯示該菜單,因此我已經處理了用戶控件類的右鍵單擊事件並在那里進行了工作

但是命令不起作用,這些命令是從I命令派生的,並在TreeViewModel類中實例化。 我嘗試調試Command.execute從未成功! 任何幫助將不勝感激,因為我是.net和wpf的新手。

TreeViewModel類

<UserControl Name="PFDBUserCtrl" x:Class="BFSimMaster.BFSMTreeview"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:BFSimMaster.ViewModel"
         xmlns:cmd="clr-namespace:BFSimMaster.Commands"
         mc:Ignorable="d" 
         d:DesignHeight="66" d:DesignWidth="300">
<UserControl.Resources>
    <!--cmd:ActivateProjectCmd x:Key="CMDActivateProject"/-->
    <!--cmd:DeActivateProjectCmd x:Key="CMDDeActivateProject"/-->
</UserControl.Resources>
<DockPanel>
    <!-- PF Object Browser TREE -->
    <TreeView Name="PFDataBrowser" ItemsSource="{Binding LevelOnePFObjects}" >  
        <TreeView.Resources>
            <ContextMenu x:Key ="ProjectMenu"  StaysOpen="true" >
                <!-- Text="{Binding Source={StaticResource myDataSource}, Path=PersonName}-->
                <!--MenuItem Header="Activate" Command="{Binding Source={StaticResource CMDActivateProject}}" CommandParameter="{Binding Path=PlacementTarget,RelativeSource={RelativeSource AncestorType=ContextMenu}}"/-->
                <MenuItem Header="Activate" Command="{Binding DataContext.CMDActivateProject, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" CommandParameter="{Binding Path=PlacementTarget,RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
                <MenuItem Header="Deactivate" Command="{Binding Source=TVViewModel, Path=CMDDeActivateProject}" CommandParameter="{Binding Path=PlacementTarget,RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
            </ContextMenu>
        </TreeView.Resources>
        <TreeView.ItemContainerStyle>
            <!-- This Style binds a TreeViewItem to a PFObject View Model.-->                
            <Style TargetType="{x:Type TreeViewItem}">                    
                <EventSetter Event="MouseRightButtonDown" Handler="OnRightButtonDown"/>
                <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
                <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                <Setter Property="FontWeight" Value="Normal" />

                <Style.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter Property="FontWeight" Value="Bold" />
                    </Trigger>                        
                </Style.Triggers>

            </Style>
        </TreeView.ItemContainerStyle>

        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                <TextBlock Text="{Binding Name}" />
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
</DockPanel>

課后代碼

using System;
namespace BFSimMaster
{

public partial class BFSMTreeview : UserControl
{

    readonly TreeViewItemViewModel mViewModelPFObjBrowserTree;  
    public BFSMTreeview()
    {
        InitializeComponent();

        WApplication appPF = PFAPIUtils.APIInstance.GetApplication();
        WDataObject User = appPF.GetCurrentUser();



        // Get raw objects - tree data from a PF database.
        //BFPFDataObject userdb = new BFPFDataObject(User,false,"*.IntPrj");
        BFPFDataObject userdb = new BFPFDataObject(User, true);

        // Create UI-friendly wrappers around the 
        // raw data objects (i.e. the view-model).
        mViewModelPFObjBrowserTree = new TreeViewItemViewModel(userdb);

        // Let the UI bind to the view-model.
        base.DataContext = mViewModelPFObjBrowserTree;

    }
    public TreeViewItemViewModel TVViewModel
    {
        get { return mViewModelPFObjBrowserTree; }
    }

    private void OnRightButtonDown(object sender, MouseButtonEventArgs e)
    {
        //MessageBox.Show("Right Clicked on tree view");
        if (sender is TreeViewItem)
        {
            e.Handled = true;
            (sender as TreeViewItem).IsSelected = true;

            string strObjectType = ((sender as TreeViewItem).Header as PFObjectViewModel).PFDataObject.mThisPFObject.GetClassName().GetString();
            switch (strObjectType)
            {
                case "IntPrj":
                    (sender as TreeViewItem).ContextMenu = PFDataBrowser.Resources["ProjectMenu"] as System.Windows.Controls.ContextMenu;
                    (sender as TreeViewItem).ContextMenu.PlacementTarget = (sender as TreeViewItem); 
                    break;
                case "Folder":
                    (sender as TreeViewItem).ContextMenu = PFDataBrowser.Resources["ProjectMenu"] as System.Windows.Controls.ContextMenu;
                    break;
            }

        }
    }
}

}

TreeViewModel類

using System;
namespace BFSimMaster.ViewModel
{

public class TreeViewItemViewModel 
{
    #region Data

    readonly ReadOnlyCollection<PFObjectViewModel> mLevelOnePFObjects;
    readonly PFObjectViewModel mRootOfPFObjects;

    #endregion // Data

    #region Constructor


    public TreeViewItemViewModel(BFPFDataObject rootOfPFObjectsA)
    {
        this.CMDActivateProject = new ActivateProjectCmd();
        this.CMDDeActivateProject = new DeActivateProjectCmd();
        mRootOfPFObjects = new PFObjectViewModel(rootOfPFObjectsA);

        mLevelOnePFObjects = new ReadOnlyCollection<PFObjectViewModel>(
            new PFObjectViewModel[] 
            { 
                mRootOfPFObjects 
            });            
    }

    #endregion // Constructor
    public ICommand CMDActivateProject { get; set; }
    public ICommand CMDDeActivateProject { get; set; }

    public ReadOnlyCollection<PFObjectViewModel> LevelOnePFObjects
    {
        get { return mLevelOnePFObjects; }
    }       

}
}

ContextMenu不是邏輯樹的一部分,因此此綁定"{Binding DataContext.CMDActivateProject, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"無效,因為它根本沒有UserControl類型的祖先。 如果您沒有手動設置PlacementTarget的DataContext,則可以嘗試

"{Binding PlacementTarget.DataContext.CMDActivateProject, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}"

我不確定以下內容,但我認為如果您使用ContextMenu屬性,這將是可行的:

<Treeview>
    <Treeview.ContextMenu>
        <ContextMenu>
            ...
        <ContextMenu>
    <Treeview.ContextMenu>
    ...

這里的冒險是,您不必在代碼隱藏中處理rightbuttondown事件,如果您右鍵單擊樹視圖,它將自動打開。

我已經通過為MenuItem引入VM類並使用ExtendedContextMenu.Items={Binding ContextMenu}附加屬性設置上下文菜單解決了此問題。 MenuResourcesDictionary是帶有背面.cs文件的ResourceDictionary.xaml(如下所示)。

要將其用於代碼,您需要在樹模型上添加IEnumerable<MenuItemVM> ContextMenu屬性,並將命令放在該樹模型中(例如,將其傳遞給MenuItemVM構造函數)。 然后在項目樣式中添加<Setter Property="ExtendedContextMenu.Items" Value="{Binding DataContext.ContextMenu}" />

public static class ExtendedContextMenu
{
    private static readonly StyleSelector _styleSelector = new ContextMenuItemStyleSelector();

    public static readonly DependencyProperty ItemsProperty =
        DependencyProperty.RegisterAttached("Items",
                                            typeof(IEnumerable<MenuItemVM>),
                                            typeof(ExtendedContextMenu),
                                            new FrameworkPropertyMetadata(default(IEnumerable<MenuItemVM>), ItemsChanged));

    public static void SetItems(DependencyObject element, IEnumerable<MenuItemVM> value)
    {
        element.SetValue(ItemsProperty, value);
    }

    public static IEnumerable<MenuItemVM> GetItems(DependencyObject element)
    {
        return (IEnumerable<MenuItemVM>)element.GetValue(ItemsProperty);
    }

    private static void ItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = (FrameworkElement)d;

        var items = (IEnumerable<MenuItemVM>)e.NewValue;
        var contextMenu = new ContextMenu();

        contextMenu.ItemContainerStyleSelector = _styleSelector;
        contextMenu.ItemsSource = items;

        return contextMenu;
    }

    private static void AdjustContextMenuVisibility(ContextMenu menu)
    {
        menu.Visibility = menu.HasItems ? Visibility.Visible : Visibility.Hidden;
    }
}

public class ContextMenuItemStyleSelector : StyleSelector
{
    private static readonly MenuResourcesDictionary _resources = new MenuResourcesDictionary();
    private static readonly Style _menuItemStyle = (Style)_resources[MenuResourcesDictionary.MenuItemStyleResourceKey];
    private static readonly Style _separatorStyle = (Style)_resources[MenuResourcesDictionary.SeparatorStyleResourceKey];

    public override Style SelectStyle(object item, DependencyObject container)
    {
        if (item == MenuItemVM.Separator)
            return _separatorStyle;

        return _menuItemStyle;
    }
}

public sealed partial class MenuResourcesDictionary
{
    public const string MenuItemStyleResourceKey = "MenuItemStyleResourceKey";
    public const string DynamicMenuItemStyleResourceKey = "DynamicMenuItemStyleResourceKey";
    public const string SeparatorStyleResourceKey = "SeparatorStyleResourceKey";
    public const string LoadingStyleResourceKey = "LoadingMenuItemStyleResourceKey";

    public MenuResourcesDictionary()
    {
        InitializeComponent();
    }
}

這是XAML樣式:

<Style x:Key="{x:Static local:MenuResourcesDictionary.MenuItemStyleResourceKey}">
  <Setter Property="MenuItem.Header" Value="{Binding Path=(menuVMs:MenuItemVM.Text)}" />
  <Setter Property="MenuItem.Command" Value="{Binding Path=(menuVMs:MenuItemVM.Command)}" />
</Style>

<Style x:Key="{x:Static local:MenuResourcesDictionary.SeparatorStyleResourceKey}" TargetType="{x:Type MenuItem}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate>
        <Separator />
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

MenuItemVM類或多或少很直接,所以我不在這里寫。

我在這里找到了DataTemplate並沒有使用DataTemplate的TreeView Context菜單答案: TreeView ContextMenu MVVM綁定 MVVM綁定命令到contextmenu項

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM