C# WPF反向绑定单向到源

C# WPF反向绑定单向到源,c#,wpf,xaml,data-binding,mvvm,C#,Wpf,Xaml,Data Binding,Mvvm,我有一个自定义控件,它具有以下依赖属性 public static readonly DependencyProperty PrintCommandProperty = DependencyProperty.Register( "PrintCommand", typeof(ICommand), typeof(ExportPrintGridControl), new FrameworkPropertyMetadata(null, FrameworkP

我有一个自定义控件,它具有以下依赖属性

public static readonly DependencyProperty PrintCommandProperty = DependencyProperty.Register(
      "PrintCommand",
      typeof(ICommand),
      typeof(ExportPrintGridControl),
      new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));

public ICommand PrintCommand
{
    get { return (ICommand)GetValue(PrintCommandProperty); }
    set { throw new Exception("ReadOnly Dependency Property. Use Mode=OneWayToSource"); }
}
在控件的构造函数中,我正在设置属性的默认值:

public MyControl()
{
   this.SetValue(PrintCommandProperty, new DelegateCommand<object>(this.Print));
}
publicmycontrol()
{
this.SetValue(PrintCommandProperty,新的DelegateCommand(this.Print));
}
然后,我尝试将该属性绑定到ViewModel,以便访问该属性并调用Print命令

<controls:MyControl PrintCommand="{Binding PrintCommand, Mode=OneWayToSource}"/>

但是,XAML中的绑定会导致属性值设置为null。如果在XAML中删除绑定,则在控件的构造函数中正确设置默认属性值


让我的ViewModel调用控件的Print方法的正确方法是什么?

我刚刚重读了你的问题,听起来你好像在试图从视图模型调用视图中的方法。这不是视图模型的用途

如果这确实是您想要的,则无需使用命令:视图只需调用:

view.Print()
如果要更改“打印”命令,则需要如图所示的属性。在这种情况下,视图模型将调用

view.PrintCommand.Execute()
在这两种情况下,都不需要数据绑定

更像WPF的方法是向控件的
CommandBindings
集合添加绑定,以处理内置的
应用程序。Print
命令。然后视图模型可以在需要打印时使用
RaiseEvent
发送此命令


请注意,CommandBinding是与绑定完全不同的对象。不要混淆两者。CommandBinding用于处理路由命令。绑定用于更新属性值。

我刚刚重新阅读了您的问题,听起来您好像试图从视图模型中调用视图中的方法。这不是视图模型的用途

如果这确实是您想要的,则无需使用命令:视图只需调用:

view.Print()
如果要更改“打印”命令,则需要如图所示的属性。在这种情况下,视图模型将调用

view.PrintCommand.Execute()
在这两种情况下,都不需要数据绑定

更像WPF的方法是向控件的
CommandBindings
集合添加绑定,以处理内置的
应用程序。Print
命令。然后视图模型可以在需要打印时使用
RaiseEvent
发送此命令


请注意,CommandBinding是与绑定完全不同的对象。不要混淆两者。CommandBinding用于处理路由命令。绑定用于更新属性值。

使用命令绑定的方式与MVVM中使用命令绑定的正常方式相反。通常,您会在VM中声明一个
DelegateCommand
,该命令将根据UI操作(如单击按钮)在VM中执行某些操作。由于您正在寻找相反的路径,因此最好使用源自VM的事件,然后由
ExportPrintGridControl
处理该事件。根据关系的设置方式,您可能能够在VM实例声明(与您的情况不同)或控制代码中用XAML声明事件处理程序,只需抓取
DataContext
并将其强制转换到您的VM或(更好的)包含要订阅的事件的接口

p、 您的
dependencProperty
当前已设置,以便类外部的任何内容都可以通过调用
SetValue
来设置它(所有XAML都是这样做的)。我明白了为什么您将其设置为尝试将其用作仅推式绑定,但在您真正需要的情况下,这里有一个更好的只读实现:

private static readonly DependencyPropertyKey PrintCommandPropertyKey = DependencyProperty.RegisterReadOnly(
  "PrintCommand",
  typeof(ICommand),
  typeof(ExportPrintGridControl),
  new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));

public static readonly DependencyProperty PrintCommandProperty = PrintCommandPropertyKey.DependencyProperty;

public ICommand PrintCommand
{
    get { return (ICommand)GetValue(PrintCommandProperty); }
    private set { SetValue(PrintCommandPropertyKey, value); }
}

您使用命令绑定的方式与MVVM中使用的正常方式相反。通常,您会在VM中声明一个
DelegateCommand
,该命令将根据UI操作(如单击按钮)在VM中执行某些操作。由于您正在寻找相反的路径,因此最好使用源自VM的事件,然后由
ExportPrintGridControl
处理该事件。根据关系的设置方式,您可能能够在VM实例声明(与您的情况不同)或控制代码中用XAML声明事件处理程序,只需抓取
DataContext
并将其强制转换到您的VM或(更好的)包含要订阅的事件的接口

p、 您的
dependencProperty
当前已设置,以便类外部的任何内容都可以通过调用
SetValue
来设置它(所有XAML都是这样做的)。我明白了为什么您将其设置为尝试将其用作仅推式绑定,但在您真正需要的情况下,这里有一个更好的只读实现:

private static readonly DependencyPropertyKey PrintCommandPropertyKey = DependencyProperty.RegisterReadOnly(
  "PrintCommand",
  typeof(ICommand),
  typeof(ExportPrintGridControl),
  new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));

public static readonly DependencyProperty PrintCommandProperty = PrintCommandPropertyKey.DependencyProperty;

public ICommand PrintCommand
{
    get { return (ICommand)GetValue(PrintCommandProperty); }
    private set { SetValue(PrintCommandPropertyKey, value); }
}