不从DataTemplate ContextMenu调用WPF命令

时间:2014-08-04 08:29:18

标签: wpf user-controls datatemplate

我再次从WPF难倒了。有时候事情并不是直截了当的!我已经搜索了高低的答案,但我尝试的所有内容都失败了。

我正在尝试使用datatemplate创建一个通用的复制和粘贴菜单。然后每个控件我希望使用该上下文菜单我可以设置该控件的模板并提供正确的函数绑定,理论上它应该正常工作。而不是在每个自定义控件文件中复制相同的菜单。但显然ContextMenu只是一场噩梦。

我所知道的:

  1. 上下文菜单不继承数据上下文,因为它们不是可视树的一部分
  2. 我可以使用DataContext =“{Binding PlacementTarget,RelativeSource = {RelativeSource Self}}来解决这个问题,它应该继承。
  3. 我不能使用WPF检查器来确定上下文菜单的datacontext是否为NULL。这很烦人。也许还有另一种方式。但是输出中没有错误,所以我必须假设它不是空的。
  4. 所以基于我的代码,它应该工作。有人可以指出一个特别神奇的组合,“哦,等等,在WPF你不能这样做,这个,如果这和这等于这个”。回答? :)

    这是我的自定义控件(请原谅我一直在黑客攻击试图让这个工作!)

        /// <summary>
    /// Interaction logic for Pointer.xaml
    /// </summary>
    public partial class Expander : UserControl
    {
        /// <summary>
        /// Command_ArrayAdd
        /// </summary>
        public class PasteCommand : ICommand
        {
            public PasteCommand(Expander _parent)
            {
                m_Parent = _parent;
            }
    
            /// <summary>
            /// Execute
            /// </summary>
            public bool Execute()
            {
                return true;
            }
    
            /// <summary>
            /// UnExecute
            /// </summary>
            public void UnExecute()
            {
            }
    
            Expander m_Parent;
        }
    
        /// <summary>
        /// Command_ArrayAdd
        /// </summary>
        public class CopyCommand : ICommand
        {
            public CopyCommand()
            {
            }
    
            /// <summary>
            /// Execute the change on the field
            /// </summary>
            public bool Execute()
            {
                return true;
            }
    
            /// <summary>
            /// Undo the change on the field
            /// </summary>
            public void UnExecute()
            {
            }
        }
    
        /// <summary>
        /// 
        /// </summary>
        public PasteCommand OnPasteCommand
        {
            get { return m_OnPasteCommand;  }
            set { m_OnPasteCommand = value; }
        }
        PasteCommand m_OnPasteCommand;
    
        /// <summary>
        /// 
        /// </summary>
        public CopyCommand OnCopyCommand
        {
            get { return m_OnCopyCommand; }
            set { m_OnCopyCommand = value; }
        }
        CopyCommand m_OnCopyCommand;
    
        public Expander(Database.DatabaseInstance.Struct _dbStruct, string _headerName)
        {
            try
            {
                InitializeComponent();
            }
            catch (System.Exception ex)
            {
                ErrorConsole.Instance.LogError(ex.Message + "\n" + ex.InnerException.Message);
            }
    
            m_dbStruct = _dbStruct;
            DataContext = this;
            m_HeaderName = _headerName;
            ExpanderLabel.Content = m_HeaderName;
    
            //AddHandler(CustomEvents.Copy, new RoutedEventHandler(OnCopyEvent));
    
            m_OnCopyCommand = new CopyCommand();
            m_OnPasteCommand = new PasteCommand(this);
        }
    
        private void OnUnloaded(object obj, RoutedEventArgs e)
        {
            //RemoveHandler(CustomEvents.Copy, new RoutedEventHandler(OnCopyEvent));
        }
    
        void OnMenuOpened(object obj, RoutedEventArgs e)
        {
            //string _clipboardData = (string)Clipboard.GetDataObject().GetData(DataFormats.Text);
            //((MenuItem)ExpanderLabel.Template.FindName("PasteMenuItem", ExpanderLabel)).IsEnabled = View.ViewModel.CanCopyFromTo(_clipboardData, m_dbStruct);
        }
    
        void _OnCopyCommand()
        {
            Clipboard.SetDataObject(m_dbStruct.Serialized);
        }
    
        void _OnPasteCommand()
        {
            CommandManager.Instance.Queue(new Database.DatabaseCommands.Command_PasteStruct(m_dbStruct, null));
        }
    
        Database.DatabaseInstance.Struct m_dbStruct;
        string m_HeaderName;
    }
    

    这是我的数据模板:

        <Style x:Key="RightClickCopyPasteLabel" TargetType="{x:Type Label}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Label">
                    <Label>
                    <Label.ContextMenu>
                            <ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">
                                <MenuItem x:Name="CopyMenuItem" Command="{Binding DataContext.OnCopyCommand, PresentationTraceSources.TraceLevel=High}" InputGestureText="Ctrl+C" Header="Copy" />
                                <MenuItem x:Name="PasteMenuItem" Command="{Binding DataContext.OnPasteCommand, PresentationTraceSources.TraceLevel=High}" InputGestureText="Ctrl+P" Header="Paste" />
                            </ContextMenu>
                    </Label.ContextMenu>
                    </Label>
                <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="FontWeight" Value="Bold"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

    编辑:

    在另一个线程上,我找到了输出更多数据的方法,但不幸的是,这对我没有任何意义。这是我点击右键时得到的结果:

    System.Windows.Data Warning: 96 : BindingExpression (hash=13029119): Got PropertyChanged event from MenuItem (hash=24459401) for DataContext
    System.Windows.Data Warning: 79 : BindingExpression (hash=13029119): Deactivate
    System.Windows.Data Warning: 103 : BindingExpression (hash=13029119): Replace item at level 0 with {NullDataItem}
    System.Windows.Data Warning: 103 : BindingExpression (hash=13029119): Replace item at level 1 with {NullDataItem}
    System.Windows.Data Warning: 78 : BindingExpression (hash=13029119): Activate with root item Label (hash=25041938)
    System.Windows.Data Warning: 107 : BindingExpression (hash=13029119):   At level 0 using cached accessor for Label.DataContext: DependencyProperty(DataContext)
    System.Windows.Data Warning: 104 : BindingExpression (hash=13029119): Replace item at level 0 with Label (hash=25041938), using accessor DependencyProperty(DataContext)
    System.Windows.Data Warning: 101 : BindingExpression (hash=13029119): GetValue at level 0 from Label (hash=25041938) using DependencyProperty(DataContext): Expander (hash=20086501)
    System.Windows.Data Warning: 107 : BindingExpression (hash=13029119):   At level 1 using cached accessor for Expander.OnCopyCommand: RuntimePropertyInfo(OnCopyCommand)
    System.Windows.Data Warning: 104 : BindingExpression (hash=13029119): Replace item at level 1 with Expander (hash=20086501), using accessor RuntimePropertyInfo(OnCopyCommand)
    System.Windows.Data Warning: 101 : BindingExpression (hash=13029119): GetValue at level 1 from Expander (hash=20086501) using RuntimePropertyInfo(OnCopyCommand): CopyCommand (hash=9651034)
    System.Windows.Data Warning: 80 : BindingExpression (hash=13029119): TransferValue - got raw value CopyCommand (hash=9651034)
    System.Windows.Data Warning: 84 : BindingExpression (hash=13029119): TransferValue - implicit converter produced <null>
    System.Windows.Data Warning: 89 : BindingExpression (hash=13029119): TransferValue - using final value <null>
    System.Windows.Data Warning: 96 : BindingExpression (hash=58885068): Got PropertyChanged event from MenuItem (hash=65477567) for DataContext
    System.Windows.Data Warning: 79 : BindingExpression (hash=58885068): Deactivate
    System.Windows.Data Warning: 103 : BindingExpression (hash=58885068): Replace item at level 0 with {NullDataItem}
    System.Windows.Data Warning: 103 : BindingExpression (hash=58885068): Replace item at level 1 with {NullDataItem}
    System.Windows.Data Warning: 78 : BindingExpression (hash=58885068): Activate with root item Label (hash=25041938)
    System.Windows.Data Warning: 107 : BindingExpression (hash=58885068):   At level 0 using cached accessor for Label.DataContext: DependencyProperty(DataContext)
    System.Windows.Data Warning: 104 : BindingExpression (hash=58885068): Replace item at level 0 with Label (hash=25041938), using accessor DependencyProperty(DataContext)
    System.Windows.Data Warning: 101 : BindingExpression (hash=58885068): GetValue at level 0 from Label (hash=25041938) using DependencyProperty(DataContext): Expander (hash=20086501)
    System.Windows.Data Warning: 107 : BindingExpression (hash=58885068):   At level 1 using cached accessor for Expander.OnPasteCommand: RuntimePropertyInfo(OnPasteCommand)
    System.Windows.Data Warning: 104 : BindingExpression (hash=58885068): Replace item at level 1 with Expander (hash=20086501), using accessor RuntimePropertyInfo(OnPasteCommand)
    System.Windows.Data Warning: 101 : BindingExpression (hash=58885068): GetValue at level 1 from Expander (hash=20086501) using RuntimePropertyInfo(OnPasteCommand): PasteCommand (hash=50152377)
    System.Windows.Data Warning: 80 : BindingExpression (hash=58885068): TransferValue - got raw value PasteCommand (hash=50152377)
    System.Windows.Data Warning: 84 : BindingExpression (hash=58885068): TransferValue - implicit converter produced <null>
    System.Windows.Data Warning: 89 : BindingExpression (hash=58885068): TransferValue - using final value <null>
    System.Windows.Data Warning: 96 : BindingExpression (hash=13029119): Got PropertyChanged event from MenuItem (hash=24459401) for DataContext
    System.Windows.Data Warning: 79 : BindingExpression (hash=13029119): Deactivate
    System.Windows.Data Warning: 103 : BindingExpression (hash=13029119): Replace item at level 0 with {NullDataItem}
    System.Windows.Data Warning: 103 : BindingExpression (hash=13029119): Replace item at level 1 with {NullDataItem}
    System.Windows.Data Warning: 78 : BindingExpression (hash=13029119): Activate with root item <null>
    System.Windows.Data Warning: 106 : BindingExpression (hash=13029119):   Item at level 0 is null - no accessor
    System.Windows.Data Warning: 103 : BindingExpression (hash=13029119): Replace item at level 1 with {NullDataItem}
    System.Windows.Data Warning: 80 : BindingExpression (hash=13029119): TransferValue - got raw value {DependencyProperty.UnsetValue}
    System.Windows.Data Warning: 88 : BindingExpression (hash=13029119): TransferValue - using fallback/default value <null>
    System.Windows.Data Warning: 89 : BindingExpression (hash=13029119): TransferValue - using final value <null>
    System.Windows.Data Warning: 96 : BindingExpression (hash=58885068): Got PropertyChanged event from MenuItem (hash=65477567) for DataContext
    System.Windows.Data Warning: 79 : BindingExpression (hash=58885068): Deactivate
    System.Windows.Data Warning: 103 : BindingExpression (hash=58885068): Replace item at level 0 with {NullDataItem}
    System.Windows.Data Warning: 103 : BindingExpression (hash=58885068): Replace item at level 1 with {NullDataItem}
    System.Windows.Data Warning: 78 : BindingExpression (hash=58885068): Activate with root item <null>
    System.Windows.Data Warning: 106 : BindingExpression (hash=58885068):   Item at level 0 is null - no accessor
    System.Windows.Data Warning: 103 : BindingExpression (hash=58885068): Replace item at level 1 with {NullDataItem}
    System.Windows.Data Warning: 80 : BindingExpression (hash=58885068): TransferValue - got raw value {DependencyProperty.UnsetValue}
    System.Windows.Data Warning: 88 : BindingExpression (hash=58885068): TransferValue - using fallback/default value <null>
    System.Windows.Data Warning: 89 : BindingExpression (hash=58885068): TransferValue - using final value <null>
    

1 个答案:

答案 0 :(得分:1)

通过查看代码,乍看之下一切看起来还不错,但仍有问题

问题是由于使用了不正确的ICommand接口来实现命令。 System.Windows.Input.ICommand的实现用于绑定WPF中的命令

现在让我试着解释一下我是如何找出问题的。

从踪迹中查看这3行

  

System.Windows.Data警告:80:BindingExpression(hash = 58885068):TransferValue - 得到原始值PasteCommand(hash = 50152377)

上面说它从绑定

获得了PasteCommand类型的值
  

System.Windows.Data警告:84:BindingExpression(hash = 58885068):TransferValue - 生成隐式转换器

上面的行说它会尝试将收到的值转换为适当的类型,例如'System.Windows.Input.ICommand`在这种情况下

  

System.Windows.Data警告:89:BindingExpression(hash = 58885068):TransferValue - 使用最终值

上面的

表示它使用的最终值为<null>,这意味着转换为适当的类型失败

分析上面的行告诉绑定是正确的,以解析值但是该值与源类型不匹配,因此无法使用它。

这迫使我查看命令的实现,即PasteCommand,我发现实现与所需的接口不匹配。