【问题标题】:RadMenu and RadMenuItem Caliburn.MicroRadMenu 和 RadMenuItem Caliburn.Micro
【发布时间】:2013-04-01 13:24:06
【问题描述】:

我使用 Caliburn.Micro 以编程方式加载一个没有问题的 radMenu,Xaml 看起来像这样:

<telerik:RadMenu ItemsSource="{Binding .MenuItems}"
                 VerticalAlignment="Top"
                 cal:Action.TargetWithoutContext="{Binding RelativeSource={RelativeSource Self}}"
                 cal:Message.Attach="[Event ItemClick] = [Action MenuItemClick($this)]">
  <telerik:RadMenu.ItemContainerStyle>
    <Style TargetType="telerik:RadMenuItem">
      <Setter Property="Tag"
              Value="{Binding .Tag}" />
      <Setter Property="Header"
              Value="{Binding .Text}" />
      <Setter Property="Icon"
              Value="{Binding .Image}" />
      <Setter Property="ItemsSource"
              Value="{Binding .SubItems}" />
      <Setter Property="Command"
              Value="{Binding .SubItems}" />
    </Style>
  </telerik:RadMenu.ItemContainerStyle>
</telerik:RadMenu>

在我的 ViewModel 上,我有从数据库填充的相应 MenuItems 属性。代码如下所示:

Property MenuItems As New ObservableCollection(Of MenuItem)

Public Sub MenuItemClick(item As MenuItem)
    MessageBox.Show(item.Tag)
End Sub

问题是ItemClick事件的接线,我需要接收radMenuItem对象,我的意思是,我需要知道哪个MenuItem被点击了。

我在 Action.TargetWithoutContext 属性上尝试了各种组合,到目前为止,我只获得了 MenuItems 集合。

提前致谢

【问题讨论】:

    标签: wpf telerik caliburn.micro radmenu


    【解决方案1】:

    点击的项目将在RadRoutedEventArgs属性OriginalSource的事件回调中。 例如

    void RadMenu_ItemClick(object sender, Telerik.Windows.RadRoutedEventArgs e)
    {
        var menuItem = e.OriginalSource as RadMenuItem;
    }
    

    由于RadRoutedEventArgsSystem.Windows.EventArgs 的子类,您应该能够从中提取OriginalSource

    有几种方法(我认为其中一种是更好的方法)

    方法 1(可行,但我喜欢在 VM 中工作太多):

    只需将事件参数传递给 VM 上的处理程序方法,然后您就可以在 VM 代码中提取所选项目

    cal:Message.Attach="[Event ItemClick] = [Action MenuItemClick($eventargs)]"
    
    public class ViewModel 
    {
        public void MenuItemClick(System.Windows.EventArgs e) 
        {
            var menuItem = e.OriginalSource;
            // menuItem should be RadMenuItem, you can use FrameworkElement base type to get DataContext
            var fe = menuItem as FrameworkElement;
            var data = fe.DataContext; // (obviously do your null checks etc!)
        }
    }
    

    但是,这有一个问题,它让 VM 担心如何从 eventargs 中获取所选项目。我不太喜欢这种方法,因为如果您更改正在使用的控件等,它很容易中断。

    方法2:

    我假设您的 MenuItem 类是自定义类?您真的不想在您的 VM 代码中依赖 3rd 方类型(以防您更改为其他控件提供程序,例如 Infragistics 或您拥有的),因此您应该在单击时将实际绑定对象传递回您的视图模型.如果不是,这种方法仍然有效(但您最终会在您的 VM 中获得 RadMenuItem 引用)

    您可以通过自定义 Caliburn.Micro 的MessageBinder.SpecialValues 集合来提取原始源或实际绑定的项目,然后将选定的项目直接传递给 VM。 (您可以将此代码放入您的Bootstrapper 某处)

    以下是获取绑定到所选菜单项的数据项的方法:

    MessageBinder.SpecialValues.Add("$selecteditem", (context) =>
    {
        if (context.EventArgs is EventArgs)
        {          
            var e = context.EventArgs as EventArgs;
    
            // If the control is a FrameworkElement it will have a DataContext which contains the bound item
            var fe = e.OriginalSource as FrameworkElement;
    
            if (fe != null)
                return fe.DataContext;
        }
    
        return null;
    });
    

    如果您想要实际的 RadMenuItem 本身,您可以将上述实现更改为:

    MessageBinder.SpecialValues.Add("$selecteditem", (context) =>
    {
        if (context.EventArgs is EventArgs)
        {          
            var e = context.EventArgs as EventArgs;
            return e.OriginalSource;
        }
    
        return null;
    });
    

    并在 XAML 中使用:

    cal:Message.Attach="[Event ItemClick] = [Action MenuItemClick($selecteditem)]"
    

    这种方法的好处是 ViewModel 只接收绑定的项目,它不需要知道如何提取值:

    public class ViewModel 
    {
        public void MenuItemClick(TheActualTypeThatWasBound item) 
        {
            // Do stuff with item
        }
    }
    

    当然,除非您要传回实际的菜单项:

    public class ViewModel 
    {
        public void MenuItemClick(RadMenuItem item) 
        {
            // Do stuff with item
            var boundData = item.DataContext;
        }
    }
    

    但我强烈建议不要这样做(我有一个使用 Rad 控件的相当大的项目,我从来不需要从 VM 中引用任何 Rad 控件)

    对不起,我不能真正使用 VB,因为我不使用 VB,但你可以在这个网站上转换:

    http://www.developerfusion.com/tools/convert/vb-to-csharp/

    免责声明:

    $selecteditem 可能是个坏名字——也许是$originalsourcedatacontext 但这有点拗口 :)

    【讨论】:

    • 我最终使用你提到的第一种方法让它工作,但现在我正在阅读你的答案,我现在正在改变它。感谢您抽出宝贵的时间来回答我从您的回答中学到了很多东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多