locked
Databinding to a command inside a DataTemplate RRS feed

  • Question

  • User25782 posted

    Hi there, I'm just having a play with Xamarin Forms and databinding and am having a problem working out the syntax. Say I've got a view model associated with some XAML. Inside the view model I've got a class Foo

        class Foo
        {
                public string Name {get; set;}
                public string Details {get; set;}
        }
    

    I've also got a command

        public ICommand DoSomethingCommand { protected set; get; }
    

    and an observable collection of Foos

        private ObservableCollection<Foo> _foos = new ObservableCollection<Foo>();
        public ObservableCollection<Foo> Foos
                {
                    get { return _foos; }
                }
    

    In my XAML, I've got a ListView. The binding to each field of my Foo works fine. However, I want to bind a command to each row, so that I can do something when the user taps on the row. The binding doesn't work though, presumably because the command isn't inside the Foo object? I've done some checking online and people suggest using RelativeSource to get to the command object but this doesn't work (I get a runtime xaml parse error). Anyone got any solution to this?

    <ListView x:Name="FooView" ItemsSource="{Binding Foos}">
        <ListView.ItemTemplate>
          <DataTemplate>
    
                        <TextCell Text="{Binding Name}" Detail="{Binding Details}" Command="{Binding DoSomethingCommand}" />
    
          </DataTemplate>
        </ListView.ItemTemplate>
      </ListView>
    
    Thursday, July 10, 2014 3:21 PM

Answers

  • User14 posted

    Xamarin.Forms Xaml is not the same as WPF. Currently there's no RelativeSource capability in our binding resolution.

    You kinda already figured that out - just wanted to confirm.

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Thursday, July 31, 2014 7:38 PM

All replies

  • User40009 posted

    WHY CAN"T YOU DELETE POSTS!!!

    Thursday, July 10, 2014 3:22 PM
  • User25782 posted

    Hi @RyanHatfield, the properties aren't the problem. My listview populated fine with the correct values. It's the command binding that's the issue. I've just checked and if I move the command inside the Foo class everything works as expected. I want the command inside the viewmodel though, so there must be an issue with the binding syntax. As I've mentioned, various people suggest using RelativeSource.

    For example

    http://stackoverflow.com/questions/18245936/binding-to-viewmodel-from-inside-a-datatemplate

    I thought I could do something like this, but the syntax doesn't work.

       Command="{Binding DoSomethingCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ViewModel}}"
    
    Thursday, July 10, 2014 3:35 PM
  • User40009 posted

    I'm bad at XAML stuff... It makes no sense to me. But if I understand it right, it makes sense that you can only bind to things in the binding context?

    Thursday, July 10, 2014 3:37 PM
  • User25782 posted

    Hi @RyanHatfield?, I think that's the general idea yes. I'm guessing that binding ItemsSource to 'Foos' means that the scope of further bindings are restricted to the Foo class. RelativeSource seems to be a solution for general WPF but it doesn't work for me with the Xamarin parser.

    Thursday, July 10, 2014 3:44 PM
  • User48732 posted

    Bump, running into this exact same problem

    Thursday, July 31, 2014 7:11 PM
  • User14 posted

    Xamarin.Forms Xaml is not the same as WPF. Currently there's no RelativeSource capability in our binding resolution.

    You kinda already figured that out - just wanted to confirm.

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Thursday, July 31, 2014 7:38 PM
  • User47452 posted

    Same problem here...

    I have a VM with a collection and an int property, this colection is binded to a listview and the int property would represent the item font size, but I cant access the parent property on item. =(

    Thursday, August 14, 2014 10:59 PM
  • User12150 posted

    Any updates on this issue?

    Friday, October 3, 2014 7:12 AM
  • User75222 posted

    Same here, according MVVM pattern, the commands must be in viewmodel, but with this limitation, we need to put in model.

    Friday, October 3, 2014 7:28 PM
  • User12150 posted

    @Alexandre.2342? I've found Xamarin.Forms.Behaviors: http://codeworks.it/blog/?p=216

    Haven't tried it yet, but it should work.

    Sunday, October 5, 2014 3:58 PM
  • User75222 posted

    Hello @AlexeiVinidiktov? looks promising! I tried to download and run the project, no success, filled and issue on git https://github.com/corradocavalli/Xamarin.Forms.Behaviors/issues

    Monday, October 6, 2014 11:08 PM
  • User3066 posted

    Hi All, Xamarin.Forms.Behaviors has a sort of Relative Binding in DataTemplates, blogged about it here: http://codeworks.it/blog/?p=216, some limitation applies, like on indicated on Git issues, when using elements that do not propagate BindingContext.

    Wednesday, October 8, 2014 5:05 PM
  • User38313 posted

    Why not add a reference to your ViewModel on your Foo class?
    Foo {
    Public string Name;
    Public string Details;
    Public MyViewModel Model;
    }

    Doing so you could reference the command from XAML like so:
    Command="{Binding Model.DoSomethingCommand}".

    If you (like me) think the back reference to the Model in the Foo class is ugly you could transform all your Foos into anonymous objects with the model added just prior to binding them to the view. Like so:

    var myFos = ..
    var anonymousFos = myFos.Select(x=> new {x.Name, x.Details, Model = this});

    Friday, December 12, 2014 5:47 PM
  • User6349 posted

    Please vote for this feature. :) Thank you: http://xamarin.uservoice.com/forums/258559-xamarin-forms-suggestions/suggestions/6451625-support-for-relativesource-in-xaml-binding

    Tuesday, March 3, 2015 10:55 PM
  • User112992 posted

    Kind of infuriating, actually. Makes data binding in a listview pretty difficult.

    Monday, March 9, 2015 1:17 AM
  • User101467 posted

    would be nice if it could be "fixed" in one of the future releases of xamarin.forms, having to work around this is rather stupid.

    Thursday, March 19, 2015 3:27 PM
  • User21590 posted

    If you're using MvvmLight you can bind to Locator.ViewModel.Command

    http://mvvmlight.codeplex.com/discussions/80447

    Monday, May 11, 2015 6:33 PM
  • User76049 posted

    @DerekBeattie.6675

    Nice tip, I'm using view 1st binding and ViewModelLocator pattern & MVVM Light with Forms, curious to see if that works.

    I'm using CorradoCavalli's library at the moment and it works very well for binding to commands in data templates.

    <ListView Grid.Row="1" ItemsSource="{Binding Customers}" VerticalOptions="Fill" x:Name="ListviewCustomer"> <ListView.ItemTemplate> <DataTemplate> <customRenderers:CustomImageCell Text="{Binding CustomerName}" Detail="{Binding CustId}"> <b:Interaction.Behaviors> <b:BehaviorCollection> <b:EventToCommand CommandNameContext="{b:RelativeContext Details}" EventName="Tapped" CommandName="SelectCommand" CommandParameter="{Binding .}" /> </b:BehaviorCollection> </b:Interaction.Behaviors> </customRenderers:CustomImageCell> </DataTemplate> </ListView.ItemTemplate> </ListView>

    Monday, May 11, 2015 7:03 PM
  • User21407 posted

    There was a fix in Xamarin.Forms v1.4.4 for x:Reference inside a DataTemplate, so this is now supported. See my post here: http://forums.xamarin.com/discussion/comment/144204/#Comment_144204

    Tuesday, August 4, 2015 7:01 PM
  • User142462 posted

    I can vouch for @TomSoderling 's solution, works like a charm

    Monday, February 29, 2016 7:27 AM
  • User250789 posted

    You can achieve this using a mix of bindings , in order not to loose our Item as bindingcontext , you can bind your item to your context via Reference binding.

    <ContenPage x:Name="MainPage">
    <ListView Grid.Row="1"
                  ItemsSource="{Binding Customers}"
                  VerticalOptions="Fill"
                  x:Name="ListviewCustomer">
          <ListView.ItemTemplate>
            <DataTemplate>
          <Label Text="{Binding Property}"/>
              <Button Command="{Binding BindingContext.ItemCommand, Source={x:Reference MainPage}}" 
                             CommandParameter="{Binding .}">Click me</Button>
            </DataTemplate>
          </ListView.ItemTemplate>
        </ListView>
    </ContentPage>
    
    Thursday, August 25, 2016 3:21 PM
  • User149773 posted

    Hi, I was just about to post a new question regarding a very similar issue i'm having. The difference is that I want to re-use the data template in other pages and allow it to bind to an external command.

    BooksPage.xaml - it has a corresponding BooksPageModel as it's binding context:

    ```

      <ListView 
            CachingStrategy="RecycleElement"
            x:Name="listView" 
            ItemsSource="{Binding Books}">
        <ListView.ItemTemplate>
    
          <DataTemplate x:Name="dataTemplate">
    
        <!-- Do I need to pass anything else in here?  -->
            <local:CustomViewCellComponent BindingContext="{Binding .}">
    
          </DataTemplate>
    
        </ListView.ItemTemplate>
      </ListView>
    
    </ContentPage.Content>
    

    ``` CustomViewCellComponent.xaml - I want to reuse this component in several xaml pages:

    ```

        <!-- How to get this command to pick up the parent list view binding context, or parent page? -->
        <!-- OnMoreInfoCommand is a simple Command on the BooksPageModel -->
        <Button Command="{Binding Source={x:Reference listView}, Path=BindingContext.OnMoreInfoCommand}"
                CommandParameter="{Binding .}"
                Text="More Info" TextColor="White" 
                BackgroundColor="Green">
        </Button>
    
    </StackLayout>
    

    ```

    Thursday, August 25, 2016 3:36 PM
  • User76261 posted

    @DonalFarrell.8833 said: Hi, I was just about to post a new question regarding a very similar issue i'm having. The difference is that I want to re-use the data template in other pages and allow it to bind to an external command.

    BooksPage.xaml - it has a corresponding BooksPageModel as it's binding context:

    ```

    <ListView 
          CachingStrategy="RecycleElement"
          x:Name="listView" 
          ItemsSource="{Binding Books}">
      <ListView.ItemTemplate>
    
        <DataTemplate x:Name="dataTemplate">
    
      <!-- Do I need to pass anything else in here?  -->
          <local:CustomViewCellComponent BindingContext="{Binding .}">
    
        </DataTemplate>
    
      </ListView.ItemTemplate>
    </ListView>
    

    ``` CustomViewCellComponent.xaml - I want to reuse this component in several xaml pages:

    ```

      <!-- How to get this command to pick up the parent list view binding context, or parent page? -->
      <!-- OnMoreInfoCommand is a simple Command on the BooksPageModel -->
      <Button Command="{Binding Source={x:Reference listView}, Path=BindingContext.OnMoreInfoCommand}"
              CommandParameter="{Binding .}"
              Text="More Info" TextColor="White" 
              BackgroundColor="Green">
      </Button>
    

    ```

    Hi, did you resolve this??

    Tuesday, February 28, 2017 8:42 AM
  • User306807 posted

    @CraigDunn said: Xamarin.Forms Xaml is not the same as WPF. Currently there's no RelativeSource capability in our binding resolution.

    You kinda already figured that out - just wanted to confirm.

    Has anything changed since July 2014 concerning this topic, I assume there is still no 'RelativeSource' in XF?

    Monday, March 20, 2017 3:21 PM
  • User210933 posted

    @jesulink2514 said: You can achieve this using a mix of bindings , in order not to loose our Item as bindingcontext , you can bind your item to your context via Reference binding.

    <ContenPage x:Name="MainPage">
    <ListView Grid.Row="1"
                  ItemsSource="{Binding Customers}"
                  VerticalOptions="Fill"
                  x:Name="ListviewCustomer">
          <ListView.ItemTemplate>
            <DataTemplate>
          <Label Text="{Binding Property}"/>
              <Button Command="{Binding BindingContext.ItemCommand, Source={x:Reference MainPage}}" 
                             CommandParameter="{Binding .}">Click me</Button>
            </DataTemplate>
          </ListView.ItemTemplate>
        </ListView>
    </ContentPage>
    

    Thant works like a charm! Including for other properties like Text.

    Thanks!

    @wend0rlin read the post comments. More than one solution is there for some time. Like this one.

    Tuesday, April 11, 2017 9:47 PM
  • User306807 posted

    @dpedrinha said:

    @jesulink2514 said: You can achieve this using a mix of bindings , in order not to loose our Item as bindingcontext , you can bind your item to your context via Reference binding.

    <ContenPage x:Name="MainPage">
    <ListView Grid.Row="1"
                  ItemsSource="{Binding Customers}"
                  VerticalOptions="Fill"
                  x:Name="ListviewCustomer">
          <ListView.ItemTemplate>
            <DataTemplate>
          <Label Text="{Binding Property}"/>
              <Button Command="{Binding BindingContext.ItemCommand, Source={x:Reference MainPage}}" 
                             CommandParameter="{Binding .}">Click me</Button>
            </DataTemplate>
          </ListView.ItemTemplate>
        </ListView>
    </ContentPage>
    

    Thant works like a charm! Including for other properties like Text.

    Thanks!

    @wend0rlin read the post comments. More than one solution is there for some time. Like this one.

    oh thank's for the hint, but even after reading it again and again, this solution only works if you use the template inside the content page. But it's not working if you want to resue the template in different pages. That's not a replacement for 'relative source'.

    Wednesday, April 12, 2017 8:09 AM
  • User328707 posted

    Same issue here, none of the above works for me, x:Reference works great when inside a DataTemplate that is defined within the page where the referenced named element is also defined; but move that DataTemplate to App.xaml as a named/keyed resource, and x:Reference does not work anymore. If anyone knows how to use x:Reference or an alternative from within a DataTemplate defined as a resource in App.xaml so it can be re-used across multiple pages, please share.

    @wend0rlin please let me know if/when you find a solution.

    Thanks!

    Tuesday, June 6, 2017 4:15 AM
  • User57571 posted

    @krispenner Did you found a solution for this?

    Friday, October 6, 2017 9:56 PM
  • User328707 posted

    @15mgm15 sorry for the delay in getting back to you I was away from my code. I never found a proper solution to this, but I did figure out a workaround/hack that gets me past this issue.

    I created a public static class with public fields to hold the the parent page of the ListView on and then databind to this. You need to have a different field for any page that has a list view on it that may have another child/nested page appear that also has a listview on it, because they can't both share one field.

    I'm not sure how clear that was but here is the code to help get the gist of what I did to get around this:

      public static class StaticReferences
      {
        #region Fields
        **public static BasePage CurrentProjectListPage;**
        public static BasePage CurrentResourceListPage;
        public static BasePage CurrentScheduleList;
        #endregion
      }
    
      public partial class ProjectListPage : BasePage
      {
        #region Constructors
        public ProjectListPage()
          : base(new ProjectListViewModel())
        {
          **StaticReferences.CurrentProjectListPage = this;**
          InitializeComponent();
        }
        #endregion
    
        #region Methods
        protected override void OnParentSet()
        {
          base.OnParentSet();
          **if (Parent == null && ReferenceEquals(StaticReferences.CurrentProjectListPage, this))
            StaticReferences.CurrentProjectListPage = null;**
        }
        #endregion
      }
    
          <DataTemplate x:Key="ProjecListItemTemplate">
            <ViewCell>
              <ViewCell.ContextActions>
                <MenuItem Command="{Binding **BindingContext**.ViewItemCommand, **Source={x:Static v:StaticReferences.CurrentProjectListPage}**}"
                          CommandParameter="{Binding .}"
                          Text="View" />
              </ViewCell.ContextActions>
              <Grid Style="{StaticResource ListItemGridStyle}">
              </Grid>
            </ViewCell>
          </DataTemplate>
    

    Again, sorry for the delay, I hope that helps, if you find a better proper solution please share!

    Monday, October 16, 2017 2:07 AM
  • User269466 posted

    @krispenner you saved my day! Thanks!

    Friday, August 17, 2018 11:27 AM