Change all xamarin forms button background inside a listview - xamarin.forms

I have ListView with buttons inside.When button is clicked I need some way to change the background color of all other buttons exept the clicked button.
Initially all buttons inside my listview have a white background, when a button is clicked i check is background color is white then change to gray color and need to change background colors to white for all other buttons.
This is the code:
<control:ListViewNestedScroll
x:Name="ClassLevelListView"
HasUnevenRows="True"
RowHeight="30"
SeparatorVisibility="None"
IsPullToRefreshEnabled="True"
IsRefreshing="{Binding IsRunning, Mode=TwoWay}"
RefreshCommand="{Binding LoadClassLevelsCommand}"
ItemsSource="{Binding ClassLevels}">
<ListView.ItemTemplate>
<DataTemplate>
<control:CustomViewCell SelectedBackgroundColor="{StaticResource GreyColor}">
<StackLayout Margin="0,0,0,10">
<control:CustomButton
Text="{Binding KeyName, Converter={StaticResource I18N}}"
CornerRadius="20"
BorderColor="Black"
BorderWidth="2"
TextColor="Black"
BackgroundColor="White"
CommandParameter="{Binding .}"
Clicked="Button_OnClicked" />
</StackLayout>
</control:CustomViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</control:ListViewNestedScroll>
private void Button_OnClicked(object sender, EventArgs e)
{
var classLevelButton = (Button)sender;
var classLevel = classLevelButton.CommandParameter as ClassLevelModel;
if (classLevelButton.BackgroundColor == Color.White)
{
classLevelButton.BackgroundColor = (Color)Application.Current.Resources["GreyColor"];
((RegisterTeacherClassLevelViewModel)BindingContext).AddTeacherClassLevel(classLevel);
}
else
{
classLevelButton.BackgroundColor = Color.White;
((RegisterTeacherClassLevelViewModel)BindingContext).RemoveTeacherClassLevel(classLevel);
}
}

Related

When change an object inside a CollectionView multiple objects are affected

If I hide an image visibility in CollectionView, multiple image visibility is affecting but image Tapped event fires once.
Simplified CollectionView xaml..
<CollectionView x:Name="favCollectionView"
ItemsSource="{Binding FavoriteCollection}"
RemainingItemsThresholdReachedCommand="{Binding GetNextDatas}"
RemainingItemsThreshold="1"
ItemSizingStrategy="MeasureAllItems"
ItemsLayout="VerticalList"
SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid VerticalOptions="FillAndExpand">
<Label Grid.Row="0" Text="{Binding TargetText}"/>
<Image Grid.Row="0" Aspect="AspectFill" Source="seeResult.png">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="Tapped_TranslatedResult"/>
</Image.GestureRecognizers>
</Image>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Code behind..
void Tapped_TranslatedResult(System.Object sender, System.EventArgs e)
{
var img = sender as Image;
if (img != null)
{
img.Opacity = 0;
}
}
For example, If I have 50 rows in CollectionView and tapped once top second image item, next ninth image's visibility is changed too and again next ninth one too, so on..
What could be the problem?
I changed the Image to ImageButton and then added Command parameter. The key was the Jason's comment. Binding the Model property to my ImageButton's IsVisibility property and it worked correctly.

Xamarin CollectionView - Scroll Programatically

I have collection view . See below code
<CollectionView ItemsSource="{Binding photos}" HeightRequest="300"
ItemSizingStrategy="MeasureAllItems" Margin="10,0,10,0"
x:Name="photosView"
ItemsUpdatingScrollMode="KeepScrollOffset">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="3" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="2">
<Frame BackgroundColor="Red" HeightRequest="79" WidthRequest="53" Padding="0" Margin="0"
IsClippedToBounds="True" HasShadow="False" CornerRadius="10">
<Image Aspect="AspectFill" Source="{Binding imageUrl}"/>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
I am showing 3 rows and 3 columns of the images. If I have more than 9 images then I am showing Button which says Scroll for more photos. Now On click on the imageI have below code
void OnScrollMore(System.Object sender, System.EventArgs e)
{
//photosView.SendScrolled(new ItemsViewScrolledEventArgs() { FirstVisibleItemIndex = 0 });
photosView.ScrollTo(photosView.Y + 10, position: ScrollToPosition.MakeVisible, animate: true);
}
But nothing is happening . It is not getting scrolled to next row.
Any suggestions?
The reason your ScrollTo method is not working is because the photosView can't find the item 'photosView.Y + 10' in your photosView itemssource. The method you're invoking is trying to find an item in the ItemsSource. It is not scrolling to a y-position like you're trying to do. You can see it in the description of the method when going to the definition. It is waiting for an 'object item'.
public void ScrollTo(object item, object group = null, ScrollToPosition position = ScrollToPosition.MakeVisible, bool animate = true);
If what you're trying to do is scroll to the last added item of the collectionview, then try this working approach and build it up from there. Here everytime you press the button, an item (string) gets added. This item is set as the ScrollTo object at the end of the button click handler.
MainPage.xaml
<StackLayout Orientation="Vertical">
<CollectionView ItemsSource="{Binding photos}" HeightRequest="300"
ItemSizingStrategy="MeasureAllItems" Margin="10,0,10,0"
x:Name="photosView"
ItemsUpdatingScrollMode="KeepLastItemInView">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="3" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="2">
<Frame BackgroundColor="Red" HeightRequest="79" WidthRequest="53" Padding="0" Margin="0"
IsClippedToBounds="True" HasShadow="False" CornerRadius="10">
<Label Text="{Binding}" TextColor="White"
HorizontalOptions="Center" VerticalOptions="Center"
HorizontalTextAlignment="Center" VerticalTextAlignment="Center"/>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Button Text="scroll more" HorizontalOptions="Center" VerticalOptions="End" Clicked="OnScrollMore"/>
</StackLayout>
MainPage.xaml.cs
public partial class MainPage : ContentPage
{
ObservableCollection<string> ObservableItems { get; set; }
public MainPage()
{
InitializeComponent();
ObservableItems = new ObservableCollection<string>(new List<string>() { "een", "twee", "drie" });
photosView.ItemsSource = ObservableItems;
}
void OnScrollMore(System.Object sender, System.EventArgs e)
{
var item = (ObservableItems.Count + 1).ToString();
ObservableItems.Add(item);
photosView.ScrollTo(item, position: ScrollToPosition.MakeVisible, animate: true);
}
}
Resulting in:

How can I remove Margin from a Button in Xamarin Forms XAML?

I'm totally new to Xamarin, so please be patient!
Somehow Xamarin adds a mysterious Margin to all my Buttons and I don't know how to get rid of it.
Here is my Code:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="RockStamp.CameraSearch_Scan">
<StackLayout Orientation="Vertical" Padding="0" Spacing="0">
<StackLayout Orientation="Horizontal" Padding="0" Spacing="0">
<Button Text="Test" HeightRequest="50" WidthRequest="60" TextColor="#333333" x:Name="btnBack" VerticalOptions="Center" HorizontalOptions="Start" ></Button>
<Label Text="Scan a..." FontSize="20" FontAttributes="Bold" BackgroundColor="{StaticResource BlueBackColor}" TextColor="White" VerticalOptions="Start" HorizontalOptions="FillAndExpand" />
</StackLayout>
<Label Text="Steady now, we try to detect your..." FontSize="16" VerticalOptions="Start" HorizontalOptions="Start" />
<!-- Camera Placeholder -->
<BoxView HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="#eeeeee" ></BoxView>
<StackLayout Orientation="Horizontal" Padding="0" Spacing="0">
<Button Text="Cancel" TextColor="#333333" x:Name="btnCancel" VerticalOptions="Center" HorizontalOptions="FillAndExpand" ></Button>
<Button Text="Scan now!" TextColor="#333333" x:Name="btnScan" VerticalOptions="Center" HorizontalOptions="FillAndExpand" ></Button>
</StackLayout>
</StackLayout >
</ContentPage>
Here an image:
You can clearly see the space around the Button. Where does it come from - and more important: How can I remove it?
The problem is that the default button background contains this margin. You have to set the BackgroundColor to a color and set the BorderWidth and BorderRadius to zero manually.
<Button
BackgroundColor="Fuchsia"
BorderRadius="0"
BorderWidth="0"
Text="Test"
HeightRequest="50"
WidthRequest="60"
TextColor="#333333"
x:Name="btnBack"
Margin="0"
VerticalOptions="Start"
HorizontalOptions="Start" />
You may have fixed the problem :
The way I fixed this is to create a renderer on android to override the button on xamarin.
public class FixedMarginRenderer : ButtonRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if (Control != null)
{
// remove default background image
Control.Background = null;
Control.SetBackgroundColor(Element.BackgroundColor.ToAndroid());
}
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == "BackgroundColor")
{
// You have to set background color here again, because the background color can be changed later.
Control.SetBackgroundColor(Element.BackgroundColor.ToAndroid());
}
}
}
Just to add on to Sven-Michael Stübe's answer.
If none of your buttons require the Margin then create a Style or a custom control in your PCL (eg: MarginLessButton).
Setting BackgroundColor, BorderWidth, and BorderRadius manually does not work anymore. But you can use platform configuration to remove the padding. It is also necessary to remove the shadow otherwise there will be some vertical margin.
Try something like this:
using Xamarin.Forms;
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
namespace MyControls
{
public class ButtonNoMargin : Xamarin.Forms.Button
{
public ButtonNoMargin() : base()
{
this.On<Android>().SetUseDefaultPadding(false);
this.On<Android>().SetUseDefaultShadow(false);
}
}
}
For more information, see https://github.com/xamarin/Xamarin.Forms/pull/1935

How do I set the size of an image within a ListView?

How do I set the size of an image within a ListView?
The targeted device is Windows Phone 10 (i.e. Windows Universal Platform).
I've discovered the following documentation:
Note that when targeting Windows Phone 8.1, ImageCell will not scale
images by default. Also, note that Windows Phone 8.1 is the only
platform on which detail text is presented in the same color and font
as primary text by default. Windows Phone 8.0 renders ImageCell as
seen below:
I've tried:
<ListView Grid.Row="1" ItemsSource="{Binding Photos}" SelectedItem="{Binding SelectedPhoto, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<ImageCell ImageSource="{Binding ImageSource}" Text="{Binding Description}" TextColor="Silver" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The above image shows a full-blown image without confining the size of the image to fit as a listview item.
I've also tried:
<ListView Grid.Row="1" ItemsSource="{Binding Photos}" SelectedItem="{Binding SelectedPhoto, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding ImageSource}" Aspect="AspectFit" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The above code doesn't show any image. It just shows a white background.
Few things:-
ImageCell has no ability to specify the image width / height (v2.0.x).
Your second example is more on track, however, you need to wrap it in a ViewCell as you are dealing with a ListView like so:-
<ListView ItemsSource="{Binding Photos}" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Image Source="{Binding MyImage}" Aspect="AspectFit" WidthRequest="{Binding MyWidth}" HeightRequest="{Binding MyHeight}" />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Also, note that the default for a ListView is set to have equal row heights.
Therefore if you have different image sizes, chances are this may not produce the output you want.
To get around this, specify HasUnevenRows='True'.
If you further do BindableProperties for what you want the ImageWidth and ImageHeight in your ViewModel, and specify them as in the example above using WidthRequest and HeightRequest for Image you will get something like this for the output when specifying different values:-
Just adding salt to a cooked meal, You can also do it dynamically:
<Slider x:Name="slider" Maximum="600" Minimum="30" />
<ListView RowHeight="55" x:Name="lv_prayers_categories_page"
ItemsSource="{Binding SimpleList}"
HasUnevenRows="true"
BackgroundColor="Transparent"
SeparatorVisibility="None">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="#eee" HeightRequest="50" >
<StackLayout Orientation="Horizontal">
<Image Aspect="AspectFill" Source="{Binding Image}" HeightRequest="{Binding Source={x:Reference slider}, Path=Value}" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
<Label Text="{Binding Name}"
TextColor="#f35e20" />
<Label Text="{Binding ID}"
HorizontalOptions="EndAndExpand"
TextColor="#503026" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
View Modal:
private ObservableCollection<SimpleImage> _impleList;
public ObservableCollection<SimpleImage> SimpleList
{
get => _impleList;
set => SetProperty(ref _impleList, value);
}
SimpleList = new ObservableCollection<SimpleImage>()
{
new SimpleImage(){
ID = 0,
Name = "Female",
Image = "https://griffonagedotcom.files.wordpress.com/2016/07/profile-modern-2e.jpg"
},
new SimpleImage(){
ID = 1,
Name = "Male",
Image = "https://media.istockphoto.com/photos/profile-view-of-confident-sportsman-picture-id488758510?k=6&m=488758510&s=612x612&w=0&h=yIwLu2wdd2vo317STdyNlKYIVIEJEFfDKfkY8pBIfaA="
},
new SimpleImage(){
ID = 2,
Name = "Android",
Image = "https://www.cnn.co.jp/storage/2015/11/06/17626d508c2c2a8c8c322d353631a431/zuckerberg-getty.jpg"
},
};
Modal:
public class SimpleImage : BindableBase
{
private int _id;
public int ID
{
get { return _id; }
set { SetProperty(ref _id, value); }
}
private string _name;
public string Name
{
get { return _name; }
set { SetProperty(ref _name, value); }
}
private ImageSource _image;
public ImageSource Image
{
get { return _image; }
set { SetProperty(ref _image, value); }
}
}

WP7 Updating Pivot control title

I have a Pivot control which I am using as following within the XAML.
I have bound the Pivot Title to a method on my view model as its content will vary depending upon what is being displayed.
<controls:Pivot x:Name="MainPivot" ItemsSource="{Binding PivotItemHeaders}" Title="{Binding ApplicationTitle}" >
<controls:Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Description}"/>
</DataTemplate>
</controls:Pivot.HeaderTemplate>
<controls:Pivot.ItemTemplate>
<DataTemplate>
<ListBox x:Name="EventsListbox"
ItemsSource="{Binding allEventItems}"
ItemTemplate="{StaticResource EventDisplay3}"
SelectionChanged="EventsListbox_SelectionChanged"/>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>
The collection of items is being refreshed and the binding is working fine for these objects - however the Pivot title is not refreshing with the new value.
It seems stuck at the value when the page/pivot control was first shown.
Any ideas how I can get the pivot control to refresh? - Thanks
I just did a quick test, binding works just fine:
<controls:Pivot Title="MY APPLICATION" ItemsSource="{Binding Items}">
<controls:Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding LineOne}" />
</DataTemplate>
</controls:Pivot.HeaderTemplate>
<controls:Pivot.ItemTemplate>
<DataTemplate>
<Grid>
<Button Content="Update" Click="Button_Click" />
</Grid>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>
And in the C#
private void Button_Click(object sender, RoutedEventArgs e)
{
App.ViewModel.Items.Clear();
App.ViewModel.Items.Add(new ItemViewModel() { LineOne = "foo" });
App.ViewModel.Items.Add(new ItemViewModel() { LineOne = "bar" });
App.ViewModel.Items.Add(new ItemViewModel() { LineOne = "baz" });
}
So clearly you're doing something very wrong. Post your code and we'll take a look.
Update
Title Binding also works
XAML
<controls:Pivot Title="{Binding Title}">
<controls:PivotItem Header="first">
<Grid>
<Button Click="Button_Click" Content="OK!" />
</Grid>
</controls:PivotItem>
</controls:Pivot>
C#:
private void Button_Click(object sender, RoutedEventArgs e)
{
Title = "foobar!";
PropertyChanged(this, new PropertyChangedEventArgs("Title"));
}

Resources