how do i print a visual or window from the ViewModel by just calling a method to print without using a RelayCommand as shown in this example: Print WPF Visuals with MVVM pattern?
var printDlg = new PrintDialog();
printDlg.PrintVisual(View, "JOB PRINTING")
Ok this is a quick and dirty but reusable attached behavior class.
Disclaimer: I just hacked this in a couple of minutes and it has its flaws, which should be easy to overcome.
First we need our service class.
public class VisualPrinter
{
private static RoutedUICommand PrintVisualCommand = new RoutedUICommand("PrintVisualCommand", "PrintVisualCommand", typeof(VisualPrinter));
#region ab PrintCommand
public static ICommand GetPrintCommand(DependencyObject aTarget)
{
return (ICommand)aTarget.GetValue(PrintCommandProperty);
}
public static void SetPrintCommand(DependencyObject aTarget, ICommand aValue)
{
aTarget.SetValue(PrintCommandProperty, aValue);
}
public static readonly DependencyProperty PrintCommandProperty =
DependencyProperty.RegisterAttached("PrintCommand", typeof(ICommand), typeof(VisualPrinter), new FrameworkPropertyMetadata(PrintVisualCommand));
#endregion
#region ab EnablePrintCommand
public static bool GetEnablePrintCommand(DependencyObject aTarget)
{
return (bool)aTarget.GetValue(EnablePrintCommandProperty);
}
public static void SetEnablePrintCommand(DependencyObject aTarget, bool aValue)
{
aTarget.SetValue(EnablePrintCommandProperty, aValue);
}
public static readonly DependencyProperty EnablePrintCommandProperty =
DependencyProperty.RegisterAttached("EnablePrintCommand", typeof(bool), typeof(VisualPrinter), new FrameworkPropertyMetadata(false, OnEnablePrintCommandChanged));
private static void OnEnablePrintCommandChanged(DependencyObject aDependencyObject, DependencyPropertyChangedEventArgs aArgs)
{
var newValue = (bool)aArgs.NewValue;
var element = aDependencyObject as UIElement;
if(newValue)
{
element.CommandBindings.Add(new CommandBinding(PrintVisualCommand, OnPrintVisual));
}
}
private static void OnPrintVisual(object aSender, ExecutedRoutedEventArgs aE)
{
// the element is the one were you set the EnablePrintCommand
var element = aSender as Visual;
var printDlg = new PrintDialog();
// do the printing
}
#endregion
}
Here we define two attached properties. PrintCommand
is used to inject the actual print command into a view model, this must be done with OneWayToSource.
The second, EnablePrintCommand
, is to enable the printing, setting which element should be printed and to register the command binding.
My current version has a flaw, that you can't set both properties on the same element, but this can easily be overcome. So to print a a button, it would look like this:
<Grid local:VisualPrinter.EnablePrintCommand="True">
<Button Content="Test" local:VisualPrinter.PrintCommand="{Binding ViewModelPrint, Mode=OneWayToSource">
</Grid>
While ViewModelPrint
is a property of type ICommand in the view model, which can be executed and will then print the grid(therefore the button).