Xamarin.Forms Template Command TapGesture Inner Label - mvvm

guys,
I need help on Xamarin.Forms.
I have a custom template, this template contains two labels. I just need one of the labels to get a TapGesture command.
In my code, my entire template receives the TapGesture command.
Can someone help me?
Code ScheduleHeaderTitleTemplate: MyCustomTemplate
public partial class ScheduleHeaderTitleTemplate : ContentView
{
#region Title
public static readonly BindableProperty TitleProperty = BindableProperty.Create(
propertyName: "Title",
returnType: typeof(string),
declaringType: typeof(ScheduleHeaderTitleTemplate),
defaultValue: string.Empty,
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: TitlePropertyChanged
);
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
private static void TitlePropertyChanged(BindableObject bindable, Object oldValue, Object newValue)
{
var scheduleHeaderTitleTemplate = (ScheduleHeaderTitleTemplate)bindable;
scheduleHeaderTitleTemplate.title.Text = (string)newValue;
}
#endregion
#region Command
public static readonly BindableProperty CommandProperty = BindableProperty.Create(
propertyName: nameof(Command),
returnType: typeof(ICommand),
declaringType: typeof(Label),
defaultValue: null
);
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
#endregion
public ScheduleHeaderTitleTemplate()
{
InitializeComponent();
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.Tapped += (sender, e) =>
{
if (Command != null && Command.CanExecute(null))
Command.Execute(null);
};
GestureRecognizers.Add(tapGestureRecognizer);
}
}
View ScheduleHeaderTitleTemplate: MyCustomTemplate
<ContentView.Content>
<StackLayout Padding="10, 10" Spacing="0" Orientation="Horizontal" BackgroundColor="{StaticResource Primary}">
<StackLayout Orientation="Horizontal" VerticalOptions="Center">
<!--TAPGESTURE FOR THIS LABEL -->
<Label Text="" Margin="0, 0, 15, 0" Style="{StaticResource IconWithFontAwesome}" />
<Label x:Name="title" Margin="0, 3, 0, 0" Style="{StaticResource ScheduleSubTitle}"/>
</StackLayout>
</StackLayout>
</ContentView.Content>

That's quite simple. Instead of adding a TapGestureRecognizer right in the constructor, add it to the label you want to. There are two ways for doing that:
You add a x:Name property to your label, for example "lblLink", and in your constructor you add the gesture to it, like lblLink.GestureRecognizers.Add(yourGestureRecognizer).
You bind the command to the label in the XAML. You'll exactly the same thing, but in the XAML. You basically have to add a x:Name property to the ContentView and add a TapGestureRecognizer to the label:
<ContentView ...
x:Name="View">
<ContentView.Content>
<StackLayout Padding="10, 10" Spacing="0" Orientation="Horizontal" BackgroundColor="{StaticResource Primary}">
<StackLayout Orientation="Horizontal" VerticalOptions="Center">
<!--TAPGESTURE FOR THIS LABEL -->
<Label Text="" Margin="0, 0, 15, 0" Style="{StaticResource IconWithFontAwesome}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Command, Source={x:Reference View}}" />
</Label.GestureRecognizers>
</Label>
<Label x:Name="title" Margin="0, 3, 0, 0" Style="{StaticResource ScheduleSubTitle}"/>
</StackLayout>
</StackLayout>
</ContentView.Content>
</ContentView>
Hope it helps!

Related

Listview IsEnabled property not working in .Net maui

Listview IsEnabled property not working in .Net Maui. Please look into the below code.
<StackLayout>
<ListView x:Name="listView" ItemsSource="{Binding Source}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid ColumnDefinitions="100,*">
<Label Grid.Column="0" Text="{Binding Name}" />
<Switch Grid.Column="1" IsToggled="{Binding Enabled}"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Text="Button1" Clicked="Button_Clicked1"/>
<Button Text="Button2" Clicked="Button_Clicked2"/>
</StackLayout>
Code Behind
public partial class MainPage : ContentPage
{
//static public FoodViewModel Foods;
public MainPage()
{
InitializeComponent();
//Foods = new FoodViewModel();
this.BindingContext = new FoodViewModel();
}
private void Button_Clicked2(object sender, EventArgs e)
{
listView.IsEnabled = false;
}
private void Button_Clicked1(object sender, EventArgs e)
{
listView.IsEnabled = true;
}
}
In the upper code the Switch should be Enabled when listview enabled but im unable to toggle the switch.
Try this.BindingContext = this;
Try using Enabled property.
listView.Enabled = true;

How to bind attributes values in MAUI component

I'm trying to make a windows-like navigation item.
This is the implementation:
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="NavItem.NavItem"
xmlns:local="clr-namespace:NavItem"
x:DataType="local:NavItem">
<Frame HeightRequest="50" CornerRadius="6" BackgroundColor="{StaticResource Tertiary}" BorderColor="{StaticResource Secondary}" Padding="10">
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped" />
</Frame.GestureRecognizers>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label x:Name="LblText" Text="{Binding Text}" Grid.Column="0" TextColor="{StaticResource White}" />
<Label Text=">" Grid.Column="1" TextColor="{StaticResource White}" FontSize="16" />
</Grid>
</Frame>
</ContentView>
public partial class NavItem : ContentView
{
string text;
public string Text
{
get => text;
set { text = value; OnPropertyChanged(); }
}
public string PageName { get; set; }
public NavItem()
{
InitializeComponent();
}
private async void TapGestureRecognizer_Tapped(object sender, EventArgs e)
{
await Shell.Current.GoToAsync(PageName);
}
}
<VerticalStackLayout>
<local:NavItem Text="Page 1" PageName="Page1" />
<local:NavItem Text="Page 2" PageName="Page2" />
</VerticalStackLayout>
The navigation is ok but the binding fails to set Text property of label LblText.
So this is the rendering:
EDIT: I also tried with a bindable attribute, same result
public string Text
{
get => (string)GetValue(TextProperty);
set { SetValue(TextProperty, value); OnPropertyChanged(); }
}
public static readonly BindableProperty TextProperty =
BindableProperty.Create(nameof(Text), typeof(string), typeof(NavItem), "", BindingMode.TwoWay);
I just had to set the binding context to itself:
public NavItem()
{
InitializeComponent();
BindingContext = this;
}

Xamarin Forms - Set BindingContext of a controltemplate

I have a xamarin forms application. It has a tabbedpage within it multiple tabs. The tabbedpage and te tabs, each of them has their own viewmodel as a bindingcontext.
In the app.xaml I defined a controltemplate. I use this control template in each tab, because I want each of those tabs to have a button at the bottom of the page.
At this moment: the button in the controltemplate binds with a property defined in each tab. But I want the button to bind at one place. Isn't it possible to create a viewmodel special for the controltemplate and bind the button defined in the controltemplate with that viewmodel?
Current code:
<ControlTemplate x:Key="ActivityStatusButton">
<StackLayout>
<ContentPresenter>
</ContentPresenter>
<StackLayout VerticalOptions="EndAndExpand" HorizontalOptions="Fill" Padding="15">
<Button Style="{StaticResource RedBackGroundWithWhiteTextButtonStyle}" Command="{TemplateBinding BindingContext.ClickOnStatusButton, Mode=TwoWay}" Text="{TemplateBinding BindingContext.ok, Mode=TwoWay}"></Button>
</StackLayout>
</StackLayout>
</ControlTemplate>
A typical tab:
<ContentPage ...>
<ContentPage.Content>
<Label Text="hello"></Label>
</ContentPage.Content>
<!--The control template is placed here (the button) -->
You could create a Custom Control (a subclass of ContentView) like
<?xml version="1.0" encoding="UTF-8"?>
<ContentView 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:Name="template"
x:Class="App24.MyControlTemplate">
<ContentView.Content>
<StackLayout VerticalOptions="EndAndExpand" HorizontalOptions="Fill" Padding="15">
<Button Clicked="Button_Clicked" Command="{Binding Source={x:Reference template},Path=ButtonCommand}" Text="{Binding Source={x:Reference template},Path=ButtonText}" CommandParameter="{Binding Source={x:Reference template},Path=CommandParameter}" />
</StackLayout>
</ContentView.Content>
</ContentView>
using System;
using System.Windows.Input;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace App24
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MyControlTemplate : ContentView
{
public event EventHandler ButtonClick;
public static readonly BindableProperty ButtonTextProperty =
BindableProperty.Create("ButtonText", typeof(string), typeof(MyControlTemplate), default(string));
public string ButtonText
{
get => ((string)GetValue(ButtonTextProperty));
set => SetValue(ButtonTextProperty, value);
}
public static readonly BindableProperty ButtonCommandProperty =
BindableProperty.Create("ButtonCommand", typeof(ICommand), typeof(MyControlTemplate), null, BindingMode.Default, null);
public ICommand ButtonCommand
{
get => (ICommand)GetValue(ButtonCommandProperty);
set
{
SetValue(ButtonCommandProperty, value);
}
}
public static readonly BindableProperty CommandParameterProperty =
BindableProperty.Create("CommandParameter", typeof(object), typeof(MyControlTemplate), null);
public object CommandParameter
{
get => (object)GetValue(CommandParameterProperty);
set => SetValue(CommandParameterProperty, value);
}
public MyControlTemplate()
{
InitializeComponent();
}
private void Button_Clicked(object sender, EventArgs e)
{
ButtonClick?.Invoke(sender, e);
}
}
}
Now you could add it to any page and binding Text , Command or CommandParameter in code behind .
<StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<local:MyControlTemplate ButtonText="{Binding ButtonText}" ButtonCommand="{Binding ClickCommand}" CommandParameter="test" />
</StackLayout>

How to detect clickable label position inside listview xamarin forms

I'm trying to do something like this
Like This
I have Listview with clicked label " Edit " I want when i click this label it's position is detected and display
label at Aliaddress is clicked
I Used TapGestureRecognizer for this but when i google it i fount that selected item doesn't work with TapGesture
This is my xaml
<ListView ItemsSource="{Binding UserAdresses}" SelectedItem="{Binding SelectedAddress}" HorizontalOptions="{Binding HoriRLLR}" RowHeight="{Binding RowHeight}" VerticalOptions="FillAndExpand">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout VerticalOptions="FillAndExpand">
<Label Text="{Binding Country}" TextColor="Orange" FontSize="Large" FontAttributes="Bold"></Label>
<Label Text="{Binding Address}" TextColor="Black" FontSize="Medium"></Label>
<Label Text="{Binding City}" TextColor="Black" FontSize="Medium"></Label>
<Label Text="{translator:Translate Edit}" TextColor="Black" FontSize="Medium">
<Label.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Path=BindingContext.EditAddressesCommand, Source={x:Reference CustomerAdressesPage}}"/>
</Label.GestureRecognizers>
<Label.Effects>
<controls:UnderlineEffect></controls:UnderlineEffect>
</Label.Effects>
</Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
my code
public DelegateCommand EditAddressesCommand => new DelegateCommand(EditAddresses);
public DelegateCommand DeleteAddressesCommand => new DelegateCommand(DeleteAddresses);
private readonly IPageDialogService _dialogService;
private ObservableCollection<CustomerAdressesModel> _userAdresses;
public ObservableCollection<CustomerAdressesModel> UserAdresses
{
get { return _userAdresses; }
set { SetProperty(ref _userAdresses, value);
}
}
private CustomerAdressesModel _selectedAddress;
public CustomerAdressesModel SelectedAddress
{
get { return _selectedAddress; }
set { SetProperty(ref _selectedAddress, value); }
}
private void EditAddresses()
{
_dialogService.DisplayAlertAsync("Test", "Edit Clicked", "Ok");
}
How can i do this and detect the position of clicked label
You can use this: CommandParameter="{Binding .}" inside TapGestureRecognizer
Xaml:
<Label.GestureRecognizers>
<TapGestureRecognizer
CommandParameter="{Binding .}"
Command="{Binding Path=BindingContext.EditAddressesCommand, Source={x:Reference CustomerAdressesPage}}"/>
</Label.GestureRecognizers>
ViewModel:
public ICommand EditAddressesCommand
{
get
{
return new Command<YourModel>((YourModel model) =>
{
//Access your model properties
});
}
}
Hope this may solve your problem.

Content view binding not working

I have ContentView which need ViewModel binding
Test.xaml
<ContentView.Content>
<Frame x:Name="HelpBaseFrame" BackgroundColor="White" CornerRadius="16" HorizontalOptions="Fill" VerticalOptions="Center">
<StackLayout>
<ListView HasUnevenRows="True" x:Name="lstview" SeparatorColor="White">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell IsEnabled="False">
<ScrollView x:Name="ScrollView" Orientation="Vertical" Padding="0, 1, 0, 0" BackgroundColor="Transparent" HorizontalOptions="Center">
<StackLayout>
<Label x:Name="LabelHeader" FontAttributes="Bold" Font="HiraginoSans-W6, 16"
HorizontalOptions="Center" Margin="0,20,0,0">
<Label.Text>
<Binding Path="HeaderData"></Binding>
</Label.Text>
</Label>
<local:LineSpacingLabel x:Name="LabelHeaderDesceiption" LineSpacing="6"
Font="HiraginoSans-W3, 16" FontAttributes="None" Margin="0,20,0,0">
<Label.Text>
<Binding Path="DescriptionData"></Binding>
</Label.Text>
</local:LineSpacingLabel>
</StackLayout>
</ScrollView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</Frame>
</ContentView.Content>
BindingClass
public void SetData(Dictionary<string, string> dictionary)
{
............
lstview.ItemsSource = HelpDataList; // HelpDataList is observable collection of HElp Data
}
Model class :
public class HelpData : BaseViewModel
{
private string Header = string.Empty;
private string Description = string.Empty;
public string HeaderData
{
get { return Header; }
set
{
Header = value;
OnPropertyChanged("HeaderData");
}
}
public string DescriptionData { get; set; }
}
This view model for above view.
This binding is not working.
Is anything wrong?
This view model for above view.
This binding is not working.
Is anything wrong?
This view model for above view.
This binding is not working.
Is anything wrong?
You have to set bindingContext on the target control by using x:Reference markup extension.
BindingContext="{x:Reference Name=ViewModelField}"
Or
BindingContext="{x:Reference ViewModelField}"
Label.Text should be binding with string not viewModel.
Text="{Binding Path=Value}"
Or
Text="{Binding Value}" ( “Path=” part of the markup extension can be omitted if the path is the first item in the Binding markup extension)
Refer to Bindings
Update
<Binding> is not a valid tag.
Modify the label :
<Label Text="{Binding Path = HeaderData}">