How paint a item selected with differents colors? - xamarin.forms

i have a collection
<CollectionView SelectionMode="Single"
ItemsSource="{Binding Cities}"
ItemsLayout="HorizontalList">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Margin="5">
<Image Source="{Binding Image}" />
<Label TextColor="Black" text="Text"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
How can i painting with diferents colors the image and label when i select a item?

According to your description, you have Image and Label in CollectionView DataTemplate, you want to set Image and Label different background color when you select one item, am I right?
If yes, I suggest you can use binding Background color to do this, please take a look my code:
<ContentPage.Resources>
<Style TargetType="StackLayout">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="White" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout>
<CollectionView
ItemsSource="{Binding images}"
SelectionChanged="CollectionView_SelectionChanged"
SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Margin="5">
<Frame BackgroundColor="{Binding imagecolor}" CornerRadius="5">
<Image Source="{Binding Image}" />
</Frame>
<Label
BackgroundColor="{Binding labelcolor}"
Text="{Binding cityname}"
TextColor="Black" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage.Content>
public partial class Page3 : ContentPage
{
public ObservableCollection<imagemodel> images { get; set; }
public Page3()
{
InitializeComponent();
images = new ObservableCollection<imagemodel>()
{
new imagemodel(){Image="a5.jpg",cityname="beijing",imagecolor=Color.White,labelcolor=Color.White},
new imagemodel(){Image="a6.jpg",cityname="shanghai",imagecolor=Color.White,labelcolor=Color.White},
new imagemodel(){Image="a7.jpg",cityname="shenzhen",imagecolor=Color.White,labelcolor=Color.White},
new imagemodel(){Image="a8.jpg",cityname="xiamen",imagecolor=Color.White,labelcolor=Color.White}
};
this.BindingContext = this;
}
private void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
imagemodel previous = (e.PreviousSelection.FirstOrDefault() as imagemodel);
imagemodel current = (e.CurrentSelection.FirstOrDefault() as imagemodel);
//Set the current to the color you want
current.imagecolor = Color.Pink;
current.labelcolor = Color.Green;
if (previous != null)
{
//Reset the previous to defaulr color
previous.imagecolor = Color.White;
previous.labelcolor = Color.White;
}
}
}
public class imagemodel:ViewModelBase
{
public string Image { get; set; }
public string cityname { get; set; }
private Color _imagecolor;
public Color imagecolor
{
get { return _imagecolor; }
set
{
_imagecolor = value;
RaisePropertyChanged("imagecolor");
}
}
private Color _labelcolor;
public Color labelcolor
{
get { return _labelcolor; }
set
{
_labelcolor = value;
RaisePropertyChanged("labelcolor");
}
}
}
The ViewModelbase implement INotifyPropertyChanged interface:
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Update:
If you want to use mvvm mode to do this, and put CollectionView_SelectionChanged method in my viewModel, I suggest you can bind SelectionChangedCommand to do this, please take a look my code:
The ContentPage:
<ContentPage.Resources>
<Style TargetType="StackLayout">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="White" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout>
<CollectionView
ItemsSource="{Binding images}"
SelectedItem="{Binding CurrentSelection}"
SelectionChangedCommand="{Binding selectioncommand}"
SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Margin="5">
<Frame BackgroundColor="{Binding imagecolor}" CornerRadius="5">
<Image Source="{Binding Image}" />
</Frame>
<Label
BackgroundColor="{Binding labelcolor}"
Text="{Binding cityname}"
TextColor="Black" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage.Content>
public partial class Page3 : ContentPage
{
public Page3()
{
InitializeComponent();
this.BindingContext = new imageviewmodel();
}
}
The imageviewmodel.cs:
public class imageviewmodel:ViewModelBase
{
public ObservableCollection<imagemodel> images { get; set; }
private imagemodel _PreviousSelection;
public imagemodel PreviousSelection
{
get { return _PreviousSelection; }
set
{
_PreviousSelection = value;
RaisePropertyChanged("PreviousSelection");
}
}
private imagemodel _CurrentSelection;
public imagemodel CurrentSelection
{
get { return _CurrentSelection; }
set
{
if(CurrentSelection!=value)
{
PreviousSelection = CurrentSelection;
_CurrentSelection = value;
RaisePropertyChanged("CurrentSelection");
}
}
}
public Command selectioncommand { get; set; }
public imageviewmodel()
{
images = new ObservableCollection<imagemodel>()
{
new imagemodel(){Image="a5.jpg",cityname="beijing",imagecolor=Color.White,labelcolor=Color.White},
new imagemodel(){Image="a6.jpg",cityname="shanghai",imagecolor=Color.White,labelcolor=Color.White},
new imagemodel(){Image="a7.jpg",cityname="shenzhen",imagecolor=Color.White,labelcolor=Color.White},
new imagemodel(){Image="a8.jpg",cityname="xiamen",imagecolor=Color.White,labelcolor=Color.White}
};
selectioncommand = new Command(changecolor);
}
private void changecolor()
{
foreach(imagemodel model in images)
{
if(model.cityname==CurrentSelection.cityname)
{
model.imagecolor = Color.Pink;
model.labelcolor = Color.Green;
}
else if(PreviousSelection != null && model.cityname==PreviousSelection.cityname)
{
model.imagecolor = Color.White;
model.labelcolor = Color.White;
}
}
}
}
The screenshot is same.
The screenshot:

Related

How one ViewModel contains multiple ViewModel xamatin

I have 2 ViewModels (MVVM). I let show 2 as shown, it only shows data 1 ViewModel (the one below).
I put 1 and it shows up as normal.
This is how I display the data
<RefreshView x:DataType="locals:SliderViewModel"
Command="{Binding LoadSliderCommand}"
IsRefreshing="{Binding IsBusy, Mode=OneWay}">
<StackLayout Padding="8,0,8,4"
BindableLayout.ItemsSource="{Binding SliderShowInfos}"
Orientation="Horizontal"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand">
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout x:DataType="model:SliderShowInfo">
<Frame Padding="4"
HasShadow="False"
IsClippedToBounds="True"
BackgroundColor="Transparent">
<StackLayout Orientation="Horizontal">
<Frame Padding="0"
HasShadow="False"
CornerRadius="7"
IsClippedToBounds="True">
<Image Source="{Binding ImagesSlider}">
</Image>
</Frame>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</RefreshView>
<RefreshView x:DataType="locals:ProductViewModel"
Command="{Binding LoadProductCommand}"
IsRefreshing="{Binding IsBusy, Mode=OneWay}">
<StackLayout Padding="8"
Orientation="Horizontal"
BindableLayout.ItemsSource="{Binding ProductInfos}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Frame Padding="5,0"
HasShadow="False"
IsClippedToBounds="True"
BackgroundColor="#fff">
<StackLayout x:DataType="model:ProductInfo">
</StackLayout>
</Frame>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</RefreshView>
This is how I display the data. I'm trying to display product listing and photo listing data. Please give me a solution that can combine 2 ViewModel
Update
SliderViewModel.cs
public class SliderViewModel:BaseSliderViewModel
{
ISliderShowRepository sliderShowRepository = new SliderShowService();
public Command LoadSliderCommand { get; }
public ObservableCollection<SliderShowInfo> SliderShowInfos { get; }
public SliderViewModel()
{
LoadSliderCommand = new Command(async () => await ExecuteLoadSliderCommand());
SliderShowInfos = new ObservableCollection<SliderShowInfo>();
}
public void OnAppearing()
{
IsBusy = true;
}
async Task ExecuteLoadSliderCommand()
{
}
}
ProductViewModel.cs
public class ProductViewModel : BaseProductViewModel
{
IProductRepository productRepository = new ProductService();
public Command LoadProductCommand { get; }
public ObservableCollection<ProductInfo> ProductInfos { get; }
public Command ProductTappedView { get; }
public ProductViewModel(INavigation _navigation)
{
LoadProductCommand = new Command(async () => await ExecuteLoadProductCommand());
ProductInfos = new ObservableCollection<ProductInfo>();
ProductTappedView = new Command<ProductInfo>(OnViewDetailProduct);
Navigation = _navigation;
}
private async void OnViewDetailProduct(ProductInfo prod)
{
await Navigation.PushAsync(new DetailProduct(prod));
}
public void OnAppearing()
{
IsBusy = true;
}
async Task ExecuteLoadProductCommand()
{
IsBusy = true;
try
{
ProductInfos.Clear();
var prodList = await productRepository.GetProductsAsync();
foreach (var prod in prodList)
{
ProductInfos.Add(prod);
}
}
catch(Exception)
{
throw;
}
finally
{
IsBusy = false;
}
}
}
DashboardViewModel.cs
public class DashboardViewModel
{
public SliderViewModel SliderShowVM { get; set; }
public ProductViewModel ProductVM { get; set; }
}
Dashboard.xaml.cs
public Dashboard()
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, true);
BindingContext = new DashboardViewModel();
}
protected override void OnAppearing()
{
base.OnAppearing();
}
You cant just have 2 ViewModels for a single page. Instead, you can create another ViewModel, which will contains those 2 ViewModels that you need.
public class DashboardViewModel
{
public SliderShowViewModel SliderShowVM { get; set; }
public ProductViewModel ProductVM { get; set; }
}
And in dashboard constructor, assign the BindingContext
BindingContext = new DashboardViewModel();
And in your view, bind data like this:
...
<Image Source="{Binding SliderShowVM.ImagesSlider}">
...
BindableLayout.ItemsSource="{Binding ProductVM.ProductInfos}"
...
Also, if you don't need all data from SliderShowViewModel or ProductViewModel on your Dashboard, then you can define the properties that you really need for the dashboard inside DashboardViewModel, and to inject SliderShowViewModel and ProductViewModel instances via constructor (Might not be the best solution, but this way you will keep you view cleaner)
public class DashboardViewModel
{
public string RelevantProperty1 { get; set; }
public int RelevantProperty2 { get; set; }
...
public DashboardViewModel(SliderShowViewModel sliderVm, ProductViewModel productVm)
{
RelevantProperty1 = sliderVm.Something;
RelevantProperty2 = productVm.SomethingElse;
...
}
}
More explicit
DashboardViewModel class: It is a class with two properties of type SliderShowViewModel and ProductViewModel. These properties will store some instances (aka objects) of SliderShowViewModel and ProductViewModel respectively.
Create a DashboardViewModel instance and pass it as BindingContext for your Dashboard View:
public Dashboard()
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, true);
var viewModel = new DashboardViewModel();
// Now we have the viewModel, but there is a problem.
// Remember those two viewModels (SliderShowViewModel and ProductViewModel)?
// Well, those properties are null, we have to provide values for them
// before setting the binding context.
viewModel.SliderViewModel = new SliderViewModel();
viewModel.ProductViewModel = new ProductViewModel();
BindingContext = viewModel;
}
Bind values from DashboardViewModel on our View:
<RefreshView Command="{Binding SliderViewModel.LoadSliderCommand}"
IsRefreshing="{Binding SliderViewModel.IsBusy, Mode=OneWay}">
<StackLayout Padding="8,0,8,4"
BindableLayout.ItemsSource="{Binding SliderViewModel.SliderShowInfos}"
Orientation="Horizontal"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand">
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame Padding="4"
HasShadow="False"
IsClippedToBounds="True"
BackgroundColor="Transparent">
<StackLayout Orientation="Horizontal">
<Frame Padding="0"
HasShadow="False"
CornerRadius="7"
IsClippedToBounds="True">
<Image Source="{Binding SliderViewModel.ImagesSlider}">
</Image>
</Frame>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</RefreshView>
<RefreshView Command="{Binding ProductViewModel.LoadProductCommand}"
IsRefreshing="{Binding ProductViewModel.IsBusy, Mode=OneWay}">
<StackLayout Padding="8"
Orientation="Horizontal"
BindableLayout.ItemsSource="{Binding ProductViewModel.ProductInfos}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Frame Padding="5,0"
HasShadow="False"
IsClippedToBounds="True"
BackgroundColor="#fff">
</Frame>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</RefreshView>
Give it a try and let me know if it works.

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.

OnApplyTemplate doesn't capture the BindingContext of the parent?

In a test project, I'm trying to get the BindingContext of the parent control with template binding,
here, in the MainPage, I have two templates temp1 and temp2
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:vm="clr-namespace:MyXam.ViewModels"
xmlns:views="clr-namespace:MyXam.Views"
x:Class="MyXam.Views.MainPage"
x:DataType="vm:MainViewModel">
<ContentPage.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="temp1">
<views:View1/>
</ControlTemplate>
<ControlTemplate x:Key="temp2">
<views:View2/>
</ControlTemplate>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout x:Name="stk">
<Button Text="Switch view" Command="{Binding SwitchViewCommand}"/>
<ContentView x:Name="cv" ControlTemplate="{StaticResource temp2}" VerticalOptions="Start" HorizontalOptions="Center">
<ContentView.Triggers>
<DataTrigger TargetType="ContentView" Binding="{Binding IsView1}" Value="False">
<Setter Property="ControlTemplate" Value="{StaticResource temp2}"/>
</DataTrigger>
<DataTrigger TargetType="ContentView" Binding="{Binding IsView1, Mode=TwoWay}" Value="True">
<Setter Property="ControlTemplate" Value="{StaticResource temp1}"/>
</DataTrigger>
</ContentView.Triggers>
</ContentView>
</StackLayout>
</ContentPage>
I want to get the BindingContext of the MainPage in View2, in the ctor:
SetBinding(BindingContextProperty, new Binding("Parent.BindingContext", source: RelativeBindingSource.TemplatedParent));
but when I try to get its vzlue in the OnApplyTemplate it's null:
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
vm = this.GetValue(BindingContextProperty);
}
However binding is resolved in xaml:
<Label Text="{Binding Name, Source={Reference this}}"/>
I couldn't see the detail of your other code, but you can refer to the following code.
Define a BindableProperty for this Label in xaml.cs and use the Name Property,e.g. x:Name="TestControlView" and binding like this
<Label Text="{Binding Source={x:Reference TestControlView}, Path=TestText}" />
You can check the full demo here.
The main code is like this:
TestControl.xaml.cs(TestControl is a ContentView)
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class TestControl : ContentView
{
public static readonly BindableProperty TestTextProperty = BindableProperty.Create(nameof(TestText), typeof(string), typeof(TestControl));
public string TestText
{
get { return (string)GetValue(TestTextProperty); }
set { SetValue(TestTextProperty, value); }
}
public TestControl()
{
InitializeComponent();
}
}
TestControl.xaml
MainPage.xaml
<ListView x:Name="lstView" HorizontalOptions="Fill" HasUnevenRows="True" RefreshAllowed="true" IsPullToRefreshEnabled="true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame CornerRadius="10" BackgroundColor="White" Margin="0,5,0,5">
<StackLayout Orientation="Horizontal" HorizontalOptions="Center">
<controls:TestControl TestText="{Binding Title}" VerticalOptions="Center"/>
<Label Text="{Binding Type}" FontSize="Medium" TextColor="#F0BB7F" FontAttributes="Bold" VerticalOptions="Center"/>
</StackLayout>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
MainPage.xaml.cs
public partial class MainPage : ContentPage
{
public ObservableCollection<TestModel> veggies { get; set; }
public MainPage()
{
InitializeComponent();
veggies = new ObservableCollection<TestModel>();
veggies.Add(new TestModel { Title = "Tomato", Type = "Fruit" });
veggies.Add(new TestModel { Title = "Zucchini", Type = "Vegetable" });
veggies.Add(new TestModel { Title = "Tomato" , Type = "Vegetable" });
veggies.Add(new TestModel { Title = "Romaine", Type = "Fruit" });
veggies.Add(new TestModel { Title = "Zucchini", Type = "Vegetable" });
lstView.ItemsSource = veggies;
BindingContext = this;
}
}

Change Style name for some view inside ViewCell upon Listview TappedItem, Xamarin Forms

I've Xamarin Forms app and I have Listview which looks like this :
<ListView x:Name="CalendarList" VerticalOptions="FillAndExpand" VerticalScrollBarVisibility="Never" RowHeight="100"
Grid.Row="0" SeparatorVisibility="None" ItemTapped="CalendarList_OnItemSelected" BackgroundColor="Transparent" >
<ListView.ItemTemplate>
<DataTemplate>
<local:MyCell>
<pcv:PancakeView **x:Name="YearsContainer"** Margin = "0,10,0,10" Style="{StaticResource cell_years}" IsClippedToBounds="true" >
<StackLayout HorizontalOptions = "StartAndExpand" Orientation="Horizontal">
<Label Style = "{DynamicResource bold_label}" Text="{Binding Year}" VerticalOptions="Center" />
</StackLayout>
</pcv:PancakeView>
</local:MyCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
private async void CalendarList_OnItemSelected(object sender, EventArgs e)
{
await Task.Delay(350);
var selectedItem = ((ListView)sender).SelectedItem;
var item = ((YearsList)selectedItem);
((ListView)sender).SelectedItem = null;
vm.ViewDetailCommand.Execute(item); // goto details page
}
public class MyCell: ViewCell
{
protected async override void OnTapped()
{
base.OnTapped();
await Task.Run(async () => await AnimationHelper.AnimateClick(this.View));
}
}
//IOS Renderer
[assembly: ExportRenderer(typeof(MyCell), typeof(MyCellRenderer))]
namespace CountDown.iOS.Renderers
{
public class MyCellRenderer : ViewCellRenderer
{
public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
{
var cell = base.GetCell(item, reusableCell, tv);
if (cell != null)
{
cell.SelectionStyle = UITableViewCellSelectionStyle.None;
}
return cell;
}
}
}
Now the question is :
Is it possible to change the style for PCV: PancakeView to different style names once a cell is selected?
I'm using Xamarin Forms ver 4.3.0 btw.
I've been able to change the color of the whole cell but I am not sure how to change the style.
According to your description, I guess that you want to change PancakeView style in ListView ItemTapped event?
If yes, I do one sample that you can take a look. I use Label control instead of PancakeView, it is the same.
<ContentPage.Resources>
<Style x:Key="LabelStyle" TargetType="Label">
<Setter Property="TextColor" Value="Color.Black" />
<Setter Property="FontAttributes" Value="None" />
</Style>
<Style x:Key="LabelChangedStyle" TargetType="Label">
<Setter Property="TextColor" Value="Color.Red" />
<Setter Property="FontAttributes" Value="Bold" />
</Style>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout>
<ListView ItemTapped="ListView_ItemTapped" ItemsSource="{Binding model3s}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Style="{Binding LabelStyle}" Text="{Binding str}">
<Label.Triggers>
<DataTrigger
Binding="{Binding istap}"
TargetType="Label"
Value="true">
<Setter Property="Style" Value="{StaticResource LabelChangedStyle}" />
</DataTrigger>
</Label.Triggers>
</Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
public partial class Page12 : ContentPage
{
public ObservableCollection<model3> model3s { get; set; }
public model3 model;
public Page12 ()
{
InitializeComponent ();
model3s = new ObservableCollection<model3>()
{
new model3(){str="this is test!",istap=false },
new model3(){str="this is test!",istap=false},
new model3(){str="this is test!",istap=false},
new model3(){str="this is test!",istap=false},
new model3(){str="this is test!",istap=false}
};
this.BindingContext = this;
}
private void ListView_ItemTapped(object sender, ItemTappedEventArgs e)
{
if(model!=null)
{
model.istap = false;
}
model3 m = e.Item as model3;
m.istap = true;
model = m;
}
}
public class model3:ViewModelBase
{
public string str { get; set; }
private bool _istap;
public bool istap
{
get { return _istap; }
set
{
_istap = value;
RaisePropertyChanged("istap");
}
}
}
The ViewModelBase is the class that implement INotifyPropertyChanged
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
When you tap one item in ListView, the style will change.

WPF data grid combo box column selected item data binding in C#

When I change selection in combo box debugger will hit TestSelectedItem {set} in User class, but I want to hit debugger, TestSelectedItem {set} in MainWindow class. Please suggests me correct solution.
public class User
{
public string Name { get; set; }
public ObservableCollection<string> TypeCollection { get; set; }
private string _testSelectedItem;
public string TestSelectedItem
{
get { return _testSelectedItem; }
set { _testSelectedItem = value; }
}
public User()
{
TypeCollection = new ObservableCollection<string>();
TypeCollection.Add("A");
TypeCollection.Add("B");
TypeCollection.Add("C");
}
}
public partial class MainWindow : Window
{
public List<User> Users { get; set; }
private string _testSelectedItem;
public string TestSelectedItem
{
get { return _testSelectedItem; }
set { _testSelectedItem = value; }
}
public MainWindow()
{
InitializeComponent();
Users = new List<User>();
Users.Add(new User() { Name = "User 1" });
Users.Add(new User() { Name = "User 2" });
Users.Add(new User() { Name = "User 3" });
myGrid.DataContext = this;
}
}
<Window x:Class="WpfApplication11.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication11"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid Name ="myGrid">
<StackPanel>
<DataGrid Name="MyDataGrid" AutoGenerateColumns="False" ItemsSource="{Binding Users}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}"
Header="Name"
Width="90"
CanUserResize="False"
CanUserSort="False"
CanUserReorder="False"
IsReadOnly="True" />
<DataGridComboBoxColumn Header="Product Type"
DisplayMemberPath="ProductType"
SelectedValuePath="ProductTypeId"
SelectedValueBinding="{Binding SelectedValuePath, UpdateSourceTrigger=PropertyChanged}">
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding TypeCollection}"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding TypeCollection}"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
<DataGridTemplateColumn Header="Bug">
<DataGridTemplateColumn.CellTemplate >
<DataTemplate>
<ComboBox Height="25" Width="200"
x:Name ="ppCombo"
ItemsSource="{Binding TypeCollection }"
SelectedItem="{Binding TestSelectedItem ,Mode=TwoWay ,UpdateSourceTrigger=PropertyChanged}">
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</Grid>
</Window>
I think I just found a solution but not sure is that the correct one
SelectedItem="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}, Path=TestSelectedItem}">

Resources