2

我使用 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 集合。

提前致谢

4

1 回答 1

1

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

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

由于RadRoutedEventArgs子类System.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 中获取选定的项目。我不太喜欢这种方法,因为如果您更改正在使用的控件等,它很容易中断。

方法二:

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

于 2013-04-10T09:22:53.940 回答