Can I populate a Label within my CollectionView with a value outside the ItemsSource List that populates the view?

259 Views Asked by At

I have a Label within my CollectionView that I need to populate with a value outside the ItemsSource List that populates the view. The following code is an example of what I am trying to accomplish but it seems that the CollectionView is limiting the binding context to just the Items list. I have tried naming the label and setting it in my c# code but I cant seem to access the label in c#. I suppose I could build the whole page in c# rather than using the .xaml but unlike this example my actual code uses multiple templates and a template selector. If I could figure this out without rewriting hours of code I would prefer it.

ItemsPage.xaml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="TabTest.Views.ItemsPage"
             Title="{Binding Title}"
             x:Name="BrowseItemsPage">

    <ContentPage.ToolbarItems>
        <ToolbarItem Text="Add" Clicked="AddItem_Clicked" />
    </ContentPage.ToolbarItems>
    <StackLayout Padding="10">
        <Label Text="{Binding TestVal}" FontSize="16" HeightRequest="20" />
        <!-- ^^^^ This label displays just as expected -->
        <RefreshView IsRefreshing="{Binding IsBusy, Mode=TwoWay}" Command="{Binding LoadItemsCommand}">
            <CollectionView x:Name="ItemsCollectionView"
                ItemsSource="{Binding Items}">
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <StackLayout Padding="10">
                            <Label x:Name="TestV" Text="{Binding Path=BindingContext.TestVal}" />
                            <!-- ^^^^ I want this Label to display the TestVal string in the ViewModel -->
                            <Label Text="{Binding Text}" 
                                d:Text="{Binding .}"
                                LineBreakMode="NoWrap" 
                                Style="{DynamicResource ListItemTextStyle}" 
                                FontSize="16" />
                            <Label Text="{Binding Description}" 
                                d:Text="Item descripton"
                                LineBreakMode="NoWrap"
                                Style="{DynamicResource ListItemDetailTextStyle}"
                                FontSize="13" />
                            <StackLayout.GestureRecognizers>
                                <TapGestureRecognizer NumberOfTapsRequired="1" Tapped="OnItemSelected"></TapGestureRecognizer>
                            </StackLayout.GestureRecognizers>
                        </StackLayout>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </RefreshView>
    </StackLayout>
</ContentPage>

ItemsViewModel.cs

namespace TabTest.ViewModels
{
    public class ItemsViewModel : BaseViewModel
    {
        public ObservableCollection<Item> Items { get; set; }
        public Command LoadItemsCommand { get; set; }

        private string testVal;     
        public string TestVal       // I want the value of this variable in that Label
        {
            get
            {
                return testVal;
            }
            set
            {
                testVal = value;
            }
        }

        public ItemsViewModel()
        {
            Title = "Browse";
            TestVal = "Value123";

            Items = new ObservableCollection<Item>();
            LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());


            MessagingCenter.Subscribe<NewItemPage, Item>(this, "AddItem", async (obj, item) =>
            {
                var newItem = item as Item;
                Items.Add(newItem);
                await DataStore.AddItemAsync(newItem);
            });
        }

        async Task ExecuteLoadItemsCommand()
        {
            IsBusy = true;

            try
            {
                Items.Clear();
                var items = await DataStore.GetItemsAsync(true);
                foreach (var item in items)
                {
                    Items.Add(item);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
            finally
            {
                IsBusy = false;
            }
        }
    }
}
1

There are 1 best solutions below

0
On

I ended up using a dynamic resource in Xaml and used code behind to modify the resource when it needed to change.

Xaml:

<Label x:Name="TestV" Text="{DynamicResource TestValue}" />

Code Behind:

Application.Current.Resources["TestValue"] = NewValue;

App.xaml:

<x:String x:Key="TestValue">Value123</x:String>