zappasan
zappasan

Reputation: 82

ScrollView as a Custom Control

I am implementing an app where in every page I have got an horizontal menu as a scroll view, where the labels of some buttons can change in response of some actions pushed by the user. These labels must remain the same in every page.

Is it correct to use a custom control for the purpose of mantaining the labels, considering the template bound to a specific viewModel?

Morover, to achieve this result I put a custom control in the resource dictionary of App.xaml file, but I am unable to reference it in the page where I want to use the template, because scroll view doesn't have ControlTemplate property.

Thank you in advance

App.xaml

<ControlTemplate x:Key="HeaderTemplate">
                <controls:TouchResponsiveScrollView BackgroundColor="#fcb1b1b1" Orientation="Horizontal" VerticalOptions="Start" Padding="8, 24" HorizontalScrollBarVisibility="Never" VerticalScrollBarVisibility="Never" HeightRequest="100">
                <!-- template code here -->     
                </controls:TouchResponsiveScrollView>

RootPage.xaml

<ContentPage
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    xmlns="http://xamarin.com/schemas/2014/forms" 
    x:Class="com.v2home.v2AppTool.Views.RootPage"
    xmlns:local="clr-namespace:com.v2home.v2AppTool.ViewModels"
    xmlns:controls="clr-namespace:com.v2home.v2AppTool.Controls"
    xmlns:viewmodels="clr-namespace:com.v2home.v2AppTool.ViewModels" x:DataType="viewmodels:AutomationViewModel"
    x:Name="rootPage"
>
    <StackLayout>
        <controls:TouchResponsiveScrollView ControlTemplate="{StaticResource HeaderTemplate}">
            
        </controls:TouchResponsiveScrollView>
        <ContentView>
            <Label Text="My text"></Label>
        </ContentView>
    </StackLayout>

Update 1

That's my header template and TopButton is the button I want with the same label in every page. This button has bound to a converter that converts a bool to a string. What happen is that the bool variable, IsConnected, passed to the converter is not the same and in every page the label is different. What I understand is that every instance of HeaderTemplate has its own instance of MainViewModel.

 <ControlTemplate x:Key="HeaderTemplate">
                <controls:TouchResponsiveScrollView BackgroundColor="#fcb1b1b1" Orientation="Horizontal" VerticalOptions="Start" Padding="8, 24" HorizontalScrollBarVisibility="Never" VerticalScrollBarVisibility="Never" HeightRequest="100">
                    <controls:TouchResponsiveScrollView.BindingContext>
                        <local:MainViewModel/>
                    </controls:TouchResponsiveScrollView.BindingContext>
                    <controls:TouchResponsiveScrollView.Content>
                        <StackLayout Orientation="Horizontal" VerticalOptions="Start" HorizontalOptions="Center" Spacing="18" MinimumHeightRequest="100">
                              <controls:TopButton ContentLayout="Top" Text="{Binding IsConnected, Converter={StaticResource boolToStringConverter}, ConverterParameter='CommunicationLabel'}" 

That's my MainViewModel. Also if I mark as static _isConnected, the label is not not the same in every page.

MainViewModel

public class MainViewModel{

  private  bool _isConnected;
  public bool IsConnected
        {
            set
            {
                if (_isConnected != value)
                {
                    _isConnected = value;
                    NotifyPropertyChanged();
                }
            }
            get {
                    return _isConnected;}
        }         
}

Upvotes: 2

Views: 218

Answers (1)

ToolmakerSteve
ToolmakerSteve

Reputation: 21213

A ContentView accepts a control template, which can contain any view hierarchy. Your control template is fine. To have shared contents on every page, the BindingContext of the template should point to static data.

Put the properties that need to be "shared" between pages, into their own viewmodel. In that class, declare a static property to contain the single shared instance:

// in namespace YourNameSpace
public class CommonViewModel : INotifyPropertyChanged   // exact declaration depends on MVVM library used.
{
    // static Singleton.
    // "{ get; }": it is a Property.
    public static CommonViewModel It { get; } = new CommonViewModel();

    // --- declare the properties of CommonViewModel to share ---

    private MyType1 _myProperty1;
    public MyType1 MyProperty1 {
        get => _myProperty1;
        set {
            if (_myProperty1 != value) {
                _myProperty1 = value;
                OnPropertyChanged("MyProperty1");   // Or see your MVVM library docs.
            }
        }
    }
}

At top of XAML file containing ControlTemplate

<...
    xmlns:mynamespace="clr-namespace:YourNameSpace"

Have template bind to that static property:

< ControlTemplate x:Key="HeaderTemplate" BindingContext="{x:Static mynamespace:CommonViewModel.It}">

Use template like this:

<ContentPage
    ...
>
    <StackLayout>
        ... other content on page ...
        <ContentView ControlTemplate="{StaticResource HeaderTemplate}" />
        ... other content on page ...
    </StackLayout>
</ContentPage>

Upvotes: 1

Related Questions