【问题标题】:Multiple dataContext for one control - MVVM一个控件的多个 dataContext - MVVM
【发布时间】:2013-03-08 02:12:27
【问题描述】:

我不确定我的问题标题是否完全代表我的问题,我会尽力解释:

我有一个网格单元 DataTemplate:(网格属于第三方公司,但对我的问题并不重要)

<DataTemplate>
    <TextBlock>
        <Hyperlink Command="{Binding OpenLinkCommand}"> 
            <Hyperlink.ToolTip>
                <TextBlock Text="{Binding Data.MapLink}"/>
            </Hyperlink.ToolTip>
            <TextBlock Text="{Binding Data.MapLink}" TextDecorations="underline">
        </Hyperlink>
    </TextBlock>
</DataTemplate>

我想让这个 DataTemplate 显示一些超链接(“Data.MapLink”是包含链接值的对象),每次点击这个链接都会触发命令“OpenLinkCommand”。

问题是“Data.MapLink”和“OpenLinkCommand”位于不同的dataContext中,然后我必须选择以下选项之一:

  1. 保留超链接 dataContext 不变 - 该命令将不起作用,超链接将获取 Data.MapLink 值。

  2. 将超链接 dataContext 更改为命令 datacontext - 命令将起作用,但超链接名称将为空。

遗憾的是我没有将这些项目放在同一个 dataContext 中的选项,所以我必须找到一种方法来告诉命令它的 dataContext 是“X”并告诉超链接它的 dataContext 是“Y”。

我希望我的问题很清楚 我该如何解决这个问题?

【问题讨论】:

  • 第二个数据上下文来自哪里?它是否绑定到一个元素,因为您可以将元素数据上下文绑定到另一个元素并设置相对源。如果您可以访问视图模型中的两个数据上下文(假设您使用的是视图模型),则可以拉入另一个命令。
  • 在 Binding 中使用 RelativeSource 来查找正确的数据上下文
  • 我刚刚向 Microsoft 报告了该错误(另一次?):connect.microsoft.com/VisualStudio/feedback/details/1398835/…

标签: wpf mvvm datacontext


【解决方案1】:

您必须拥有所需数据上下文的实例(通常在控件或窗口的资源中)。一旦你有了它,你应该能够显式设置文本块的数据上下文,而不是自动继承父数据上下文。

例如:

<TextBlock DataContext="{StaticResource MyDataMapLinkDataContext}" Text="{Binding Data.MapLink}" TextDecorations="underline"/>

【讨论】:

  • 是的,我想过这种方式,但我无法创建另一个数据上下文实例(我的数据上下文必须是 singleTon)。还有其他建议吗?
  • 您可以使用 relativesource FindAncestor 将您的超链接绑定到父数据上下文。确切的绑定代码取决于您如何构建 xaml。如果需要帮助,也许可以发布您的 xaml。
  • 另外,你说过你不能把两个命令放在同一个数据上下文中,如果你使用 mvvm,你可以将两个视图模型包装在第三个视图模型中并公开两个命令。
  • failedprogramming - 如果我理解你的解决方案,its not good. If i will do that the command will work (as I said before) but my hyperLink wont 可以访问 Data.MapLink 值也请再次查看 - 我只有 1 个命令。绑定它的另一个项目给我链接值的一些属性
【解决方案2】:

如果您确实需要为额外的数据上下文使用另一个属性,那么您可以使用附加属性。

XAML

    <Window.Resources>
        <Style TargetType="Button">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <ContentPresenter Content="{Binding (local:ExtraDataContextProvider.ExtraDataContext), RelativeSource={RelativeSource TemplatedParent}}"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

    <Grid>
        <Button Margin="172,122,131,79" Foreground="Green" local:ExtraDataContextProvider.ExtraDataContext="A test">
            test
        </Button>
    </Grid>
</Window>

代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication1
{

    public class ExtraDataContextProvider : DependencyObject
    {
        public static object GetExtraDataContext(DependencyObject obj)
        {
            return (object)obj.GetValue(ExtraDataContextProperty);
        }

        public static void SetExtraDataContext(DependencyObject obj, object value)
        {
            obj.SetValue(ExtraDataContextProperty, value);
        }

        public static readonly DependencyProperty ExtraDataContextProperty = DependencyProperty.RegisterAttached("ExtraDataContext", typeof(object), typeof(ExtraDataContextProvider), new PropertyMetadata(null));
    }

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

【讨论】:

    【解决方案3】:

    您可以使用一些绑定属性为您的绑定指定不同的Source,而不是默认的DataContext

    最常见的是ElementNameRelativeSource,它们会在VisualTree 中找到另一个UI 元素,以便您可以绑定到它的属性。

    例如下面使用ElementName告诉绑定它应该使用MyGridView作为绑定源,并绑定到MyGridView.DataContext.OpenLinkCommand

    <Hyperlink Command="{Binding ElementName=MyGridView, 
                                 Path=DataContext.OpenLinkCommand}"> 
    

    您还可以在绑定中使用RelativeSource 以在指定对象类型的VisualTree 中进一步查找对象,并将其用作绑定源。这个例子和上面的例子做的一样,除了它使用RelativeSource而不是ElementName,所以你的GridView不需要指定Name

    <Hyperlink Command="{Binding 
                   RelativeSource={RelativeSource AncestorType={x:Type GridView}}, 
                   Path=DataContext.OpenLinkCommand}"> 
    

    第三种选择是将绑定的Source 属性设置为静态对象,如下所示:

    <Hyperlink Command="{Binding 
                   Source={x:Static local:MyStaticClass.OpenLinkCommand}}"> 
    

    基于your comment here 关于绑定到单例,这可能是您的最佳选择。

    【讨论】:

    • 您好,您的解决方案似乎是我正在寻找的。我今天会尝试并报告它是否解决了我的问题。
    猜你喜欢
    • 1970-01-01
    • 2011-11-14
    • 1970-01-01
    • 2019-08-27
    • 2011-02-16
    • 2010-12-21
    • 2012-03-27
    • 1970-01-01
    • 2011-02-03
    相关资源
    最近更新 更多