At the moment I am programming an application based on Xamarin. My goal is to toggle the switch based on values in a table. Problem is, Xamarin is not noticing my x:Name toggle_true connected to my switch.
Here is my script in xaml:
<ListView x:Name="defineBuildingItems">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<StackLayout Orientation="Vertical">
<Label Text="{Binding defineDescription}" x:Name="Current_item"/>
</StackLayout>
<Switch BindingContext ="{Binding defineId}" HorizontalOptions="EndAndExpand"
Toggled="Handle_Toggled" x:Name="toggled_true"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Here is my c# code in code behind:
var currentQuestions = _define.Where(s => DefineId.Contains(s.defineId));
//Remember what building was defined like last time defineBuilding was proceeded.
foreach (DefineTable i in currentQuestions)
{
toggled_true.IsToggled = true;
}
defineBuildingItems.ItemsSource = posts;
base.OnAppearing();
}
Notice how it recognizes the x:Name defineBuildingItems. The error i get on toggled_true is: The name toggled_true does not exist in the current namespace. Is there something I am doing wrong or missing?
Access to control by name inside datatemplate not working. You must using binding. This is simply example:
Model:
public class Data
{
public bool IsToggled {get;set;}
....
}
Code behind:
public YourPage
{
BindingContext = this;
}
....
private List<Data> _items;
public List<Data> Items
{
get { return _items;}
set
{
_items = value;
OnPropertyChanged();
}
}
Your xaml:
<ListView x:Name="defineBuildingItems" ItemSources={Binding Items}>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<StackLayout Orientation="Vertical">
<Label Text="{Binding defineDescription}" />
</StackLayout>
<Switch IsToggled ="{Binding IsToggled, Mode =TwoWay}" HorizontalOptions="EndAndExpand" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Related
I have a CollectionView which has 1 Frame inside, and the backgroundcolor of the Frame would change bases on the string value of the variable "GetColor" that collects string data from each object of Database, but the backgroundcolor of the Frame remains as "Red" all the time.
#CollectionView
<CollectionView Margin="5" ItemsSource="{Binding ListGroupData}"
ItemsUpdatingScrollMode="KeepLastItemInView" ItemTemplate="{StaticResource
GroupDataTemplateSelector}" VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"/>
<ResourceDictionary>
<DataTemplate x:Key="RedTemplate">
<StackLayout>
<Frame HasShadow="False" Padding="10" HorizontalOptions="StartAndExpand"
BackgroundColor="Red"
CornerRadius="15">
<Label Text="{Binding Name}" TextColor="Black"/>
</Frame>
</StackLayout>
</DataTemplate>
<DataTemplate x:Key="GreenTemplate">
<StackLayout>
<Frame HasShadow="False" Padding="10" HorizontalOptions="EndAndExpand"
BackgroundColor="Green"
CornerRadius="15">
<Label Text="{Binding Name}" TextColor="Black"/>
</Frame>
</StackLayout>
</DataTemplate>
<Local:GroupDataViewModel x:Key="GroupDataTemplateSelector" RedTemplate="
{StaticResource
RedTemplate}" GreenTemplate="{StaticResource GreenTemplate}"/>
</ResourceDictionary>
#TemplateSelector Code
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
if (GetColor == "Red")
return RedTemplate;
else
return GreenTemplate;
}
public DataTemplate RedTemplate { get; set; }
public DataTemplate GreenTemplate { get; set; }
#Public Variable
public string GetColor;
public ObservableCollection<GroupData> ListGroupData = new ObservableCollection<GroupData>();
#Supported Code
FirebaseClient fc = new FirebaseClient("...");
var result = await fc.Child("GroupData").OnceAsync<GroupData>();
foreach (var item in result)
{
GetColor = item.Object.Color;
ListGroupData.Add(item.Object);
}
///this part the item that is being added to the ListGroupData(CollectionView) suppose to
have different backgroundcolor bases on its data
You dont need the public property GetColor. Because that property gets evaluated for every object in the collection, not in the viewmodel.
You will need to modify your Template selector
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
//Your list is a list of GroupData. then you will need to cast item to the type of your object
var targetColor = (GroupData)item.Color;
if (targetColor == "Red") //this if the item.Color is String
return RedTemplate;
else
return GreenTemplate;
}
PD:
Or if your item.Color is a Color type, you can just use it inside the CollectionView.ItemTemplate to colour your Frame.You just have to add a binding to that property. (and you can delete all the TemplateSelector code)
If your item.Color is not a Color type, you will have to add a Converter (you will have to code it), to transform the value into a Color.
<CollectionView Margin="5"
ItemsSource="{Binding ListGroupData}"
ItemsUpdatingScrollMode="KeepLastItemInView"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame HasShadow="False"
Padding="10"
HorizontalOptions="EndAndExpand"
BackgroundColor="{Binding Color}"
CornerRadius="15">
<Label Text="{Binding Name}" TextColor="Black"/>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
I am using ToolKits Expander and I am trying to bind a command, this is what I got so far:
public partial class AssignTaskPage : ContentPage
{
public AssignTaskPage()
{
InitializeComponent();
GetMathSubCatgories = new Command(() => MathSubCatgoriesCommand());
}
public ICommand GetMathSubCatgories { get; private set; }
void MathSubCatgoriesCommand()
{
Console.Write("Here");
}
}
And in my view
<xct:Expander Command="{Binding GetMathSubCatgories}">
<xct:Expander.Header>
<Frame Padding="10" Margin="10" HasShadow="False" BorderColor="LightGray" VerticalOptions="CenterAndExpand">
<StackLayout Orientation="Horizontal">
<Image Source="{Binding icon}" WidthRequest="25" HeightRequest="25"></Image>
<Label Text="{Binding name}" TextColor="{Binding textColor}" FontSize="Large" FontAttributes="Bold" HeightRequest="35" VerticalOptions="CenterAndExpand"></Label>
</StackLayout>
</Frame>
</xct:Expander.Header>
<Grid Padding="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ListView x:Name="SubCategories" ItemsSource="{Binding subCategories}" ItemSelected="SubCategories_ItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding name}" TextColor="#02cc9d" FontAttributes="Bold" HeightRequest="35" VerticalOptions="CenterAndExpand"></Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</xct:Expander>
This does not work at all, (I put a break point on Console.Write("Here"); and its not hitting it)
So I did some digging and found this tutorial:
https://www.syncfusion.com/kb/12154/how-to-bind-command-to-expander-in-itemtemplate-of-xamarin-forms-listview-sflistview
and here is the sample in git.
https://github.com/SyncfusionExamples/command-to-expander-in-itemtemplate-listview-xamarin
I understand what I have to do here, the problem I am facing is when this Command is called, I was looking to get a value and use it in my AssignTaskPage, but what the tutorial is saying to have a ViewModel which is in a separate file. So should I setup a MessagingCenter in my AssignTaskPage and call it in the ViewModel to get the value I want and pass it to AssignTaskPage?
Because your command isn't defined in the ViewModel that you're binding to.You could bind the command which is defined in your AssignTaskPage,and then bind the viewmodel for the parent element of the expander.
For example :
public partial class AssignTaskPage : ContentPage
{
public AssignTaskPage()
{
InitializeComponent();
GetMathSubCatgories = new Command(() => MathSubCatgoriesCommand());
BindingContext = this;
}
public ICommand GetMathSubCatgories { get; private set; }
void MathSubCatgoriesCommand(object obj)
{
DisplayAlert("Alert!", "" + (obj as Contact).ContactName + "expanded", "Ok");
}
}
the xaml (here use the xaml codes of the above sample),the grid bind the viewmodel,and your expander bind the command of the root (your page):
<?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:ExpanderXamarin"
x:Class="ExpanderXamarin.ExpandableListView"
x:Name="root"
xmlns:sflistview="clr-namespace:Syncfusion.ListView.XForms;assembly=Syncfusion.SfListView.XForms"
xmlns:expander="clr-namespace:Syncfusion.XForms.Expander;assembly=Syncfusion.Expander.XForms">
<ContentPage.Content>
<Grid x:Name="mainGrid" BackgroundColor="#F0F0F0" Padding="4">
<Grid.BindingContext>
<local:ViewModel />
</Grid.BindingContext>
<sflistview:SfListView x:Name="listView" AutoFitMode="DynamicHeight" ItemsSource="{Binding ContactsInfo}">
<sflistview:SfListView.ItemTemplate>
<DataTemplate>
<Frame x:Name="frame" CornerRadius="2" Padding="{OnPlatform Android=1, iOS=1, UWP=0}" Margin="{OnPlatform Android=1, iOS=1, UWP=0}" OutlineColor="White" HasShadow="{OnPlatform Android=true, iOS=false, UWP=true}">
<Grid Padding="{OnPlatform Android=2, iOS=2, UWP=0}" Margin="{OnPlatform Android=1, iOS=1, UWP=0}" BackgroundColor="White" >
<expander:SfExpander x:Name="expander" HeaderIconPosition="None">
<expander:SfExpander.Behaviors>
<local:EventToCommandBehavior Command="{Binding Path=BindingContext.GetMathSubCatgories, Source={x:Reference root}}" EventName="Expanding" CommandParameter="{Binding .}"/>
</expander:SfExpander.Behaviors>
<expander:SfExpander.Header>
...
</expander:SfExpander.Header>
<expander:SfExpander.Content>
..
</expander:SfExpander.Content>
</expander:SfExpander>
</Grid>
</Frame>
</DataTemplate>
</sflistview:SfListView.ItemTemplate>
</sflistview:SfListView>
</Grid>
</ContentPage.Content>
</ContentPage>
if you want get the parameters you could bind the CommandParameter like above.
I am having a page(MyPage) and Corresponding view Model(MypageViewModel). I have another view model called(listItemLogicVM) and its declared as observable collection in MypageViewModel.
MyPage XAML
<ListView x:Name="lstvwItemSelected" ItemsSource="{Binding
LstlistItemLogicVM}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<StackLayout>
<Entry Text="{Binding RequestingQty,Mode=TwoWay}"/>
<Image Source="ArrowUp.png"><Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding QtyDecrementCommand}"/>
</Image.GestureRecognizers>
</Image>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
MypageViewModel
public class MypageViewModel
{
ObservableCollection<listItemLogicVM> lstvwItemSelected = new ObservableCollection<listItemLogicVM>()
.
-- OtherLogics
.
}
listItemLogicVM
public class listItemLogicVM
{
public Command QtyDecrementCommand { get; set; }
public int RequestingQty
{
get { return _requestingQty; }
set { _requestingQty = value; OnPropertyChanged();}
}
}
Above Binding throws error. Can anyone help me to bind the command and property of listItemLogicVM to the list view in MyPage XAML
It looks to me like your listview XAML is incorrect. Try this (note the only changes are to the x:Name and ItemsSource attribute of your ListView):
<ListView x:Name="myUniqueListName" ItemsSource="{Binding
lstvwItemSelected}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<StackLayout>
<Entry Text="{Binding RequestingQty,Mode=TwoWay}"/>
<Image Source="ArrowUp.png"><Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding QtyDecrementCommand}"/>
</Image.GestureRecognizers>
</Image>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
That should call the QtyDecrementCommand on the item that is tapped in the list. This assumes that you've correctly assigned some code to that command for each item in the list.
You need to add command in your MypageViewModel and your xaml code look like :
<TapGestureRecognizer Command="{Binding Source={x:Reference lstvwItemSelected}, Path=BindingContext.QtyDecrementCommand}"/>
</Image.GestureRecognizers>
I am using Prism in my Xamarin forms app, I have a ListView where each Listitem has 2 images, an edit image and delete image.
I have usedTapGesturesRecognizers on these 2 images, and binded _DelegateCommands for these TapGestureRecognizers. However these DelegateCommands do not get called.
Thanks in advance
This is my XAML code
<ListView x:Name="lstAddress" HasUnevenRows="True" SeparatorVisibility="None" ItemsSource="{Binding ListItems}" CachingStrategy="RecycleElement" >
<ListView.Behaviors>
<b:EventToCommandBehavior EventName="ItemTapped"
Command="{Binding ListItemSelectCommand}" EventArgsParameterPath="Item"/>
</ListView.Behaviors>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Description}" FontSize="15" TextColor="#959595">
</Label>
<Image Source="Edit.png" HeightRequest="50" WidthRequest="50" IsVisible="{Binding ShowEdit}">
<Image.GestureRecognizers>
<TapGestureRecognizer Command ="{Binding EditAddressCommand}"></TapGestureRecognizer>
</Image.GestureRecognizers>
</Image>
<Image Source="Delete.png" ClassId="{Binding ListID}" HeightRequest="30" WidthRequest="30" IsVisible="{Binding ShowIcon}">
<Image.GestureRecognizers>
<TapGestureRecognizer Command ="{Binding DeleteAddressCommand}"></TapGestureRecognizer>
</Image.GestureRecognizers>
</Image>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
In my ViewModel:
public class AddressBookViewModel : BindableBase
{
INavigationService _navigationService;
public DelegateCommand EditAddressCommand { get; set; }
public DelegateCommand DeleteAddressCommand { get; set; }
public ObservableCollection<ListModel> ListItems {get;set;} = new ObservableCollection<ListModel>();
public DelegateCommand<ListModel> ListItemSelectCommand { get; set; }
public MyZypListsViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
EditAddressCommand = new DelegateCommand(EditAddress);
DeleteAddressCommand = new DelegateCommand(DeleteAddress);
ListItemSelectCommand = new DelegateCommand<ListModel>(ListItemSelected);
}
private void EditAddress()
{
//Edit listitem
}
private void DeleteAddress()
{
//Delete listitem
}
}
For each item on your list, your BindingContext is not the same as the ListView's BindingContext. Locally your BindingContext is the item itself, this is why you can obtain the 'Description' property, for example. Xamarin is searching for an ICommand called EditAddressCommand in your item, not in your view model.
You can make a Cross Binding reference if you want... Just replace your commands at item template to this way:
Command ="{Binding BindingContext.EditAddressCommand, Source={x:Reference lstAddress}"
It may work.
I started to learn Xamarin, and i am trying to create first test project. I created the ListView which displays the ObservableCollection from BindingContext. "Take" is a table that has three properties. The problem is, that when i run app on emulator the following eror dialog appears:"Process system isn't responding. Do you want to close it?"
But if i erase tag and all internal XAML code everything works well, but i want to dispalay values of properties of class "Take" in each element of ListView.
<?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="App1.Views.Page1">
<ContentPage.Content>
<StackLayout>
<Label Text="Welcome to my first project"></Label>
<Label Text="Why does it does not work?"></Label>
<ListView ItemsSource="{Binding GetList}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Word}"></TextCell>
<Button Text="SomeText"></Button>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
And this is my C# BindingContext
public class SQLiteSamplePage
{
private readonly SQLiteConnection _sqLiteConnection;
private ObservableCollection<Take> list;
public SQLiteSamplePage()
{
_sqLiteConnection = DependencyService.Get<ISQLite>().GetConnection();
_sqLiteConnection.CreateTable<Take>();
_sqLiteConnection.Insert(new Take
{
Word = "SomeWord1",
Translation = "Some translation 1"
});
_sqLiteConnection.Insert(new Take
{
Word = "SomeWord",
Translation = "SomeTranslation"
});
list =new ObservableCollection<Take>( _sqLiteConnection.Table<Take>());
}
public ObservableCollection<Take> GetList
{
get { return list; }
}
}
And here is a code of a table
public class Table
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string Word { get; set; }
public string Translation { get; set; }
}
Try to put the TextCell and the Button in a StackLayout or any kind of layout inside a <ViewCell> element:
<ListView ItemsSource="{Binding GetList}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<TextCell Text="{Binding Word}"></TextCell>
<Button Text="SomeText"></Button>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The child of the DataTemplate element must be of or derive from type ViewCell.
You cannot combine a TextCell and something else, in your case a Button. If you want to show both Text and the Button you will need to use a custom cell.
This is done using the base class ViewCell and inside there you define the layout you want to show
<StackLayout>
<Label Text="Welcome to my first project"></Label>
<Label Text="Why does it does not work?"></Label>
<ListView ItemsSource="{Binding GetList}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Word}"></Label>
<Button Text="SomeText"></Button>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
Hope this helps.