【问题标题】:Binding from DependecyProperty to DataContext (ViewModel) in XAML在 XAML 中从 DependecyProperty 绑定到 DataContext (ViewModel)
【发布时间】:2012-10-14 15:55:18
【问题描述】:

假设这种情况:
我用 DependencyProperty“SuperValue”创建了一个新控件(“MyControl”)。
现在,在 XAML 中,我将“SuperValue”设置为“TestValue”:

<local:MyControl SuperValue="TestValue" />

此控件有一个 ViewModel (DataContext)。
我想将 DependencyProperty 的值(在本例中为“TestValue”)传递给 ViewModel 中的属性。

我该怎么做?

假设我的控件的 ViewModel 做了一些计算,例如:用户输入国家名称,控件给他一个当前存在的时间。

问题是:如何提供计算结果?假设这是 ViewModel 中的公共属性“Results”。我想创建一个像“TextBox.Text”、“ListView.SelectedItem”这样的属性,它向“外部”提供一部分 ViewModel 数据。

例如TextBox和Text属性:

<TextBox Text={Binding GiveMeTextValue} />

在这种情况下,DP“文本”提供给当前存储输入文本的 ViewModel 属性之外。

我想以同样的方式使用我的控件。

【问题讨论】:

  • 我们能否获得更多关于“无法设置”的上下文?你试过什么?您是否遇到编译错误或运行时异常,或者应用程序在您期望的时候什么也不做?
  • 无法设置的MyDependencyProperty在哪里?
  • 我添加了有问题的新信息。

标签: c# wpf mvvm binding dependency-properties


【解决方案1】:

我不知道我的问题是否正确:您想将 XAML 中的静态非绑定值设置为控件的 DependencyProperty 并将控件的 DataContext 上的属性设置为该静态值?如果您需要这样做,您的概念有问题,为什么不在相应字段中的ViewModel上提供此值并将控件的DP绑定到该字段?

但是,你能做什么得到你想要的:

在注册 DP 时定义一个 PropertyChangedCallback

// Dependency Property
public static readonly DependencyProperty TestProperty =
DependencyProperty.Register("Test", typeof(string),
typeof(MyControl), new FrameworkPropertyMetadata("123", new PropertyChangedCallback(OnTestChanged)));

在 OnTestChanged 方法中,将 DataContext 转换为 ViewModel 的类型,并将 ViewModel 上的相应值设置为新值:

private static void OnTestChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MyControl c = d as MyControl;
            ViewModelType vm = c.DataContext as ViewModelType;
            vm.Property = e.New;
            Console.WriteLine(e.NewValue);
        }

这是你要求的吗?

【讨论】:

  • 是的,这应该可行,但我真的不知道这是否与 MVVM 模式和组件分离规则 100% 一致。
  • 这不是很好的 MVVM。视图定义 (XAML) 不应包含“真实数据”,即以某种方式在逻辑中处理的数据。你想做什么?显然,您希望像当前​​在 XAML 中所做的那样定义一个值为“TestValue”的常量。为什么不在 ViewModel 中定义常量,而只公开一个返回常量的公共只读属性?然后你可以将你的控件绑定到 ViewModel 的这个属性...
【解决方案2】:

如何从属性SomethingValueInDataContextsetter 设置MyDependencyProperty

编辑

您可以设置控件DependencyProperty 使用控件的位置而不是其声明。这将起作用(本地是控制所在的命名空间) -

<Grid>
   <local:MyOwnControl MyDependencyProperty="{Binding Test}"/>
</Grid>

就像您在这样的 xaml 中创建 TextBox 的实例时可以设置 Width 一样-

<TextBox Width="{Binding PropertyName}"/>

【讨论】:

  • 听起来不错,但我使用的是 MVVM 模式,所以 ViewModel (DataContext) 对 View 一无所知。
  • 好的,你能详细说明为什么你不能从视图中设置你的MyDependencyProperty吗?这个 DP 在哪里?
  • 这几乎是好的,但是我的控件提供了在 ViewModel 中进行的操作的(外部)结果,所以我不能使用你的解决方案,因为我必须为 MyDependencyProperty 设置目标点。您的解决方案会很好,但它会使属性依赖属性不可用(无法访问获取或设置)。属性“Test”所在的 ViewModel 是 ControlViewModel,没有“ApplicationViewModel”。
【解决方案3】:

注意,您的 xaml 的根是 UserControl不是 MyOwnControl。 UserControl 是 MyOwnControl 的基类;您的属性未在基类中定义。这就是为什么不能从UserControl 的根元素中引用MyDependencyProperty 的原因。

使用您的示例,您可以切换绑定并获得所需的效果。

<UserControl 
    x:Class="namespace.MyOwnControl"
    x:Name="root">
    <UserControl.DataContext>
         <local:ControlViewModel  
             Test={Binding MyDependencyProperty, ElementName=root}" />
    </UserControl.DataContext>
</UserControl>

【讨论】:

  • 看起来不错,但出现错误:无法在“ControlViewModel”类型的“测试”属性上设置“绑定”。只能在 DependencyObject 的 DependencyProperty 上设置“绑定”。我可以尝试从 ControlViewModel DependecyObject 制作,但我真的不知道这是否自然并与 MVVM 一致?
  • @Never:是的。 ControlViewModel 必须扩展 DependencyObject 并且 Test 必须是 DependencyProperty。我总是制作我的 VM 的 DependencyObjects。它让生活变得如此轻松。此外,DP 绑定是最快的绑定,因此您可以获得速度优势。它从来都不是问题,直到它成为(几乎总是从来没有)。
  • 好的,所以我需要从 DependencyObject 派生并以与我在问题中创建 MyDependencyProperty 相同的方式制作“测试”DP?
  • @Never:正确。我不确定这是否是您设计的最佳解决方案,但它是可行的。您可能只需要创建一个自定义 IMultiValueConverter 并完成它。
  • 我确实像你说的那样,但绑定永远不会更新 MyDependencyProperty。看起来那行: 不起作用。当我更改 Test 属性的值时,MyDependencyProperty 事件回调不会触发。我已将代码上传到:pastebin.com/gMSnfVV2 所有测试项目:sendspace.com/file/75ypba 感谢尝试帮助。
【解决方案4】:

由于您使用的是 MVVM 设计范例,所有数据都应该与 ViewModel 相关。所以你的 DP 应该通过你的 VM 属性中的绑定来设置。

如果要在 Blend/VS 设计器中使用测试数据,您可以检查它与 Debug/Release...然后根据测试检查对您的属性进行某种分配。

【讨论】:

  • 好的,但是怎么做?如何通过绑定到我的 VM 属性来设置我的 DP 的值?
【解决方案5】:

您可以向MyControl 添加一个名为InitialSuperValue 的属性,该属性在设置时会设置SuperValue 的值。然后像这样写一些 XAML:

<local:MyControl InitialSuperValue="TestValue" SuperValue="{Binding SuperValueInViewModel, Mode=OneWayToSource}" />

【讨论】:

  • 是的,它会起作用,但是每次我使用控件时都写“SuperValue="{Binding SuperValueInViewModel, Mode=OneWayToSource}"" 有点疯狂。
  • 同意。如果您希望重复使用此绑定逻辑(即项目控件中的控件可能具有##### 的实例 - 或类似的场景),那么我建议您模板化您的控件并设置在模板中绑定。
猜你喜欢
  • 2015-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-09
  • 1970-01-01
  • 2013-04-16
  • 2016-07-11
  • 1970-01-01
相关资源
最近更新 更多