This is a migrated thread and some comments may be shown as answers.

Accessing Picker in ContentView

3 Answers 88 Views
SlideView
This is a migrated thread and some comments may be shown as answers.
Michael
Top achievements
Rank 1
Michael asked on 06 Nov 2018, 03:00 PM

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 ?

3 Answers, 1 is accepted

Sort by
0
Accepted
Lance | Manager Technical Support
Telerik team
answered on 06 Nov 2018, 06:30 PM
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
0
Rodney
Top achievements
Rank 1
answered on 06 Nov 2018, 11:23 PM
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?
0
Lance | Manager Technical Support
Telerik team
answered on 07 Nov 2018, 05:09 PM
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
Tags
SlideView
Asked by
Michael
Top achievements
Rank 1
Answers by
Lance | Manager Technical Support
Telerik team
Rodney
Top achievements
Rank 1
Share this question
or