Member not found in data context - xamarin.forms

I am trying to bind the ImageSource property of the NewGames class to the Source property of an Image control in a CarouselView but i keep getting the same error. Here is my code.
New Game Class
namespace FYP.ViewModels
{
public class NewGames
{
public int Id { get; set; }
public string GameTitle { get; set; }
public double Rating { get; set; }
public string ImageSource { set; get; }
}
}
This is my view model
using System.ComponentModel;
using System.Text;
namespace FYP.ViewModels
{
public class NewReleasesViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<NewGames> NewGames;
public ObservableCollection<NewGames> Games
{
get { return NewGames; }
set { NewGames = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Games"));
}
}
public NewReleasesViewModel()
{
Games = new ObservableCollection<NewGames>();
AddData();
}
private void AddData()
{
Games.Add(new NewGames
{
Id = 0,
GameTitle = "The Elder Scrolls Online",
Rating = 4.9,
ImageSource= "https://assets-prd.ignimgs.com/2022/01/05/elderscrollsonline- 1641413357689.jpg"
});
Games.Add(new NewGames
{
Id = 1,
GameTitle = "World Of Warcraft",
Rating = 4.9,
ImageSource = "https://assets-prd.ignimgs.com/2021/12/10/wow-1639126324635.jpg"
});
Games.Add(new NewGames
{
Id = 2,
GameTitle = "Star Wars: The Old Republic",
Rating = 4.9,
ImageSource = "https://assets-prd.ignimgs.com/2022/01/27/swotor-sq1-1643302998212.jpg"
});
}
}
}
And this is where i am trying to bind it to
<CarouselView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame HeightRequest="300"
WidthRequest="180"
BackgroundColor="white"
Padding="0"
CornerRadius="10"
HasShadow="True"
Margin="15"
HorizontalOptions="CenterAndExpand">
<Grid>
<StackLayout BackgroundColor="DimGray">
<Image Source="{Binding ImageSource}" Aspect="AspectFill"></Image>
</StackLayout>
<StackLayout Margin="-5">
<Label Text="{Binding GameTitle}"
TextColor="PaleGoldenrod"
FontSize="18"
FontAttributes="Bold"
Margin="15"
VerticalOptions="EndAndExpand"/>
</StackLayout>
</Grid>
</Frame>
</StackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
It seems i am binding the NewGames class correcly because the carouselView is getting populated but for some reason none of the properties of the class go through and i don't know why. Hopefully this helps you guys understand was i am trying to do.

You're using compiled bindings when you're using the x:DataType property.
In order to make your bindings work like you expect, you need to explicitly set the x:DataType whenever the context changes. This is usually the case when you're using a DataTemplate.
In your case this would be something like this:
<CarouselView ItemsSource={Binding Games}>
<CarouselView.ItemTemplate>
<DataTemplate
x:DataType="local:NewGames">
<StackLayout>
<!-- ... -->
</StackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
Where it says "local:NewGames" you need to put the correct namespace and class name.

Related

How to change image source when a property changes through databinding in XAML from viewmodel in xamarin forms?

I am working on providing wishlist feature for my app by tapping wishlist icon on each product in list through MVVM. Once tapped, an API call is made to update database(add/remove from wishlist table). Based on result from api call, I updated the specific product's respective property to either 'True' or 'False'. Once property updated, I want to change the icon image source of corresponding product. I am using trigger on wishlist icon to differentiate non-wishlist and wiahlist products while binding the list itself.
My code is below,
MODEL
public class PublisherProducts
{
public long ProductId { get; set; }
public string ProductName { get; set; }
public string ImageURL { get; set; }
public decimal Price { get; set; }
public bool IsWishlistProduct { get; set; }
}
VIEWMODEL
public class OnlineStoreViewModel : BaseViewModel
{
private ObservableCollection<PublisherProducts> publisherProducts;
public Command<long> WishlistTapCommand { get; }
public OnlineStoreViewModel()
{
publisherProducts = new ObservableCollection<PublisherProducts>();
WishlistTapCommand = new Command<long>(OnWishlistSelected);
}
public ObservableCollection<PublisherProducts> PublisherProducts
{
get { return publisherProducts; }
set
{
publisherProducts = value;
OnPropertyChanged();
}
}
public async Task GetProducts(long selectedCategoryId)
{
try
{
...
PublisherProducts = new ObservableCollection<PublisherProducts>(apiresponse.ProductList);
...
}
catch (Exception ex) { ... }
finally { ... }
}
async void OnWishlistSelected(long tappedProductId)
{
if (tappedProductId <= 0)
return;
else
await UpdateWishlist(tappedProductId);
}
public async Task UpdateWishlist(long productId)
{
try
{
var wishlistResponse = // api call
var item = PublisherProducts.Where(p => p.ProductId == productId).FirstOrDefault();
item.IsWishlistProduct = !item.IsWishlistProduct;
PublisherProducts = publisherProducts; *Stuck here to toggle wishlist icon*
await App.Current.MainPage.DisplayAlert("", wishlistResponse.Message, "Ok");
}
catch (Exception ex) { ... }
finally { ... }
}
}
XAML
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" ... >
<ContentPage.Content>
<ScrollView>
<StackLayout Padding="15,0,15,10">
<FlexLayout x:Name="flxLayout" BindableLayout.ItemsSource="{Binding PublisherProducts}" ...>
<BindableLayout.ItemTemplate>
<DataTemplate>
<AbsoluteLayout Margin="6" WidthRequest="150">
<Frame Padding="0" WidthRequest="150" CornerRadius="10" HasShadow="True">
<StackLayout Orientation="Vertical" Padding="10" HorizontalOptions="FillAndExpand">
<Image Source="{Binding ImageURL}" WidthRequest="130" HeightRequest="130" HorizontalOptions="Center"/>
<Label Text="{Binding ProductName}" Style="{StaticResource ProductNameStyle}"></Label>
...
<StackLayout ...>
...
<Frame x:Name="wlistFrame" Padding="0" WidthRequest="30" HeightRequest="30" CornerRadius="10" BorderColor="#02457A">
<StackLayout Orientation="Horizontal" VerticalOptions="Center" HorizontalOptions="Center">
<Image x:Name="wlImage" WidthRequest="13" HeightRequest="12" HorizontalOptions="Center" VerticalOptions="Center" Source="ic_wishlist_open">
<Image.Triggers>
<DataTrigger TargetType="Image" Binding="{Binding IsWishlistProduct}" Value="true">
<Setter Property="Source" Value="ic_wishlist_close" />
</DataTrigger>
</Image.Triggers>
</Image>
</StackLayout>
<Frame.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={RelativeSource AncestorType={x:Type local:OnlineStoreViewModel}}, Path=WishlistTapCommand}" CommandParameter="{Binding ProductId}" NumberOfTapsRequired="1" />
</Frame.GestureRecognizers>
</Frame>
</StackLayout>
</StackLayout>
</Frame>
</AbsoluteLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</FlexLayout>
</StackLayout>
</ScrollView>
</ContentPage.Content>
</ContentPage>
I am stuck at this place to change wishlist icon, when 'IsWishlistProduct' property value is changed in UpdateWishlist().
Guessing through your code, the BaseViewModel contains code similar to the following:
public class BaseViewModel : INotifyPropertyChanged
{
...
public event PropertyChangedEventHandler PropertyChanged;
...
public void OnPropertyChanged(string name)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
...
}
And your viewmodel should be like this:
...
public ObservableCollection<PublisherProducts> PublisherProducts
{
get { return publisherProducts; }
set
{
publisherProducts = value;
OnPropertyChanged(nameof(PublisherProducts));
}
}
...
As Jason mentioned, If there is a change in data in the ViewModel, it is reflected in the UI when it is notified to the View through NotifyPropertyChanged. You already implemented "OnPropertyChanged" function in your BaseViewModel but it seems you don't pass the object name.

CollectionView Grouping with Observables

Following this example to create a grouping for CollectionView, I notice that none of the properties are INotifyPropertyChanged, nor is the base class an ObservableCollection.
While the latter is easy to fix by changing List to ObservableCollection:
public class AnimalGroup : ObservableCollection<Animal>
{
public string Name { get; private set; }
public AnimalGroup(string name, ObservableCollection<Animal> animals) : base(animals)
{
Name = name;
}
private string _someOtherPropertyIWantToChangeAtRuntime = "hey";
public string SomeOtherPropertyIWantToChangeAtRuntime { get => _someOtherPropertyIWantToChangeAtRuntime, set => SetProperty(ref _someOtherPropertyIWantToChangeAtRuntime, value); }
}
It isn't clear how to make Name, or any other property (e.g. SomeOtherPropertyIWantToChangeAtRuntime), I want to associate with the group as an INotifyPropertyChanged. Treating it is as a normal class by adding the interface to base causes this warning:
Base interface 'INotifyPropertyChanged' is redundant because AnimalGroup inherits 'ObservableCollection'
Yet, there is nothing for the setter to call, such as SetProperty(ref _name, Value) and the existing PropertyChanged object is just for monitoring a group's collection changes. It isn't invokable, just handleable.
If I ignore the warning and implement INotifyPropertyChanged anyway (and name my event PropChanged to avoid colliding with ObservableCollection.PropertyChanged),
protected bool SetProperty<T>(ref T backingStore, T value, [CallerMemberName]string propertyName = "", Action onChanged = null)
{
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
backingStore = value;
onChanged?.Invoke();
PropChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
return true;
}
public event PropertyChangedEventHandler PropChanged;
and let my ViewModel manage the value of SomeOtherPropertyIWantToChangeAtRuntime, the bound <Label> never sees any changes.
<CollectionView ItemsSource="{Binding AnimalGroups}" HorizontalOptions="FillAndExpand">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Label
Text="{Binding Name}"
HorizontalOptions="Start"
FontSize="24.44"
TextColor="Black"
FontAttributes="Bold"
Margin="0,0,0,10"/>
<Label
Text="{Binding SomeOtherPropertyIWantToChangeAtRuntime}" FontSize="15"
TextColor="Black"
Margin="0,0,0,0">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding BindingContext.FindGroupAndChangeTextCommand, Source{x:Reference thisPageName}" CommandParameter="{Binding Name}"/>
</Label.GestureRecognizers>
</Label>
...
ViewModel:
public ObservableCollection<AnimalGroup> AnimalGroups {get; private set;}
public ICommand FindGroupAndChangeTextCommand {get; private set;}
public void FindGroupAndChangeText(string name)
{
var group = AnimalGroups.FirstOrDefault(t => t.Name == name);
if (group != null)
group.SomeOtherPropertyIWantToChangeAtRuntime = DateTime.Now.ToString();
}
ViewModel()
{
AnimalGroups = LoadData(); // not shown
FindGroupAndChangeTextCommand = new Command(FindGroupAndChangeText);
}
The result is that the label remains "hey" (which is the default value) and never changes even though I can see that the above command fires and the code finds the group and sets the text.
Agree with Jason, ObservableCollection has inherited INotifyPropertyChanged interface , So you will get the warning
Base interface 'INotifyPropertyChanged' is redundant because AnimalGroup inherits 'ObservableCollection'
And please see following screenshot about ObservableCollection<T>.
If you want to change the item at the runtime like this GIF.
Based on your code. I add two properties in the Animal class. For achieve the change the text of properties at the runtime, we can achieve the INotifyPropertyChanged in Animal class. Here is AnimalGroup.cs
public class AnimalGroup : ObservableCollection<Animal>
{
public string Name { get; private set; }
public AnimalGroup(string name, ObservableCollection<Animal> animals) : base(animals)
{
Name = name;
}
}
public class Animal : INotifyPropertyChanged
{
string animalName;
public string AnimalName
{
set
{
if (animalName != value)
{
animalName = value;
OnPropertyChanged("AnimalName");
}
}
get
{
return animalName;
}
}
string animalArea;
public string AnimalArea
{
set
{
if (animalArea != value)
{
animalArea = value;
OnPropertyChanged("AnimalArea");
}
}
get
{
return animalArea;
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
For testing click the command, I achieve the MyAnimalViewModel.cs like following code.
public class MyAnimalViewModel
{
public ObservableCollection<AnimalGroup> AnimalGroups { get; private set; } = new ObservableCollection<AnimalGroup>();
public ICommand FindGroupAndChangeTextCommand { protected set; get; }
public MyAnimalViewModel()
{
ObservableCollection<Animal> ts = new ObservableCollection<Animal>();
ts.Add(new Animal() { AnimalArea = "Asia", AnimalName = "cat" });
ts.Add(new Animal() { AnimalArea = "Asia", AnimalName = "dog" });
ObservableCollection<Animal> ts2 = new ObservableCollection<Animal>();
ts2.Add(new Animal() { AnimalArea = "Eourp", AnimalName = "keep" });
ts2.Add(new Animal() { AnimalArea = "Eourp", AnimalName = "gggg" });
AnimalGroups.Add(new AnimalGroup("Animal1", ts));
AnimalGroups.Add(new AnimalGroup("Animal2", ts2));
FindGroupAndChangeTextCommand = new Command<Animal>((key) =>
{
key.AnimalName = "testggggg";
});
}
}
I notice you want to achieve the group for CollectionView. Here is my edited layout.
<ContentPage.Content>
<CollectionView x:Name="MyCollectionView" ItemsSource="{Binding AnimalGroups}" IsGrouped="True" HorizontalOptions="FillAndExpand">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical"/>
</CollectionView.ItemsLayout>
<CollectionView.GroupHeaderTemplate>
<DataTemplate>
<Label Text="{Binding Name}"
BackgroundColor="LightGray"
FontSize="Large"
FontAttributes="Bold" >
</Label>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Label
Text="{Binding AnimalArea}"
HorizontalOptions="Start"
FontSize="24.44"
TextColor="Black"
FontAttributes="Bold"
Margin="0,0,0,10"/>
<Label
Text="{Binding AnimalName}" FontSize="15"
TextColor="Black"
Margin="0,0,0,0">
<Label.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1"
Command="{ Binding BindingContext.FindGroupAndChangeTextCommand, Source={x:Reference Name=MyCollectionView} }" CommandParameter="{Binding .}"
/>
</Label.GestureRecognizers>
</Label>
</StackLayout>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage.Content>
Here is layout background code.
public partial class Page2 : ContentPage
{
public Page2()
{
InitializeComponent();
this.BindingContext = new MyAnimalViewModel();
}
}

Xamarin Forms CollectionView Command not working

I have a collection view with the command binded, but for some reason when I select an item the action is never called in the viewmodel, heres my ViewModel code:
public class PlatillosViewModel : INotifyPropertyChanged
{
private INavigation Navigation;
public event PropertyChangedEventHandler PropertyChanged;
public List<PlatilloModel> Platillos { get; set; }
public List<GrupoModel> Grupos { get; set; }
public ICommand SelectedGroupCommand => new Command(SelectedGroup);
public PlatillosViewModel(INavigation navigation)
{
Navigation = navigation;
PlatillosRepository repository = new PlatillosRepository();
Platillos = repository.GetAll().ToList();
GrupoRepository grupoRepository = new GrupoRepository();
Grupos = grupoRepository.GetAll().ToList();
}
public ICommand SelectedPlatilloCommand => new Command<PlatilloModel>(async platillo =>
{
await Navigation.PushAsync(new PlatilloView());
});
void SelectedGroup()
{
PlatillosRepository platillosRepository = new PlatillosRepository();
//Platillos = platillosRepository.GetFilteredByGroup(grupoSeleccionado);
}
protected virtual void OnPropertyChanged(string property = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
}
And here is my Page:
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ComanderoMovil.Views.PlatillosView"
xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Page.UseSafeArea="true"
xmlns:behaviorsPack="clr-namespace:Xamarin.Forms.BehaviorsPack;assembly=Xamarin.Forms.BehaviorsPack">
<ContentPage.Content>
<StackLayout>
<SearchBar> </SearchBar>
<StackLayout Orientation="Horizontal">
<CollectionView ItemsSource="{Binding Grupos}"
HeightRequest="50"
ItemsLayout="HorizontalList"
SelectionMode="Single"
SelectedItem="{Binding SelectedGroupCommand, Mode=TwoWay}">
<CollectionView.ItemTemplate>
<DataTemplate>
<ContentView>
<Label Margin="2"
BackgroundColor="Black"
Text="{Binding nombre}"
TextColor="White"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"
FontSize="Small"></Label>
</ContentView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
<ListView Grid.Column="2"
HasUnevenRows="True"
SeparatorVisibility="None"
ItemsSource="{Binding Platillos}">
<ListView.Behaviors>
<behaviorsPack:SelectedItemBehavior Command="{Binding SelectedPlatilloCommand}"/>
</ListView.Behaviors>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ContentView Padding="2, 5, 5, 0">
<Frame OutlineColor="Black"
Padding="10"
HasShadow="False">
<StackLayout Orientation="Horizontal">
<Label Margin="10"
Text="{Binding clave_platillo}"
FontSize="Large"
HorizontalOptions="Start"></Label>
<Label Margin="10"
HorizontalTextAlignment="End"
Text="{Binding nombre}"></Label>
</StackLayout>
</Frame>
</ContentView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
I have tried adding the command to the items inside the collection view, replacing labels for buttons, but still doesn't work, I've also tried to use SelectionChangedCommand in the collection view, and still the same issue, the only way I can make it work is handling the item selection in the View, but I want to stay true to MVVM.
Here is my GrupoModel:
public class GrupoModel
{
public string clave_grupo { get; set; }
public int id_clasificacion { get; set; }
public int id_grupo { get; set; }
public string nombre { get; set; }
public bool pedirClave { get; set; }
public bool status { get; set; }
public int tipo { get; set; }
}
and here is an image of what im trying to do:
If you read the document:
When the SelectionMode property is set to Single, a single item in the
CollectionView can be selected. When an item is selected, the
SelectedItem property will be set to the value of the selected item.
When this property changes, the SelectionChangedCommand is executed
(with the value of the SelectionChangedCommandParameter being passed
to the ICommand), and the SelectionChanged event fires.
When you want to bind a Commond, you should bind to the SelectionChangedCommand instead of SelectedItem. Change your code like below and it will work:
<CollectionView
HeightRequest="50"
ItemsLayout="HorizontalList"
SelectionMode="Single"
SelectionChangedCommand="{Binding SelectedGroupCommand, Mode=TwoWay}"
>
The command should go in the class of GrupoModel instead of the PlatillosViewModel
public List<GrupoModel> Grupos { get; set; }
Should be "linked" to class GrupoModel that have properties and a commandwhich will listen, something like:
Class GrupoModel
{
public int Id { get; set; }
public string Foo { get; set; }
public ICommand SelectedGroupCommand => new Command(Completar);
private async void Completar()
{
await ViewModels.PlatillosViewModel.GetInstancia().SelectedGroup(this);
}
}
This way each element of Grupos will have a command to listen.
BTW: Shouldn't Grupos be an ObservableCollection?

Binding data to a listview and hiding a field

I have the code below in the constructor of my .cs file of a page. I am able to pull
data without a problem
void InitData()
{
ArticlesService objArtServ = new ArticlesService();
Task<List<ArticlesModel>> dataRetrieved = objArtServ.GetValues("News");
//Bind headlines and Id to listview but hide Id
// datalist.itemsource = ?
}
Here is the service that returns the data for me without any problem.
public class ArticlesService
{
HttpClient client;
public async Task<List<ArticlesModel>> GetValues(string category){
client = new HttpClient();
var response = await client.GetStringAsync("http://testing-dev.com/Api/Articles/DefaultArticles/" + category);
var articlesModel = JsonConvert.DeserializeObject<List<ArticlesModel>>(response);
return articlesModel;
}
}
I have a grid on this main page and a list view which will list the headlines from my model and Id. The id will be hidden
and not displayed on the list.
Here is the code below
<StackLayout Grid.Column="1" Orientation="Vertical" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" Padding="0" Spacing="0">
<SearchBar x:Name="searchBar" Placeholder="Search" SearchCommandParameter="{Binding Source={x:Reference searchBar}, Path=Text}"/>
<StackLayout VerticalOptions="FillAndExpand">
<StackLayout VerticalOptions="FillAndExpand" Padding="1" BackgroundColor="Black">
<ListView x:Name="dataList" BackgroundColor="White">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label FontSize="20" VerticalOptions="CenterAndExpand" TextColor="Black" Text="{Binding HeadLines}"></Label>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</StackLayout>
</StackLayout>
Here is my model I am using
public class ArticlesModel
{
public Int32 Id { get; set; }
public string HeadLines { get; set; }
public string Url { get; set; }
public string Category { get; set; }
public string Summary { get; set; }
}
Questions
How do I bind only the HeadLines and Id to my listview such that my Id will be hidden but the headlines will show in the listview
On the click of each row in my listview, I want to be able to pass the associated Id so I can use the Id to query my list for other things.
How do I achieve this?
You don't need to bind the id if you're not displaying it. The ItemSelected event will pass you the complete ArticlesModel object for the row that was tapped, and you can easily get the ID from the model.
dataList.ItemSelected += (s,e) {
if (e.SelectedItem == null) return;
// item will be a pointer to the selected ArticlesModel object
var item = (ArticlesModel)e.SelectedItem;
// then you can use item.Id or any other property on ArticlesModel
};

Windows Universal App Pivot Binding and one Static PivotItem

I try to bind an pivot to the DataContext in an Windows Universal app.
Everything works fine except it seems that I am unable to mix binding and "static" PivotItems.
I need to create 0 to n PivotItems based on a list and on static PivotItem containing settings.
This is what I tried. If I remove the HeaderTemplate and ItemTemplate Element the PivotItem-Element is shown. If I let the Template Elements on there place the bound data is shown but not the extra PivotItem.
Is it even possible to mix?
<Pivot Name="PivotMain" Title="Title" ItemsSource="{Binding Path=Parts}">
<Pivot.HeaderTemplate>
<DataTemplate x:DataType="viewmodel:DetailModel">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</Pivot.HeaderTemplate>
<Pivot.ItemTemplate>
<DataTemplate x:DataType="viewmodel:DetailModel">
<TextBlock Text="TestTest"/>
</DataTemplate>
</Pivot.ItemTemplate>
<PivotItem Name="Settings" Header="Settings">
<ScrollViewer VerticalScrollMode="Auto" VerticalScrollBarVisibility="Auto">
<ListView ItemsSource="{Binding Path=Settings}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="viewmodel:SettingModel">
<RelativePanel>
<ToggleSwitch Name="OnOff"
OffContent="{Binding OffContent}" OnContent="{Binding OnContent}" IsOn="{Binding IsMonitored, Mode=TwoWay}"
RelativePanel.AlignLeftWithPanel="True" />
</RelativePanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
</PivotItem>
</Pivot>
Is it even possible to mix?
As far as I known, it is impossible. But you can use other ways to meet your requirements. What you actually want to do is the first one PivotItem has different content with others. You should be able use a Data​Template​Selector that you can select a different DataTemplate for the first item (which header is settings) with others. For example, code as follows:
XAML
<Page.Resources>
<DataTemplate x:Key="itemstemplate" x:DataType="local:DetailModel">
<TextBlock Text="TestTest"/>
</DataTemplate>
<DataTemplate x:Key="settingtemplate" x:DataType="local:DetailModel">
<ScrollViewer VerticalScrollMode="Auto" VerticalScrollBarVisibility="Auto">
<ListView ItemsSource="{Binding Path=Settingss}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:SettingModel">
<RelativePanel>
<ToggleSwitch Name="OnOff" OffContent="{Binding OffContent}" OnContent="{Binding OnContent}" IsOn="{Binding IsMonitored, Mode=TwoWay}" RelativePanel.AlignLeftWithPanel="True" />
</RelativePanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
</DataTemplate>
<local:PivotTemplateSelector
itemstemplate="{StaticResource itemstemplate}"
settingtemplate="{StaticResource settingtemplate}"
x:Key="PivotTemplateSelector" />
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Pivot Name="PivotMain" Title="Title" ItemsSource="{Binding Path=Parts}" ItemTemplateSelector="{StaticResource PivotTemplateSelector}">
<Pivot.HeaderTemplate>
<DataTemplate x:DataType="local:DetailModel">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</Pivot.HeaderTemplate>
</Pivot>
</Grid>
Code behind
public sealed partial class MainPage : Page
{
ObservableCollection<DetailModel> Parts;
ObservableCollection<SettingModel> Settingss;
public MainPage()
{
this.InitializeComponent();
Settingss = new ObservableCollection<SettingModel>()
{
new SettingModel()
{
IsMonitored=true,
OffContent="work at",
OnContent="content"
}
};
Parts = new ObservableCollection<DetailModel>()
{
new DetailModel()
{
Name="Settings",
Settingss=Settingss
},
new DetailModel()
{
Name="test1"
},
new DetailModel()
{
Name="test2"
}
};
datasources datasource = new datasources()
{
Parts = Parts
};
this.DataContext = datasource;
}
}
public class PivotTemplateSelector : DataTemplateSelector
{
public DataTemplate itemstemplate { get; set; }
public DataTemplate settingtemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
DetailModel itemget = item as DetailModel;
if (itemget.Name == "Settings")
{
return settingtemplate;
}
else
return itemstemplate;
return base.SelectTemplateCore(item);
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
return SelectTemplateCore(item);
}
}
public class datasources
{
public ObservableCollection<DetailModel> Parts { get; set; }
}
public class DetailModel
{
public string Name { get; set; }
public ObservableCollection<SettingModel> Settingss { get; set; }
}
public class SettingModel
{
public string OffContent { get; set; }
public string OnContent { get; set; }
public bool IsMonitored { get; set; }
}

Resources