i want to pass a parameter in a xaml button - xamarin

hello i want to pass the Label with the button in xaml
its a list view and each row has her own Label and i want update each row by the label
<Label Grid.Column="2"
Grid.Row="1"
Text="{Binding Label}"
FontSize="20"
TextColor="Black"
Margin="0,10,0,0"
FontFamily="{StaticResource font}"
HorizontalOptions="Start"
VerticalOptions="Center"/>
<ImageButton Grid.Column="2"
Grid.Row="0"
HorizontalOptions="End"
VerticalOptions="End"
Source="plus.png"
Margin="9"
clicked ="update"
BackgroundColor="Transparent"/>
and the function in the class
public void update (object sender , EventArgs e)
{
update by the Label
}
i know that's there is something with commands but i'm beginner and i don't know how to use it i tried this and i didn't work.
Command="{Binding Path=BindingContext.UpdateCommand, Source={x:Reference Name=listViewEvent}}"
CommandParameter="{Binding Label}"
and the function is this
UpdateCommand = new Command<string>(async (args) => {
String Label = args as string;
DisplayAlert("update", "update", "OK");
_ = Navigation.PushAsync(new AddReminder(Label));
});
and the alert didn't show
please i need help

you don't need to "pass" the Label
<ImageButton Grid.Column="2" Cilcked="update" ... />
protected void update(object sender, EventArgs a)
{
var btn = (ImageButton)sender;
// MyClassName should be the name of your model class
// this will get you the object referenced by the selected row
var item = (MyClassName)btn.BindingContext;
// then you can reference any property of item
// ie, item.Label, etc
}

<Label x:Name="myLabel"
Grid.Column="2"
Grid.Row="1"
Text="{Binding Label}"
FontSize="20"
TextColor="Black"
Margin="0,10,0,0"
FontFamily="{StaticResource font}"
HorizontalOptions="Start"
VerticalOptions="Center"/>
<ImageButton Grid.Column="2"
Grid.Row="0"
HorizontalOptions="End"
VerticalOptions="End"
Source="plus.png"
Margin="9"
clicked ="update"
BackgroundColor="Transparent"
CommandParameter={x:Reference myLabel}/>
And then in code behind you can get the label
protected void update(object sender, EventArgs a)
{
var btn = (ImageButton)sender;
var label = btn.CommandParameter as Xamarin.Forms.Label;
}

Related

How to change button color when it is clicked in Xamarin

I am quite new in xamarin and I am trying to add a click events to my buttons. So here are my 4 buttons:
<StackLayout HorizontalOptions="Center" VerticalOptions="Center">
<Button Text="Page 1" TextColor="#EEF2FF" FontSize="20" HorizontalOptions="Center" BackgroundColor="#FF5959" />
</StackLayout>
<StackLayout Grid.Column="1" HorizontalOptions="Center" VerticalOptions="Center">
<Button Text="Page 2" Clicked="Handle_Page" TextColor="#676FA3" FontSize="20" HorizontalOptions="Center" BackgroundColor="#EEF2FF"/>
</StackLayout>
<StackLayout Grid.Column="2" HorizontalOptions="Center" VerticalOptions="Center">
<Button Text="Page 3" TextColor="#676FA3" FontSize="20" HorizontalOptions="Center" BackgroundColor="#EEF2FF"/>
</StackLayout>
<StackLayout Grid.Column="3" HorizontalOptions="Center" VerticalOptions="Center">
<Button Text="Page 4" TextColor="#676FA3" FontSize="20" HorizontalOptions="Center" BackgroundColor="#EEF2FF"/>
</StackLayout>
So the colour of the buttons are #EEF2FF but when I click on the button I want it to be changed to #FF5959. But if there is another button clicked already, then it should also change to the main colour, #EEF2FF. So we can cay synchronized click event.
I am quite new, so any help would be appreciated.
add a clicked handler
<Button Clicked="ButtonClicked" ... />
then in the handler
protected void ButtonClicked(object sender, EventArgs args)
{
// set the other buttons back to the base color
// you will need to assign each button an x:Name in xaml
btn1.BackgroundColor = Color.FromHex("EEF2FF");
...
btn10.BackgroundColor = Color.FromHex("EEF2FF");
// then change the color of only the selected button
var btn = (Button)sender;
btn.BackgroundColor = Color.FromHex("FF5959");
}
protected override void OnCreate(Bundle savedInstanceState)
{
ScreenClickButton.Click += ChangeColorToRed;
}
private void ChangeColorToRed(object sender, EventArgs e)
{
ScreenClickButton.SetBackgroundColor(color: Color.Red);
}

Xamarin: CollectionView columns to trigger different actions

I have this in XAML:
<CollectionView ItemsSource="{Binding Accepted}"
SelectionMode="Single" SelectionChanged="OnAcceptedSelected">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding friendlyname}"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
And this is the OnClick handler:
async void OnAcceptedSelected(object sender, SelectionChangedEventArgs e) {
MyItem selectedMI = e.CurrentSelection.FirstOrDefault() as MyItem;
// do something
}
I want to be able to do different things with selectedMI depending on what column the user clicked on, something like this:
<CollectionView ItemsSource="{Binding Accepted}"
SelectionMode="Single" SelectionChanged="OnAcceptedSelected">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding friendlyname}"/>
<Label x:Name="Action_A" />
<Label x:Name="Action_B" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
so that I could do something like this:
async void OnAcceptedSelected(object sender, SelectionChangedEventArgs e) {
MyItem selectedMI = e.CurrentSelection.FirstOrDefault() as MyItem;
// if clicked on Action_A do something and
// if clicked on Action_B do something else
}
Xamarin doesn't seem to offer an obvious way to do that. Any ideas how to implement this functionality?
Thanks.
Adding gesture to Label is a good choice.
I wrote a small example for your reference.
Two labels are added to each row of the CollectionView, and two events are respectively bound. Clicking on a different label will enter two different methods, and you can get the information of the label you clicked inside the method.
Here is the xaml code:
<CollectionView ItemsSource="{Binding Accepted}" >
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding .}" BackgroundColor="Red" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="tapCommand"/>
</Label.GestureRecognizers>
</Label>
<Label Text="{Binding .}" BackgroundColor="blue" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="tapCommand1"/>
</Label.GestureRecognizers>
</Label>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Here is the background code:
public partial class MainPage : ContentPage
{
public ObservableCollection<string> Accepted { get; set; }
public MainPage()
{
Accepted = new ObservableCollection<string>();
Accepted.Add("aaa");
Accepted.Add("bbb");
Accepted.Add("ccc");//Simulation data
InitializeComponent();
BindingContext = this;
}
private void tapCommand(object sender, EventArgs e)//event1
{
string res = (sender as Label).Text;
}
private void tapCommand1(object sender, EventArgs e)//event2
{
string res = (sender as Label).Text;
}
}

Xamarin - Entry Focused and TapGestureRecognizer not working

<StackLayout Orientation="Horizontal" FlowDirection="RightToLeft" HorizontalOptions="EndAndExpand" Spacing="0">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="GoToBasket"></TapGestureRecognizer>
</StackLayout.GestureRecognizers>
<Frame x:Name="frmBasket" CornerRadius="24" Padding="8" BackgroundColor="#FFFFFF">
<StackLayout Orientation="Horizontal">
<Entry x:Name="lblTotalBasket" TextChanged="lblTotalBasket_TextChanged" HorizontalOptions="FillAndExpand" IsReadOnly="True" Text="{Binding TotalPrice, StringFormat='₺{0:0.00}'}" Margin="0, 0, 5, 0" HorizontalTextAlignment="Center" FontSize="13" VerticalTextAlignment="Center" FontAttributes="Bold" BackgroundColor="#FFFFFF" TextColor="{StaticResource Primary}"></Entry>
<Label x:Name="lblBasketIcon" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" BackgroundColor="Transparent" Text="" FontSize="15" TextColor="{StaticResource Primary}" Margin="8, 0, 0, 0" FontFamily="{StaticResource FontAwesomeSolid}"></Label>
</StackLayout>
</Frame>
</StackLayout>
StackLayout TapGestureRecognizer working except Entry element. I tried add TapGestureRecognizer and Focused attribute for Entry element but also not worked.
How StackLayout TapGestureRecognizer does work on Entry element tap ?
If you set the IsReadOnly=false to entry, the TapGestureRecognizer won't work because it will get fouced when tap it and user can type something. In this cause, you can call your method in the foucsed event:
<Entry x:Name="lblTotalBasket" Focused="lblTotalBasket_Focused"/>
And in code behind:
private void lblTotalBasket_Focused(object sender, FocusEventArgs e)
{
Console.WriteLine("lblTotalBasket_Focused-entry");
}
If you set the IsReadOnly=ture to entry, the TapGestureRecognizer will execute and you can also add TapGestureRecognizer to entry directly:
<Entry x:Name="lblTotalBasket" Focused="lblTotalBasket_Focused" HorizontalOptions="FillAndExpand" IsReadOnly="True" Text="{Binding TotalPrice, StringFormat='₺{0:0.00}'}" Margin="0, 0, 5, 0" HorizontalTextAlignment="Center" FontSize="13" VerticalTextAlignment="Center" FontAttributes="Bold" BackgroundColor="#FFFFFF">
<Entry.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"></TapGestureRecognizer>
</Entry.GestureRecognizers>
</Entry>
And in code behind:
private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
{
Console.WriteLine("TapGestureRecognizer_Tapped-entry");
}
Update:
In Android, you also need to set isEnable = false to make TapGestureRecognizer work:
<Entry x:Name="lblTotalBasket" IsEnabled="False"/>
Try setting TapGesture for parent control and for your entry set InputTransparent="True" so that when you tap on entry it will actually recognized as tap on parent control.

Is there a way to simulate the clicking of a button?

I'm using this code to create something looking like a button:
<Grid Grid.Column="0" ColumnSpacing="0" Margin="0,0,10,0">
<Frame Grid.Column="0" CornerRadius="5" OutlineColor="Black">
<Label x:Name="faveIconLabel" Style="{StaticResource mediumIcon}" Margin="0,2,0,0" HorizontalOptions="Fill" FontFamily="FontAwesome" VerticalOptions="Center" VerticalTextAlignment="Center" />
</Frame>
<Frame Grid.Column="1" CornerRadius="5" OutlineColor="Black">
<Label x:Name="hiddenIconLabel" Style="{StaticResource mediumIcon}" Margin="0,2,0,0" HorizontalOptions="Fill" FontFamily="FontAwesome" VerticalOptions="Center" VerticalTextAlignment="Center" />
</Frame>
</Grid>
Is there a way that I can simulate the click event to make it look like something actually got pressed when they click on the label?
If you don't want to use a custom renderer, a simple way would be to change the background color in the handleClick, and then revert it back to its original color after a few milliseconds. For example,
private void handleClick(object sender, EventArgs e) {
var view = (View)sender;
view.BackgroundColor = Color.FromHex("#DD000000");
Device.StartTimer(
TimeSpan.FromMilliseconds(100),
() =>
{
// Revert it back to the original color, whatever it may be.
Device.BeginInvokeOnMainThread(() =>
{
view.BackgroundColor = Color.Transparent;
});
return false; // return false to prevent the timer from calling again
});
}
You can add a TapGestureRecognizer to virtually any VisualElement, including Label, Image, etc.
faveIconLabel.GestureRecognizers.Add(new TapGestureRecognizer((view) => OnLabelClicked()));

How to display a ListView and Other Controls in a ScrollView?

I want to display a ListView and other controls inside a ScrollView. All is bound to a ViewModel. My attempts failed because it's not recommend to put a ListView inside a ScrollView. As I use a complex ViewCell DataTemplate, I did not consider to add my items in the code behind file as Buttons instead of a ListView.
Hope someone can show me a Xaml or CS pattern to achieve my goal.
Please only suggest a solution which works on iOS and Android!
Thanks
Eric
This is XAML code
<ScrollView Padding="2">
<StackLayout HorizontalOptions="FillAndExpand">
<Grid HorizontalOptions="FillAndExpand">
<StackLayout>
<ScrollView Orientation="Horizontal">
<ListView BackgroundColor="Transparent" ItemsSource="{Binding UsersList}" SeparatorVisibility="None" x:Name="YourListView" RowHeight="50">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="Transparent" Padding="5">
<Button Text="{Binding UserName}" WidthRequest="115" HorizontalOptions="FillAndExpand" TextColor="White" BackgroundColor="#4b76c4" FontAttributes="Bold" FontSize="20" FontFamily="Avenir Book"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollView>
</StackLayout>
</Grid>
</StackLayout>
</ScrollView>
and .cs file you need set BindingContext
BindingContext = new YourViewModel();
Solution:
As Rodrigo E suggested I download the latest Xamarin Evolve App 2016. After digging through the code I adjusted/simplified the FeedPage.xaml in the solution to that:
<?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:local="clr-namespace:XamarinEvolve.Clients.UI;assembly=XamarinEvolve.Clients.UI"
xmlns:pull="clr-namespace:Refractored.XamForms.PullToRefresh;assembly=Refractored.XamForms.PullToRefresh"
x:Class="XamarinEvolve.Clients.UI.FeedPage"
x:Name="FeedPage"
Title="Evolve Feed"
Icon="tab_feed.png"
BackgroundColor="{DynamicResource WindowBackgroundTable}">
<pull:PullToRefreshLayout
IsPullToRefreshEnabled="True"
RefreshCommand="{Binding RefreshCommand}"
IsRefreshing="{Binding IsBusy}">
<local:AlwaysScrollView
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<StackLayout>
<StackLayout Spacing="0">
<local:NonScrollableListView
x:Name="ListViewSessions"
ItemsSource="{Binding Sessions}">
<local:NonScrollableListView.RowHeight>
<OnPlatform x:TypeArguments="x:Int32" Android="50" iOS="50" WinPhone="50"/>
</local:NonScrollableListView.RowHeight>
<local:NonScrollableListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Button Text="{Binding Title}" BackgroundColor="Black" TextColor="Green" />
</ViewCell>
</DataTemplate>
</local:NonScrollableListView.ItemTemplate>
</local:NonScrollableListView>
</StackLayout>
<StackLayout Padding="0" Spacing="0" BackgroundColor="Green">
<Button Text="OTHER" BackgroundColor="Blue" TextColor="White" />
<Button Text="OTHER" BackgroundColor="Blue" TextColor="White" />
<Button Text="OTHER" BackgroundColor="Blue" TextColor="White" />
<Button Text="OTHER" BackgroundColor="Blue" TextColor="White" />
<Button Text="OTHER" BackgroundColor="Blue" TextColor="White" />
<Button Text="OTHER" BackgroundColor="Blue" TextColor="White" />
</StackLayout>
</StackLayout>
</local:AlwaysScrollView>
</pull:PullToRefreshLayout>
There are a few things to do:
In the FeedViewModel.cs I added that code for a quick test:
async Task ExecuteLoadSessionsCommandAsync()
{
if (LoadingSessions)
return;
LoadingSessions = true;
try
{
NoSessions = false;
Sessions.Clear();
OnPropertyChanged("Sessions");
#if DEBUG
await Task.Delay(1000);
#endif
var sessions = await StoreManager.SessionStore.GetNextSessions();
var testSessions = new List<Session>();
testSessions.Add(new Session
{
Title = "TEST"
});
testSessions.Add(new Session
{
Title = "TEST"
});
testSessions.Add(new Session
{
Title = "TEST"
});
sessions = testSessions;
if(sessions != null)
Sessions.AddRange(sessions);
NoSessions = Sessions.Count == 0;
}
catch(Exception ex)
{
ex.Data["method"] = "ExecuteLoadSessionsCommandAsync";
Logger.Report(ex);
NoSessions = true;
}
finally
{
LoadingSessions = false;
}
}
You have to reference the package Refractored.XamForms.PullToRefresh to get the Pull-to-Refresh behavor.
This is in that namespace referenced: xmlns:pull="clr-namespace:Refractored.XamForms.PullToRefresh;assembly=Refractored.XamForms.PullToRefresh"
You have to Copy the AlwaysScrollView , NonScrollableListView to your PCL library.
refercene it with: xmlns:local="clr-namespace:"
In your iOS Project add that custom ListView Renderer:
public class NonScrollableListViewRenderer : ListViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (Control != null)
Control.ScrollEnabled = false;
}
}
public class AlwaysScrollViewRenderer : ScrollViewRenderer
{
public static void Initialize()
{
var test = DateTime.UtcNow;
}
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
this.AlwaysBounceVertical = true;
}
}
See file: Renderer
Put that CollectionChanged Handler in your Code-behind file:
ViewModel.Sessions.CollectionChanged += (sender, e) =>
{
var adjust = Device.OS != TargetPlatform.Android ? 1 : -ViewModel.Sessions.Count + 1;
ListViewSessions.HeightRequest = (ViewModel.Sessions.Count * ListViewSessions.RowHeight) - adjust;
};
See File FeedPage.cs.xaml: FeedPage.cs.xaml

Resources