click command for Button into dataTemplate

Topics: Prism v2 - Silverlight 3
Aug 5, 2009 at 10:10 AM

Hi,

I have the following DataGrid Template Column

<data:DataGridTemplateColumn Header="Mostra utenti">
     <data:DataGridTemplateColumn.CellTemplate>
           <DataTemplate>
                 <Button
                      Content="Click"  
                        cal:Click.Command="{Binding MethodName}"
                  />
            </DataTemplate>
      </data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>

If I put this button outside the grid, the MethodName (that is DelegateCommand on the viewModel) is called correctly, while if the button is, like in this case, inside a data template, nothing occurs.

How can i do?

Thank you very much

Aug 5, 2009 at 4:28 PM

Your DataContext is no longer the same as outside the DataTemplate. One way this can be achieved is to use the DataContext="{Binding DataContext, ElementName=GridName}" to retarget the button's DataContext. However, when you do this, you then lose the ability to add a CommandParameter from the context of the current item if you need something like the ID. If you don't need this, then you should be fine.

If you do need this context, I got around that by putting in a hidden field to bind to: <TextBlock x:Name="MyItem" Visibility="Collapsed" Text="{Binding Id} /> and then use the cal:Click.CommandParameter="{Binding Text, ElementName=MyItem}".

Anyone have a better solution?

Aug 5, 2009 at 5:39 PM

Not necessarilly a better solution but a different solution.  You can subscribe to the click event at the UserControl level Blogged about here.   This blog is in regards to WPF Desktop, not Silverlight.   I have a solution for Silverlight which emulates this behavior which will be available in a few days when I activate my http://MultiTargeting.Codeplex.com project - this project uses a single code base for WPF, Silverlight, RIA and WinForms (using PRISM).

 

Aug 15, 2009 at 10:43 PM
Edited Aug 15, 2009 at 10:44 PM

I don't think you lose the ability to add parameters from the itemssource even if you bind outside the datacontext of your itemcontrol. It seems like this works for me

 <DataTemplate>

 

<Button Content="{Binding Name}" prism:Click.CommandParameter="{Binding Id}" prism:Click.Command="{Binding DataContext.LaunchCommand, ElementName=LayoutRoot}"/>  </DataTemplate>

 

 

Sep 10, 2009 at 1:17 PM

Sorry for the delay.

Yes, leflef, it works! It was simpler than I thought!

Thank you

Sep 10, 2009 at 1:34 PM

For the command, it is ok, as I said, using the leflef solution!

Cause I need to pass the row Id, I tried to use the fredhirschfeld solution and it doesn't work; I attach some code:

<Grid x:Name="LayoutRoot" DataContext="{Binding Path=., Source={StaticResource amministraSocietaVM}}">
        
        <CArtData:DataGrid ItemsSource="{Binding DataGridSocietaItemsSource}"
                                       Width="700"
                                       Height="300"
                                       RunningMode="Client"
                           >
            <CArtData:DataGrid.Columns >
                <CArtData:DataGridTextColumn x:Name="IdColumn" Width="200"  Binding="{Binding IdSocieta}" Visibility="Collapsed"/>
                <CArtData:DataGridTextColumn Width="200" Header="Codice società" Binding="{Binding CodiceSocieta}" />
                <CArtData:DataGridTextColumn  Width="200" Header="Ragione sociale" Binding="{Binding RagioneSociale}" />
                <CArtData:DataGridTemplateColumn  Width="200" Header="Modifica" >
                    <CArtData:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock x:Name="IdValue" Text="{Binding IdSocieta}" Visibility="Collapsed" />
                                 <Button     Content="Modifica"
                                                  prism:Click.CommandParameter="{Binding Text, ElementName=IdValue}"
                                                  prism:Click.Command="{Binding DataContext.ModificaSocieta, ElementName=LayoutRoot}"/>
                            </StackPanel>
                        </DataTemplate>
                    </CArtData:DataGridTemplateColumn.CellTemplate>
                </CArtData:DataGridTemplateColumn>
            </CArtData:DataGrid.Columns>
            
        </CArtData:DataGrid>

    </Grid>

I think it doesn't work because also the hidden TextBlock is inside the DataTemplate.. but... How Could I do to move this textblock outside the DataTemplate?

Thank you

Sep 11, 2009 at 11:11 AM

Last thing:

I said that works correclty (except the commandParameters question), but I forgot to tell you that I was using the ComponentArt Grid.

Id I use the standard silverlight grid, the solution proposed by lef lef doesn't work.

In particular, If I create a test button, equal to the one in the template column, it works, but the button inside the template column doesn't raise the event!

Any help?

Sep 12, 2009 at 5:13 PM

I have a modified version of what I was doing in the past using some Silverlight 2.0 binding I found:

<Button Content="Upload File" cmd:Click.Command="{Binding Tag.UploadDocumentCommand, RelativeSource={RelativeSource Self}}" cmd:Click.CommandParameter="{Binding}" Visibility="{Binding File, Converter={StaticResource HasValueVisibilityConverter}, ConverterParameter=True}">
  <ssutl:BindingHelper.Binding>
    <ssutl:BindingProperties SourceProperty="DataContext" 
                  TargetProperty="Tag" RelativeSourceAncestorType="SubmissionDocumentsView" />
  </ssutl:BindingHelper.Binding>
</Button>

The BindingHelper allows more flexible navigation of the binding to properties through proxies: http://www.scottlogic.co.uk/blog/wpf/2009/02/relativesource-binding-in-silverlight/

From this you can see that I am using the proxy binding to bind to the parent user control (my view type) so I can get the data context. I found that ElementName binding to a parent sometimes does not work correctly and so this was the a good workaround.

It appears that you are trying to get the row ID from the grid, correct? Do you need the row ID or just the underlying object? If just the object, then I would use CommandParameter="{Binding}" and then your method on the VM would accept that type and process. Unfortunately the DataGridRow only has a method to retrieve the Index and so you could not bind to it directly. I have typically used ObservableCollections in the VM and then passed the data item to search the collection for the index.

Hope this gives you some ideas.

Sep 14, 2009 at 10:04 AM

Thank you!

It works!!!

Sep 15, 2009 at 6:42 AM

hi guys,

I tried

<DataTemplate>

<Button Content="{Binding Name}" prism:Click.CommandParameter="{Binding Id}" prism:Click.Command="{Binding DataContext.LaunchCommand, ElementName=LayoutRoot}"/>  </DataTemplate>

Some guys said it works. But it didnt work for me. Can you please who said it works upload the example?

Thanks



 


Sep 16, 2009 at 9:31 PM
This is how I solved it:

<
DataTemplate> <Button Width="60" Content="{Binding Name}" Command="{Binding Path=DataContext.MySelectedTask, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Controls:DataGrid}}}" CommandParameter="{Binding}"/> </DataTemplate>

Hope this helps!

 

Sep 28, 2009 at 4:38 PM

am trying to use in Silverlight 3.0.. it does not work.. here is the code snippet..

<UserControl.Resources>

 <DataTemplate x:Key="dataTemplateUS"> 

<Button Height="30" Width="30" Commands:Click.Command="{Binding Path=DataContext.OnImageClickCommand, ElementName=DocumentListView}" Commands:Click.CommandParameter="{Binding}" > <font size="2" color="#a31515"><font size="2" color="#a31515">

 

</font></font><font size="2" color="#a31515">

 

</font>

<Image x:Name="_Image" Source="{Binding Converter={StaticResource RowIndexConverter},ConverterParameter=US}" HorizontalAlignment="Center" Width="30" Height="30" /> <font size="2" color="#a31515"><font size="2" color="#a31515">

 

</font></font><font size="2" color="#a31515">

 

</font>

</Button></DataTemplate>

 Any help will be appreciated..

Sep 29, 2009 at 9:10 AM
Edited Sep 29, 2009 at 9:13 AM

Hi gent boy,

 

I faced the same situation some days ago, it seems that the solution you're using works only in wpf, but not in silverlight 3.0.

What I did is to use the binding helper class mentionned by fredhirschfeld just above. It is working fine.

 

Hope it helps

Sep 30, 2009 at 3:25 AM

Thanks mkadoussi... It works..

Apr 20, 2010 at 1:25 AM

To brandontruong,

 You can get it working without changing the datacontext by moving your DelegateCommand LaunchCommand property into your Data Template Item object (may be a new property on the silverlight client using partial class) and set its handler in the presenter like below

<font size="2">

  item.LaunchCommand =

</font>new DelegateCommand<object>(OnLaunchExecute, OnLaunchCanExecute);

 Now you can access all you Data Template item properties within this data template and handle the LaunchCommand in one place.

Hope it helps.

 

Sep 23, 2010 at 11:58 AM

Hi,
I'm using a telerik radgridview.

<telerikGridView:RadGridView x:Name="gvMain" Margin="10" AutoGenerateColumns="False" SelectionMode="Extended" ItemsSource="{Binding Products}">                   
            <telerikGridView:RadGridView.Columns>                                   

                <telerikGridView:GridViewDataColumn  IsReadOnly="False" >
                                        <telerikGridView:GridViewDataColumn.CellTemplate>
                                            <DataTemplate>
                                                <StackPanel>
                                                    <CheckBox                                                        
                                                        IsChecked="{Binding IsSelected, Mode=TwoWay}"
                                                         Commands:Click.Command="{Binding DataContext.SelectClicked}"
                                                              />                                                   
                                                </StackPanel>
                                            </DataTemplate>
                                        </telerikGridView:GridViewDataColumn.CellTemplate>
                </telerikGridView:GridViewDataColumn>
            </telerikGridView:RadGridView.Columns>           
        </telerikGridView:RadGridView>

                    
SelectClicked is my ICommand property from my ViewModel. But It doesn't seems to work. I've read the whole thread but couldn't figure out the solution at least I know the problem part.
Anyone who can guide me what am I doing wrong here.
Thanks in advance. 
                    
                                                
               
                
                                        
                                            
                                                
                                                                                                        
                                                
                                            
                                        
                

                
                        
        

Sep 23, 2010 at 6:00 PM

First as a tip, you could take a look in the output window from debug, since you might receive a couple of messages with a similar text as shown below:

“BindingExpression path error: 'YourCommand' property not found on 'YourView+YourItemSource'…”

If it is your case, this is because the Binding is not able to reach the DataContext, so there isn’t way to execute the command this button.

In the Stock Trader RI can find a possible approach to a similar scenario. So you can review this application in the following files under StockTrader.RI.Modules.Position:

  • PositionSummaryView.xaml: here you can find how was set the Click.Command dependency property for the Action buttons, they are inside of a DataGrid named PositionsGrid. At this point, you will notice that has been set the Source property with Observable Commands. This is to avoid running into timing issues when the resource will be set and when will be consumed.
  • PositionSummaryView.xaml.cs: this codebehind not only sets its Model property, but also will set the Observable Commands

I hope this helps,

Fernando Antivero
http://blogs.southworks.net/fantivero

Sep 24, 2010 at 2:02 PM

Hi,

Thanks for the reply I checked out the code. but I also found another workaround DataContextProxy which doesn't involve any code behind plus minimal centralized code and its working just fine.

Sep 24, 2010 at 2:14 PM

Hi,

Nice to see that you solved your scenario and thanks for sharing this with the rest of the community, since it could be really helpful to other users.

Fernando Antivero
http://blogs.southworks.net/fantivero