0

This is quite the reversal of what people usually have do, so every information I can find is about binding a UI property to a VM method.

TL;DR

MVVM. Code inside the VM, a method that -through a usual command delegate- manages the click on a button; I'm totally -and correctly- separated from the UI in this context. But...from here I need to call a method on a UI control inside the UI container which this VM istance is bound to. How is it possible? Can I somehow add a property to the VM in a way that the property value is bound in the XML to the method I need to call?


Edit explain it better

The user press the "Print" button. The VM receive the command. All is really really MVVM; the VM know nothing about the UI. I want to try to not break the MVVM paradigm.

Now, the user press the Print button because he want on paper the exact copy of many Usercontrol that are on the UI, so I have to call a method on each one of those that gives me back the its bitmap rapresentation. Those usercontrol do not expose a "Bitmap" property, I need to call their method.

motoDrizzt
  • 1,082
  • 11
  • 23
  • The usual way to do this sort of thing is for the command code in the VM to set a property indicating whatever new state the VM is now in, and raise `PropertyChanged` just in case somebody is listening. The view would then have a trigger that does something appropriate when the value of that property changes. I can't give you more specifics without more specifics about exactly what you're trying to do. – 15ee8f99-57ff-4f92-890c-b56153 Jun 17 '16 at 14:42
  • What are you asking for ? You want to bind a button to a command in VM, which should call another method in the view class ? – Nawed Nabi Zada Jun 17 '16 at 14:42
  • As I wrote, all the "bind a button to a command in a VM" is pretty standard stuff and I already implemented it. I'm exactly inside the command code. Now I need to call a method of a UI control. – motoDrizzt Jun 17 '16 at 14:48
  • @Ed that is what the author of the code I'm working on has proposed to do, but I'm not that happy with it :-\ – motoDrizzt Jun 17 '16 at 14:49
  • 2
    You're trying to kill the MVVM. Your VM doesn't know anything about the view. If it is requirement for the UI control only, you could use the Click event of button to do some stuff in your UI control. – Nawed Nabi Zada Jun 17 '16 at 14:52
  • Why are you unhappy with it? – 15ee8f99-57ff-4f92-890c-b56153 Jun 17 '16 at 14:52
  • What method are you trying to call, Which UI control are you talking about ? are you using any third party control ? – Abin Jun 17 '16 at 14:53
  • 2
    re: edit: It looks to me like your print command has nothing to do with the VM at all. It's the View printing itself. Do it with a Click event in code behind. At most, the codebehind might slap together the raster image and then pass it to a method on the viewmodel -- if for example you already have extensive viewmodel support for printing, then you would want to use that support for the sake of consistency, *after* the view has cobbled together something printable. In the absence of any compelling reason to involve the VM, don't. – 15ee8f99-57ff-4f92-890c-b56153 Jun 17 '16 at 15:03
  • @EdPlunkett: yeah...it was more or less my thougth, in the end. I was just trying to understand if there was something different to do, but yes...this has nothing to do with MVVM in the end. – motoDrizzt Jun 17 '16 at 15:09
  • I see now what you mean about the vm property thing. A command that sets `IsPrintView = true;` with a trigger on that property in the view -- that would be a kill-it-with-fire level kludge. A less horrific way to do that would be for the VM to have a `PrintView` event that the view could put a handler on in its DataContextChanged event, and the command would raise that event. But you'd still be jumping through hoops to get a VM involved in something that doesn't concern it. – 15ee8f99-57ff-4f92-890c-b56153 Jun 17 '16 at 15:17
  • 1
    Printing is a UI concern, and therefore code for it belongs in the UI codebehind. MVVM != no codebehind. –  Jun 17 '16 at 15:37

2 Answers2

0

You could make an interface called IBitmapProvider or something similar. Give it a method like GetBitmap(). Have your view inherit this interface. Pass the interface into the construction of the view model. Call the IBitmapProvider method on the command.

Kip Morgan
  • 728
  • 3
  • 12
0

Without a more specific question, including a good Minimal, Complete, and Verifiable code example that shows clearly what you're trying to do, it's impossible to know for sure what the best answer is. That said…

Your view model is not what should be handling the print command. Your view should be handling that. Use ApplicationCommands.Print or equivalent, creating your command binding in the view for an Executed event handler in the view. The view model need not know anything at all about printing.

Furthermore, you mention using bitmaps, but really there is no need for this either. The printing API allows you to print a Visual directly; rendering the Visual to a bitmap first and then printing the bitmap is a waste and will also create headaches trying to match your expected output resolution with the actual resolution of the printer.

You can either print the actual UI Visual objects directly, or you can reference your existing view model in a new ContentControl using the same template you're using for the view, or even a print-specific template if necessary. There are a variety of ways to accomplish this; you can find a simple example in an answer I provided in a different question.

Community
  • 1
  • 1
Peter Duniho
  • 68,759
  • 7
  • 102
  • 136