This is a migrated thread and some comments may be shown as answers.

Using Image Control in grid to delete row instead of Button (using MVVM)

9 Answers 224 Views
GridView
This is a migrated thread and some comments may be shown as answers.
lori guymon
Top achievements
Rank 1
lori guymon asked on 28 May 2010, 09:10 PM
I am developing an application using the MVVM pattern and would LOVE to use a delete icon to remove a row from inside a grid instead of a big ol' button.  I thought this would be a relatively easy thing to do but apparently not and I haven't found anyone else who has been doing this.

My approach was to use EventTriggers to listen for the event  MouseLeftButtonUp of the image control and then use the CallDataMethod to call a method in my viewmodel to handle removing the data from my datasource.  But the MouseLeftButtonUp doesn't seem to be firing and I'm stuck.

My column containing the image control is defined like this:
<telerikGridView:GridViewColumn CellTemplate="{StaticResource DeleteRowTemplate}" /> 

 And the DeleteRowTemplate code looks like this:
<DataTemplate x:Key="DeleteRowTemplate">  
                <Image Source="/FMSL;component/Assets/Images/Icons/Delete.png" >  
                    <swi:Interaction.Triggers>  
                        <swi:EventTrigger EventName="MouseLeftButtonUp">  
                            <esi:CallDataMethod Method="RemoveRow"/>  
                         </swi:EventTrigger>  
                    </swi:Interaction.Triggers>  
                </Image>  
</DataTemplate> 

I use EventTriggers often and the code works if an image control does not live inside a grid so I suspect one cannot use EventTriggers inside a grid. 

Can any confirm this?  And if this is the case, is there an alternative approach to trying to do what I'd like to do?  Our organization is use to removing rows using images when we were using the Telerik RadControls for AJAX and would like to continue this convention as we move to silverlight.

Thank You!

9 Answers, 1 is accepted

Sort by
0
Maya
Telerik team
answered on 01 Jun 2010, 02:27 PM
Hello lori guymon,

There is no problem to use EventTriggers inside the grid. However, there are a couple of things you need to do. Firstly, please use the newest version of the binaries Microsoft.Expression.Interactions.dll and System.Windows.Interactivity.dll and add reference to them:

xmlns:swi="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:mei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"

Then you can define the triggers in the way you want:
<UserControl.Resources>
        <my:MyViewModel x:Key="MyViewModel"/>
        <DataTemplate x:Key="DeleteRowTemplate">
            <Image Source="Images/Koala.jpg" Width="50" Height="50">
                <swi:Interaction.Triggers>
                    <swi:EventTrigger EventName="MouseLeftButtonUp" >
                        <mei:CallMethodAction MethodName="MyMethod" TargetObject="{StaticResource MyViewModel}" /> 
                    </swi:EventTrigger>
                </swi:Interaction.Triggers>
            </Image>
        </DataTemplate>
    </UserControl.Resources>



Kind regards,
Maya
the Telerik team

Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
0
lori guymon
Top achievements
Rank 1
answered on 01 Jun 2010, 06:25 PM
Thank you, Maya.  After looking at your solution, it appears the way I am implementing MVVM is getting in the way of the EventTrigger firing.  I usually wire-up the ViewModel in the xaml code.  However, this is a dialog window so I am using a technique of creating the ViewModel class first in the calling class (and passing parameters to the constructor of the viewmodel) and then passing the ViewModel object into the code-behine of the view as a parameter:

public partial class MaintainOrders : ChildWindow {  
 
        public MaintainOrders(MaintainOrdersViewModel model)  
        {  
            InitializeComponent();  
           
            DataContext = model;  
            model.Completed += OnWindowModelCompleted;  
        }  
 
        private void OnWindowModelCompleted(object sender, EventArgs e) {  
            DialogResult = ((MaintainOrdersViewModel)sender).IsCommitted;  
        }  
    } 

So I set the datacontext in the code-behind - not in xaml.  I'm new to MVVM but doing this way, the EventTrigger doesn't seem to be able to "find" my Method as it seems like it doesn't know where to look (like the binding of DataContext is happening too late???).  If I test out the EventTrigger by specifying the viewmodel in xaml, all works well. 

I tried setting the TargetObject parameter to "{Binding DataContext}" and a couple of other things in hopes of it finding the method in the viewmodel but have had no luck.  If you or anyone else knows how I can have the best of both worlds here (without having to rework my code so that I bind the viewmodel in xaml), I would appreciate it.  Otherwise, I'll keep trying...

Thanks for pointing me in the right direction!
0
lori guymon
Top achievements
Rank 1
answered on 01 Jun 2010, 08:45 PM
Hi Maya,
After playing around some more, I found a site that used the CallMethodAction with their ViewModel as I have it.  The TargeObject parameter is set to {Binding Mode=OneWay} in order to get the action to find the method in the viewmodel.

I modified my template like this:
<DataTemplate x:Key="DeleteRowTemplate">  
                <Image Source="/FMSL;component/Assets/Images/Icons/Delete.png" > 
                    <swi:Interaction.Triggers> 
                        <swi:EventTrigger EventName="MouseLeftButtonUp">  
                            <mei:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="RemoveRow"/>  
                         </swi:EventTrigger> 
                    </swi:Interaction.Triggers> 
                </Image> 
        </DataTemplate> 

Now when I run the program, instead of absolutely nothing happening, I get a "System.AccessViolationException" error with the message "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."  If I move the Image OUTSIDE the grid, the method is invoked in my viewmodel just fine.  So there seems to be an issue with calling the method INSIDE the grid. 

Would you have a working example of your code that invokes a method on the image control when it is INSIDE a grid I could download and compare?  I'm just beating my head against a wall now!

Thank you in advance?
0
Accepted
Maya
Telerik team
answered on 02 Jun 2010, 12:15 PM
Hello lori guymon,

 
Indeed, when the image is specified outside the grid, the case with TargetObject="{Binding Mode=OneWay}" works quite fine. But if it is define inside, you need to tell where the method can be found or mainly what is the element you are targeting the method to. That is why you have to specify it in the TargetObject.
I am sending you a sample project with an image defined inside the grid. Here clicking on it shows just a message box, but you can implement whatever logic you need.
I hope that helps.


Best wishes,
Maya
the Telerik team

Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
0
HDD
Top achievements
Rank 1
answered on 01 Jul 2010, 05:24 PM
Maya,
While browsing through the need for the click event trigger on images, I happen to find this post containing your sample.
Exactly what I was looking for. I got this implemented in my code. Thanks a bunch.
Now, to extend this a bit, can you help me to pass the currently selected row to my view model, so that instead of displaying something like "I am clicked!", I can make it more specific to the selected Grid's row data.
I mean,  lets say, I want to display "You clicked on Row number 12."
So, I would need to pass in some parameter in the below statement to my viewmodel:
<mei:CallMethodAction MethodName="MyMethod" TargetObject="{StaticResource MyViewModel}" />  

Any suggestions here.
Thanks.
0
Maya
Telerik team
answered on 05 Jul 2010, 07:30 AM
Hello,

The ViewModel in the project attached exposes a property SelectedItem and you can use it as a connection with the information you require. For example, we may bind it to the property of the grid SelectedItem:

<telerik:RadGridView Name="playersGrid"
        ItemsSource="{Binding Players}"
     SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
        AutoGenerateColumns="False">

An important thing here is to set the Mode of the binding to "TwoWay" because otherwise, the ViewModel will not be aware of the changes and SelectedItem. 
And then in the method called when clicking the image, you can take the information you need - for example about the Property "Country" of the item:
public void MyMethod()
        {
            var myItem = this.SelectedItem as Player;
            MessageBox.Show("This player is from " + myItem.Country);
        }


Sincerely yours,
Maya
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
HDD
Top achievements
Rank 1
answered on 06 Jul 2010, 07:03 PM
Thanks Maya, that did the work !!!
Appreciate much.

Thanks.
0
shivir
Top achievements
Rank 1
answered on 20 May 2011, 10:15 PM
Hi Maya,

My View Modal is defined as and I have no parameterless ViewModal

public

 

 

MyAnalyticsVM(IService serviceProxy)

 

 

{

 

 

 

this.serviceProxy = serviceProxy;

 

}

How can I do the same ?

0
Milan
Telerik team
answered on 25 May 2011, 12:10 PM
Hello shivir,

Having such ViewModel will not allow you to create it in XAML but you can introduce an intermediate object to host your actual ViewModel. For example, you can create a ViewModel container and setup all binding through the container. Then,  in code behind, add your actual ViewModel to the container.

public class ViewModelContainer
{
    public MyViewModel ViewModel
    {
        get;
        set;
    }
}

public MainPage()
{
    InitializeComponent();
  
    var container = this.Resources["MyViewModelContainer"] as ViewModelContainer;
    container.ViewModel = new MyViewModel("SDFSDFS");
}

 

<UserControl.Resources>
    <my:ViewModelContainer x:Key="MyViewModelContainer"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" 
      Background="White">
  
    <telerik:RadGridView Name="playersGrid" 
                                 ItemsSource="{Binding Players}" 
                                 SelectedItem="{Binding ViewModel.SelectedItem, Source={StaticResource MyViewModelContainer}}"
                                 AutoGenerateColumns="False">

Hope this helps.


All the best,
Milan
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
Tags
GridView
Asked by
lori guymon
Top achievements
Rank 1
Answers by
Maya
Telerik team
lori guymon
Top achievements
Rank 1
HDD
Top achievements
Rank 1
shivir
Top achievements
Rank 1
Milan
Telerik team
Share this question
or