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;
//...
}
Related
I'm looking to have a Select All checkbox that will update all the other checkboxes in the listview when it's selected or deselected but I can't find a way to make them update. I've tried a foreach statement, as well as a for statement in the ViewModel and to run the task when the Select All checkbox is changed, but they don't seem to update the UI. Any help is appreaciated!
view model:
public class SyncViewModel : BaseViewModel
{
public ObservableCollection<Company> CompaniesCollection { get; set; }
public ObservableCollection<WellGroup> WellGroupCollection { get; set; }
public ObservableCollection<Well> WellsCollection { get; set; }
public SyncViewModel()
{
Title = "Sync";
CompaniesCollection = new ObservableCollection<Company>();
WellGroupCollection = new ObservableCollection<WellGroup>();
WellsCollection = new ObservableCollection<Well>();
}
public async Task InitializeData()
{
var wellDataStore = new WellDataStore();
var companies = await wellDataStore.GetAllGroups();
if (companies != null)
{
CompaniesCollection.Clear();
foreach (var company in companies)
{
CompaniesCollection.Add(company);
}
}
}
public async Task SyncData()
{
IsBusy = true;
// load and process data
IsBusy = false;
}
}
}
xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:viewModel="clr-namespace:SiteVisits.ViewModels" xmlns:model="clr-namespace:SiteVisits.Models"
x:DataType="viewModel:SyncViewModel"
x:Class="SiteVisits.Views.Sync">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Sync" Clicked="Sync_Clicked" />
</ContentPage.ToolbarItems>
<StackLayout>
<ActivityIndicator
IsVisible="{Binding IsBusy}"
IsRunning="{Binding IsBusy}" />
<CheckBox x:Name="SelectAll" Color="Blue" CheckedChanged="CheckAll" />
<Label Text="Select All" FontSize="Large" VerticalOptions="Center"/>
<ListView x:Name="Companies"
ItemsSource="{Binding CompaniesCollection}"
SelectionMode="Single"
HasUnevenRows="True"
ItemTapped="Companies_Selection">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="10" x:DataType="model:Company">
<CheckBox x:Name="Name" Color="Blue" IsChecked="{Binding IsChecked}" />
<Label Text="{Binding Name}"
FontSize="Large"
VerticalOptions="Center"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
xaml.cs:
SyncViewModel viewModel;
public Sync(SyncViewModel viewModel)
{
InitializeComponent();
this.viewModel = viewModel;
BindingContext = this.viewModel;
}
protected override async void OnAppearing()
{
await viewModel.InitializeData();
}
async private void Sync_Clicked(object sender, EventArgs e)
{
await viewModel.SyncData();
}
private void Companies_Selection(object sender, ItemTappedEventArgs e)
{
if (e.Item != null)
{
var company = e.Item as Company;
company.IsChecked = !company.IsChecked;
}
}
Since you are using MVVM, I would use a binding for the checkbox
<CheckBox x:Name="SelectAll" Color="Blue" IsChecked="{Binding AllChecked}" />
So then you will need this bool property, something like this. So when the value changes, it updates all the collection
private bool _allChecked;
public bool AllChecked { get => _allChecked;
set
{
if (value != _allChecked)
{
UpdateCompaniesCollection(value);
OnPropertyChanged(nameof(AllChecked));
}
}
}
And then you will need the method to update the collection. One way would be
void UpdateCompaniesCollection(bool newValue)
{
for(int i = 0; i < CompaniesCollection.Count; i++)
{
var tempCompany = CompaniesCollection[i];
tempCompany.IsChecked = newValue;
CompaniesCollection[i] = tempCompany;
}
}
That should do the trick. This only will trigger the change of the elements inside the collection when the Checkbox is checked. But if you want to also the the other way round (if a item in unchecked, then deselect the allCheck), that would be more complicated.
I would like to select multiple images in my gallery and the selected image should display on my screen. I can already select multiple images but I don't know how can I display its preview? I'm using Xamarin.MediaGallery plugin to select the image files. I am also using MVVM Prism
This is the preview I want to create
Here is my view model
public class MainPageViewModel : ViewModelBase
{
private readonly IPageDialogService _pageDialogService;
public DelegateCommand UploadPhotoCommand { get; set; }
public MainPageViewModel(INavigationService navigationService, IPageDialogService pageDialogService)
: base(navigationService)
{
Title = "New Diary";
UploadPhotoCommand = new DelegateCommand(UploadPhotoAsync);
_pageDialogService = pageDialogService;
}
private ImageSource _selectedImage;
public ImageSource SelectedImage
{
get { return _selectedImage; }
set {SetProperty (ref _selectedImage, value); }
}
private async void UploadPhotoAsync()
{
var results = await MediaGallery.PickAsync(4, MediaFileType.Image);
if (results?.Files == null)
{
return;
}
foreach (var media in results.Files)
{
var fileName = media.NameWithoutExtension;
var extension = media.Extension;
var contentType = media.ContentType;
await _pageDialogService.DisplayAlertAsync(fileName, $"Extension: {extension}, Content-type: {contentType}", "OK");
}
}
}
here is my View
<StackLayout Margin="10">
<Frame HasShadow="True" CornerRadius="5">
<StackLayout>
<Label Text="Add Photo to site diary"
FontAttributes="Bold"/>
<StackLayout Orientation="Horizontal">
<Image HeightRequest="80"
WidthRequest="80"
Source="{Binding SelectedImage}"/>
</StackLayout>
<Button Text="Add a photo"
TextColor="White"
BackgroundColor="LawnGreen"
CornerRadius="5"
Command="{Binding UploadPhotoCommand}"/>
<StackLayout Orientation="Horizontal">
<Label Text="Include in photo gallery"/>
<CheckBox Color="LawnGreen"
HorizontalOptions="EndAndExpand"/>
</StackLayout>
</StackLayout>
</Frame>
</StackLayout>
I have an image button in my listview and I want to open google maps when press here is my code
private async void pin_Clicked(object sender, EventArgs e )
{
await Launcher.OpenAsync(this.BindingContext.ToString());
}
here is my XAML
<ListView ItemTapped="MTZ_ItemTapped" HasUnevenRows="True" ItemsSource="{Binding CL }" IsVisible="{Binding IsVisible}" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<StackLayout >
<ImageButton Source="pin4" IsVisible="{Binding NIsVisible}" Clicked="pin_Clicked"></ImageButton>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ListView>
here is my property
public class Person
{
public string CITY2 { get; set; }
}
public ObservableCollection<Person> CL { get; set; } = new ObservableCollection<Person>()
{
new Person() { CITY2="https://www.google.com/maps/search/?api=1&query=30.199097,31.137771"}
}
and here is the error
'Invalid URI: The format of the URI could not be determined.
so then where is the problem or what is the right code syntax?
thx :)
first, you don't need to specify a BindingContext on your ImageButton
<ImageButton Source="pin4" IsVisible="{Binding NIsVisible}" Clicked="pin_Clicked" />
then in your handler
var btn = (ImageButton)sender;
var item = (Person)btn.BindingContext;
await Launcher.OpenAsync(item.CITY2);
I have a list view with one item for this moment.
<ContentPage.Content>
<StackLayout>
<ListView x:Name="MyListView"
CachingStrategy="RecycleElement"
SelectionMode="Single">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Text}" Detail="{Binding Detail}" Something to identify item individually ??? />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Text="Commencer" VerticalOptions="End" HorizontalOptions="Center" Clicked="StartProcessButton"/>
</StackLayout>
</ContentPage.Content>
I want to get an id or name or something who can individually get this item in my viewModel.
For example If I have an id system on this item :
void Action() {
if (listView.itemSelected.id == 1) {
then ....
}
}
I'm looking for this kind of thing. I checked google but I didn't found something for me.
You could create a id property.
Contact.cs
public class Contacts
{
private int id;
public int Id
{
get { return id; }
set { id = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private string address;
public string Address
{
get { return address; }
set { address = value; }
}
private string image;
public string Image
{
get { return image; }
set { image = value; }
}
}
MainPage.xaml
<ListView
x:Name="ContactsList"
IsVisible="True"
ItemsSource="{Binding MyList}" ItemSelected="ContactsList_ItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Image
HeightRequest="50"
Source="{Binding Image}"
WidthRequest="50" />
<Label Text="{Binding Id}" />
<Label Text="{Binding Name}" />
<Label Text="{Binding Address}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
MainPage.xaml.cs
public partial class MainPage : ContentPage
{
private ObservableCollection<Contacts> myList;
public ObservableCollection<Contacts> MyList
{
get { return myList; }
set { myList = value; }
}
public MainPage()
{
InitializeComponent();
this.BindingContext = this;
MyList = new ObservableCollection<Contacts>();
for (int i = 1; i < 10; i++)
{
MyList.Add(new Contacts() { Id = i, Name = "Student" + i.ToString(), Address = "Address" + i.ToString(), Image = "usa.png" });
}
ContactsList.ItemsSource = MyList;
}
private void ContactsList_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var item = (Contacts)e.SelectedItem;
if (item.Id == 1)
{
//.......do something you want
DisplayAlert("Id", "the id of item is 1", "Cancel");
}
}
}
In the ContactsList_ItemSelected event, you could get the ID from the e.SelectedItem. I use DisplayAlert to show the result.
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}" />