I am working on xamarin.forms. I am facing one issue. I have one ListView. I am giving List object as ItemSource to that listView without any MVVM pattern (Not follow MVVM). List object is updated on Item Tap or Image gesture tap and then I again give itemsource to Listview.
In ios when I rebind item source to listview, automatically scroll goes to top. So selected item is not visible to user.
In Android it works perfect.
<ListView x:Name="lstLeaveNotificationDetails" HorizontalOptions="FillAndExpand" HasUnevenRows="True"
VerticalOptions="FillAndExpand" SeparatorVisibility="None" BackgroundColor="Transparent"
AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,0,1,1" IsVisible="false">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout x:Name="StkForListItems" ClassId="{Binding TapId}">
<!--Left Side Orange Color Padding-->
<StackLayout Padding="4,0,0,0" BackgroundColor="{Binding BgMainStackColor}">
<StackLayout BackgroundColor="{Binding BgColor}" HorizontalOptions="Start">
<Grid Padding="3" HorizontalOptions="StartAndExpand" VerticalOptions="Center" RowSpacing="1" ColumnSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<StackLayout Grid.Row="0" Grid.Column="0" Grid.RowSpan="5" HorizontalOptions="Center" VerticalOptions="Center" >
<ffimageloading:CachedImage Source="{Binding CheckSelect}" Aspect="Fill" ClassId="{Binding TapId}" HorizontalOptions="Center" VerticalOptions="Center" >
<ffimageloading:CachedImage.GestureRecognizers>
<TapGestureRecognizer Tapped="img_Tapped" NumberOfTapsRequired="1" />
</ffimageloading:CachedImage.GestureRecognizers>
</ffimageloading:CachedImage>
</StackLayout>
<StackLayout Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="3">
<Label Text="{Binding EmpNm}" TextColor="Black" FontSize="Medium" FontAttributes="Bold"/>
</StackLayout>
<Label Text="From" Grid.Row="1" Grid.Column="1" TextColor="#B0B0B0" HorizontalOptions="StartAndExpand" VerticalOptions="Start" FontSize="Small"/>
<Label Text="To" Grid.Row="1" Grid.Column="2" TextColor="#B0B0B0" HorizontalOptions="StartAndExpand" VerticalOptions="Start" FontSize="Small"/>
<Label Text="Leave Days" Grid.Row="1" Grid.Column="3" TextColor="#B0B0B0" HorizontalOptions="StartAndExpand" VerticalOptions="Start" FontSize="Small"/>
<Label Text="{Binding FromDate}" Grid.Row="2" Grid.Column="1" TextColor="Black" HorizontalOptions="StartAndExpand" FontSize="Small" />
<Label Text="{Binding ToDate}" Grid.Row="2" Grid.Column="2" TextColor="Black" HorizontalOptions="StartAndExpand" FontSize="Small" />
<Label Text="{Binding NoOfLeave}" Grid.Row="2" Grid.Column="3" TextColor="Black" HorizontalOptions="StartAndExpand" FontSize="Small" />
<StackLayout Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="3" VerticalOptions="EndAndExpand" HorizontalOptions="Start">
<Label Text="Reason" TextColor="#b0b0b0" FontSize="Small"/>
</StackLayout>
<StackLayout Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="3" VerticalOptions="StartAndExpand" HorizontalOptions="StartAndExpand">
<Label Text="{Binding Reason}" TextColor="Black" FontSize="Small" />
</StackLayout>
</Grid>
</StackLayout>
</StackLayout>
<BoxView HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" HeightRequest="3"/>
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="OnItemTapped" NumberOfTapsRequired="1" />
</StackLayout.GestureRecognizers>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
BackEnd code : On Image Tap I have called following function. Update List object and give it to itemSource
public void ItemSelectionChanged(CachedImage source, StackLayout lstView)
{
var objClassId = "";
if (source != null)
{
objClassId = source.ClassId;
}
else
{
objClassId = lstView.ClassId;
}
switch (Key)
{
case "LA":
if (objLstLeaveLst != null)
{
LeaveLst objtempLeaveLst = objLstLeaveLst.Find(s => s.TapId.ToString() == objClassId);
int index = objLstLeaveLst.IndexOf(objtempLeaveLst);
if (objLstLeaveLst[index].CheckSelect.ToString() == AppResources.ImgNotificationSelectionFalse)
{
objLstLeaveLst[index].CheckSelect = AppResources.ImgNotificationSelectionTrue;
List<bool> ImageSelectionFlag = objLstLeaveLst.Select(s => s.CheckSelect.ToString() == "check_sel.png").ToList();
ChangeSelectionImage(ImageSelectionFlag);
}
else
{
objLstLeaveLst[index].CheckSelect = AppResources.ImgNotificationSelectionFalse;
imgSelectAll.Source = "check_nor.png";
imgSelectAll.ClassId = "false";
lblSelectAll.ClassId = "false";
}
if (objLstLeaveLst[index].BgMainStackColor.Equals(Color.FromHex("#dddddd")))
{
objLstLeaveLst[index].BgMainStackColor = Color.FromHex("#f15a23");
}
else
{
objLstLeaveLst[index].BgMainStackColor = Color.FromHex("#dddddd");
}
lstLeaveNotificationDetails.ItemsSource = null;
lstLeaveNotificationDetails.ItemsSource = objLstLeaveLst;
if (Device.OS == TargetPlatform.iOS)
{
lstLeaveNotificationDetails.ScrollTo(objtempLeaveLst, ScrollToPosition.MakeVisible, false);
}
}
break;
}
}
To solve this problem I put following Code
if (Device.OS == TargetPlatform.iOS)
{
lstLeaveNotificationDetails.ScrollTo(objtempLeaveLst, ScrollToPosition.MakeVisible, false);
}
but It does't give me a proper output. How to maintain scroll position in ios. Please help me to do rendering of listView in ios. Don't want to scroll listview when I update Item source.
I have also tried ObservableCollection but My GUI is not updated on Item tap (Image tap and stack tap).
The way iOS handles updating the ListView and its ItemsSource is to update the ViewSource underlying the UITableView. That, on Xamarin.Forms, or native iOS, is going to clear your entire list, and re-add the items.
The way to accomplish what you're trying to do is to use an ObservableCollection AND for your model to implement INotifyPropertyChanged.
If your model that acts and the BindingContext for your individual Cell updates a property bound to the view, then it will update that single Cell without having to rebind the entire list.
Also, re-applying the ItemsSource is an expensive process on the UI, while updating a single cell is cheap!
Here's an example:
The model-
public class TodoItem : INotifyPropertyChanged
{
private string _text;
public string Text
{
get
{
return _text;
}
set
{
_text = value;
PropertyChanged?.Invoke(new PropertyChangedEventArgs("Text"));
}
}
}
Then your view:
<ListView x:Name="MyListView" ItemsSource="{Binding TodoItems}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Text}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Then your code behind:
...
MyListView.BindingContext = this;
...
public ObservableCollection<TodoItem> TodoItems { get; set; }
...
// change the text of one item
TodoItems[1].Text = "New Text!";
...
Then you'll see the proper cell update the text field without having to update any other items, and also keeping your scroll position!
Use listView.ScrollTo() method, see below:
listView.ItemSelected += (sender, e) =>
{
listView.ScrollTo(e.SelectedItem, ScrollToPosition.MakeVisible, false);
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With