C# 在XAML中从DependecProperty绑定到DataContext(ViewModel)

C# 在XAML中从DependecProperty绑定到DataContext(ViewModel),c#,wpf,mvvm,binding,dependency-properties,C#,Wpf,Mvvm,Binding,Dependency Properties,假设这种情况: 我创建了一个新控件(“MyControl”),其DependencyProperty为“SuperValue”。 现在,在XAML中,我将“SuperValue”设置为“TestValue”: 此控件有一个ViewModel(DataContext)。 我想将DependencyProperty的值(在本例中为“TestValue”)传递给ViewModel中的属性 我该怎么做 假设我的控件的ViewModel做了一些计算,例如:用户输入国家的名称,控件给他一个当前存在的时间

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


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

我该怎么做

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

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

例如文本框和文本属性:

<TextBox Text={Binding GiveMeTextValue} />

在这种情况下,DP“Text”向外部提供了ViewModel属性,该属性当前存储输入的文本


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

如何从属性
setter
设置
MyDependencyProperty

编辑

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


注意,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>


我不知道我是否理解您的问题:您想在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设计范例,所以所有数据都应该与ViewModel相关。因此,应该通过VM属性中的绑定设置DP


如果测试数据将在Blend/VS designer中使用,您可以检查与调试/发布。。。然后根据测试检查对属性进行某种赋值。

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

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


我们能否获得更多关于“无法设置”的上下文信息?你试过什么?您是否遇到编译错误或运行时异常,或者应用程序在您预期的情况下什么也不做?您无法设置的
MyDependencyProperty
在哪里?我添加了相关的新信息。听起来不错,但我使用MVVM模式来查看模型(DataContext)我对视图一无所知。好的,你能详细说明一下为什么不能从视图中设置你的
MyDependencyProperty
?此DP位于何处?它几乎很好,但我的控件(向外部)提供了在ViewModel中执行的操作结果,因此我无法使用您的解决方案,因为我必须为MyDependencyProperty设置目标点。您的解决方案会很好,但它会导致属性依赖属性不可用(无法访问get或set)。属性“Test”存在的ViewModel是ControlViewModel,没有“ApplicationViewModel”。它看起来不错,但我有一个错误:不能在类型为“ControlViewModel”的“Test”属性上设置“Binding”。只能对DependencyObject的DependencyProperty设置“绑定”。我可以尝试从ControlViewModel DependecyObject生成,但我不知道这是否自然,是否与MVVM一致?@Never:是的
ControlViewModel
必须扩展
DependencyObject
Test
必须是
DependencyProperty
。我总是让我的VM的DependencyObjects。这让生活变得容易多了。此外,DP绑定是最快的绑定,因此您可以获得速度优势。在它出现之前,它从来都不是问题(这几乎永远都不是)。好的,所以我需要从DependencyObject派生并以相同的方式进行“测试”DP,就像我在问题中创建了我的DependencyProperty一样?@never:正确。我不确定这是否是您设计的最佳解决方案,但它是可行的。您可能只需要创建一个自定义IMultiValueConverter并完成它。我按照您所说的做了,但绑定永远不会更新MyDependencyProperty。这句话看起来像是:行不通。当我更改Test属性的值时,MyDependencyProperty事件回调不会启动。我已在:All Test project:上上载了代码,感谢您的帮助。是的,这应该可以工作,但我真的不知道这是否与MVVM模式和组件分离规则100%一致。MVVM不好。视图定义(XAML)不应包含“真实数据”,即以某种方式在逻辑中处理的数据。你想干什么?显然,您希望定义一个值为“TestValue”的常量,就像您目前在XAML中所做的那样。为什么不在ViewModel中定义常量,然后只公开一个返回常量的公共只读属性呢?然后您可以将控件绑定到ViewModel的这个属性……是的,它可以工作,但是写入“SuperValue=“{Binding SuperValueInViewModel,Mode=OneWayToSource}”永远不会
// Dependency Property
public static readonly DependencyProperty TestProperty =
DependencyProperty.Register("Test", typeof(string),
typeof(MyControl), new FrameworkPropertyMetadata("123", new PropertyChangedCallback(OnTestChanged)));
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);
        }
<local:MyControl InitialSuperValue="TestValue" SuperValue="{Binding SuperValueInViewModel, Mode=OneWayToSource}" />