I asked this before but no one could answer. Thanks in advance to the person who can help.
<Grid>
<ListView x:Name="lstOrder">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Text="{Binding OrderName}" Grid.Row="0" Grid.Column="0" HorizontalTextAlignment="Start" x:Name="lblName"/>
<Label Text="{Binding OrderCount}" Grid.Row="0" Grid.Column="1" HorizontalTextAlignment="Start" x:Name="lblStepperValue"/>
<Label Text="{Binding OrderDetail}" Grid.Row="1" Grid.Column="0" HorizontalTextAlignment="Start" x:Name="edtDetail"/>
<Label Text="{Binding OrderPrice}" Grid.Row="1" Grid.Column="1" HorizontalTextAlignment="Start" x:Name="lblPriceNormal"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button BackgroundColor="Red" VerticalOptions="End" Text="Sipariş ver" x:Name="giveOrder" Clicked="giveOrder_Clicked"/>
</Grid>
This way I have a simple list view. And data is sent from realmDB to this list view. I want to send the data sent from RealmDB to this list view to my Firebase database when the button is clicked.
I don't want to write data to listview via firebase.
What I want to do is print the data in listview to firebase.
This is like printing the text on a label to firebase. I want to print the data from listview to firebase.
This is my button's code block. So when I press this button, the data in listview will be written to firebase.
that is, it will send the data on the labels to firebase.
private async void giveOrder_Clicked(object sender, System.EventArgs e)
{
await firebaseHelper.AddDoner(lstOrder.**!I can't do this part!**);
}
Hopefully it's revealing enough.
Thanks :)
This is the part I wrote for firebase, I wonder if there could be a mistake here?
public class FirebaseHelper
{
readonly FirebaseClient firebase = new FirebaseClient("my firebase link");
public async Task<List<DonerModel>> GetAllDoners()
{
return (await firebase
.Child("Doners")
.OnceAsync<DonerModel>()).Select(item => new DonerModel
{
OrderList = item.Object.OrderList
}).ToList();
}
public async Task AddDoner( string lstOrder)
{
await firebase
.Child("Doners")
.PostAsync(new DonerModel() { OrderList = lstOrder});
}
}
enter image description here
To get the list of objects that have been bound to the ListView you can use the ItemSource property.
Another point to note is that if you need the exact type (Order in your example) you can do something like this
private async void giveOrder_Clicked(object sender, System.EventArgs e)
{
if(lstOrder.ItemsSource != null && lstOrder.ItemsSource is List<OrderRealm> orders)
{
//send orders to firebase
foreach(var order in orders)
{
await firebaseHelper.AddDoner(order.*field you want to add to firebase*);
}
}
}
Related
I am getting this runtime error saying that the CellView needs a View. I have not found anything on this so far, here on StackOverflow or on google, so I am in the total dark about what needs to be fixed.
I need to set up a list view with 2 sections. the first one is for the bikes that are in the database and the other section is for the ones that we detected but are not saved in the DB yet.
Both sections use the same UI (cell) and so I need to be able to have a sliding button (ContextAction MenuItem) in the first section and for the second section this action needs to be disabled/removed.
If it's not possible then I would need to have the action for the second section "Add" instead of "Forget".
This is why I created a subclass.
this is my code.
(edit: corections)
---- .xaml file ----
<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="EGrid18.Components.BikeSelectionCell"
x:Name="ThisCell">
<ViewCell.View>
<StackLayout>
<Grid ColumnSpacing="10"
BindingContext="{x:Reference ThisCell}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="32"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Text="{Binding BikeName}"
StyleClass="bikecellname"
Grid.Row="0"
Grid.Column="0"
VerticalOptions="Center"
HorizontalOptions="StartAndExpand"/>
<Image Source="{Binding Image}"
HeightRequest="16"
WidthRequest="16"
VerticalOptions="Center"
Aspect="AspectFit"
Grid.Column="1"
Grid.Row="0"/>
<Label Text="{Binding Distence, StringFormat='{0:F2} M'}"
Grid.Row="0"
Grid.Column="2"
VerticalOptions="Center"/>
</Grid>
</StackLayout>
</ViewCell.View>
</ViewCell>
---- .cs file ----
using System.Runtime.CompilerServices;
using System.Windows.Input;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace EGrid18.Components
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class BikeSelectionCell : ViewCell
{
public static BindableProperty BikeNameProperty =
BindableProperty.Create(nameof(BikeName), typeof(string), typeof(BikeSelectionCell), string.Empty);
public string BikeName
{
get => (string)GetValue(BikeNameProperty);
set => SetValue(BikeNameProperty, value);
}
public static BindableProperty ImageProperty =
BindableProperty.Create(nameof(Image), typeof(string), typeof(BikeSelectionCell), string.Empty);
public string Image
{
get => (string)GetValue(ImageProperty);
set => SetValue(ImageProperty, value);
}
public static BindableProperty DistenceProperty =
BindableProperty.Create(nameof(Distence), typeof(double), typeof(BikeSelectionCell), 0.0);
public double Distence
{
get => (double)GetValue(DistenceProperty);
set => SetValue(DistenceProperty, value);
}
public static readonly BindableProperty ForgetCommandProperty =
BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(BikeSelectionCell), null);
public ICommand ForgetCommand
{
get { return (ICommand)GetValue(ForgetCommandProperty); }
set { SetValue(ForgetCommandProperty, value); }
}
public Command OnForget => new Command(() => Execute(ForgetCommand));
// Helper method for invoking commands safely
public static void Execute(ICommand command)
{
if (command == null) return;
if (command.CanExecute(null))
{
command.Execute(null);
}
}
protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if(propertyName == nameof(Image))
{
this.ContextActions.Clear();
if (Image != "unknown")
{
this.ContextActions.Add(new MenuItem()
{
Text = "Forget",
Command = ForgetCommand,
CommandParameter = this
});
}
}
}
}
}
--- the .xaml file that consumes the CellView subclass ---
<?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:vm="clr-namespace:EGrid18.ViewModels"
xmlns:iOS="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
xmlns:components="clr-namespace:EGrid18.Components"
iOS:Page.UseSafeArea="True"
x:Class="EGrid18.Views.BikeSelectionPage"
Title="Bike Selection List">
<ContentPage.Resources>
<ResourceDictionary>
<vm:BikeListViewModel x:Key="vm"/>
<StyleSheet Source="/CSS/Styles.css"/>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.ToolbarItems>
<ToolbarItem x:Name="ScanButton" Text="Scan"
Command="{Binding Source={StaticResource vm}, Path=OnScanCommand}"
CommandParameter="{Binding Source={StaticResource vm}, Path=IsScanning}" />
</ContentPage.ToolbarItems>
<ContentPage.Content>
<StackLayout Margin="8,8,8,8">
<Label Text="Bike Selection Page"
StyleClass="titlelabel"/>
<ListView x:Name="ListView"
BindingContext="{StaticResource vm}"
StyleClass="listview"
ItemsSource="{Binding BikeList}"
IsGroupingEnabled="True"
SelectedItem="{Binding SelectedBike}"
Margin="8,8,8,8">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Heading}"
VerticalOptions="Center"
Margin="8,8,8,8"/>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<components:BikeSelectionCell
BikeName="{Binding Name}"
Image="{Binding Image}"
Distence="{Binding Distence}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
A ViewCell is not a View - it isn't part of View heirarchy. It is a "wrapper" that is needed by ListView, around each item.
Personally, I never create subclasses of ViewCell, though that can be done.
IMHO, Its more straightforward to make a custom View, then wrap that in <ViewCell> to use with ListView.
As a View, you can inherit from any view class. If you don't know what else to use, inherit from ContentView. (Or from StackLayout, if need to add multiple children views.) In your case, your View is a StackLayout.
public partial class BikeSelectionView : StackLayout
... // All the lines of code you have in BikeSelectionCell go here.
xaml:
<StackLayout ... x:Name="ThisCell">
<Grid ColumnSpacing="10" ...>
... All the remaining lines of code from your xaml ...
</StackLayout>
Usage inside ListView's ItemTemplate:
<DataTemplate>
<ViewCell>
<components:BikeSelectionView
BikeName="{Binding Name}"
Image="{Binding Image}"
Distence="{Binding Distence}"/>
</ViewCell>
</DataTemplate>
One advantage of this approach is if you switch from ListView to CollectionView (which does not use ViewCells), you can still use the custom class:
<CollectionView.ItemTemplate>
<DataTemplate>
<components:BikeSelectionView ... />
</DataTemplate>
</CollectionView.ItemTemplate>
The error was coming from a missing constructor that needed to initialize the Component.
public BikeSelectionCell()
{
InitializeComponent();
}
In the end I used the suggestion ToolmakerSteve. I also used a custom DataTemplateSelector to set specifics DataTemplate for the 2 different sections
I am setting this as the answer for any one looking for this problem as the problem was really the missing call to InitializeComponent();
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.
I'm trying to call a function in a Xamarin project by using the SelectionChanged property.
Inside this property, I've called a function that I've declared in the cs file.
Here is the XAML code:
<CollectionView x:Name="PCCollection" SelectionMode="Single" SelectionChanged="Cell_Tapped" AutomationId="{Binding Tipologia_Alimento}">
Here is the CS function:
private async void Cell_Tapped(object sender, System.EventArgs e) {
Console.WriteLine("Tapped");
Console.WriteLine((sender as Cell).AutomationId.ToString());
}
When I click on the Collection View cell, it prints the value "Tapped" but it gives me also the Break Mode error: "The application is in break mode".
Could you help me with this error?
Thanks in advance.
Your syntax is not valid. The Collection View control does not have AutomationId property.
Sample
<CollectionView ItemsSource="{Binding Monkeys}"
SelectionChanged="Cell_Tapped"
SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
void Cell_Tapped(object sender, SelectionChangedEventArgs e)
{
if (((CollectionView)sender).SelectedItem == null)
return;
string current = (e.CurrentSelection.FirstOrDefault() as Monkey)?.Name;
}
You can find more here
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/collectionview/selection
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/collectionview/populate-data
Edit: apologies for the bad title, apparently something like "Setting bindingmode in code behind" didn't fit the highly nebulous requirements of SO. A title that is clearly more obvious than what the current one is.
Original: I am trying to set the binding of my listview in the code behind of its data selector template. The reason i am doing this, as I suspect (because doing something similar to it in a different template selector fixed it) that once you exit that page android seems to still contain a reference to it and then throws a amarin.forms.platform.android.viewcellrendererA disposed object exception.
my current xaml looks as follows:
<StackLayout Orientation="Vertical"
Padding="0, 20, 0, 0"
HorizontalOptions="FillAndExpand"
VerticalOptions="StartAndExpand">
<Label
x:Name="LabelName"
FontAttributes="Bold"
TextColor="Black"
FontSize="14"
VerticalOptions="Start"
HorizontalOptions="FillAndExpand"/>
<ListView x:Name="MultiselectList"
SeparatorVisibility="None"
RowHeight="30"
Margin="0, 10, 0, 0"
VerticalOptions="FillAndExpand"
HorizontalOptions="StartAndExpand"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<customcontrols:NoHighlightCell>
<StackLayout Orientation="Horizontal"
HorizontalOptions="FillAndExpand"
VerticalOptions="StartAndExpand">
<Image
x:Name="image"
Source="{Binding ImageUrl}"
VerticalOptions="StartAndExpand"
HorizontalOptions="Start"
Margin="0, 2, 0, 0"
WidthRequest="15"
HeightRequest="15" />
<Label
x:Name="name"
Text="{Binding Name}"
TextColor="Black"
VerticalOptions="StartAndExpand"
FontSize="14"
HorizontalOptions="Start"/>
</StackLayout>
</customcontrols:NoHighlightCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Label Text="Selection required"
TextColor="Red"
Margin="0, 10, 0, 0"
IsVisible="{Binding ValidationRequired}"
VerticalOptions="StartAndExpand"
HorizontalOptions="FillAndExpand"
FontSize="14"/>
</StackLayout>
Here's my code behind:
private SoapNoteControlsViewModel viewModel;
public SelectListTemplate()
{
InitializeComponent();
}
protected override void OnDisappearing()
{
base.OnDisappearing();
}
protected override void OnAppearing()
{
base.OnAppearing();
LabelName.Text = viewModel.Label;
MultiselectList.ItemsSource = viewModel.CheckboxItems;
MultiselectList.SelectedItem = viewModel.SelectedItem;
//how would i set the BindingMode here? Doing .SetBinding doesn't seem to do it.
}
protected override void OnBindingContextChanged()
{
try
{
base.OnBindingContextChanged();
if(BindingContext == null)
{
return;
}
viewModel = BindingContext as SoapNoteControlsViewModel;
} catch (Exception e)
{
Console.WriteLine(e);
}
}
}
I tried doing .SetBinding, but it keeps saying that BindingMode is a type (given that it is an enum). Looking at some of the examples on MSDN haven't really helped
You would do it like this:
MultiselectList.SetBinding(ListView.ItemsSourceProperty, nameof(viewModels.CheckboxItems), BindingMode.TwoWay);
The first parameter is the property that you want to bind to - e.g. the ItemsSource.
The second parameter is the name of the property to look for - e.g. your viewModel's CheckBoxItems. This collection will be bound/populated in the list.
The last parameter is what you would want to achieve - the BindingMode. You are correct in saying that it is an enum, so here we can set it to BindingMode.TwoWay.
For reference: BindingMode's Remarks page.
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"));
}