Silverlight GridViewComboBoxColumn Binding Commands with MVVM Not working - silverlight

I am trying to run a command from a GridViewColumn, and the RadGridView is bound to my ViewModel. The code below runs the command, but when I select a value from the ComboBox, it saves the row immediately without allowing me to make changes to other cells first. This behavior happens whether or not I have the command bound to the RADComboBox. If I take the command away, still happens.
XAML:
<telerik:RadGridView x:Name="GV1"
ItemsSource="{Binding Path=Material}"
AutoGenerateColumns="False"
IsReadOnly="{Binding IsGridReadOnly}"
ShowGroupPanel="False"
VerticalAlignment="Top"
HorizontalAlignment="Center"
RowDetailsVisibilityMode="VisibleWhenSelected">
<i:Interaction.Triggers>
<i:EventTrigger EventName="RowEditEnded">
<cmd:EventToCommand Command="{Binding RowEditEndedCommand}"
PassEventArgsToCommand="True" />
</i:EventTrigger>
<i:EventTrigger EventName="CancelRowEdit">
<cmd:EventToCommand Command="{Binding CancelEditCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<telerik:RadGridView.Columns>
<telerik:GridViewColumn Header="Material Code">
<telerik:GridViewColumn.CellEditTemplate>
<DataTemplate>
<telerik:RadComboBox ItemsSource="{Binding DataSource.AllMaterials, Source={StaticResource DCP}}"
DisplayMemberPath="Code"
SelectedValuePath="Code"
SelectedValue="{Binding Path=MaterialCode, Mode=TwoWay}"
IsEnabled="{Binding Path=IsMaterialEditable, Mode=TwoWay}"
Command="{Binding DataSource.MaterialCodeChangedCommand, Source={StaticResource DCP}}"/>
</DataTemplate>
</telerik:GridViewColumn.CellEditTemplate>
<telerik:GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding MaterialCode}" />
</DataTemplate>
</telerik:GridViewColumn.CellTemplate>
</telerik:GridViewColumn>
<!--7 Other Columns here-->
</telerik:RadGridView.Columns>
</telerik:RadGridView>
Code Behind
public RelayCommand MaterialCodeChangedCommand { get; private set; }
//IN Constructor
this.MaterialTypeChangedCommand = new RelayCommand(MaterialTypeChange);
private void MaterialCodeChange()
{
//Command code here
}
When I take the ComboBox out of the CellEditTemplate and try to use the GridViewComboBox, I can't figure out how to get the binding to work, but it doesn't fire off the RowEditEnded just by selecting the drop down so that part work correctly with this code:
<telerik:GridViewComboBoxColumn Header="Material Type"
ItemsSource="{Binding DataSource.AllTypeCodes, Source={StaticResource DCP}}"
SelectedValueMemberPath="Code"
DataMemberBinding="{Binding Path=MaterialType, Mode=TwoWay}"
DisplayMemberPath="Display">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding DataSource.MaterialTypeChangedCommand, Source={StaticResource DCP}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</telerik:GridViewComboBoxColumn>
If this is unclear let me know, it's late and I may not be clear. Thanks for any help you can offer. I should note that the RowEditEnded acts like this on other drop downs in my application as well when set up in the CellEditTemplate. Converting to the to the GridViewComboBoxCOlumn resolves that but then the binding issue...

Related

How do i keep two different commands at menu item and sub menu item generated through HierarchicalDataTemplate wpf

In the below piece of code, nested menu's get generated from an observable collection called CollectionOfAuthors. I've placed two commands, One at the 'ToplevelMenuItem' and another for submenu item (through textblock.InputBindings).
Though the command for submenuitem is working, I am unable to hit the command for the TopLevelMenuItem:
Need to understand what extra i need to do ?
<MenuItem x:Name="TopLevelMenuItem" Header="Authors" ItemsSource="{Binding CollectionOfAuthors}" Command="{Binding DataContext.RefreshAuthorsList, RelativeSource={RelativeSource AncestorType=Menu}}" >
<MenuItem.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Books}">
<TextBlock Text="{Binding AuthorName}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding BookName}" >
<TextBlock.InputBindings>
<MouseBinding Command="{Binding DataContext.NavigateToBook, RelativeSource={RelativeSource AncestorType=Menu}}" MouseAction="LeftClick" />
</TextBlock.InputBindings>
</TextBlock>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
Try with
<MenuItem x:Name="TopLevelMenuItem" Header="Authors" ItemsSource="{Binding CollectionOfAuthors}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="SubmenuOpened">
<i:InvokeCommandAction Command="{Binding DataContext.RefreshAuthorsList}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
If you want to prevent from firing command from submenues you will need to pass {Binding .} to command, and if param is not type of your ViewModel, then don't fire your action.
Also, you need to add reference to System.Windows.Interactivity and
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" in your xaml header

Wpf, How to find Element name from one user control in another

<TextBox x:Name="DescriptionTextBox"
Text="{Binding SelectedEntity.Description,
ValidatesOnExceptions=True}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus" SourceName="DescriptionTextBox">
<ei:CallMethodAction MethodName="RaiseCanExecuteChanged"
TargetObject="{Binding Command, ElementName=SaveButton}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
<userControls:SaveCloseUserControl />
Inside this user control
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<Button Width="50"
Command="{Binding SaveCommand}"
Content="Save" />
<Button Width="50"
Command="{Binding CloseCommand}"
Content="Close" />
</StackPanel>
The problem here is that this TargetObject="{Binding Command, ElementName=SaveButton}" does not find SaveButton because its inside of userControls:SaveCloseUserControl
I looked online and I found a solution (from 2009) that required code behind, is there not an easy way of doing this stuff today?
Regards
Edit
Based on #huzle answer I did this in the code behind of the user control
public object CreateButton { get { return CreateChild; } }
and in xaml i added a name to the save button.
so the my final version looks like this
<TextBox x:Name="DescriptionTextBox"
Text="{Binding SelectedEntity.Description,
ValidatesOnExceptions=True}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus" SourceName="DescriptionTextBox">
<ei:CallMethodAction MethodName="RaiseCanExecuteChanged"
TargetObject="{Binding CreateButton.Command,ElementName=MySaveCloseUserControl}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
<userControls:SaveCloseUserControl x:Name="MySaveCloseUserControl"/>
Give your "SaveCloseUserControl" a public properties for the "SaveButton" named "InnerSaveButton" and bind with ElementName to your SaveCloseUserControl and use the Path for getting to the Command of your inner button.
<TextBox x:Name="DescriptionTextBox"
Text="{Binding SelectedEntity.Description,
ValidatesOnExceptions=True}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus" SourceName="DescriptionTextBox">
<ei:CallMethodAction MethodName="RaiseCanExecuteChanged"
TargetObject="{Binding InnerSaveButton.Command, ElementName=MySaveCloseUserControl}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
<userControls:SaveCloseUserControl X:Name="MySaveCloseUserControl"/>

Why is the click event of a button inside a DataGrid is not fired?

I am using MVVM pattern and MVVM Light to convert an event into a command, in my XAML I have this code:
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="+" Padding="0,0,0,0" Height="Auto">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding MyCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
In my view model I have this code:
private RelayCommand<SelectionChangedEventArgs> _myCommand;
public RelayCommand<SelectionChangedEventArgs> MyCommandCommand
{
get { return _myCommand ?? (_myCommand = new RelayCommand<SelectionChangedEventArgs>(myCommandCommand)); }
}
private void myCommand(SelectionChangedEventArgs e)
{
// code
}
But the click event is not fired. However, I am using this way for every button in my application and when the button is into a user control or window, the event is fired.
Thanks.
Change your binding, the DataContext that it's trying to look for is the DataContext for the Template which might be different depending on your structure.
Change it to this
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=DataGrid}, Path=DataContext.MyCommand}" /
Besides the above answer, I found that it was also necessary to specify ClickMode="Press" in Xaml.
<Button Content="" Focusable="True" FontFamily="Segoe UI Symbol" FontSize="16" Background="{StaticResource HeroLightGray}" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center"
ClickMode="Press"
Command="{Binding DataContext.CopyMetadataSourceAsync, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" CommandParameter="{Binding .}" />
I do not recall having to do this in the past, but after spending hours troubleshooting, converting RelayCommand to IAsyncCommand, etc. this is the only thing that worked. In fact, I couldn't even get a regular code-behind "Click event" method to fire unless I included that ClickMode="Press"!

Pivot control MVVM-Light-EventToCommand SelectedIndex sends previous index

I get the index of the Pivot item I'm leaving, not the Pivot Item that I am going to.
I have searched for some time now and can think of some solutions like using an event in the view and then sending a message using MVVM-Light to the ViewModel. But I'd rather not do that, I'd rather stick to this current implementation, slightly different of course.
Any help is appreciated
My xaml:
<controls:Pivot x:Name="ContentPivot" Margin="12,0,12,0">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command ="{Binding SelectSlideCommand}"
CommandParameter="{Binding SelectedIndex, ElementName=ContentPivot}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<controls:PivotItem x:Name="PivotItem0" Header="0">
<Image Source="{Binding ViewingSlides[0].Path}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</controls:PivotItem>
<controls:PivotItem x:Name="PivotItem1" Header="1">
<Image Source="{Binding ViewingSlides[1].Path}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</controls:PivotItem>
<controls:PivotItem x:Name="PivotItem2" Header="2">
<Image Source="{Binding ViewingSlides[2].Path}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</controls:PivotItem>
</controls:Pivot>
and c#:
public RelayCommand<int> SelectSlideCommand;
SelectSlideCommand = new RelayCommand<int>((pivotItem) => SelectSlideAction(pivotItem));
void SelectSlideAction(int parameter)
{
currentIndex = parameter;
UpdateViewingSlides();
Debug.WriteLine("SelectSlideAction: " + parameter);
}
Do you have `SelectedItem Property in your Control... you can hook it up in Your ViewModel to a property in a TwoWay binding Mode to always get the updated Value (Then you will not need this command).... Also yoou can try
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command ="{Binding SelectSlideCommand}"
CommandParameter="{Binding SelectedItem, ElementName=ContentPivot}" />
</i:EventTrigger>
</i:Interaction.Triggers>

WPF Telerik RadGridView - compare startDatePicker EndDatePicker and display error if there is one

I have the current code where 2 DatePicker are in a templeted cells of a RadGridView.
<telerik:RadGridView AutoExpandGroups="True" AutoGenerateColumns="False" ColumnWidth="Auto" HorizontalAlignment="Left"
ItemsSource="{Binding entries, Mode=TwoWay}" Name="gridControl1" VerticalAlignment="Top"
RowIndicatorVisibility="Collapsed">
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn Width="0.2*" DataFormatString="{}{0:M/yyyy}" Header="{my:LocString ResourceKey=EntitySheet_OwnerShip_DisplayStartDate}" SortingState="Ascending">
<telerik:GridViewColumn.CellTemplate>
<DataTemplate>
<DatePicker x:Name="StartDateTimePicker" SelectedValue="{Binding StartDate,Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=True,UpdateSourceTrigger=LostFocus}"/>
</DataTemplate>
</telerik:GridViewColumn.CellTemplate>
</telerik:GridViewDataColumn>
<telerik:GridViewDataColumn Width="0.2*" DataFormatString="{}{0:M/yyyy}" Header="{my:LocString ResourceKey=EntitySheet_OwnerShip_DisplayEndDate}" SortingState="Ascending">
<telerik:GridViewColumn.CellTemplate>
<DataTemplate>
<DatePicker x:Name="StartDateTimePicker" SelectedValue="{Binding EndDate,Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=True,UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</telerik:GridViewColumn.CellTemplate>
</telerik:GridViewDataColumn>
</telerik:RadGridView.Columns>
<i:Interaction.Triggers>
<i:EventTrigger EventName="PropertyChanged">
<cmd:EventToCommand Command="{Binding Path=ValidateStartDateCommand, Mode=OneWay}" CommandParameter="{Binding SelectedItem, ElementName=gridControl1}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</telerik:RadGridView>
I want to compare the startDate with the endDate and display an error if endDate < startDate when the focus is lost on one of the fields but no events is raised (event are raised on other columns).
How I should do to raise an event permiting me to get the new values of the edited row and compare them?
Thank you in advance
Have you tried implementing the IDataErrorInfo interface on your ViewModel (assuming you are using MVVM) or whatever other class you are binding your datagrid to. Implementing that interface should allow you to write the validation code in the indexer to give you the desired results.
Hope this helps out a bit.

Resources