I made a ContentView with an Expander. I want to duplicate this Xaml code multiple times in an other Xaml file. But I want for each Expander a different Binding.
I linked this code (ContentView code):
<?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:expandable="clr-namespace:Expandable;assembly=ExpandableView"
x:Class="Hello.ExpandableView">
<ContentView.Content>
<expandable:ExpandableView Padding="5">
<expandable:ExpandableView.PrimaryView>
<Frame BackgroundColor="White" Padding="5" CornerRadius="10">
<StackLayout Orientation="Horizontal">
<Label x:Name="label" FontSize="16" TextColor="Black" FontAttributes="Bold" Padding="5" HorizontalTextAlignment="Start" HorizontalOptions="StartAndExpand"/>
<Image Source="arrow.png" WidthRequest="25" HeightRequest="25" Margin="5"/>
</StackLayout>
</Frame>
</expandable:ExpandableView.PrimaryView>
<expandable:ExpandableView.SecondaryViewTemplate>
<DataTemplate>
<Frame BackgroundColor="White" Padding="5" CornerRadius="10">
<Label Text="{Binding Tip1Uitleg}" FontSize="15" TextColor="Black" Padding="5"/>
</Frame>
</DataTemplate>
</expandable:ExpandableView.SecondaryViewTemplate>
</expandable:ExpandableView>
</ContentView.Content>
</ContentView>
namespace Hello
{
public partial class ExpandableView : ContentView
{
public static BindableProperty LabelProperty =
BindableProperty.Create(nameof(Label),
typeof(string),
typeof(ExpandableView),
propertyChanged: (b, o, n) => (b as ExpandableView).OnLabelChanged());
private void OnLabelChanged()
{
label.Text = Label; //label is the x:Name of your Label control in ExpandableView.xaml
}
public string Label
{
get => (string)GetValue(LabelProperty);
set => SetValue(LabelProperty, value);
}
}
}
To this code:
This works:
<local:ExpandableView Label="Hello"/>
But I want this. This does not work:
<?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:expandable="clr-namespace:Expandable;assembly=ExpandableView"
xmlns:local="clr-namespace:Hello"
x:Class="Hello.Health.HealthDetail"
Title="{Binding Name}">
<ContentPage.Content>
<ScrollView>
<StackLayout>
<Image Source="{Binding Image}"/>
<Label Text="{Binding Tip1Uitleg}" FontSize="15" TextColor="Black" Padding="10, 5, 10, 5"/>
<local:ExpandableView Label="{Binding Tip1}"/> //This is what it is all about
</StackLayout>
</ScrollView>
</ContentPage.Content>
</ContentPage>
CodeBehind:
namespace Hello.Health
{
public partial class HealthDetail : ContentPage
{
public HealthDetail(HealthStrings healthStrings)
{
if (healthStrings == null)
throw new ArgumentNullException();
BindingContext = healthStrings;
InitializeComponent();
}
}
}
How do I make this work? I have to make this above more dynamic, but I do not know how.
BTW This also works:
<Label Text="{Binding Tip1}" />
I am sorry for the unclear explanation, I hope someone can help me.
Thank you for your time :)
You should not bind to 'this' since you are using a BindableProperty. Instead you should update the Label.Text property when the value of the BindableProperty changes.
public static BindableProperty LabelProperty =
BindableProperty.Create(nameof(Label),
typeof(string),
typeof(ExpandableView),
propertyChanged:(b, o, n) => (b as ExpandableView).OnLabelChanged());
private void OnLabelChanged()
{
label.Text = Label; //label is the x:Name of your Label control in ExpandableView.xaml
}
public string Label
{
get => (string)GetValue(LabelProperty);
set => SetValue(LabelProperty, value);
}
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="YourProject.ExpandableView">
<Grid>
<Label x:Name="label"/>
</Grid>
</ContentView>
Normally, when you want to binding a value for binableproperty, you could try the code below:
ExpandableView: I make a simple contentview with the same binableproperty for you reference.
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamarinDemo.Pages.ExpandableView">
<ContentView.Content>
<StackLayout>
<Label Text="Hello"></Label>
<Label x:Name="label"></Label>
</StackLayout>
</ContentView.Content>
</ContentView>
Code behind:
public partial class ExpandableView : ContentView
{
public static BindableProperty LabelProperty =
BindableProperty.Create(nameof(Label),
typeof(string),
typeof(ExpandableView),
propertyChanged: (b, o, n) => (b as
ExpandableView).OnLabelChanged());
private void OnLabelChanged()
{
label.Text = Label; //label is the x:Name of your Label control in ExpandableView.xaml
}
public string Label
{
get => (string)GetValue(LabelProperty);
set => SetValue(LabelProperty, value);
}
public ExpandableView()
{
InitializeComponent();
}
}
Usage:
<ContentPage.Content>
<local:ExpandableView Label="{Binding str}"></local:ExpandableView>
</ContentPage.Content>
Code Behind:
public partial class Page1 : ContentPage
{
public string str { get; set; }
public Page1()
{
InitializeComponent();
str = "okay";
this.BindingContext = this;
}
}
Related
If you swipe several times on an already opening field, then after closing the swiped element will return to the position from which the last swipe was.
For example:
I upload project for replay problem: link
XAML Code:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TestSwipeView.MainPage">
<CollectionView x:Name="collectionView"
ItemsSource="{Binding TestSequence}">
<CollectionView.ItemTemplate>
<DataTemplate>
<SwipeView>
<SwipeView.LeftItems>
<SwipeItems>
<SwipeItem Text="F"
BackgroundColor="LightGreen"/>
<SwipeItem Text="D"
BackgroundColor="LightPink"/>
</SwipeItems>
</SwipeView.LeftItems>
<Grid BackgroundColor="White"
Padding="10">
<Label Text="{Binding .}"></Label>
</Grid>
</SwipeView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage>
Xaml.cs code:
namespace TestSwipeView
{
public partial class MainPage : ContentPage
{
public List<String> TestSequence { get; set; }
public MainPage()
{
TestSequence = new List<string>();
for (int i=0; i<10; i++)
{
TestSequence.Add(String.Format("Test {0}",i));
}
InitializeComponent();
this.BindingContext = this;
}
}
}
I tried to implement the package ZXing.Net.Mobile.Forms
this is my xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:zxing="clr-namespace:ZXing.Net.Mobile.Forms;assembly=ZXing.Net.Mobile.Forms"
Title="{Binding Title}">
<ContentPage.Content>
<StackLayout>
<Label x:Name="scanResultText" />
<zxing:ZXingScannerView
OnScanResult="ScanViewOnScanResult"/>
</StackLayout>
</ContentPage.Content>
and this my xaml.cs :
public partial class QRCodePage : ContentPage
{
public QRCodePage()
{
InitializeComponent();
BindingContext = new QRCodeViewModel();
}
public void ScanViewOnScanResult(Result result)
{
Device.BeginInvokeOnMainThread(async () =>
{
scanResultText.Text = result.Text;
});
}
}
On my device i visualize the fragment but it seems not scanning
Try adding the following code (IsScanning="True") to your xaml:
<StackLayout>
<Label x:Name="scanResultText" />
<zxing:ZXingScannerView IsScanning="True"
OnScanResult="ScanViewOnScanResult"/>
</StackLayout>
I am trying to create a little application using MVVM. I would like to open a second page that scan a QR code and then back the value of the QR code to the main page.
I have this code:
Main view:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="QRScannerXamarinForms.Views.MainPageView"
xmlns:zxing="clr-namespace:ZXing.Net.Mobile.Forms;assembly=ZXing.Net.Mobile.Forms"
xmlns:vm="clr-namespace:QRScannerXamarinForms.ViewModels">
<ContentPage.BindingContext>
<vm:MainPageViewModel/>
</ContentPage.BindingContext>
<StackLayout>
<Frame BackgroundColor="#2196F3" Padding="24" CornerRadius="0">
<Label Text="Barcode Sample" HorizontalTextAlignment="Center" TextColor="White" FontSize="36" />
</Frame>
<Button x:Name="ucBtnEscanear" Text="Escanear"
Command="{Binding EscanearCommand}"/>
</StackLayout>
</ContentPage>
Main view model:
private INavigationService _navigationService;
public ICommand EscanearCommand { get; private set; }
private void Escanear()
{
string miCodigoQr = _navigationService.AbrirPaginaEscaner();
}
Second view:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="QRScannerXamarinForms.Views.ScannerView"
xmlns:zxing="clr-namespace:ZXing.Net.Mobile.Forms;assembly=ZXing.Net.Mobile.Forms"
xmlns:vm="clr-namespace:QRScannerXamarinForms.ViewModels">
<ContentPage.BindingContext>
<vm:ScannerViewModel/>
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout>
<Frame BackgroundColor="#2196F3" Padding="24" CornerRadius="0">
<Label Text="Barcode Sample" HorizontalTextAlignment="Center" TextColor="White" FontSize="36" />
</Frame>
<Label x:Name="ucScanResultText" />
<zxing:ZXingScannerView x:Name="ucZXingScannerView" IsScanning="True" IsAnalyzing="True" Result="{Binding CodigoQr}" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
Second view model:
class ScannerViewModel : BaseViewModel
{
private string _codigoQr;
public string CodigoQr
{
get { return _codigoQr; }
set { _codigoQr = value; }
}
}
Interface to open pages:
namespace QRScannerXamarinForms.Services
{
interface INavigationService
{
string AbrirPaginaEscaner();
}
}
Implementation of the interface that allows navigation.
namespace QRScannerXamarinForms.Services
{
class ViewNavigationService : INavigationService
{
public string AbrirPaginaEscaner()
{
ScannerView miScannerView = new ScannerView();
ScannerViewModel miScannerViewModel = miScannerView.BindingContext as ScannerViewModel;
Application.Current.MainPage.Navigation.PushModalAsync(miScannerView);
return miScannerViewModel.CodigoQr;
}
}
}
But in the implementation of the interface, the second page is not shown. So this line doesn't work:
Application.Current.MainPage.Navigation.PushModalAsync(miScannerView);
How could I open from this class?
Thanks.
I have a custom view which will be used across many pages. I have a Close Button in the Custom View where I need to bind the CloseButton Command in my MainViewModel. Any help would be appreciated.
Here is my HeaderView.xaml.cs file
public partial class HeaderView : ContentView
{
public HeaderView ()
{
InitializeComponent ();
}
public static readonly BindableProperty CloseButtonClickedProperty = BindableProperty.Create(nameof(CloseButtonClick), typeof(ICommand), typeof(HeaderView), null);
public ICommand CloseButtonClick
{
get => (ICommand)GetValue(CloseButtonClickedProperty);
set => SetValue(CloseButtonClickedProperty, value);
}
}
Here is my close button code used in HeaderView.Xaml file
<?xml version="1.0" encoding="UTF-8" ?>
<ContentView
HeightRequest="65"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="NameSpace.Views.HeaderView" x:Name="headerView">
<Image x:Name="CloseButton" Source="ic_closewhite.png" WidthRequest="20" HeightRequest="20" VerticalOptions="CenterAndExpand" HorizontalOptions="EndAndExpand">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding CloseButtonClick, Source={x:Reference headerView}}" />
</Image.GestureRecognizers>
</Image>
</ContentView>
Here is where I am trying to use the command in my MainView.xaml.
<c:HeaderView CloseButtonClick ="{Binding CloseButtonClickCommand}"/>
But it throws an error:
You are doing correct but only one small thing missing that is the x:Name of the ContentView HeaderView.
Just include this line of code in Xaml of HeaderView.
x:Name="headerView"
Here is your modified Xaml:-
<?xml version="1.0" encoding="UTF-8" ?>
<ContentView
HeightRequest="65"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Name="headerView"
x:Class="NameSpace.Views.HeaderView" x:Name="headerView">
<Image x:Name="CloseButton" Source="ic_closewhite.png" WidthRequest="20" HeightRequest="20" VerticalOptions="CenterAndExpand" HorizontalOptions="EndAndExpand">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding CloseButtonClick, Source={x:Reference headerView}}" />
</Image.GestureRecognizers>
</Image>
</ContentView>
public static readonly BindableProperty CloseButtonClickedProperty = BindableProperty.Create(nameof(CloseButtonClick), typeof(ICommand), typeof(HeaderView), null);
the issue is on this line,as the error message said,
event found for 'CloseButtonClick', or mismatching type between value
and property
you should change CloseButtonClickedProperty to CloseButtonClickProperty .
public static readonly BindableProperty CloseButtonClickedProperty = BindableProperty.Create(nameof(CloseButtonClick), typeof(ICommand), typeof(HeaderView), null);
public ICommand CloseButtonClick
{
get => (ICommand)GetValue(CloseButtonClickedProperty);
set => SetValue(CloseButtonClickedProperty, value);
}
to
public static readonly BindableProperty CloseButtonClickProperty = BindableProperty.Create(nameof(CloseButtonClick), typeof(ICommand), typeof(HeaderView), null);
public ICommand CloseButtonClick
{
get => (ICommand)GetValue(CloseButtonClickProperty);
set => SetValue(CloseButtonClickProperty, value);
}
I have a custom control that I supply a List<string> parameter and it draws a box for each string as a label.
Here is a version that is working. Clicking 'Add Tab' adds one tab at a time for each click.
I want to change the code so the List is converted into a different type of object and that is what the control displays.
First I show the code that is working for the image above. Then I show a changed version of the code that I am unable to get working. Hopefully for anyone answering this question, seeing the before code that works and the after code that doesn't work, you can easily spot the issue.
MainPage.xaml
<?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:App7"
x:Class="App7.MainPage">
<StackLayout>
<BoxView HeightRequest="100" />
<local:CustomControl
SideTabs="{Binding MainNavigationTabs}"
/>
<Button Text="Add Tab" Command="{Binding AddTab}" />
</StackLayout>
</ContentPage>
MainPageModel.cs
public class MainPageModel : FreshBasePageModel
{
public MainPageModel() { }
public List<string> MainNavigationTabs { get; set; }
private int _index = 0;
public Command AddTab
{
get
{
return new Command(() =>
{
_index++;
var tabs = new List<string>();
for (var index = 1; index <= _index; index++)
{
tabs.Add($"Tab {index}");
}
MainNavigationTabs = tabs;
});
}
}
}
CustomControl.xaml
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App7.CustomControl"
BackgroundColor="Beige"
x:Name="this">
<ContentView.Content>
<StackLayout>
<StackLayout Orientation="Vertical"
BindableLayout.ItemsSource="{Binding Source={x:Reference this}, Path=SideTabs}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<ContentView WidthRequest="237"
Margin="0"
BackgroundColor="Blue"
Padding="10">
<Label Text="{Binding .}" TextColor="White" />
</ContentView>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</StackLayout>
</ContentView.Content>
</ContentView>
CustomControl.xaml.cs
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CustomControl : ContentView
{
public CustomControl()
{
InitializeComponent();
}
public static readonly BindableProperty SideTabsProperty = BindableProperty.Create(
propertyName: "SideTabs",
returnType: typeof(List<string>),
declaringType: typeof(CustomControl),
defaultBindingMode: BindingMode.OneWay,
defaultValue: new List<string>());
public List<string> SideTabs
{
get { return base.GetValue(SideTabsProperty) as List<string>; }
set { base.SetValue(SideTabsProperty, value); }
}
}
I changed the CustomControl to transform the List<string> to a List<SideTab> object and have the control bind to that. Here's the code...
CustomControl.xaml.cs
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CustomControl : ContentView
{
public CustomControl()
{
InitializeComponent();
}
public static readonly BindableProperty SideTabsProperty = BindableProperty.Create(
propertyName: "SideTabs",
returnType: typeof(List<string>),
declaringType: typeof(CustomControl),
defaultBindingMode: BindingMode.OneWay,
defaultValue: new List<string>());
public List<string> SideTabs
{
get
{
var tabs = new List<string>();
foreach (var tab in _SideTabs)
{
tabs.Add(tab.Text);
}
return tabs;
}
set
{
var tabs = new List<SideTab>();
foreach (var tab in value)
{
tabs.Add(new SideTab() { Text = tab });
}
_SideTabs = tabs;
}
}
public List<SideTab> _SideTabs
{
get { return base.GetValue(SideTabsProperty) as List<SideTab>; }
set { base.SetValue(SideTabsProperty, value); }
}
}
public class SideTab
{
public string Text { get; set; }
}
CustomControl.xaml
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App7.CustomControl"
BackgroundColor="Beige"
x:Name="this">
<ContentView.Content>
<StackLayout>
<StackLayout Orientation="Vertical"
BindableLayout.ItemsSource="{Binding Source={x:Reference this}, Path=_SideTabs}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<ContentView WidthRequest="237"
Margin="0"
BackgroundColor="Blue"
Padding="10">
<Label Text="{Binding Text}" TextColor="White" />
</ContentView>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</StackLayout>
</ContentView.Content>
</ContentView>
Notice the addition of a property _SideTabs. When SideTabs is set, it transforms the List<string> into a List<SideTab>.
How can I make this work? Here is the result from the above code changes...
Try like this,
public static readonly BindableProperty TabsListProperty = BindableProperty.Create(nameof(TabsList), typeof(List<TabItem>), typeof(ScrollableTabs), null, propertyChanged: (bindable, oldValue, newValue) =>
{
((ScrollableTabs)bindable).InitializeTabs();
});
private void InitializeTabs()
{
//Write your logic here
}
public List<TabItem> TabsList
{
get
{
return (List<TabItem>)GetValue(TabsListProperty);
}
set
{
SetValue(TabsListProperty, value);
}
}