Xamarin Forms : Access list data when click of a Button inside listview-viewcell - xamarin.forms

I have a button inside listview-viewcell. For the button, I am using clicked event. So on click of the button, I need the details of the selected list item like the first name, email etc. I tried like following:
Xaml code:
<ListView x:Name="MyDirectories"
HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Button
BorderRadius="25"
HeightRequest="40"
WidthRequest="150"
TextColor="White"
HorizontalOptions="CenterAndExpand"
Font="Bold,15"
Margin="0,0,0,5"
BackgroundColor="#004F7E"
Clicked="MoreDetails"
Text="More Details"/>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Xaml.cs code:
public class MyListItemEventArgs : EventArgs
{
public UserProfileTO MyItem { get; set; }
public MyListItemEventArgs(UserProfileTO item)
{
this.MyItem = item;
}
}
public void MoreDetails(Object sender, MyListItemEventArgs args)
{
var item = args.MyItem;
if (item != null)
{
Debug.WriteLine("Firstname:>"+item.firstName);
}
}
When I run getting InvalidCastException: Specified cast is not valid.
Anybody, please suggest any other solution.
Thanks in advance.

The problem was with the model class given in MyListEventArgs:
public class MyListItemEventArgs : EventArgs
{
public UserProfileHBList MyItem { get; set; }
public MyListItemEventArgs(UserProfileHBList item)
{
this.MyItem = item;
}
}
public void MoreDetails(Object sender, MyListItemEventArgs args)
{
var item = args.MyItem;
if (item != null)
{
Debug.WriteLine("Firstname:>" + item.userProfileTO.firstName);
}
}
The firstname, email etc are another json(userProfileTO) inside of the main json(UserProfileHBList). Also forget to add stacklayout, thank you Alessandro Caliaro.

Related

Adding data to CarouselView item source results in error

I have a Xamarin CarouselView initialized with an empty ObservableCollection. The Carousel view correctly shows the EmptyView on page load.
However, when I add an item to the Observable Collection iOS throws the following exception:
attempt to insert item 0 into section 0, but there are only 0 items in section 0 after the update
The way I'm populating the item source is after the page loads I've hooked a button to an event handler to add items to the Observable Collection.
If I initialize the Observable Collection with initial data then the CarouselView works fine, it's just when I add items later that it breaks.
Page:
...
<ContentPage.BindingContext>
<viewModel:MatchesPageViewModel></viewModel:MatchesPageViewModel>
</ContentPage.BindingContext>
<CarouselView Margin="-10,15,-10,0"
ItemsSource="{Binding PendingMatches}"
HorizontalOptions="FillAndExpand"
HorizontalScrollBarVisibility="Never"
IsSwipeEnabled="True"
VerticalOptions="StartAndExpand">
<CarouselView.EmptyView>
<Frame>
<Label Text="It's empty"></Label>
</Frame>
</CarouselView.EmptyView>
<CarouselView.ItemTemplate>
<DataTemplate>
<Label Text="Some Content"></Label>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
View Model:
public class MatchesPageViewModel : BaseViewModel
{
public ObservableCollection<MatchResponse> PendingMatches { get; set; } =
new ObservableCollection<MatchResponse>();
//pretend it's invoked from a button in the page
public void SomeEventHandler()
{
//throws exception: attempt to insert item 0 into section 0...
PendingMatches.Add(new MatchResponse());
}
}
I guess that you may have some problem about adding item in observablecollection for Button click method. I do one demo using Button command binding that you can take a look.
<CarouselView
HorizontalOptions="FillAndExpand"
HorizontalScrollBarVisibility="Never"
IsSwipeEnabled="True"
ItemsSource="{Binding PendingMatches}"
VerticalOptions="StartAndExpand">
<CarouselView.EmptyView>
<Frame>
<Label Text="It's empty" />
</Frame>
</CarouselView.EmptyView>
<CarouselView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding str}" />
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
<Button
x:Name="btn1"
Command="{Binding command1}"
Text="add data" />
public partial class Page2 : ContentPage
{
public Page2()
{
InitializeComponent();
this.BindingContext = new MatchesPageViewModel();
}
}
public class MatchesPageViewModel
{
public ObservableCollection<MatchResponse> PendingMatches { get; set; } = new ObservableCollection<MatchResponse>();
public ICommand command1 { get; set; }
public MatchesPageViewModel()
{
command1 = new Command(SomeEventHandler);
}
public void SomeEventHandler()
{
//throws exception: attempt to insert item 0 into section 0...
PendingMatches.Add(new MatchResponse() { str = "test" });
}
}
public class MatchResponse
{
public string str { get; set; }
}

How a user select to display 1 out of two (or more) fields on a single Label in Xamarin

I'm trying to use a single Label to display one of the two data fields alternately in Xamarin Forms. Only Label 1 Displaying the binding field (Contact_Name), while second Label which I am trying to use a variable "DisplayField" is not displaying either 'Contact_Address' or 'Contact_eMail' .
Question posted before and Another user tried to help but it didn't work!
Model Class
public class Contacts
{
[PrimaryKey][Autoincrement]
public int Contact_ID { get; set; }
public string Contact_Name { get; set; }
public string Contact_Address { get; set; }
public string Contact_eMail { get; set; }
}
XAML Page
<StackLayout>
<Button Text="Display Address" FontSize="Large" HorizontalOptions="Center" VerticalOptions="Fill" Clicked="Display_Address" />
<Button Text="Display Email" FontSize="Large" HorizontalOptions="Center" VerticalOptions="Fill" Clicked="Display_eMail" />
<Entry HorizontalOptions="FillAndExpand" Text="{Binding DisplayField}" />
<ListView x:Name="listView" HasUnevenRows="True" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<StackLayout Orientation="Vertical" VerticalOptions="CenterAndExpand" >
<Frame >
<StackLayout Orientation="Vertical" VerticalOptions="Center">
<Label Text="{Binding Contact_Name}" FontSize="Medium" LineBreakMode="WordWrap" />
<Label Text="{Binding DisplayField}" LineBreakMode="WordWrap" />
</StackLayout>
</Frame>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
Code Behind
public partial class FieldSwap : ContentPage
{
readonly FieldViewModel _fieldViewModel;
readonly SQLiteAsyncConnection _connection = DependencyService.Get<ISQLite>().GetConnection();
public ObservableCollection<Contacts> CList { get; set; }
public static string DisplayField { get; private set; }
public static int caseSwitch { get; private set; }
public FieldSwap()
{
InitializeComponent();
_fieldViewModel = new FieldViewModel();
_fieldViewModel.Field = "Contact_Address";
this.BindingContext = _fieldViewModel;
}
public static void SelectField()
{
switch (caseSwitch)
{
case 1:
DisplayField = "Contact_Address";
break;
case 2:
DisplayField = "Contact_eMail";
break;
default:
DisplayField = ("Contact_Address");
break;
}
}
private void Display_Address(object sender, EventArgs e)
{
caseSwitch = 1;
SelectField();
ReadData();
}
private void Display_eMail(object sender, EventArgs e)
{
caseSwitch = 2;
SelectField();
ReadData();
}
public void ReadData()
{
var list = _connection.Table<Contacts>().ToListAsync().Result;
CList = new ObservableCollection<Contacts>(list);
listView.ItemsSource = CList;
}
}
View Model Class
public class FieldViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
String _field;
public string Field
{
set
{
if (!value.Equals(_field, StringComparison.Ordinal))
{
_field = value;
OnPropertyChanged("DisplayField");
}
}
get
{
return _field;
}
}
void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new
PropertyChangedEventArgs(propertyName));
}
}
You could use IsVisible property to achieve that, not need to bind only one lable.
Therefore, binding Contact_Address and Contact_eMail with two lables in StackLayout as follows:
<StackLayout Orientation="Vertical" VerticalOptions="Center">
<Label Text="{Binding Contact_Name}" FontSize="Medium" LineBreakMode="WordWrap" />
<Label Text="{Binding Contact_Address}" IsVisible="{Binding AddressVisible}" LineBreakMode="WordWrap" />
<Label Text="{Binding Contact_eMail}" IsVisible="{Binding EMailVisible}" LineBreakMode="WordWrap" />
</StackLayout>
Then in Contacts add two visiable proerty:
public class Contacts: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
...
private bool addressVisible;
public bool AddressVisible
{
set
{
if (addressVisible != value)
{
addressVisible = value;
OnPropertyChanged("AddressVisible");
}
}
get
{
return addressVisible;
}
}
private bool eMailVisible;
public bool EMailVisible
{
set
{
if (eMailVisible != value)
{
eMailVisible = value;
OnPropertyChanged("EMailVisible");
}
}
get
{
return eMailVisible;
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Now in Contentpage, you could modify the visiable propery when button be clicked:
private void Display_Address(object sender, EventArgs e)
{
foreach(var item in CList )
{
item.AddressVisible = true;
item.EMailVisible = false;
}
}
private void Display_eMail(object sender, EventArgs e)
{
foreach (var item in CList )
{
item.AddressVisible = false;
item.EMailVisible = true;
}
}
Here is the effect:

SelectedItem binding works in UWP but not in ios

In my Xamarin.Forms app, I have a ListView and am binding to the SelectedItem property:
<ListView x:Name="MyListView" ItemsSource="{Binding MyItems}" IsVisible="{Binding Expanded}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" SelectionMode="Single" SeparatorVisibility="None">
<!-- not relevant code -->
</ListView>
When I run it on UWP, my SelectedItem property in my view model gets set when I select an item in the list. But not in ios. Am I doing something wrong? Or is there a work around?
I wrote a simple demo and it works on my side. Here is the code:
<ListView x:Name="testListView"
Style="{StaticResource ListStyle}" SelectedItem="{Binding YourSelectedItem, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Name}"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Then in your view-model(viewModel should implement INotifyPropertyChanged):
class testViewModel : INotifyPropertyChanged
{
public string Name { get; set; }
private testViewModel _yourSelectedItem { get; set; }
public testViewModel YourSelectedItem
{
get
{
return _yourSelectedItem;
}
set
{
_yourSelectedItem = value;
OnPropertyChanged("YourSelectedItem");
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
And in the MainPage, set the BindingContext = new testViewModel();:
public partial class MainPage : ContentPage
{
ObservableCollection<testViewModel> myModels = new ObservableCollection<testViewModel>();
testViewModel model;
public MainPage()
{
InitializeComponent();
myModels.Add(new testViewModel { Name = "age" });
myModels.Add(new testViewModel { Name = "gender" });
myModels.Add(new testViewModel { Name = "name" });
testListView.ItemsSource = myModels;
BindingContext = new testViewModel();
}
}
Try it and let me know if it works for you.

Windows Universal App Pivot Binding and one Static PivotItem

I try to bind an pivot to the DataContext in an Windows Universal app.
Everything works fine except it seems that I am unable to mix binding and "static" PivotItems.
I need to create 0 to n PivotItems based on a list and on static PivotItem containing settings.
This is what I tried. If I remove the HeaderTemplate and ItemTemplate Element the PivotItem-Element is shown. If I let the Template Elements on there place the bound data is shown but not the extra PivotItem.
Is it even possible to mix?
<Pivot Name="PivotMain" Title="Title" ItemsSource="{Binding Path=Parts}">
<Pivot.HeaderTemplate>
<DataTemplate x:DataType="viewmodel:DetailModel">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</Pivot.HeaderTemplate>
<Pivot.ItemTemplate>
<DataTemplate x:DataType="viewmodel:DetailModel">
<TextBlock Text="TestTest"/>
</DataTemplate>
</Pivot.ItemTemplate>
<PivotItem Name="Settings" Header="Settings">
<ScrollViewer VerticalScrollMode="Auto" VerticalScrollBarVisibility="Auto">
<ListView ItemsSource="{Binding Path=Settings}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="viewmodel:SettingModel">
<RelativePanel>
<ToggleSwitch Name="OnOff"
OffContent="{Binding OffContent}" OnContent="{Binding OnContent}" IsOn="{Binding IsMonitored, Mode=TwoWay}"
RelativePanel.AlignLeftWithPanel="True" />
</RelativePanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
</PivotItem>
</Pivot>
Is it even possible to mix?
As far as I known, it is impossible. But you can use other ways to meet your requirements. What you actually want to do is the first one PivotItem has different content with others. You should be able use a Data​Template​Selector that you can select a different DataTemplate for the first item (which header is settings) with others. For example, code as follows:
XAML
<Page.Resources>
<DataTemplate x:Key="itemstemplate" x:DataType="local:DetailModel">
<TextBlock Text="TestTest"/>
</DataTemplate>
<DataTemplate x:Key="settingtemplate" x:DataType="local:DetailModel">
<ScrollViewer VerticalScrollMode="Auto" VerticalScrollBarVisibility="Auto">
<ListView ItemsSource="{Binding Path=Settingss}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:SettingModel">
<RelativePanel>
<ToggleSwitch Name="OnOff" OffContent="{Binding OffContent}" OnContent="{Binding OnContent}" IsOn="{Binding IsMonitored, Mode=TwoWay}" RelativePanel.AlignLeftWithPanel="True" />
</RelativePanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
</DataTemplate>
<local:PivotTemplateSelector
itemstemplate="{StaticResource itemstemplate}"
settingtemplate="{StaticResource settingtemplate}"
x:Key="PivotTemplateSelector" />
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Pivot Name="PivotMain" Title="Title" ItemsSource="{Binding Path=Parts}" ItemTemplateSelector="{StaticResource PivotTemplateSelector}">
<Pivot.HeaderTemplate>
<DataTemplate x:DataType="local:DetailModel">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</Pivot.HeaderTemplate>
</Pivot>
</Grid>
Code behind
public sealed partial class MainPage : Page
{
ObservableCollection<DetailModel> Parts;
ObservableCollection<SettingModel> Settingss;
public MainPage()
{
this.InitializeComponent();
Settingss = new ObservableCollection<SettingModel>()
{
new SettingModel()
{
IsMonitored=true,
OffContent="work at",
OnContent="content"
}
};
Parts = new ObservableCollection<DetailModel>()
{
new DetailModel()
{
Name="Settings",
Settingss=Settingss
},
new DetailModel()
{
Name="test1"
},
new DetailModel()
{
Name="test2"
}
};
datasources datasource = new datasources()
{
Parts = Parts
};
this.DataContext = datasource;
}
}
public class PivotTemplateSelector : DataTemplateSelector
{
public DataTemplate itemstemplate { get; set; }
public DataTemplate settingtemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
DetailModel itemget = item as DetailModel;
if (itemget.Name == "Settings")
{
return settingtemplate;
}
else
return itemstemplate;
return base.SelectTemplateCore(item);
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
return SelectTemplateCore(item);
}
}
public class datasources
{
public ObservableCollection<DetailModel> Parts { get; set; }
}
public class DetailModel
{
public string Name { get; set; }
public ObservableCollection<SettingModel> Settingss { get; set; }
}
public class SettingModel
{
public string OffContent { get; set; }
public string OnContent { get; set; }
public bool IsMonitored { get; set; }
}

program blows up on navigate using observable collections WP7

In maine, on my button click event handler I do:
private void addIconButton_Click(object sender, EventArgs e)
{
if (test)
{
MessageBox.Show("enters addIcon Main");
Note note = new Note();
note.Modified = DateTimeOffset.Now;
if (note != null)
{
Settings.NotesList.Add(note); //this causes the issue.
//Settings.NotesList[0] = note;
}
Settings.CurrentNoteIndex = 0;
test = false;
MessageBox.Show("right before navigate");
this.NavigationService.Navigate(new Uri("/DetailsPage.XAML", UriKind.Relative));
MessageBox.Show("after navigate");
}
//DetailsPage mynewPage = new DetailsPage();
//this.Content = mynewPage;
}
and on my on navigatedTo I do:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
MessageBox.Show("enters onNav Main");
DataContext = null;
DataContext = Settings.NotesList;
Settings.CurrentNoteIndex = -1;
Listbox.SelectedIndex = -1;
if (Settings.NotesList != null)
{
if (Settings.NotesList.Count == 0)
{
Notes.Text = "No Notes";
}
else
{
Notes.Text = "";
}
}
}
Inside my front end code I do:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox x:Name="Listbox" SelectionChanged="listbox_SelectionChanged" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Width="800" MinHeight="60">
<StackPanel>
<TextBlock x:Name="Title" VerticalAlignment="Center" FontSize="{Binding TextSize}" Text="{Binding Name}"/>
<TextBlock x:Name="Date" VerticalAlignment="Center" FontSize="{Binding TextSize}" Text="{Binding Modified,
Mode=TwoWay, Converter={StaticResource dateConverter}}"/>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>
I have an observable collections in a static class where in the constructor I set it to:
public static class Settings
{
public static ObservableCollection<Note> NotesList;
static IsolatedStorageSettings settings;
private static int currentNoteIndex;
static Settings()
{
NotesList = new ObservableCollection<Note>();
settings = IsolatedStorageSettings.ApplicationSettings;
MessageBox.Show("enters constructor settings");
}
and then inside the Notes class it just looks like this:
public class Note
{
public DateTimeOffset Modified { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int TextSize { get; set; }
}
when I click the app button and it calls the invent handler right after the navigationService is called I get:
// Code to execute on Unhandled Exceptions
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
if (System.Diagnostics.Debugger.IsAttached)
{
// An unhandled exception has occurred; break into the debugger
System.Diagnostics.Debugger.Break();
}
}
this only happens when Settings.NotesList.Add(note); is added in the addIconButton_click method..
Any suggestions???
I fixed it by setting default values to the instance variables in the Notes class inside the constructor...

Resources