Silverlight如何将列表框项的datacontext设置为其所在视图的根视图模型

时间:2011-08-12 15:49:48

标签: silverlight mvvm datatemplate

在我的项目中,我有一个使用datatemplate的Listbox。在这个数据模板中,我有一个按钮。当列表框生成结果时,此列表框的项目源设置为某个属性集合,我们将其称为结果[0]。

我遇到的问题是,当我单击按钮从视图模型调用方法时,无法找到该方法,因为调用正在查看列表框的上下文而不是根视图。我正在使用SimpleMVVM工具包,它使用类似于MVVMLight工具包的Locator。

我采用的一种方法是通过在用户控件资源中声明viewmodel并静态设置它来显式设置按钮上的数据上下文。

<UserControl.Resources>
    <formatter:HighlightConverter x:Key="FormatConverter" />
    <vml:SearchViewModel x:Key="vm" />
</UserControl.Resources>

然后按钮包含

<HyperlinkButton HorizontalAlignment="Left"
    Click="Button_Click"
    Content="{Binding Type}"
    Style="{StaticResource ListBoxtTitleHyperlink}">
 <i:Interaction.Triggers>
     <i:EventTrigger EventName="Click">
        <ei:CallMethodAction MethodName="GetDetailID" TargetObject="{Binding Source={StaticResource vm}}" />
     </i:EventTrigger>
 </i:Interaction.Triggers>
</HyperlinkButton>

这是因为我现在可以访问该方法,但它实例化一个新的视图模型,允许我访问视图的根视图模型。 Ergo我松开了我在上一个视图模型中可能拥有的任何属性,因此我无法将它们作为参数传递给方法。

我的实施可能在这里。所以我愿意接受建议。 在这样的场景中,在列表框数据模板中使用按钮的最佳方法是从视图模型调用方法并传递从所选列表框项派生的方法参数?

要查看完整的代码实现,您可以从SkyDrive Folder

下载示例项目

更新我正在开始对这个问题给予赏金,因为它让我感到难过。随意下载示例项目以供参考。为清楚起见,这个问题的目的是学习如何完成以下任务 1.从列表框中选择一行 2. selectionchanged事件将属性设置为UI中显示的文本值(使用Inotify的RecordID双向绑定) 3.单击项模板中的按钮,使用交互触发器调用存储在ViewModel中的方法,并在消息框中显示RecordID属性值。

完成步骤I和2。我遇到的问题是了解如何获取作为列表框项模板一部分的按钮,以找到根视图模型并调用该VM的方法,而无需实例化将重置所有先前存储的属性的新ViewModel。

提前致谢

2 个答案:

答案 0 :(得分:3)

以编程方式添加资源。 StaticResource绑定可能会在设计时抱怨,但在运行时它应该可以正常工作。

UserControl有一个Resources属性,它返回对ResourceDictionary的引用。您可以将ViewModel添加到此处,效果将与您的Xaml示例相同,只是您可以重用现有的ViewModel。

假设您的MVVM框架已经使用ViewModel填充了UserControl的DataContext,那么您可以使用类似于以下内容的C#代码来设置资源。

this.Resources.Add("vm", this.DataContext);

如果DataContext已经在UserControl的构造函数中设置,那么它可以去那里。否则,您需要找到稍后在UserControl生命周期中调用的挂钩。

修改:查看了您的代码。我建议进行以下修改。

  1. 不要在XAML中设置DataContext或“vm”StaticResource。
  2. 使用以下代码作为TemplateView类的构造函数。
  3. <强>代码

    public TemplateView()
    {
        var templateViewModel = new TemplateViewModel();
        this.DataContext = templateViewModel;
        this.Resources.Add("vm", templateViewModel);
        InitializeComponent();
    }
    

    这里有一些限制使我得到了这个解决方案。首先,必须在InitializeComponent之前添加资源。其次,在添加资源之前,templateViewModel必须可用。

答案 1 :(得分:0)

我是WPF开发人员并且不确定这是否适用于Silverlight但我通常会将目标对象上的绑定更改为

 <ei:CallMethodAction MethodName="GetDetailID" TargetObject="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType=ListBox, Mode=FindAncestor}}"/> 

实际上,查看树直到它找到第一个祖先ListBox,然后检查它的DataContext属性,如果我正确地读了你的问题,那就是你的ViewModel。