我使用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集合。
提前致谢
答案 0 :(得分:1)
点击的项目将位于属性RadRoutedEventArgs
中事件回调的OriginalSource
中。
e.g。
void RadMenu_ItemClick(object sender, Telerik.Windows.RadRoutedEventArgs e)
{
var menuItem = e.OriginalSource as RadMenuItem;
}
自RadRoutedEventArgs
子类System.Windows.EventArgs
起,您应该能够从中提取OriginalSource
。
有几种方法(我认为其中一种方法是更好方法)
方法1(在我喜欢的VM中工作但是工作太多了):
只需将事件args传递给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代码中依赖第三方类型(如果您更改为其他控制提供程序,例如Infragistics或您有什么),那么您应该将实际绑定对象传递回您的viewmodel 。如果不是这种方法仍然有效(但你最终会在你的虚拟机中使用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,但你可以在这个网站上转换:
http://www.developerfusion.com/tools/convert/vb-to-csharp/
声明:
$selecteditem
可能是一个坏名字 - 也许是$originalsourcedatacontext
,但这有点令人满口:)