RadMenu和RadMenuItem Caliburn.Micro

RadMenu和RadMenuItem Caliburn.Micro

问题描述:

我加载编程一个radMenu使用Caliburn.Micro没有问题,XAML中看起来是这样的:RadMenu和RadMenuItem Caliburn.Micro

<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对象,我的意思是,我需要知道哪个菜单项被点击了。

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

在此先感谢

的点击项目将在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代码

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问题了解如何从事件中获取所选项目。

我假设你MenuItem类是一个自定义类:如果你改变你使用等

方法2的控制,我不喜欢这种方法,它更是不易断裂?你并不是真的想在你的虚拟机代码中依赖第三方类型(如果你改变为另一个控制提供者,比如Infragistics或者你有什么),所以你应该在实际点击时将实际的绑定对象传回给你的viewmodel 。如果不是这种方法仍然有效(但你会在你的虚拟机一个RadMenuItem参考结束)

您可以提取通过自定义Caliburn.Micro的MessageBinder.SpecialValues收集originalsource或实际绑定项,然后直接传递所选项目到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)]" 

这种方法的好处是,视图模型简单地接收绑定项,它并不需要知道如何提取值:

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公司控制相当不错的规模的项目,我从来没有需要从虚拟机中的任何拉德控制参考)

对不起,我不能回复ŸVB它,因为我不使用VB,但你可以在这个网站上进行转换:

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

免责声明:

$selecteditem可能是因为它的名声 - 也许$originalsourcedatacontext但是这是一个有点满口:)

+0

我最终使用了你提到的第一种方法工作,但现在我正在阅读你的答案我现在正在改变它。感谢您花时间回答我已经学到了很多答案。 – Okura 2013-04-17 02:31:08