开发者

WPF Reverse Binding OneWayToSource

开发者 https://www.devze.com 2022-12-21 21:39 出处:网络
I have a custom control which has the following dependency property public static readonly DependencyProperty PrintCommandProperty = DependencyProperty.Register(

I have a custom control which has the following dependency property

public static readonly DependencyProperty PrintCommandProperty = DependencyProperty.Register(
      "PrintCommand",
  开发者_Go百科    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"); }
}

in the constructor of my control I am setting the default value of my property:

public MyControl()
{
   this.SetValue(PrintCommandProperty, new DelegateCommand<object>(this.Print));
}

I am then trying to bind the property to my ViewModel, so that I can access the property and call the Print Command.

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

However binding in the XAML causes the property value to be set to null. If I remove the binding in XAML the default property value is set properly in the constructor of my control.

What is the correct way of getting my ViewModel to call the Print method of my control?


I just reread your question, and it sounds like you are trying to call a method in your view from your view model. This is not what a view model is for.

If this is really what you want, there is no need to use a command: All your view need do is call:

view.Print()

If you want to change the print command, then you do want a property as shown. In that case your view model would call

view.PrintCommand.Execute()

In neither of these cases do you want a data binding.

A more WPF-ish way to do this is to add a binding to your control's CommandBindings collection to handle the built-in Application.Print command. Then the view model can send this command using RaiseEvent when it wants to print.

Note that a CommandBinding is a completely different object than a Binding. Do not confuse the two. A CommandBinding is used for handling routed commands. A Binding is used for updating property values.


The way you're using command binding is backwards from the normal way they're used in MVVM. Normally you wound declare a DelegateCommand in your VM which would take some action in the VM based on a UI action (like a button click). Since you're looking for the opposite path you'd probably be better off using an event originating from your VM that can then be handled by the ExportPrintGridControl. Depending on how the relationships are set up you may be able to declare the event handler in XAML on the VM instance declaration (doesn't look like it in your case) or in your control code just grab the DataContext and cast it to your VM or (better) an interface that includes the event to subscribe to.

p.s. Your DependencyProperty is currently set up so that anything external to your class can set it by calling SetValue (as all XAML does). I see why you had it set up this way to try to use it as a push-only Binding but here's a better implementation of read-only for situations when you really need that:

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); }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消