Xamarin forms save switch change to sqlite - c#

I am new to xamarin and I am stuck with a problem.
I am making a todo app, where in the listview where you see the items you could set the task to done with a switch. The switch currently displays the saved value, so it is bound to the value from the database, but I can not see how to save the state if it gets changed.
As I see somehow I need to get the object from the switch, I appreciate the help.
<ListView x:Name="MainListView"
ItemSelected="MainListView_OnItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Content}"></Label>
<Switch IsToggled="{Binding Done}" HorizontalOptions="EndAndExpand"></Switch>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This is my custom ViewcCel where the value is bound.
public ToDoItem() { }
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Content { get; set; }
public string PicturePath { get; set; }
public bool Done { get; set; }
This is the Entity.
The list is on the main page, with the page in the code behind i do other stuff, just in case here is the code https://github.com/benonymus/ToDoApp3

You can have:
<Switch x:Name="my_switch" Toggled="Switch_Toggled" />
and in page:
public MyPage()
{
my_switch.IsToggled = Done;
}
private void Switch_Toggled(object sender, ToggledEventArgs e)
{
Done = my_switch.IsToggled;
}
Edit:
You can also try:
<Switch IsToggled="{Binding Done, Mode=TwoWay}" />

Related

MAUI: ListView Binding With Custom ViewCell

I use FreshMvvm to develop and run MAUI project on Windows.
But I have some binding issues with ListView and my custom template.
The following is my code:
Model:
public class BaseModel
{
public string Code{ get; set; }
}
public class NameModel: BaseModel
{
public string Name{ get; set; }
}
ViewModel:
public class MainPageModel : FreshBasePageModel
{
private readonly IApiService _apiService;
private List<NameModel> _nameModelList;
public List<NameModel> NameModelList
{
get => _nameModelList;
private set
{
_nameModelList= value;
RaisePropertyChanged(nameof(NameModelList));
}
}
public MainPageModel(IApiService apiService)
{
_apiService = apiService;
}
protected override void ViewIsAppearing(object sender, EventArgs e)
{
base.ViewIsAppearing(sender, e);
Task.Run(() => GetNameData());
}
private async Task GetNameData()
{
var result = await _apiService.GetNameData();
NameModelList= result.GetRange(1, 10);
}
}
I create a list and use an api service to get a name model list data.
If api service gets the data, NameModelList will be updated.
NameModelList is the property which will be bind on Listview.ItemsSource
MainPage.xmal:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyNamespace.ViewCells.CustomListViewCell"
x:Class="MyNamespace.Pages.MainPage"
BackgroundColor="{DynamicResource SecondaryColor}">
<Grid RowSpacing="25"
RowDefinitions="Auto"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<ListView
x:Name="MyListView"
ItemsSource="{Binding NameModelList}"
Grid.Row="0"
WidthRequest="800"
HeightRequest="800"
BackgroundColor="Gray"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<ListView.ItemTemplate>
<DataTemplate>
<local:MyCustomViewCell/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</ContentPage>
Custom ViewCell (.xml):
<ViewCell xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyNamespace.ViewCells.CustomListViewCell.MyCustomViewCell">
<Grid RowSpacing="100" WidthRequest="100" HeightRequest="100">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100*" />
</Grid.ColumnDefinitions>
<StackLayout
GridLayout.Row="0"
GridLayout.Column="0">
<Label
Text="{Binding Code}"
FontSize="30"/>
<Label
Text="{Binding Name}"
FontSize="30"/>
</StackLayout>
</Grid>
</ViewCell>
Custom ViewCell (.cs)
public partial class MyCustomViewCell: ViewCell
{
public static readonly BindableProperty CodeProperty =
BindableProperty.Create("Code", typeof(string), typeof(MyCustomViewCell), "");
public string Code
{
get { return (string)GetValue(CodeProperty); }
set { SetValue(CodeProperty, value); }
}
public static readonly BindableProperty NameProperty =
BindableProperty.Create("Name", typeof(string), typeof(MyCustomViewCell), "");
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
}
I define a custom ViewCell files and put this ViewCell in the Listview of MainPage.
Now my question is my Listview can't show data successfully.
I'm sure that NameModelList has value and its count is more than 1.
But I can see nothing.
The output log has no error, and the breakpoints in MyCustomViewCell.cs are never triggered.
So I think I have some binding issues, but I can't find it out.
To get to the bottom of this I took your code and put it in a project so I could have a little play with it. You can find the repo here. Not to be rude here or anything, but might be a good idea for a next question to do that yourself, that will help speed things up :)
Anyway, the problem is much more subtle. Because you're using XAML for your layout, you'll have to call InitializeComponent in the constructor. So adding this to your MyCustomViewCell made it work:
public MyCustomViewCell()
{
InitializeComponent();
}

Xamarin Forms Get Object element on image click

I have a problem. I created a CollectionView from a List called: List<Set> Sets and in a Set I have a List called List<Picture> Pictures.
Here is what the classes look like:
public class Set
{
public int Id { get; set; }
public List<Picture> Pictures{ get; set; }
}
And the picture class looks like this:
public class Picture
{
public int Id { get; set; }
public string Name { get; set; }
}
Now in my XAML I added a click event on every image, because I need to know which image has been clicked. The problem is that I also need to know in which set the image click has been done, because an image can be in multiple sets.
Here is the XAML:
<CollectionView ItemsSource="{Binding Sets}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<ScrollView Orientation="Horizontal">
<StackLayout BindableLayout.ItemsSource="{Binding Pictures}" Orientation="Horizontal">
<BindableLayout.ItemTemplate>
<DataTemplate>
<ff:CachedImage Aspect="AspectFill" Source="{Binding imageSource}">
<ff:CachedImage.GestureRecognizers>
<TapGestureRecognizer Tapped="AlbumFoto_Clicked" />
</ff:CachedImage.GestureRecognizers>
</ff:CachedImage>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ScrollView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Now I already got this code:
private void AlbumFoto_Clicked(object sender, EventArgs e)
{
CachedImage image = (CachedImage)sender;
var setPicture = image.Source.BindingContext as Picture;
var ImageId = setPicture.Id;
var Pictureindex = 0;
foreach (var set in Sets.Where(set => Pictures.Picture.Any(p => p.Id == ImageId)))
{
Pictureindex = set.Pictures.Picture.FindIndex(p => p.Id == ImageId);
}
}
Now how can I get the Id from the set of clicked image?
Instead of using an click event, you should use Command and CommandParameter and use the BindingContext of the parent Collection
<CollectionView ItemsSource="{Binding Sets}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<ScrollView x:Name="ParentCollection" Orientation="Horizontal">
<StackLayout BindableLayout.ItemsSource="{Binding Pictures}" Orientation="Horizontal">
<BindableLayout.ItemTemplate>
<DataTemplate>
<ff:CachedImage Aspect="AspectFill" Source="{Binding imageSource}">
<ff:CachedImage.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ImageClickCommand}" CommandParameter="{Binding BindingContext.Id, Source={x:Reference Name=ParentCollection}}"/>
</ff:CachedImage.GestureRecognizers>
</ff:CachedImage>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ScrollView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
And in your ViewModel:
public Command<int> ImageClickCommand{ get; set; }
And in your ViewModel Constructor:
ImageClickCommand = new Command<int>((Id) =>
{
//Id -> id of the image
});
But if you still want to use the Clicked Event, i would sugest you do this change.
Add a new property to your Picture Class:
public class Picture
{
public int Id { get; set; }
public int SetId { get; set; }
public string Name { get; set; }
}
Assuming that you receive that Collection from a Service, you could iterate over it and set your SetId like this:
foreach (var item in Collection)
{
foreach (var picture in item.Pictures)
{
picture.SetId = item.Id
}
}
Now in your Clicked you should have access to both Picture Id and the respetive Set Id:
private void AlbumFoto_Clicked(object sender, EventArgs e)
{
CachedImage image = (CachedImage)sender;
var setPicture = image.Source.BindingContext as Picture;
var ImageId = setPicture.Id;
var SetId = setPicture.SetId;
//...
}

Retrieving ListView selected item value in Xamarin.Forms

I'm developing/learning XamarinForms. I'm using Web Api to get values and use them to populate a ListView. Now I want to get current values on ItemSelected and store them for later use, but I don't seem to work it out. I'm using the MVVM.
This is my ListView
<ListView x:Name="ProfileDetails" ItemsSource="{Binding Profiles}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Margin="20,0,0,0" Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Label Text="{Binding ProfileType}" VerticalTextAlignment="Center" HorizontalOptions="StartAndExpand" TextColor="LightGray"/>
<Label Text="{Binding ProfileChamber}" VerticalTextAlignment="Center" HorizontalOptions="StartAndExpand" TextColor="LightGray"/>
<Label Text="{Binding ProfileWidhtMM}" VerticalTextAlignment="Center" HorizontalOptions="StartAndExpand" TextColor="LightGray"/>
<Label Text="{Binding ProfilePrice}" VerticalTextAlignment="Center" HorizontalOptions="StartAndExpand" TextColor="LightGray"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This is the ViewModel
APIServices _apiServices = new APIServices();
private List<Profile> _profiles;
public List<Profile> Profiles
{
get { return _profiles; }
set
{
_profiles = value;
OnPropertyChanged();
}
}
public ICommand GetProfilesCommand
{
get
{
return new Command(async () =>
{
Profiles = await _apiServices.GetProfilesAsync(_accessToken);
});
}
}
And this is my API request
public async Task<List<Profile>> GetProfilesAsync(string accessToken)
{
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var json = await client.GetStringAsync(Constants.GetProfilesUrl);
var profiles = JsonConvert.DeserializeObject<List<Profile>>(json);
return profiles;
}
And this is the Model
public long Id { get; set; }
public string ProfileType { get; set; }
public int ProfileChamber { get; set; }
public int ProfileWidhtMM { get; set; }
public double ProfilePrice { get; set; }
Answer from Oluwasayo is correct but I see that you are using MVVM already so using this solution might be better for you, just in case if you want to keep your code-behind class clean and leave any mixing code-behind and ViewModel code for one functionality.
I don't know if you are using some MVVM framework or not, but there is a very nice and helpful behavior called EventToCommandBehavior you can use it to "translate" any event and bind it to a command in your ViewModel.
You can find implementation of it here on GitHub, you can easly include it in your project. There is a lot of other implementations from MVVM frameworks.
Steps to make this in the way I advice you are:
Include that class in your project and you can use it in xaml pages.
Edit VM code and add some aditional lines of code.
ViewModel code:
// Property for binding SelectedItem from ListView.
private Profile _selectedProfile;
public Profile SelectedProfile
{
get { return _profiles; }
set
{
_selectedProfile= value;
OnPropertyChanged();
}
}
// Command which we will use for Event to Command binding.
public DelegateCommand ItemTappedCommand{ get; private set; }
// ...
// Code inside of the ctor in VM:
ItemTappedCommand = new Command(ItemTapped);
// ...
// Method which will be executed using our command
void ItemTapped()
{
// Here you can do whatever you want, this will be executed when
// user clicks on item in ListView, you will have a value of tapped
// item in SlectedProfile property
}
Edit your XAML page code and add few code lines.
XAML Page:
<!-- In your page xaml header add xaml namespace to EventToCommandBehaviour class-->
xmlns:b="clr-namespace:Namespace.ToYour.EventToCommandBehaviourClass"
<ListView x:Name="ProfileDetails" ItemsSource="{Binding Profiles}"
SelectedItem={Binding SelectedProfile}>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Margin="20,0,0,0" Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Label Text="{Binding ProfileType}" VerticalTextAlignment="Center" HorizontalOptions="StartAndExpand" TextColor="LightGray"/>
<Label Text="{Binding ProfileChamber}" VerticalTextAlignment="Center" HorizontalOptions="StartAndExpand" TextColor="LightGray"/>
<Label Text="{Binding ProfileWidhtMM}" VerticalTextAlignment="Center" HorizontalOptions="StartAndExpand" TextColor="LightGray"/>
<Label Text="{Binding ProfilePrice}" VerticalTextAlignment="Center" HorizontalOptions="StartAndExpand" TextColor="LightGray"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Behaviors>
<b:EventToCommandBehavior EventName="ItemTapped"
Command="{Binding ItemTappedCommand}" />
</ListView.Behaviors>
</ListView>
Hope that this makes sense to you, using this approach your code-behind class will stay clean without mixing the code between vm and code-behind, just my tip for you.
Wishing you lots of luck with coding!
In your xaml add the ItemTapped property. Can be:
ItemTapped="ProfileDetails_Selected"
Then you should have the method handling the event in your code behind as:
private void ProfileDetails_Selected(object sender, ItemTappedEventArgs e)
{
var myItem = e.Item ...; //from here you can get your item and store for later use
}

Xamarin Forms + Azure Reading Column

I just dived in to Xamarin Forms and using Azure.
I am able to successfully call the row from the database but it's displaying something into the ListView instead of what I want it to display.
My codes:
private async void generateList()
{
var clientUsers = await App.MobileService.GetTable<iSoftTicket.Model.TblUser>().Where(u => u.uc_category == "Client").ToListAsync();
lvClient.ItemsSource = clientUsers;
}
I want it to display the column with Gulfden on it. Any help is appreciated.
Thanks.
You should create your ListView's ItemTemplate(e.g. ViewCell) and then add some label to display your data like:
<ListView x:Name="MyListView">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Admin}"/>
<Label Text="{Binding Tickets}"/>
<Label Text="{Binding Clients}"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I notice that you have set your listview's ItemSource, please make sure your model's property names is Corresponding to the Binding name in the XAML, you can refer to my sample in code behind:
ObservableCollection<MyModel> list = new ObservableCollection<MyModel>();
for (int i=0; i<10; i++)
{
list.Add(new MyModel { Admin = "admin" + i, Clients = "client", Tickets = "tickets" });
}
MyListView.ItemsSource = list;
public class MyModel
{
public string Admin { set; get; }
public string Tickets { get; set; }
public string Clients { get; set; }
}

How do you bind to a complex object in usercontrol.resources for Windows Phone 8.1 (C#)

I have searched the web for the last few days but can't seem to find something that I would have thought was quite a simple task. I would like to add a resource in my XAML page of my windows phone application which will reference a complex object but I can't find the correct method. Is this possible? Object is made up something similar to:
Public class ComplexClass
{
Public string name { get; set; }
Public int ID { get; set; }
Public observablecollection<SimpleClass> simpleObjects { get; set; }
Public addSimpleObject(SimpleClass newSimpleObject)
{
if (simpleObjects == null)
simpleObjects = new ObservableCollection<SimpleClass>();
simpleObjects.Add(newSimpleObject);
}
}
Public Class SimpleClass
{
Public String Name { get; set; }
Public String Disc { get; set; }
}
You could use MVVM do achieve this. There are already heaps of tutorials available that you can access to show you how to follow this design pattern, so I won't go into that.
Instead I'll just show you a simple way of getting the data to your view.
In the constructor of your UserControl (or Page or whatever), set up the DataContext to an instance of your ComplexClass:
ComplexClass complexClass;
public MyUserControl1()
{
complexClass = new ComplexClass();
complexClass.AddSimpleObject(new SimpleClass { Name = "Bob" });
this.DataContext = complexClass;
this.InitializeComponent();
}
Then in your XAML you can bind to it like this:
<StackPanel>
<!-- Binding to properties on ComplexClass -->
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding ID}" />
<ListView ItemsSource="{Binding SimpleObjects}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<!-- Binding to properties on SimpleClass -->
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding Disc}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
Without knowing specifics of your code, it's hard for me to suggest a method that is most suitable for you. I'd read up on MVVM and view models.

Categories

Resources