sfDataGrid the MVVM way
<Syncfusion:SfDataGrid.Columns>
<Syncfusion:GridTextColumn MappingName="FirstName" HeaderText="First Name" AllowSorting="True" AllowEditing="True"/>
<Syncfusion:GridTextColumn MappingName="LastName" HeaderText="Last Name" AllowSorting="True"/>
</Syncfusion:SfDataGrid.Columns>
{
private Action<object> execute;
private Func<object, bool> canExecute;
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
{
this.execute = execute;
this.canExecute = canExecute;
}
{
return this.canExecute == null || this.canExecute(parameter);
}
{
this.execute(parameter);
}
}
|
<i:Interaction.Triggers>
<i:EventTrigger EventName="RowValidated">
<i:InvokeCommandAction Command="{Binding Path=RowValidated}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
private ICommand _rowValidated;
public ICommand RowValidated
{
get
{
return _rowValidated ?? (_rowValidated = new RelayCommand(CanExecute));
}
}
private bool _canExecute;
public void CanExecute(object obj)
{
} |
I tried your code and it gets into my Save and Can Save methods of my ICommand but the problem is: it gets me all the objects in my list. I want to get an object which was being modified so that I can write it to the database.
Can you please modify your code to show me, how can I get the changed object?
Thanks
<Syncfusion:SfDataGrid.RecordContextMenu>
<ContextMenu Style="{x:Null}">
<MenuItem Header="Edit">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding Path=EditMemberCommand}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</MenuItem>
</ContextMenu>
</Syncfusion:SfDataGrid.RecordContextMenu>
I also tried the following and that is also not working.
<Syncfusion:SfDataGrid.RecordContextMenu>
<ContextMenu Style="{x:Null}">
<MenuItem Header="Edit" Command="{Binding EditMemberCommand}" CommandParameter="{Binding}"/>
</ContextMenu>
</Syncfusion:SfDataGrid.RecordContextMenu>
|
<Syncfusion:SfDataGrid x:Name="datagrid"
AllowEditing="True"
SelectionUnit="Cell"
AutoGenerateColumns="False"
AllowFiltering="True"
ShowGroupDropArea="True"
ItemsSource="{Binding GDCSource}"
AllowSorting="True">
<i:Interaction.Triggers>
<i:EventTrigger EventName="RowValidated">
<i:InvokeCommandAction Command="{Binding Path=RowValidated}" CommandParameter="{Binding ElementName=datagrid, Path=CurrentItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Syncfusion:SfDataGrid> |
|
<Syncfusion:SfDataGrid ItemsSource="{Binding GDCSource}"
AllowSorting="True">
<Syncfusion:SfDataGrid.RecordContextMenu>
<ContextMenu Style="{x:Null}">
<MenuItem Command="{Binding DataGrid.DataContext.CMenuCommand}" Header="Header"/>
</ContextMenu>
</Syncfusion:SfDataGrid.RecordContextMenu>
</Syncfusion:SfDataGrid> |
The command on RowValidated is working fine now. Thanks for your input on it.
For now, I am trying to use the same command for the contextMenu but it is not working.
One thing I don't understand is: Why you have set the command to be DataGrid.DataContext.CMenuCommand
because CMenuCommand is available at Window DataContext and not the DataGrid DataContext level.
Here is my XAML
<Syncfusion:SfDataGrid x:Name="datagrid"
AllowEditing="True"
SelectionUnit="Cell"
AllowFiltering="True"
AutoGenerateColumns="True"
ShowGroupDropArea="True"
ItemsSource="{Binding GDCSource}"
AllowSorting="True">
<Syncfusion:SfDataGrid.RecordContextMenu>
<ContextMenu Style="{x:Null}">
<MenuItem Command="{Binding DataGrid.DataContext.CMenuCommand}" Header="Header"/>
</ContextMenu>
</Syncfusion:SfDataGrid.RecordContextMenu>
<i:Interaction.Triggers>
<i:EventTrigger EventName="RowValidated">
<i:InvokeCommandAction Command="{Binding Path=RowValidated}" CommandParameter="{Binding ElementName=datagrid, Path=CurrentItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Syncfusion:SfDataGrid>
By mistake, I copied and pasted your XAML code:
Here is mine:
<Syncfusion:SfDataGrid ItemsSource="{Binding MembersList, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" AutoGenerateColumns="False" x:Name="MembersGrid">
<i:Interaction.Triggers>
<i:EventTrigger EventName="RowValidated">
<i:InvokeCommandAction Command="{Binding Path=EditMemberCommand}" CommandParameter="{Binding ElementName=FamilyMembersGrid, Path=CurrentItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Syncfusion:SfDataGrid.Columns>
<Syncfusion:GridTextColumn MappingName="FirstName" HeaderText="First Name" AllowSorting="True" AllowEditing="True" SetCellBoundValue="True" CellTemplate="{StaticResource celltemplate}"/>
<Syncfusion:GridTextColumn MappingName="LastName" HeaderText="Last Name" AllowSorting="True"/>
<Syncfusion:GridDateTimeColumn MappingName="DateOfBirth" HeaderText="Birth Date" AllowSorting="True"/>
<Syncfusion:GridTextColumn MappingName="City" HeaderText="City" AllowSorting="True"/>
</Syncfusion:SfDataGrid.Columns>
<Syncfusion:SfDataGrid.RecordContextMenu>
<ContextMenu Style="{x:Null}">
<MenuItem Header="Edit" Command="{Binding DataGrid.DataContext.EditMemberCommand}">
</MenuItem>
</ContextMenu>
</Syncfusion:SfDataGrid.RecordContextMenu>
</Syncfusion:SfDataGrid>
Thanks for your response.
Looks like Command is working now. New problem is Command Parameter doesn't pass the selected object data. I tried CurrentItem, SelectedItem, SelectedIndex but no luck.
In Save and CanSave method, object passed is null.
Same Command is working fine for RowValidated and passes the CurrentItem object fine as per our previous discussion.
Sorry to give you trouble but since I started MVVM way, I don't want to do anything non-mvvm way otherwise, Click event is working already on context menu item. I tested it yesterday.
Here is my XAML
<MenuItem Header="Edit" Command="{Binding DataGrid.DataContext.EditMemberCommand}" CommandParameter="{Binding ElementName=FamilyMembersGrid, Path=CurrentItem}">
</MenuItem>
Thanks
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:syncfusion="clr-namespace:Syncfusion.UI.Xaml.Grid;assembly=Syncfusion.SfGrid.WPF">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Styles/sfDataGridStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
|
<Syncfusion:SfDataGrid x:Name="datagrid" >
<Syncfusion:SfDataGrid.RecordContextMenu>
<ContextMenu Style="{x:Null}">
<MenuItem Command="{Binding DataGrid.DataContext.CMenuCommand}" CommandParameter="{Binding}" Header="Header"/>
</ContextMenu>
</Syncfusion:SfDataGrid.RecordContextMenu>
</Syncfusion:SfDataGrid> |
|
<Syncfusion:SfDataGrid x:Name="datagrid" >
<Syncfusion:SfDataGrid.RecordContextMenu>
<ContextMenu Style="{x:Null}">
<MenuItem Command="{Binding DataGrid.DataContext.CMenuCommand}" CommandParameter="{Binding Path=DataGrid.CurrentItem}" Header="Header"/>
</ContextMenu>
</Syncfusion:SfDataGrid.RecordContextMenu>
</Syncfusion:SfDataGrid> |
Thanks for your response.
I managed to get the CurrentItem object upon clicking the context menu item but for some reason, I can't get the style to work unless I add it to as UserControl's resources.
I tried your code to move the resources at the app.xaml level and it is working.. That is not a big problem. Only I will have to do is, I will have to add it at the UserControl level instead at global level.
I just have one more question on Grid. Currently I have only four data in my table to display in a grid (It will grow over time though) and Grid is displayed using the RowDefinition to occupy rest of the space on a screen
<RowDefinition Height="Auto"></RowDefinition> -----> for heading
<RowDefinition Height="*"></RowDefinition> -----> for a grid
<RowDefinition Height="Auto"></RowDefinition> ---> for a button
Now the problem is, even though , I have a only four rows, grid occupies the complete space. How can I instruct Grid to occupy the space that are of only records height and then expand to * and provide stroller later when the data grows?
Thanks
|
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions> |
|
void sfdatagrid_Loaded(object sender, RoutedEventArgs e)
{
this.sfdatagrid.MaxHeight = this.Height;
} |
I have run into one more issue of data not populating into sfDataGrid. I have a similar grid where data is being populated just fine.
Here is my View model property which contains OnservableCollection<Institution>
I conformed that it has few rows of data in it..
ViewModel Class property declaration
public ObservableCollection<Institution> InstitutionList { get; set; }
In my VieModel Constructor,
InstitutionList = new ObservableCollection<Institution>(institutionOperations.GetAllInstitutions());
Here is my very simple DataGrid xaml for my user control
<UserControl.DataContext>
<viewModels:AllInstitutionsViewModel />
</UserControl.DataContext>
<Syncfusion:SfDataGrid Grid.Row="1" ItemsSource="{Binding Path=InstitutionList, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" AutoGenerateColumns="False" x:Name="InvestorsGrid" HorizontalAlignment="Center" Margin="10,20,10,10" SelectionUnit="Row" AllowFiltering="True" ShowGroupDropArea="True" Style="{DynamicResource SfDataGridStyle1}">
<Syncfusion:SfDataGrid.Columns>
<Syncfusion:GridTextColumn MappingName="Name" HeaderText="Name" AllowSorting="True" HorizontalHeaderContentAlignment="Stretch"/>
</Syncfusion:SfDataGrid.Columns>
</Syncfusion:SfDataGrid>
When I run this, the grid is completely empty. It even doesn't have the column called "Name"
Can someone please point me what I am doing wrong here.
As I said, I have similar model which works perfectly fine.
Hi,
I have run into one more issue of data not populating into sfDataGrid. I have a similar grid where data is being populated just fine.
Here is my View model property which contains OnservableCollection<Institution>
I conformed that it has few rows of data in it..
ViewModel Class property declaration
public ObservableCollection<Institution> InstitutionList { get; set; }
In my VieModel Constructor,
InstitutionList = new ObservableCollection<Institution>(institutionOperations.GetAllInstitutions());
Here is my very simple DataGrid xaml for my user control
<UserControl.DataContext>
<viewModels:AllInstitutionsViewModel />
</UserControl.DataContext>
<Syncfusion:SfDataGrid Grid.Row="1" ItemsSource="{Binding Path=InstitutionList, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" AutoGenerateColumns="False" x:Name="InvestorsGrid" HorizontalAlignment="Center" Margin="10,20,10,10" SelectionUnit="Row" AllowFiltering="True" ShowGroupDropArea="True" Style="{DynamicResource SfDataGridStyle1}">
<Syncfusion:SfDataGrid.Columns>
<Syncfusion:GridTextColumn MappingName="Name" HeaderText="Name" AllowSorting="True" HorizontalHeaderContentAlignment="Stretch"/>
</Syncfusion:SfDataGrid.Columns>
</Syncfusion:SfDataGrid>
When I run this, the grid is completely empty. It even doesn't have the column called "Name"
Can someone please point me what I am doing wrong here.
As I said, I have similar model which works perfectly fine.
Well,
It was working but with one issue. If I have exact one record in table, datagrid was not showing any columns and that one row. As soon as I added one more record to a table, it started showing both the rows.
I went through your sample and I couldn't reproduce the thing that I was running into. The problem is, my setup is pretty complex. I am using a separate API project for Database and also using entity framework and annotation for model validation for SQLite database. It is hard to put everything into one project and reproduce the same error. But as I mentioned, as soon as I added the second row into the database, it started showing both rows and after that, more rows is not a problem anymore.
I still will try to put everything in one project and see if I can reproduce the same behavior. I still consistently can reproduce it in my development project.
I also wanted to ask, if I can add the Edit link to the Datagrid? because, currently with SelectionUnit of either Cell or Any, you have to first select the cell and then hyperlink inside the cell is clickable. So it is a two step process to click on link in the cell. I want to make it so that it is clickable without selecting the cell first.
Thanks
Hi Andy,
By default in SfDataGrid the GridHyperLink column fired the link while clinking the cell at first time.
Sample:
http://www.syncfusion.com/downloads/support/directtrac/general/ze/Gridhyperlinkcolumn-519990559.zip
Could you please check this in your side and if still the this occurs then please modify the sample replicate the issue. This would be more helpful fos us to provide the better solution.
Regards,
Jai Ganesh S
How do I bind an event to GridHyperlinkColumn? I tried Binding and BindingParameter in the XAML tag but it is not available. In your provided sample, Binding is not implemented. I want to bind the click event to a RelayCommand I have in my ViewModel. Also I don't want the MappingName. Instead, I just want to display "Edit" with hyperlink and then on click, it should fire my ViewModel Binding.
I also looked at the online documentation for the GridHyperlinkColumn but it doesn't implement the MVVM way.
Thanks
|
<Syncfusion:SfDataGrid AutoGenerateColumns="False" HorizontalAlignment="Left" Name="datagrid" AllowEditing="True" ItemsSource="{Binding model}" VerticalAlignment="Top" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="CurrentCellRequestNavigate">
<i:InvokeCommandAction Command="{Binding Path=CurrentCellRequestNavigateCommand}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Syncfusion:SfDataGrid>
private RelayCommand _editCommand;
public ICommand CurrentCellRequestNavigateCommand
{
get
{
if (_editCommand == null)
{
_editCommand = new RelayCommand(param => this.LoadUser(param));
}
return _editCommand;
}
}
public void LoadUser(object ob)
{
//Write your code here
} |
I really appreciate your help. I now know how can I use regular event in MVVM.
- 21 Replies
- 4 Participants
-
AJ Andy Johnson
- Jan 11, 2017 06:02 PM UTC
- Feb 3, 2017 05:19 AM UTC