Do your controls support MVVM binding?

Hi,

I've been struggling with getting your controls to work first time I'm trying them out.
I tried working with them before and the experience was not pleasant.
For example, MVVM is the recommended data binding pattern for Xamarin forms development, but your examples appear not to use MVVM.
I tried binding to this grid in a ContentView

<sfgrid:SfDataGrid x:Name="dataGrid" ItemsSource="{Binding DataList}" AllowLoadMore="True"
           LoadMoreCommand="{Binding LoadMoreCommand}" AllowPullToRefresh="True" PullToRefreshCommand="{Binding RefreshCommand}"
                          AllowResizingColumn="True" AutoGenerateColumns="false" AllowSorting="True" AllowMultiSorting="True"
                          AllowEditing="True"
                          SelectionMode="Single" VerticalOverScrollMode="None">
 
                <sfgrid:SfDataGrid.Columns>
                    <sfgrid:GridTextColumn MappingName="Name" HeaderText="Name"></sfgrid:GridTextColumn>
                    <sfgrid:GridPickerColumn
                   MappingName="GlobalId" ItemsSource="{Binding ExpenseGroups}" DisplayMemberPath="Name" ValueMemberPath="Id"
                  HeaderFontAttribute="Bold" HeaderText="Group">
                      
                    </sfgrid:GridPickerColumn>
                    <sfgrid:GridSwitchColumn MappingName="ActiveFlag" HeaderText="Active?"></sfgrid:GridSwitchColumn>
                </sfgrid:SfDataGrid.Columns>
 
            </sfgrid:SfDataGrid>

This is the ContentView code
public CVGridExpenseCategories()
       {
           InitializeComponent();
           
           ThemeManager.ThemeName = Themes.Light;
 
 
           ViewModel = new ExpenseCategoryViewModel();
           ViewModel.LoadMoreCommand.Execute(null);
           BindingContext = ViewModel;
       }
 
 
       public ExpenseCategoryViewModel ViewModel
       { getset; }

When it runs, it throws a NullReferenceException.
Why is the binding NOT WORKING???
And why do all your examples use this inline viewmodel declaration?
 <sample:SampleView.BindingContext>
        <local:GettingStartedViewModel x:Name="viewModel" />
    </sample:SampleView.BindingContext>
Is there something wrong with binding to a viewmodel like this?
<sfgrid:SfDataGrid x:Name="dataGrid" ItemsSource="{Binding DataList}" AllowLoadMore="True"
Also, why is this not working?
 <sfgrid:GridPickerColumn
                   MappingName="GlobalId" ItemsSource="{Binding ExpenseGroups}" DisplayMemberPath="Name" ValueMemberPath="Id"
                  HeaderFontAttribute="Bold" HeaderText="Group">
                     
 </sfgrid:GridPickerColumn>
              
     
How do you reference the BindingContext for the GridPickerColumn from the viewmodel that is not declared inline?
Is this the only way of binding data to the GridPickerColumn?
BindingContext="{x:Reference viewModel}"
This has been really frustrating.
Also, I am not sure your Nuget packages add all the required dependencies to the Platform (Android,iOS) projects.
Please look into this.
Please I need working answers.
Thanks.

3 Replies

SK Shivagurunathan Kamalakannan Syncfusion Team June 27, 2018 01:46 PM UTC

Hi Ozioma, 
 
Thanks for contacting Syncfusion Support. 
 
  • Regarding this question:For example, MVVM is the recommended data binding pattern for Xamarin forms development, but your examples appear not to use MVVM.
 
SfDataGrid can be implemented in MVVM pattern. I have attached a sample in MVVM pattern. Please refer the sample for your reference. 
 
 
Regarding the exception: 
 
The exception is due to this line of code ViewModel.LoadMoreCommand.Execute(null);The LoadMoreCommand needs to be assigned in a below way.
“dataGrid.LoadMoreCommand = new Command(ExecuteLoadMoreCommand);”
 
Ø  Regarding this question:Is there something wrong with binding to a viewmodel like this?<sfgrid:SfDataGrid x:Name="dataGrid" ItemsSource="{Binding DataList}" AllowLoadMore="True"
There is nothing wrong in the above code. Please ensure whether you have set BindingContext for it.
 
  • Regarding this question:
Also, why is this not working? <sfgrid:GridPickerColumn                   MappingName="GlobalId" ItemsSource="{Binding ExpenseGroups}" DisplayMemberPath="Name" ValueMemberPath="Id"                  HeaderFontAttribute="Bold" HeaderText="Group">                      </sfgrid:GridPickerColumn>
 
We have checked your query and the PickerColumn is working fine in our side. We have prepared a working sample for your reference and you can download the same from the below link. Also refer the below UG link for your reference.  
 
 
 
  • Regarding this question : “ How do you reference the BindingContext for the GridPickerColumn from the viewmodel that is not declared inline? Is this the only way of binding data to the GridPickerColumn?
 
BindingContext="{x:Reference viewModel}"” 
 
As of now it is necessary to set BindingContext for the GridPickerColumn. You can set the BindingContext which has been set to the SfDataGrid. 
 
We have logged an issue report regarding this, So that the column considers the BindingContext of the SfDataGrid. The fix will be available in any of our upcoming releases. 
 
Regards, 
Shivagurunathan 



OZ Ozioma October 22, 2018 09:18 PM UTC

Hi, 
Thanks guys for making these quality UI controls!
I am back to evaluating them again and I hope my concerns are addressed.

Sorry but my questions were not addressed the last time.
What is WRONG with data binding like this?

ViewModel = new ExpenseCategoryViewModel();
ViewModel.LoadMoreCommand.Execute(null);
BindingContext = ViewModel;
The above works with other UI controls I use.

Meanwhile, this is not correct, as per my code
“dataGrid.LoadMoreCommand = new Command(ExecuteLoadMoreCommand);”

The LoadMoreCommand is a valid ICommand reference and works with all other controls when used like this
ViewModel.LoadMoreCommand.Execute(null);
Do you controls need the Command reference to be assigned like this?

“dataGrid.LoadMoreCommand = new Command(ExecuteLoadMoreCommand);”

If so please state it clearly, to reduce confusion.


Why do ALL your examples use this pattern??

<ContentPage.BindingContext>
        <local:ViewModel x:Name="viewModel"/>
</ContentPage.BindingContext>

And why do you need to create and attach behaviors to a databound control?
Like I asked previously, is something wrong with this style of data binding????

ViewModel = new ExpenseCategoryViewModel();
ViewModel.LoadMoreCommand.Execute(null);
BindingContext = ViewModel;

I mean its simpler and easier to read IMO.
What's the deal with using XAML and behaviours exclusively for databinding?

Thanks


VR Vigneshkumar Ramasamy Syncfusion Team October 24, 2018 03:59 AM UTC

Hi Ozioma,  
 
Regarding your query on LoadMoreCommand
 
You can set the SfDataGrid.LoadMoreCommand to any ICommand. We have prepared the sample as per your requirement, in which LoadMoreCommand is binded to the ICommand. 
Please find the code snippet of the same below. In the below code, you can observe that SfDataGrid.LoadMoreCommand is binded to the “LoadMore” of type ICommand in the ViewModel.  
<ContentPage.BindingContext> 
  <local:ViewModel x:Name="viewModel" /> 
</ContentPage.BindingContext> 
<ContentPage.Content> 
  <sfgrid:SfDataGrid x:Name="sfGrid" 
           AutoGenerateColumns="False" 
           ItemsSource="{Binding OrdersInfo}" 
           AllowResizingColumn="True" 
           ColumnSizer="Star" 
           AllowLoadMore="True" 
           LoadMoreCommand="{Binding LoadMore}" 
           IsBusy="{Binding Busy}" 
               > 
    <sfgrid:SfDataGrid.Columns> 
      <sfgrid:GridTextColumn MappingName="OrderID" /> 
      <sfgrid:GridTextColumn MappingName="EmployeeID" /> 
      <sfgrid:GridTextColumn MappingName="CustomerID" /> 
      <sfgrid:GridTextColumn MappingName="ShipCountry" HeaderText="Country"/> 
    </sfgrid:SfDataGrid.Columns> 
  </sfgrid:SfDataGrid> 
</ContentPage.Content> 
//ViewModel.cs 
public class ViewModel : NotificationObject 
{ 
     internal OrderInfoRepository order; 
 
     public ICommand LoadMore { get; set; } 
 
     private bool busy; 
     public bool Busy 
     { 
         get 
         { 
             return busy; 
         } 
 
         set 
         { 
             busy = value; 
             RaisePropertyChanged("Busy"); 
         } 
     } 
 
     public ViewModel() 
     { 
         order = new OrderInfoRepository(); 
         SetRowstoGenerate(50); 
         LoadMore = new CustomLoadMoreCommand(this); 
     } 
 
     #region ItemsSource 
 
     private ObservableCollection<OrderInfo> ordersInfo; 
     public ObservableCollection<OrderInfo> OrdersInfo 
     { 
         get { return ordersInfo; } 
         set 
         { 
             this.ordersInfo = value; 
             RaiseCollectionChanged("OrdersInfo"); 
         } 
     } 
 
     #endregion 
 
     #region ItemSource Generator 
 
     public void SetRowstoGenerate(int count) 
     { 
         OrdersInfo = order.GetOrderDetails(count); 
     } 
 
     #endregion 
} 
//CustomLoadMoreCommand.cs 
public class CustomLoadMoreCommand : ICommand 
{ 
 
    public event EventHandler CanExecuteChanged; 
 
    public ViewModel ViewModel { get; set; } 
 
    public CustomLoadMoreCommand(ViewModel viewModel) 
    { 
        ViewModel = viewModel; 
    } 
 
    public bool CanExecute(object parameter) 
    { 
        return true; 
    } 
 
    public async void Execute(object parameter) 
    { 
        // You can write your set of codes that needs to be executed 
        this.ViewModel.Busy = true; 
        await Task.Delay(new TimeSpan(0, 0, 5)); 
        for (int i = 0; i < 20; i++) 
            this.ViewModel.OrdersInfo.Add(this.ViewModel.order.GenerateOrder(this.ViewModel.OrdersInfo.Count + 1)); 
        this.ViewModel.Busy = false; 
    } 
} 
 
You can download the sample from the below link. 
 
 
Regarding the query on your below code snippet, You should not call the Command.Execute() as we will be calling the Command.Execute internally, when there is the need for command to be executed. For example we will be calling the LoadMoreCommand.Execute() method internally when the LoadMoreButton as displayed in view and true is returned from the Command.CanExecute() method. 
 
In our example code, we have set the LoadMoreCommand as in the below screenshot, as the framework has provided the Command and we used it in order to reduce the code. 
 
Regarding your query on setting the BindingContext in XAML page
 
We have set the BindingContext in XAML page, in  order to preserve the MVVM pattern, you can also set it in code behind as per your code example after calling InitializeComponents(). 
Regarding your query on Behaviors
 
We will use the Behaviors to hook the events and define it there, in order to preserve MVVM.  
 
Please let us know if this helpful. 
 
Regards, 
Vigneshkumar R 


Loader.
Up arrow icon