MVVM without xaml (binding issues)

ysteinSelbekkysteinSelbekk NOMember, University

Hi, I'm playing around with some code, trying to achieve the same thing with what I have already done with xaml, but now without it. So first of all I have simply created two .cs files one customersViewP.cs and the other customersViewP.gui.cs. These are partial classes implementing the ContentPage class. The gui file has only the InitializeComponent function implemented where all gui code takes place. The customersViewP.cs should be a complete copy of the code-behind file customersView.xaml.cs.

That being said I have a customersViewModel.cs which both of these implementations (xaml and not xaml) should use, and it is here I have encountered into binding issues for the non-xaml implementation. I am asking as I have found poor and little examples for this.

The code-behind (customersView.xaml.cs) and customersViewP.cs have the following constructor:


public CustomersViewP () { InitializeComponent (); ThemeManager.ThemeName = Themes.Light; BindingContext = new CustomersViewModel (); }

Lets being with the viewModel (CustomersViewModel):


... private string searchTerm; public string SearchTerm { get { return searchTerm; } set { if (searchTerm != value) { searchTerm = value; OnPropertyChanged ("SearchTerm"); } } } public ObservableCollection<Customer> Customers { get { return CustomerDataManager.GetInstance ().GetCustomers (); } } public ICommand SearchCustomerCommand { get; set; } ...

These are the properties I have bound in the xaml version like this


... <SearchBar Text="{Binding SearchTerm}" Placeholder="Search..." HorizontalOptions="Center" SearchCommand="{Binding SearchCustomerCommand}"/> ... <dxGrid:GridControl x:Name="grid" ItemsSource="{Binding Customers}" ColumnHeadersVisibility="false" ... ...

So how do I bind these with code? I have managed to use the event handler instead of the command property,
but out of curiosity, how does one bind a command in code to get this to work?


... SearchBar customerSearchBar = new SearchBar (); customerSearchBar.Text = ""; // new Binding() ?? customerSearchBar.Placeholder = "Search..."; customerSearchBar.HorizontalOptions = LayoutOptions.Center; //customerSearchBar.SearchCommand = new Binding (); // ?? //customerSearchBar.SearchButtonPressed += OnSearchBarButtonPressed; customerSearchBar.SetBinding (SearchBar.SearchCommandParameterProperty, new Binding ("SearchCustomerCommand")); ... GridControl gridControl = new GridControl (); gridControl.ItemsSource = new Binding("Customers"); // ?? gridControl.ColumnHeadersVisibility = false; ...

I have also a dataTemplate that looks like this in xaml (dxGrid is part of devexpress gridcontrol)


<dxGrid:TemplateColumn.DisplayTemplate> <DataTemplate> <Grid BindingContext="{Binding Source}"> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Label Text="{Binding FirstName}" Font="Bold, 20" Grid.Row="0" /> <Label Text="{Binding Email}" Font="Normal" Grid.Row="1"/> </Grid> </DataTemplate> </dxGrid:TemplateColumn.DisplayTemplate>

and like this in code, which I havn't got to test as I have not managed to get the binding to work.


templateColumn.DisplayTemplate = new DataTemplate (() => { Grid grid = new Grid (); grid.BindingContext = new Binding("Source"); **// ??** grid.RowDefinitions.Add (new RowDefinition() { Height = GridLength.Auto }); grid.RowDefinitions.Add (new RowDefinition() { Height = GridLength.Auto }); Label firstNameLabel = new Label (); firstNameLabel.SetBinding (Label.TextProperty, new Binding("FirstName")); //firstNameLabel.Text = ""; **// ??** firstNameLabel.FontAttributes = FontAttributes.Bold; firstNameLabel.FontSize = 20; Label emailLabel = new Label (); //emailLabel.Text = ""; **// ??** emailLabel.SetBinding(Label.TextProperty, new Binding("Email")); grid.Children.Add (firstNameLabel); grid.Children.Add (emailLabel); return grid; });

Best Answer

Answers

  • ysteinSelbekkysteinSelbekk NOMember, University

    Thanks :) That guided me in the right direction. However I use new Command instead of Action.


    customerSearchBar.SetBinding (SearchBar.SearchCommandProperty, new Binding ("SearchCustomerCommand")); customerSearchBar.SetBinding (SearchBar.TextProperty, new Binding("SearchTerm")); and gridControl.SetBinding (GridControl.ItemsSourceProperty, new Binding("Customers"));

    Now I have problem with the DataTemplate which I bind in xaml like this.


    <dxGrid:TemplateColumn.DisplayTemplate> <DataTemplate> <Grid BindingContext="{Binding Source}"> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Label Text="{Binding FirstName}" Font="Bold, 20" Grid.Row="0" /> <Label Text="{Binding Email}" Font="Normal" Grid.Row="1"/> </Grid> </DataTemplate> </dxGrid:TemplateColumn.DisplayTemplate>

    How should I reference that Source binding in code? I have tried the following with no luck, and I get this error


    ***.JavaProxyThrowable: System.NullReferenceException: Object reference not set to an instance of an object at at DevExpress.Mobile.DataGrid.Internal.ObjectRowData.GetFieldValue

    As I understand it, the Source binding is referencing the ItemsSource Binding. It is to access
    each items FirstName and Email variables.


    ... templateColumn.DisplayTemplate = new DataTemplate (() => { Grid grid = new Grid (); grid.BindingContext = new Binding("Source"); // ?? grid.RowDefinitions.Add (new RowDefinition() { Height = GridLength.Auto }); grid.RowDefinitions.Add (new RowDefinition() { Height = GridLength.Auto }); Label firstNameLabel = new Label (); firstNameLabel.SetBinding (Label.TextProperty, new Binding("FirstName")); firstNameLabel.FontAttributes = FontAttributes.Bold; firstNameLabel.FontSize = 20; Label emailLabel = new Label (); emailLabel.SetBinding(Label.TextProperty, new Binding("Email")); grid.Children.Add (firstNameLabel); grid.Children.Add (emailLabel); return grid; }); ...
  • JamesRussoJamesRusso USMember

    You're receiving the "Object Reference Error" because there is no property on your viewmodel called "Source". You really don't need to set the BindingContext of the Grid since it is essentially the row of the ListView, so you're other bindings should work as long as they are properties on your "Customer" model.

    For more information check out this link here by @JamesMontemagno and checkout this link at the Xamarin Documentation.

  • ysteinSelbekkysteinSelbekk NOMember, University

    Hi, thanks for your input, although I created another (hopefully a more shorter/direct) question about this.
    forums.xamarin.com/discussion/46970/binding-in-code#latest

    I'm using devexpress and the Source binding works in xaml. Their example code can be found here.
    https://documentation.devexpress.com/#Xamarin/clsDevExpressMobileDataGridTemplateColumntopic

    The problem was to do this in code. I have Finally figured it out though :) code is shown in the other thread.

Sign In or Register to comment.