Silverlight如何将列表框项的数据上下文设置为其所在视图的根视图模型

发布于 2024-11-29 02:06:45 字数 1694 浏览 0 评论 0 原文

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

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

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

<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>

This 有效,因为我现在可以访问该方法,但它实例化了一个新的视图模型,而不是允许我访问视图的根视图模型。因此,我丢失了之前视图模型中可能拥有的任何属性,因此我无法将它们作为参数传递给方法。

我的实现可能在这里关闭。所以我愿意接受建议。 在这种情况下,让列表框数据模板中的按钮调用视图模型中的方法并传递从所选列表框项派生的方法参数的最佳方法是什么?

完整的代码实现,您可以从SkyDrive 文件夹

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

步骤一和步骤二已完成。我陷入困境的是如何获取作为列表框项模板一部分的按钮来定位根视图模型并调用该虚拟机的方法,而无需实例化一个新的 ViewModel 来重置所有先前存储的属性。

提前致谢

Within my project I have a Listbox which uses a datatemplate. Within this data template I have a button. When the listbox generates results the item source for this listbox is set to some property collection let's call it Results[0].

The issue I am having is that when I click the button to call a method from the view model the method cannot be found because the call is looking to the context of the listbox and not the root view. I'm using SimpleMVVM toolkit which users a Locator similar to the MVVMLight toolkit.

One approach I took was to explicitly set the data context on the button by declaring the viewmodel in the user control resources and staticlly setting it.

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

and then the button contains

<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>

This works in the fact that I can now access the method but it instantiates a new view model vs allowing me to access the root viewmodel of the view. Ergo I loose any properties that I may have had in the previous view model so I cannot pass them to the method as parameters.

My implementation may be off here. So I am open to suggestions. In scenarios such as this what is the best approach to have a button within a listbox data template call a method from the view model and pass the method parameters that are derived from the selected listbox item?

To see the full code implementation you can download the sample project from SkyDrive Folder

Update I'm starting a bounty on this question as it has me stumped. Feel free to download the sample project for reference. For clarity the intent of this question is to learn how to accomplish the following
1. Select a row from listbox
2. The selectionchanged event will set a property to the text value displayed in the UI (RecordID two way binding using Inotify
3. Click on the button within the item template and call the method stored within the ViewModel using interaction triggers and displaying in a messagebox the RecordID property value.

Steps I and 2 are done. Where I am stuck is in understanding how to get the button which is part of the listbox item template to locate the root view model and call the method of that VM without instantiating a new ViewModel that would reset all previously stored properties.

Thanks in advance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

°如果伤别离去 2024-12-06 02:06:45

以编程方式添加资源。 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 类的构造函数。

代码

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

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

Add the resource programmatically. The StaticResource binding might complain at design time but at runtime it should just work.

The UserControl has a Resources property which returns a reference to a ResourceDictionary. You can add the ViewModel to this and the effect will be the same as your Xaml example except that you can reuse the existing ViewModel.

Assuming that your MVVM framework has already populated the DataContext of the UserControl with the ViewModel then you could use C# code similar to the following to set up the resource.

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

If the DataContext is already set within the UserControl's constructor, then it could go there. Otherwise, you will need to find a hook that is called later in the UserControl's life cycle.

Edit: Having looked at your code. I would suggest the following modifications.

  1. Do not set either the DataContext or the "vm" StaticResource in XAML.
  2. Use the following code as the constructor of the TemplateView class.

Code:

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

There are a couple of constraints here that led me to this solution. First is that the resource must be added prior to InitializeComponent. Second is that the templateViewModel must be available before the resource can be added.

高跟鞋的旋律 2024-12-06 02:06:45

我是一名 WPF 开发人员,不确定这是否适用于 Silverlight,但我通常会将目标对象上的绑定更改为类似的内容。

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

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

I'm a WPF developer and don't know for sure if this would work in Silverlight but I'd normally change the binding on your target object to something like

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

In effect, looking back up the tree until it finds the first ancestor ListBox, and then checking it's DataContext property which, if I read your question correctly, is your ViewModel.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文