Accessing Picker in ContentView

4 posts, 1 answers
  1. Michael
    Michael avatar
    8 posts
    Member since:
    Oct 2018

    Posted 06 Nov 2018 Link to this post

    Hi,

    I have a RadSlideView with a Picker in the ContentView (defined in the .xaml file). I'm trying to fill the Picker with items from the .xaml.cs, but I get an  System.NullReferenceException when accessing the Picker.

    How can I access a Picker inside a ContentView from .xaml.cs ?

  2. Answer
    Lance | Technical Support Engineer, Principal
    Admin
    Lance | Technical Support Engineer, Principal avatar
    952 posts

    Posted 06 Nov 2018 Link to this post

    Hi Michael,

    This is because a ContentView is in a different scope than the ContentPage hosting the SlideView.

    To better understand the scenario, and to also find a solution, is to define the ContentView as a file instead of inline XAML. With this approach you can access the Picker in the ContentView's code-behind and populate the items.

    Demo 

    I've attached a demo that does this. To summarize, here's the SlideView:

    <telerikPrimitives:RadSlideView x:Name="slideView">
        <telerikPrimitives:RadSlideView.ItemsSource>
            <x:Array Type="{x:Type ContentView}">
                <!-- This is a ContentView that has a Picker which is loaded in the code-behind -->
                <local:FirstView/>
     
                <!-- Inline-defined ContentView -->
                <ContentView>
                    <Label  Text="Another View"  />
                </ContentView>
            </x:Array>
        </telerikPrimitives:RadSlideView.ItemsSource>
    </telerikPrimitives:RadSlideView>

    Here's the ContentView XAML

    <?xml version="1.0" encoding="UTF-8"?>
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="ItemsCodeBehind.Portable.FirstView">
     
        <Picker x:Name="MyPicker"
                VerticalOptions="Center"
                HorizontalOptions="Center" />
     
    </ContentView>

    Finally, here's the ContentView code behind:

    public partial class FirstView : ContentView
    {
        public FirstView ()
        {
            InitializeComponent();
     
            BindingContextChanged += FirstView_BindingContextChanged;
        }
     
        private void FirstView_BindingContextChanged(object sender, EventArgs e)
        {
            this.MyPicker.ItemsSource = new List<string>
            {
                "Item 1",
                "Item 2",
                "Item 3"
            };
     
            this.MyPicker.SelectedIndex = 0;
        }
    }


    Here's the result at runtime:




    Wrapping Up

    I hope this helps you meet your goals. If you have any trouble with the implementation, please open a support ticket here and attach your code in a ZIP so we can investigate directly.

    Regards,
    Lance | Tech Support Engineer, Sr.
    Progress Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  3. Rodney
    Rodney avatar
    4 posts
    Member since:
    Jan 2014

    Posted 06 Nov 2018 in reply to Lance | Technical Support Engineer, Principal Link to this post

    How would you pass in an ID into your ContentView? How would you put an ID on <local:FirstView/> ? Or bind some field to it?
  4. Lance | Technical Support Engineer, Principal
    Admin
    Lance | Technical Support Engineer, Principal avatar
    952 posts

    Posted 07 Nov 2018 Link to this post

    Hi Rodney,

    When using the SlideView this way you're in an "unbound" operational mode and cannot access items across the views due to the visual tree and the BindingContext. This mode is appropriate for static content, like a set of "Welcome the app" getting started slides.

    If you want data binding capabilities, you'll want to switch to using the control in data bound mode. This will give you the ability to bind to element in the slides while still reusing the content you've put in the ContentViews. The whole concept behind an Items DataTemplate is to reuse a set of UI controls many times. You can even bind to elements in the DataTemplate from the same page (including x:Reference). 


    Demo

    I've updated my demo to show the control using ItemTemplate instead of direct content, find the page and models attached. Let me walk you through the key concepts.


    The DataTemplate

    This is what replaces the ContentView you were using. Take the content that is inside your ContentViews and and put it into a DataTemplate.

    Here's my example, with an additional label to bind to and display an ID property:

    <DataTemplate x:Key="MyItemTemplate">
      <Grid>
        <StackLayout VerticalOptions="Center" HorizontalOptions="Center">
          <Label Text="{Binding Id, StringFormat='Slide ID: {0}'}"/>
          <Picker ItemsSource="{Binding PickerItems}" SelectedIndex="{Binding SelectedPickerIndex, Mode=TwoWay}"/>
        </StackLayout>
      </Grid>
    </DataTemplate>

    You set this DataTemplate as the SlideView's ItemTemplate:

    <primitives:RadSlideView x:Name="slideView" ItemTemplate="{StaticResource MyItemTemplate}"/>


    The ItemsSource

    Next we set the SlideView's ItemsSource. Every item in the items source will get one instance of the DataTemplate. In my example, I've created a model for the items that will be used as the BindingContext of each DataTemplate:  


    public partial class MyPage : ContentPage
    {
        private ObservableCollection<MySlideViewItem> mySlideViewItems;
     
        public MyPage()
        {
            InitializeComponent();
     
            mySlideViewItems = new ObservableCollection<MySlideViewItem>
            {
                new MySlideViewItem
                {
                    Id = 1,
                    PickerItems = new List<string> {"Green", "Blue", "Orange", "Yellow"},
                    SelectedPickerIndex = 1
                },
                new MySlideViewItem
                {
                    Id = 2,
                    PickerItems = new List<string> {"Winter", "Spring", "Summer", "Fall"},
                    SelectedPickerIndex = 1
                }
            };
     
            slideView.ItemsSource = mySlideViewItems;
        }
    }


    Here's the model definition (remember that SelectedPickerIndex needs to have property changes wired up)

    public class MySlideViewItem : NotifyPropertyChangedBase
    {
        private int _id;
        private List<string> _pickerItems;
        private int _selectedPickerIndex;
     
        public int Id
        {
            get => _id;
            set
            {
                if (_id != value)
                {
                    _id = value;
                    OnPropertyChanged();
                }
            }
        }
     
        public List<string> PickerItems
        {
            get => _pickerItems;
            set
            {
                if (_pickerItems != value)
                {
                    _pickerItems = value;
                    OnPropertyChanged();
                }
            }
        }
     
        public int SelectedPickerIndex
        {
            get => _selectedPickerIndex;
            set
            {
                if (_selectedPickerIndex != value)
                {
                    _selectedPickerIndex = value;
                    OnPropertyChanged();
                }
            }
        }
    }

    You can expand the MySlideViewItem model to best suit your needs, but this example's properties doe the following:

    - Hold a value for ID
    - Hold a list of items for the Picker
    - Hold a value of what is selected in the Picker.


    Bonus: Querying Selections in the Slides

    If you ever wanted to access any of the values that were selected in any of the slides, you only need to look in the collection. For example, let's say I wanted to know what was selected in the Slide with ID=2

    foreach (var slide in mySlideViewItems)
    {
        if (slide.Id == 2)
        {
            var selectedValue = slide.PickerItems[slide.SelectedPickerIndex];
        }
    }


    Further Assistance

    I hope this helps clarify the difference and provide a way forward. If you have any trouble, please open a Support Ticket and attach the code you're using so that I can investigate and help directly.

    It will be very helpful to have all of the items you're using (view, model, viewmodel) so I can provide a more relevant demo that fits your actual implementation.

    Regards,
    Lance | Tech Support Engineer, Sr.
    Progress Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
Back to Top