Xamarin Forms Bind Bool Based on Multiple Values - c#

I've implemented checkboxes in my Xamarin Forms App using the following article:
https://alexdunn.org/2018/04/10/xamarin-tip-build-your-own-checkbox-in-xamarin-forms/
I'm trying to use the new BindableLayout to build a list of title's (Mr, Mrs etc):
<StackLayout x:Name="parent"
Grid.Row="0"
Grid.ColumnSpan="2"
Orientation="Horizontal"
BindableLayout.ItemsSource="{Binding Titles}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout Orientation="Horizontal">
<control:CheckBoxView VerticalOptions="CenterAndExpand"
IsChecked="..."
CheckedCommand="{Binding BindingContext.CheckCommand, Source={x:Reference parent}}"
CheckedCommandParameter="{Binding Identifier}"
HorizontalOptions="Start"
OutlineColor="{Binding BindingContext.Campaign.CampaignProfile.EntryBackgroundColor, Source={x:Reference parent}}"
CheckedOutlineColor="{Binding BindingContext.Campaign.CampaignProfile.EntryTextColor, Source={x:Reference parent}}"
CheckColor="{Binding BindingContext.Campaign.CampaignProfile.EntryTextColor, Source={x:Reference parent}}">
</control:CheckBoxView>
<Label Margin="0, 0, 20, 0"
VerticalOptions="Center"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Start"
HorizontalOptions="FillAndExpand"
TextColor="{Binding BindingContext.Campaign.CampaignProfile.TextColor, Source={x:Reference parent}}"
FontSize="{Binding BindingContext.Campaign.CampaignProfile.TextSize, Source={x:Reference parent}}"
WidthRequest="150"
MinimumWidthRequest="100"
Text="{Binding Identifier}" />
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
The above code works almost as expected - I get a label and checkbox for each title in Titles. However I need a way to ensure that only one title is checked - this is what I can't get to work.
In the CheckCommand I set a property (SelectedTitle) to the Identifier of the set in CheckedCommandParameter - works fine, however I need some way to compare the value of Identifier and SelectedTitle.
I've been trying to get this working using an IValueConverter, however I can't bind a value to the CommandParameter, I've also tried DataTriggers, however that didn't work either.
Update:
This is with the DataTriggers - it feels like the CheckBoxView isn't setting the IsChecked property
<control:CheckBoxView VerticalOptions="CenterAndExpand"
IsChecked="False"
CheckedCommand="{Binding BindingContext.CheckCommand, Source={x:Reference parent}}"
CheckedCommandParameter="{Binding Identifier}"
HorizontalOptions="Start"
OutlineColor="{Binding BindingContext.Campaign.CampaignProfile.EntryBackgroundColor, Source={x:Reference parent}}"
CheckedOutlineColor="{Binding BindingContext.Campaign.CampaignProfile.EntryTextColor, Source={x:Reference parent}}"
CheckColor="{Binding BindingContext.Campaign.CampaignProfile.EntryTextColor, Source={x:Reference parent}}">
<control:CheckBoxView.Triggers>
<DataTrigger TargetType="control:CheckBoxView"
Binding="{Binding BindingContext.SelectedTitle, Source={x:Reference parent}}"
Value="{Binding Identifier}">
<Setter Property="IsChecked"
Value="True"/>
</DataTrigger>
</control:CheckBoxView.Triggers>

Over time I'd been adding more and more complexity to this, which is usually an indication you're going in the wrong direction. In the end this was solved using standard MVVM. I added a new class called Salutation:
public class Salutation : INotifyPropertyChanged
{
private string identifier = null;
private string name = null;
private bool selected = false;
public event PropertyChangedEventHandler PropertyChanged;
[JsonProperty(PropertyName = "identifier", NullValueHandling = NullValueHandling.Ignore)]
public string Identifier
{
get
{
return identifier
}
set
{
identifier = value;
OnPropertyChanged();
}
}
[JsonProperty(PropertyName = "name", NullValueHandling = NullValueHandling.Ignore)]
public string Name
{
get
{
return name;
}
set
{
name = value;
OnPropertyChanged();
}
}
[JsonProperty(PropertyName = "selected", NullValueHandling = NullValueHandling.Ignore)]
public bool Selected
{
get
{
return selected;
}
set
{
selected = value;
OnPropertyChanged();
}
}
public override int GetHashCode() => (Identifier).GetHashCode();
public bool Equals(Salutation other) => (Identifier) == (other?.Identifier);
public override string ToString()
{
return Identifier;
}
public override bool Equals(object obj)
{
if (!(obj is Salutation item))
{
return false;
}
return Equals(item);
}
public static bool operator ==(Salutation salutation1, Salutation salutation2)
{
if (ReferenceEquals(salutation1, salutation2))
{
return true;
}
if (ReferenceEquals(salutation1, null) || ReferenceEquals(salutation2, null))
{
return false;
}
return salutation1.Equals(salutation2);
}
public static bool operator !=(Salutation salutation1, Salutation salutation2)
{
return !(salutation1 == salutation2);
}
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
I then added some Property and Collection changed event handlers:
Titles = new ObservableRangeCollection<Models.Salutation>();
Titles.CollectionChanged += Titles_CollectionChanged;
private bool handleEvent = true;
private void Titles_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
foreach (Models.Salutation item in e.NewItems)
item.PropertyChanged += Salutation_PropertyChanged;
if (e.OldItems != null)
foreach (Models.Salutation item in e.OldItems)
item.PropertyChanged -= Salutation_PropertyChanged;
}
private void Salutation_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(!handleEvent)
{
return;
}
if (e.PropertyName == "Selected")
{
handleEvent = false;
if (sender is Models.Salutation selectedSalutation)
{
if (selectedSalutation.Selected)
{
Reset(sender as Models.Salutation);
}
}
handleEvent = true;
}
}
The XAML:
<control:CheckBoxView VerticalOptions="CenterAndExpand"
IsChecked="{Binding Selected, Mode=TwoWay}"
HorizontalOptions="Start"
OutlineColor="{Binding BindingContext.Campaign.CampaignProfile.EntryBackgroundColor, Source={x:Reference parent}}"
CheckedOutlineColor="{Binding BindingContext.Campaign.CampaignProfile.EntryTextColor, Source={x:Reference parent}}"
CheckColor="{Binding BindingContext.Campaign.CampaignProfile.EntryTextColor, Source={x:Reference parent}}">
</control:CheckBoxView>
Much simpler!

Related

OnPropertyChanged not fire with label text

I am in a Xamarin app I which I have to make a to-do list. I am using listview. I have to set a label text dynamically every time I add a new to-do like so: Number of tasks 2/4 where 2 are the done tasks and 4 are the total ones. Everything goes right but I found some issues when I have to update the label text. I am using the MVVM pattern. In XAML I bind the text value to SetInfoDoneText. In MainPage, I have the bindigContext set to VM(TodoListViewModel). I use INotifyPropertyChanged with OnPropertyChanged. I made a method in which the value of setInfoDoneText is changed. The problem is that the set and get is called only once and when the setInfoDoneText is updated by the method OnPropertyChanged does not fire again. Here is the code.
THE PROBLEM IS WHEN I TRY TO UPDATE lblDoneInfo text (
)
class TodoListViewModel: INotifyPropertyChanged
{
public ObservableCollection<TodoItem> todoItems { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public String setInfoDoneText;
public String SetInfoDoneText
{
get => setInfoDoneText;
set
{
setInfoDoneText = value;
OnPropertyChanged("SetInfoDoneText");
}
}
protected void OnPropertyChanged(string propertyName = null)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
int doneTask = 0;
int totalTask = 0;
public TodoListViewModel()
{
this.todoItems = new ObservableCollection<TodoItem>();
setInfoDoneText = "Number of tasks: " + doneTask + "/" + totalTask;
}
public ICommand AddTodoCommand => new Command(AddTodoItem);
public String newTodoInputValue { get; set; }
public String selectedItem { get; set; }
public bool highPriority { get; set; }
public bool midPriority { get; set; }
public bool lowPriority { get; set; }
Color newColor = new Color();
public void AddTodoItem()
{
if (highPriority)
{
newColor = Color.Red;
AddNewItem(newColor);
highPriority = false;
}
if (midPriority)
{
newColor = Color.Orange;
AddNewItem(newColor);
midPriority = false;
}
if (lowPriority)
{
newColor = Color.Yellow;
AddNewItem(newColor);
lowPriority = false;
}
}
public TodoItem AddNewItem(Color newColor)
{
TodoItem newItem = new TodoItem(newTodoInputValue,
false,
highPriority,
midPriority,
lowPriority,
newColor);
todoItems.Add(newItem);
UpdateDoneInfo();
return newItem;
}
public ICommand RemoveTodoCommand => new Command(RemoveTodoItem);
public void RemoveTodoItem(object o)
{
TodoItem todoItemBeingRemoved = o as TodoItem;
todoItems.Remove(todoItemBeingRemoved);
}
public ICommand EditTodoCommand => new Command(EditTodoItem);
public void EditTodoItem(object o)
{
TodoItem todoItemBeingEdited = o as TodoItem;
int newIndex = todoItems.IndexOf(todoItemBeingEdited);
todoItems.Remove(todoItemBeingEdited);
TodoItem updatedTodo = AddNewItem(newColor);
//todoItems.Add(updatedTodo);
int oldIndex = todoItems.IndexOf(updatedTodo);
todoItems.Move(oldIndex, newIndex);
}
public String UpdateDoneInfo()
{
totalTask = todoItems.Count;
foreach (TodoItem item in todoItems)
{
if (item.complete) doneTask++;
}
return setInfoDoneText = "Number of tasks: " + doneTask + "/" + totalTask;
}
}
<ContentPage.BindingContext>
<local:TodoListViewModel/>
</ContentPage.BindingContext>
<StackLayout>
<Entry
x:Name="inputField"
Text="{Binding newTodoInputValue}"
Placeholder="Enter a todo..."
/>
<Label x:Name="lblDoneInfo" Text="{Binding SetInfoDoneText, Mode=TwoWay }">
</Label>
<FlexLayout AlignItems="Center" JustifyContent="SpaceBetween">
<input:CheckBox x:Name="highP"
IsChecked="{Binding highPriority}"
CheckChangedCommand="{Binding AddTodoCommand}"
Margin="0,0,20,0" />
<Label Text="High Priority" FontSize="Medium"/>
<input:CheckBox x:Name="midP"
IsChecked="{Binding midPriority}"
CheckChangedCommand="{Binding AddTodoCommand}"
Margin="0,0,20,0" />
<Label Text="Medium Priority" FontSize="Medium"/>
<input:CheckBox x:Name="lowP"
IsChecked="{Binding lowPriority}"
CheckChangedCommand="{Binding AddTodoCommand}"
Margin="0,0,20,0" />
<Label Text="Low Priority" FontSize="Medium"/>
</FlexLayout>
<ListView x:Name="todoList" ItemsSource="{Binding todoItems}" SelectedItem="{Binding selectedItem}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell Height="20">
<FlexLayout JustifyContent="SpaceBetween" AlignItems="Center" Padding="20,0">
<ContentView>
<FlexLayout AlignItems="Center">
<input:CheckBox IsChecked="{Binding complete}" Margin="5" />
<Label x:Name="todoText" TextColor="{Binding color}" Text="{Binding todoText}" FontSize="Large"/>
</FlexLayout>
</ContentView>
<ImageButton
Source="editar_24.png"
BackgroundColor="Transparent"
WidthRequest="100"
HeightRequest="100"
Margin="0,0,20,0"
Command="{Binding Path=BindingContext.EditTodoCommand,
Source={x:Reference todoList}}"
CommandParameter="{Binding .}"/>
<ImageButton
Source="basura_24.png"
BackgroundColor="Transparent"
WidthRequest="100"
HeightRequest="100"
Command="{Binding Path=BindingContext.RemoveTodoCommand,
Source={x:Reference todoList}}"
CommandParameter="{Binding .}"/>
</FlexLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
PropertyChanged only fires when you set the value of the public property SetInfoDoneText. Your code is setting the value of the field setInfoDoneText (lowercase).
It is generally best practice to make the field private to prevent this
private String setInfoDoneText;

CheckBox create a string from the values of the selected objects

I have a collection view with a checkbox.
It looks like the following:
[Image][PetName][Checkbox]
I want to create a string with all the names of the pets which have been selected the pass this value through a function.
I have tried the following code but I am getting object reference is null in selectedPets.Add(ob) I'm sure Im proably going the wrong way with this but I am new to coding.
public List<PetProfile> selectedPets;
private void CheckBox_CheckedChanged(object sender, CheckedChangedEventArgs e)
{
var checkbox = sender as CheckBox;
var ob = checkbox.BindingContext as PetProfile;
if (ob != null)
{
selectedPets.Add(ob);
}
}
private string CreatePetName()
{
var stringBuilder = new StringBuilder();
var listlenght = selectedPets.Count;
foreach (var pet in selectedPets)
{
if (selectedPets.Count == 0)
{
stringBuilder.Append(pet.PetName);
}
else if (listlenght > 0 && pet == selectedPets[0] )
{
stringBuilder.Append(pet.PetName + " ");
}
else if (pet == selectedPets[listlenght])
{
stringBuilder.Append(" " + pet.PetName );
}
else
{
stringBuilder.Append(" " + pet.PetName + " ");
}
}
return stringBuilder.ToString();
}
private async void SubmitBtn_Clicked(object sender, EventArgs e)
{
var Petnames = CreatePetName();
}
XAML:
<CollectionView x:Name="petCollectionView" ItemsSource="{Binding EmptyPetInfo}" HeightRequest="200">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10" RowDefinitions="80" ColumnDefinitions="120,60,60">
<Image Grid.Column="0"
Grid.Row="0"
x:Name="PetImage"
Source="{Binding imageUrl}"/>
<Label Grid.Column="1"
Grid.Row="0"
Text="{Binding PetName}"
FontAttributes="Bold"
x:Name="labelpetname" VerticalTextAlignment="Center" HorizontalTextAlignment="Center"/>
<CheckBox Grid.Row="0" Grid.Column="2" HorizontalOptions="End" IsChecked="{Binding Selected, Mode=TwoWay}" BindingContext="{Binding .}" CheckedChanged="CheckBox_CheckedChanged"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
I want to create a string with all the names of the pets which have been selected the pass this value through a function.
I suggest you don't need to use CheckBox_CheckedChanged event to get selected PetName, you can create one class name Petclass, implementing INotifyPropertyChanged, to notify Selected property changed.
public class Petclass:ViewModelBase
{
public string imageUrl { get; set; }
public string PetName { get; set; }
private bool _Selected;
public bool Selected
{
get { return _Selected; }
set
{
_Selected = value;
RaisePropertyChanged("Selected");
}
}
}
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Then loading some data to test in collectionview. foreach EmptyPetInfo Collectionview ItemsSource="{Binding EmptyPetInfo}" to check Selected property is true or false.
<CollectionView
x:Name="petCollectionView"
HeightRequest="200"
ItemsSource="{Binding EmptyPetInfo}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid
Padding="10"
ColumnDefinitions="120,60,60"
RowDefinitions="80">
<Image
x:Name="PetImage"
Grid.Row="0"
Grid.Column="0"
Source="{Binding imageUrl}" />
<Label
x:Name="labelpetname"
Grid.Row="0"
Grid.Column="1"
FontAttributes="Bold"
HorizontalTextAlignment="Center"
Text="{Binding PetName}"
VerticalTextAlignment="Center" />
<CheckBox
Grid.Row="0"
Grid.Column="2"
HorizontalOptions="End"
IsChecked="{Binding Selected, Mode=TwoWay}" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
public partial class Page17 : ContentPage
{
public ObservableCollection<Petclass> EmptyPetInfo { get; set; }
public Page17()
{
InitializeComponent();
EmptyPetInfo = new ObservableCollection<Petclass>()
{
new Petclass(){imageUrl="check.png",PetName="pet 1"},
new Petclass(){imageUrl="delete.png",PetName="pet 2"},
new Petclass(){imageUrl="favorite.png",PetName="pet 3"},
new Petclass(){imageUrl="flag.png",PetName="pet 4"}
};
this.BindingContext = this;
}
private void btn1_Clicked(object sender, EventArgs e)
{
var stringBuilder = new StringBuilder();
foreach (Petclass pet in EmptyPetInfo)
{
if(pet.Selected)
{
stringBuilder.Append(pet.PetName + " ");
}
}
string str = stringBuilder.ToString();
}
}
Using ObservableCollection Class, represent a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.
you need to initialize selectedPets before you use it
public List<PetProfile> selectedPets = new List<PetProfile>();

Can't update data bindings from object in Xamarin forms

Im trying to update my xamarin bindings from a object in my viewmodel. What am I doing wrong.
When i see look at the page and look at "User", i see my user object is there.
Page:
<StackLayout BindableLayout.ItemsSource="{Binding User}"
Orientation="Horizontal">
<BindableLayout.ItemTemplate>
<DataTemplate x:DataType="model:User">
<StackLayout>
<Label Text="{Binding Name, Mode=OneWay}"/>
<Label Text="{Binding PhoneNumber, Mode=OneWay}"/>
<Label Text="{Binding Adress, Mode=OneWay}"/>
<Label Text="{Binding Email, Mode=OneWay}"/>
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
What you need to know about the Viewmodel with mvvhelpers
public User User { get; set; }
public MyProfileViewModel()
{
Title = "MyProfile";
RefreshCommand = new AsyncCommand(Refresh);
AddCommand = new AsyncCommand(Add);
// RemoveCommand = new AsyncCommand<User>(Remove);
User = new User();
}
public async refrsh(){
User = await MyProfileService.GetMyProfile(2);
nameDisplay = User.Name;
}
string nameDisplay;
public string NameDisplay
{
get => nameDisplay;
set => SetProperty(ref nameDisplay, value);
}
According to Jason's opinion, you don't need to use BindableLayout and a DataTemplate if you only have a single User object, you can bind User Object to StackLayout BindingContext directly.
<StackLayout BindingContext="{Binding User}">
<Label Text="{Binding Name, Mode=OneWay}" />
<Label Text="{Binding PhoneNumber, Mode=OneWay}" />
<Label Text="{Binding Adress, Mode=OneWay}" />
<Label Text="{Binding Email, Mode=OneWay}" />
</StackLayout>
If you have collection of IEnumerable User, you can use BindableLayout.ItemsSource and a DataTemplate
You need to implement INotifyPropertyChanged for User properties, it will notify the data changes.
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
The complete code:
<StackLayout>
<StackLayout BindingContext="{Binding User}">
<Label Text="{Binding Name, Mode=OneWay}" />
<Label Text="{Binding PhoneNumber, Mode=OneWay}" />
<Label Text="{Binding Adress, Mode=OneWay}" />
<Label Text="{Binding Email, Mode=OneWay}" />
</StackLayout>
<Button
x:Name="btn1"
Command="{Binding changecommand}"
Text="change user data" />
</StackLayout>
public partial class Page27 : ContentPage
{
public Page27()
{
InitializeComponent();
this.BindingContext = new MyProfileViewModel();
}
}
public class MyProfileViewModel
{
public User User { get; set;}
public ICommand changecommand { get; }
public MyProfileViewModel()
{
User = new User();
User.Name = "cherry";
User.PhoneNumber = "123";
User.Adress = "location 1";
User.Email = "xxxxx.#outlook.com";
changecommand = new Command(() =>
{
User.Name = "barry";
});
}
}
public class User:ViewModelBase
{
private string _Name;
public string Name
{
get { return _Name; }
set
{
_Name = value;
RaisePropertyChanged("Name");
}
}
private string _PhoneNumber;
public string PhoneNumber
{
get { return _PhoneNumber; }
set
{
_PhoneNumber = value;
RaisePropertyChanged("PhoneNumber");
}
}
private string _Adress;
public string Adress
{
get { return _Adress; }
set
{
_Adress = value;
RaisePropertyChanged("Adress");
}
}
private string _Email;
public string Email
{
get { return _Email; }
set
{
_Email = value;
RaisePropertyChanged("Email");
}
}
}

How to fix ListView not showing contents of ObservableCollecton which is binded to it's ItemSource [duplicate]

This question already has an answer here:
Databindings don't seem to refresh
(1 answer)
Closed 3 years ago.
I am using MVVM pattern in my Xamarin.Forms application. I am trying to fill my page with a list of cards with simple information. For that I am using an ObservableCollection (CardsCollectionViewModel.cs) and objects of the class(CardViewModel) which are stored in the collection.
The Collection is initialized and passed to the MainPage.xaml.cs class. In the MainPage.xaml the collection name is binded to ListView ItemSource and the properties of storing objects are binded to the contents of list.
After the program starts and loads the Cards collections successfull, the page appears to be left empty.
Full project here: https://github.com/InfroLab/barkot/tree/master/Barkot
Here is my card class:
CardViewModel.cs
public class CardViewModel : INotifyPropertyChanged
{
//some code
public CardViewModel(int id, string company, string barcode, string type, string site)
{
//some code
}
private int id;
private string company = "";
private string barcode = "";
private string type = "";
private string site = "";
public int Id { get; set; }
public string Company
{
get { return company; }
set
{
//Console.WriteLine("{0}", Company);
if (company != value)
{
company = value;
OnPropertyChanged("Company");
}
}
}
public string Barcode
{
get { return barcode; }
set
{
if (barcode != value)
{
barcode = value;
OnPropertyChanged("Barcode");
}
}
}
public string Type
{
get { return type; }
set
{
if (type != value)
{
type = value;
OnPropertyChanged("Type");
}
}
}
public string Site
{
get { return site; }
set
{
if (site != value)
{
site = value;
OnPropertyChanged("Site");
}
}
}
}
Here is my collection class:
CarCollectionViewModel.cs
public class CardCollectionViewModel : INotifyPropertyChanged
{
public static ObservableCollection<CardViewModel> Cards { get; set; }
//some code
public static void UpdateCards()
{
//gettingitems from local db
Cards = App.Database.GetItems();
}
public CardCollectionViewModel()
{
Cards = new ObservableCollection<CardViewModel>();
UpdateCards();
//some code
}
}
Here is ListView from MainPage.xaml:
<ListView SeparatorVisibility="None" HasUnevenRows="True" ItemsSource="{Binding Cards}" SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Frame Margin="10" HeightRequest="148" Padding="10" CornerRadius="5" HasShadow="True" BackgroundColor="#FFFFFF" InputTransparent="False" >
<StackLayout Orientation="Vertical">
<Button Text="Edit" Command="{Binding EditCardCommand}" BackgroundColor="#EBEBEB" HeightRequest="20" HorizontalOptions="End"/>
<StackLayout Orientation="Horizontal">
<WebView Source="{Binding Site}" HeightRequest="128" WidthRequest="128" VerticalOptions="FillAndExpand"/>
<StackLayout Spacing="5" Orientation="Vertical">
<Label Text="{Binding Company}" FontSize="Small" TextColor="#232323" />
<Label Text="{Binding Barcode}" FontSize="Small" TextColor="#232323" />
<forms:ZXingBarcodeImageView BarcodeFormat="{Binding Type}" BarcodeValue="{Binding Barcode}" HeightRequest="40" WidthRequest="200">
<zx:ZXingBarcodeImageView.BarcodeOptions>
<zxcm:EncodingOptions Width="200" Height="40" PureBarcode="True"/>
</zx:ZXingBarcodeImageView.BarcodeOptions>
</forms:ZXingBarcodeImageView>
</StackLayout>
</StackLayout>
</StackLayout>
</Frame>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I expect to see a loaded list on my page, but the actual content of it is empty.
SOLUTION:
private ObservableCollection<CardViewModel> cards = new ObservableCollection<CardViewModel>();
public ObservableCollection<CardViewModel> Cards
{
get
{
return cards;
}
set
{
if (cards != value)
{
cards = value;
OnPropertyChanged("Cards");
}
}
}
when you update Cards
Cards = App.Database.GetItems();
you are not raising a PropertyChanged event because you are using a default getter for Cards

Xamarin.Forms IsVisible not working on Android after selected item

I have problem with IsVisible. I want that after select item in ListView StackLayout shows up with label but item selected not works. Of course i have rest of code. IsVisible = false its working so i have only problem with show info. I Have tried almsot everything changing code but not works fine.
public new string Title { get; set; }
public string Info { get; set; }
public int Timer { get; set; }
private bool _isVisible = false;
public new bool IsVisible
{
get => _isVisible;
set => Set(ref _isVisible, value);
}
private void Set(ref bool _isVisible, bool value)
{
return;
}
private void DO ()
{
Task.Factory.StartNew(() =>
{
ChallengeList.ItemsSource = new List<MainPage>
{
new MainPage {Title = "Cuipka", Info="Cipka"},
new MainPage {Title = "Cuipka", Info="Cipka"},
new MainPage {Title = "Cuipka", Info="Cipka"},
new MainPage {Title = "Cuipka", Info="Cipka"},
};
});
}
private void ChallengeList_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
// if (e.SelectedItem == null)
// return;
if (e.SelectedItem is MainPage viewModel)
{
viewModel.IsVisible = true;
}
// ChallengeList.SelectedItem = null;
}
XAML:
<ListView x:Name="ChallengeList" SeparatorColor="#3d122c" HasUnevenRows="True"
ItemSelected="ChallengeList_ItemSelected" RelativeLayout.YConstraint="{ConstraintExpression ElementName=Lab, Constant=0,Factor=1,Property=Height,Type=RelativeToView}"
RelativeLayout.HeightConstraint="{ConstraintExpression Property=Height,Factor=0.8,Type=RelativeToParent}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" BackgroundColor="#40FFFFFF" Padding="10">
<StackLayout HorizontalOptions="CenterAndExpand">
<Label Text="{Binding Title}" TextColor="#ff3f50" FontSize="17" FontAttributes="Bold" HorizontalOptions="Center"/>
<StackLayout HorizontalOptions="CenterAndExpand" IsVisible="{Binding IsVisible}" x:Name="More" Padding="5">
<Label Text="sdfghjkhgfdsfghjkljhgfdsadfghjkljhgfdsaSDFGHJKJHGFDSAsdfghjkhgfds" TextColor="#ff3f50" FontSize="17" FontAttributes="Bold" HorizontalOptions="Center"
LineBreakMode="WordWrap"/>
</StackLayout>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I'm not quite sure what you are doing with the Set function, but I would normally set up properties in my viewmodel like this:
private bool _isVisible;
public bool IsVisible
{
get { return _isVisible; }
set { _isVisible = value; OnPropertyChanged(nameof(IsVisible)); }
}
private bool _isVisible = false;
public bool IsVisible
{
get
{
return _isVisible
}
set
{
Set(() => IsVisible, ref _isVisible, value);
}
}
This worked for me !

Categories