我有一个用户控件(例如: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; }
}
}
}
答案 0 :(得分:0)
ContextMenu
不是逻辑树的一部分,因此绑定"{Binding DataContext.CMDActivateProject, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
不起作用,因为它没有UserControl类型的祖先。如果你没有设置PlacementTarget manuelly的DataContext,你可以尝试
"{Binding PlacementTarget.DataContext.CMDActivateProject, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}"
我不是100%肯定以下内容,但我认为如果您使用ContextMenu属性,这将有效:
<Treeview>
<Treeview.ContextMenu>
<ContextMenu>
...
<ContextMenu>
<Treeview.ContextMenu>
...
这里的冒险是,您不必在代码隐藏中处理rightbuttondown事件,如果您右键单击树视图,它会自动打开。
答案 1 :(得分:0)
我通过为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类或多或少直截了当,所以我不在这里写。
答案 2 :(得分:0)
我在这里找到了TreeView上下文菜单的答案,其中包含和不使用DataTemplate: TreeView ContextMenu MVVM Binding MVVM binding command to contextmenu item