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
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.
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!
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?
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.
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.
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
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 ?
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