Question

FINAL NOTE Final solution found in another post

Although I appreciated the clarification that was provided, the ultimate solution was in-fact provided by another solution as linked above. No matter WHAT I tried, the binding via the "Element Name" component was not working. I had to go based on the "Relative" hierarchy up the datagrid...

<Button Name="btnPrintReport" 
   Command="{Binding DataContext.MyPrintCommand, 
             RelativeSource={RelativeSource FindAncestor, 
                             AncestorType={x:Type DataGrid}}}"
   CommandParameter="{Binding}"
   Height="16" Width="16" HorizontalAlignment="Center" >
   <Image Source="MyButtonImage.png" IsHitTestVisible="True"/>
</Button>

Hope something not too complicated in WPF / MVVM environment. Here's the scenario.

I have a Window (.xaml) and a corresponding View Model (.cs). The form displays fine with all the data bindings no problem. (note: this is NOT done via any commercial "framework" )

One of the controls that is in the view window is a custom user control of a datagrid with all pre-defined columns, headings and content to be displayed when the view is shown. This works all no problem even though the control is not directly "defined" in the main window .xaml file, but just dropped on the form as the user control itself (which has its own obvious .cs code-behind).

With the main window's "DataContext" pointing to the View Model, and the user control that has a datagrid

<DataGrid AutoGenerateColumns="False" 
    Name="dataMyStuff"
    ItemsSource="{Binding Path=MyTablePropertyOnViewModel, 
        NotifyOnSourceUpdated=True, 
        NotifyOnTargetUpdated=True}" ... />

Now, what I'm looking for. On this data grid, I have a column that has an image in the first column. When I click on this image, I want to print a report specific to the record as represented by this row (it has a PK value I use). So, how do I tell the image "KeyUp" event to go to the View Model event handler since that is where the data is, and some other methods I'll need for preparing the call to the report. The view portion of the grid is for cosmetic display to the user, and thus no "functionality" directly in this control.

-- EDIT -- per progress from answers

I've adjusted my datagrid per comments from Josh and Rachel, however, something still does not appear to be quite right... Seeing the button was using a "Command" instance, I interpreted this as it needed to attach to an instance of an "ICommand" interface object on my view model. So, I created an instance. I know the command handler works as it is also used for common things like Add, Edit, Save, Cancel, Exit, etc... So I have a new one for this printing purpose. For simplicity, I have it created as an Always Execute, so there is no method to handle the "CanExecute" portion of the control. I've set the button's "Command" to almost all iterations I could think of an still nothing, but here's an update of what I'm seeing going on.

<UserControl>
   <Data grid columns / template, etc to the button>
      <DataTemplate> 
         <Button Name="btnPrintReport" 
            Command="{Binding DataContext.MyPrintCommand}" >
            <Image Source="myPrintImage.png"/>
         </Button>
      </DataTemplate>
   </Data grid columns, etc>
</UserControl>

In my ViewModel class (myICommandButtonHandler inherits from ICommand)

private myICommandButtonHandler myPrintCommand;
public myICommandButtonHandler MyPrintCommand
{
   get { if (myPrintCommand == null)
            myPrintCommand = new myICommandButtonHandler(myPrint);
         return myPrintCommand;
       }
}

private void myPrint()
{
   MessageBox.Show( "Doing the print job..." );
}

Now, what I'm seeing. During step through initialization of all the controls and such. I click menu item to call my Window to be displayed. FIRST, it creates an instance of the View Model controller. THEN, it calls the Window and passes in the View Model controller as parameter so it is immediately set at the Window level as the "DataContext" of the window. The main window then goes into it's "InitializeComponents" call and starts to build out all the other controls embedded, including this separate class that contains the data grid in question. At the constructor of this usercontrol (that has the datagrid), there is no "data context" set yet as the rest of the controls have not been initialized yet, and I don't know why / when the "bindings" apparently get "hooked" in. So, it appears that trying to do the binding to the data grid's command button are failing. HOWEVER, at run-time, the actual data IS updated in the grid, so I know that much is working.

So, the data grid has its "ItemsSource" set to a property of a "DataView" property on the view model, but the binding of the "button" doesn't appear to see the "MyPrintCommand" handler that I thought would get the hit.. and its action is to just display a message box (for now).

Was it helpful?

Solution

Usually I use an AttachedCommand Behavior which allows me to bind Events to ViewModel Commands. For example, you could use

<Image ...
       local:CommandBehavior.Event="KeyUp"  
       local:CommandBehavior.Command="{Binding DataContext.PrintCommand, ElementName=dataMyStuff}"
       local:CommandBehavior.CommandParameter="{Binding }"/>

I'd would recommend using a different event than KeyUp, since I don't think Images can have Keyboard focus so the KeyUp event will never get fired.

A better alternative is to use a Button and overwrite it's Template to be your Image. This will maintain the Click functionality, and give you access to Command and CommandParameter properties

<Button Command="{Binding DataContext.PrintCommand, ElementName=dataMyStuff}"
        CommandParameter="{Binding }">
    <Button.Template>
        <Image ... />
    </Button.Template>
</Button>

Also, the CommandParameter="{Binding }" will simply pass the current DataRow's DataContext (your data object) to the command

OTHER TIPS

Change the data template to be a button that has a image as its content. Use the command and commandparameter properties on the button to call your printing method. You can declare your print command in your viewmodel, and bind to it. Your parameter could be the selected row in your datagrid.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top