The scenario is, a content page is opened with a carousel displaying multiple images.
The images are bound as an observable collection of ImageSource and they're fine
When the page is displayed, I can see the carousels empty.
I have tried with two different CarouselView. The one that xamarin brings by default and the one from CardsView nuget library. With both of them the result is the same.
The page shows the carousel views without the image, but with the right amount of items (i.e: I can see that the observable collection has 3 items).
I suspect it must be some kind of racing condition because as soon as I force a hot reload of the view while debuggin (ie: I save the XAML and the view reloads in the device) I can see the carousels with the images displayed properly.
To reproduce it I have also added the images separately outside the carousel to prove that they're there.
I've also added both carousels to the view. This is the result on the first load:
and after I save the xaml (without doing anything on it at all) and the view refreshes, this is what I see, and it's correct.
Notice how in the first load, the 3 images are displayed correctly outside the carousel, but not inside any of the carousels, although there is no problem if what I add in the carousel is text.
Any idea where may be the issue? Is it a racing condition? Or is it a problem with both different carousels?
This is my code
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:Sasw.AforoPass.ViewModels;assembly=Sasw.AforoPass"
xmlns:panCardView="clr-namespace:PanCardView;assembly=PanCardView"
xmlns:controls="clr-namespace:PanCardView.Controls;assembly=PanCardView"
mc:Ignorable="d"
x:Class="Sasw.AforoPass.Views.MainPage"
x:DataType="viewModels:MainViewModel">
<ContentPage.Content>
<StackLayout>
<StackLayout.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</StackLayout.Resources>
<CarouselView BackgroundColor="White"
x:Name="Carousel"
ItemsSource="{Binding Images}">
<CarouselView.ItemTemplate>
<DataTemplate>
<StackLayout
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand">
<Image Source="{Binding .}"></Image>
<Label Text="image should be here"></Label>
</StackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
<panCardView:CarouselView
ItemsSource="{Binding Images}"
BackgroundColor="{StaticResource ColorPrimary}"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<panCardView:CarouselView.ItemTemplate>
<DataTemplate>
<StackLayout
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand">
<Image Source="{Binding .}"></Image>
<Label Text="image should be here"></Label>
</StackLayout>
</DataTemplate>
</panCardView:CarouselView.ItemTemplate>
<controls:LeftArrowControl />
<controls:RightArrowControl />
<controls:IndicatorsControl ToFadeDuration="1500"/>
</panCardView:CarouselView>
<Image WidthRequest="20" HeightRequest="20" Source ="{Binding Images[0]}"></Image>
<Image WidthRequest="20" HeightRequest="20" Source ="{Binding Images[1]}"></Image>
<Image WidthRequest="20" HeightRequest="20" Source ="{Binding Images[2]}"></Image>
<Button Text="Close"></Button>
</StackLayout>
</ContentPage.Content>
</ContentPage>
and the collection bound is:
public ObservableCollection<ImageSource> Images
{
get => _images;
set
{
_images = value;
OnPropertyChanged();
}
}
UPDATE 1:
I've just edited the whole question because at first I though the problem could be related with Rg.Plugins.Popup because it was happening within a popup. But I've tried the same with a normal content page and the problem remains, so it's definitely something to do with the carousel.
UPDATE 2
I keep investigating. So far, the problem seems to be with image streams in carousels, either the Xamarin carousel or the CardView's library carousel (which have different mechanisms).
I've tried adding options and height and width request to the image that accesses the stream without luck
<!--in DataTemplate within the carousel-->
<Image Source="{Binding .}" HeightRequest="100"
WidthRequest="100"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"></Image>
<Label Text="image should be here"></Label>
UPDATE 3:
Thanks to Jack Hua for his comment and repo, I updated it to reflect the issue I have and managed to reproduce it at this specific commit here
Basically I have taken the same repo, added a QRCoder library to quickly generate images as byte[] at runtime and added the image sources from stream.
public Model() {
Images = new ObservableCollection<ImageSource>();
var imageOne = GetQrImageAsBytes();
var imageTwo = GetQrImageAsBytes();
var imageThree = GetQrImageAsBytes();
// This works
//Images.Add(ImageSource.FromFile("logo.jpg"));
//Images.Add(ImageSource.FromFile("sample.jpg"));
//Images.Add(ImageSource.FromFile("ttt.png"));
Images.Add(ImageSource.FromStream(() => new MemoryStream(imageOne)));
Images.Add(ImageSource.FromStream(() => new MemoryStream(imageTwo)));
Images.Add(ImageSource.FromStream(() => new MemoryStream(imageThree)));
}
private byte[] GetQrImageAsBytes()
{
var randomText = Guid.NewGuid().ToString();
var qrGenerator = new QRCodeGenerator();
var qrCodeData = qrGenerator.CreateQrCode(randomText, QRCodeGenerator.ECCLevel.L);
var qRCode = new PngByteQRCode(qrCodeData);
var qrCodeBytes = qRCode.GetGraphic(20);
return qrCodeBytes;
}
UPDATE 4:
I found the issue, I had to try a few times to make sure this really was the problem, but it certainly is.
Re-Sharper suggests me to make a change in ItemsSource="{Binding Images}" as it does not recognize Images. So I follow Re-Sharper recommendation and let it add a x:DataType="app265:Model" in xaml's ContentPage tag. That causes the problem. I don't really know why, but I'll sleep better tonight :)
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:app265="clr-namespace:App265;assembly=App265"
mc:Ignorable="d"
x:Class="App265.MainPage"
x:DataType="app265:Model"><!--this line that Re-Sharper adds causes the issue-->
Is this a Xamarin bug? or does it make sense to you? An explanation to why this x:DataType breaks things but only on the first load would be chosen as the right answer.
x:DataType="ImageSource"
Add this to your carousel view DataTemplate. It should solve your problem.
It seems there some issues with BindignContext detecting, so you should "help" to detect it yourself.
Same problem here with xamarin.forms 5.0.0.2012 but in my case my image sources are urls. It worked with x:DataType="x:String" in the carousel view DataTemplate
<CarouselView
ItemsSource="{Binding ImageSources}"
>
<CarouselView.ItemTemplate>
<DataTemplate
x:DataType="x:String">
<forms:CachedImage
Aspect="AspectFit"
ErrorPlaceholder="Placeholder"
LoadingPlaceholder="Placeholder"
DownsampleWidth="300"
DownsampleToViewSize="True"
Source="{Binding .}">
Related
I'm getting the error System.InvalidOperationException: 'Cannot convert "VerticalGrid, 2" into Xamarin.Forms.IItemsLayout' during InitalizeComponent() of my ContentPage containing a CollectionsView.
The code works properly on UWP, and the error occurs when running on Android. Being new to xamarin.forms, I'm not really sure what to start looking for.
EDIT: it works if I choose "VerticalList".
Here's a bit of my xaml:
<ContentPage ... >
<StackLayout>
<CollectionView
x:Name="DetailGrid"
ItemsLayout="VerticalGrid, 2" >
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="20" BackgroundColor="Crimson">
<Image Source= "{Binding Path}" WidthRequest="300"/>
<Label Text="{Binding FileName}" TextColor ="Bisque" LineBreakMode="WordWrap" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage>
And here's some code-behind:
namespace varlist
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CollectionPage : ContentPage
{
public ObservableCollection<NodeData> nodes = new ObservableCollection<NodeData>();
public CollectionPage ()
{
InitializeComponent ();
nodes.Add (new ImageData { FileName = "image_chair_pk.jpg" });
...
DetailGrid.ItemsSource = nodes;
}
}
}
I got the same error with you when I use a Xamarin.forms version 4.5.0.725.
After I update my Xamarin.forms to the latest version 4.8.0.1687, everything works well.
Please update your Xamarin.forms version to fix this problem:
I found a workaround. This appears to be a framework bug.
According to Xamarin.Forms CollectionView Layout the syntax I used should work - and it does work for UWP.
They also show an alternate declaration to specify ItemsLayout:
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="2" />
</CollectionView.ItemsLayout>
And, this syntax works on Android.
I filed a bug on github:[Bug] CollectionView with ItemsLayout=VerticalGrid crashes on Android #12920
You can omit this property if you wish it vertical, the default is set to VerticalList. If you want your collectionView to be Horizontal, just use HorizontalList.
See https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/collectionview/layout
I am using the scrollView and a stackLayout in it. Adding the View dynamically to the stackLayout. I am getting the following exception when I am trying to remove the View added:
The calling thread cannot access this object because a different
thread owns it.
My code is as following
<ScrollView Orientation="Vertical" VerticalOptions="FillAndExpand"
x:Name="MessagesScrollView">
<StackLayout Padding="7" x:Name="MessagesStackLayout"
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
</StackLayout>
</ScrollView>
Add the code behind is:
MessagesStackLayout.Children.Clear();
foreach (var chat in messagesList)
{
MessagesStackLayout.Children.Add(new CustomViewCell(chat));
}
I have a feeling it is not running the code on MainThread try the following and see if that works for you:
Device.BeginInvokeOnMainThread(() =>
{
MessagesStackLayout.Children.Add(new CustomViewCell(chat));
});
When putting together a TabbedPage in Xamarin.Forms, how do I get UWP to use the page's Icon property?
It looks like UWP could support this just fine, if I configure my Forms attributes/files correctly.
Here's my TabbedPage XAML. The icons are all set up and working for iOS and Android, and even the on-page Image in UWP renders fine (meaning the files are likely in the project correctly).
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:tabbed"
x:Class="tabbed.MainPage">
<TabbedPage.Children>
<local:InitialPage Title="Tab1" Icon="star.png" />
<ContentPage Title="Tab2" Icon="gear.png">
<ContentPage.Content>
<StackLayout>
<Label Text="A nice label." />
<Image Source="star.png" /><!-- works here -->
</StackLayout>
</ContentPage.Content>
</ContentPage>
</TabbedPage.Children>
</TabbedPage>
I outlined how this is possible here http://depblog.weblogs.us/2017/07/12/xamarin-forms-tabbed-page-uwp-with-images/
In short, you need to change the default HeaderTemplate that is being used by UWP. But due to the way Xamarin forms is started, this is not straightforward.
So you need to inject a custom template into the resource dictionary.
Example project is up on Github here https://github.com/Depechie/XamarinFormsTabbedPageUWPWithIcons
Longer detail:
You need to supply your own TabbedPageStyle and switch out the one that Xamarin is using for their UWP rendering.
So the new style contains an Image where we data bind the Source to the Xamarin Icon property.
<Style x:Key="TabbedPageStyle2" TargetType="uwp:FormsPivot">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Image Source="{Binding Icon, Converter={StaticResource IconConverter}}" Width="15" Height="15" />
<TextBlock Name="TabbedPageHeaderTextBlock" Text="{Binding Title}"
Style="{ThemeResource BodyTextBlockStyle}" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
The actual style switching is done in the App.Xaml.cs like this
((Style)this.Resources["TabbedPageStyle"]).Setters[0] = ((Style)this.Resources["TabbedPageStyle2"]).Setters[0];
You'll also need a converter to be sure the Image control understands the Icon source giving by Xamarin
public class IconConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value != null && value is Xamarin.Forms.FileImageSource)
return ((Xamarin.Forms.FileImageSource)value).File;
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
As it is currently, the UWP TabbedPage renderer does not use the Icon property at all, so getting tab icons will require a custom renderer. Even the official UWP samples don't actually seem to have this baked-in, requiring a custom UserControl.
The Android TabbedPageRenderer and iOS TabbedRenderer, and even the macOS TabbedPageRenderer, use the Icon property to adjust the tab UI, but the UWP renderer would need updating to make this work.
I have the following DataTemplates defined. The TextBlock works the xctk:ShortUpDown does not. In fact whenever I use a control from another namespace it doesn't work (i.e. no data displayed or updated
<DataTemplate x:Key="intDataTemplate">
<TextBlock Text="{Binding StringFormat=\{0:F0\}}"/>
</DataTemplate>
<DataTemplate x:Key="hexDataTemplate">
<xctk:ShortUpDown ParsingNumberStyle="HexNumber"/>
</DataTemplate>
These are the column definitions. There is no CellEditorTemplate available.
<xcdg:Column FieldName="Coefficient" Width="75"
CellContentTemplate="{StaticResource hexDataTemplate}" ReadOnly="False"/>
<xcdg:Column FieldName="Measured" Width="75" CellHorizontalContentAlignment="Right"
CellContentTemplate="{StaticResource intDataTemplate}" />
There just doesn't seem to be a lot of example code out there. The columns are auto generated.
Any suggestions are appreciated.
The CellContentTemplate is for display purposes only. If you put a control meant for editing in it, such as a ShortUpDown, you will get weird results.
Editor controls should be defined in the CellEditor. Also, don't forget to set the CellEditorBinding to connect it to the underlying value.
<xcdg:CellEditor x:Key="hexCellEditor">
<xcdg:CellEditor.EditTemplate>
<DataTemplate>
<xctk:ShortUpDown Value="{xcdg:CellEditorBinding}" ParsingNumberStyle="HexNumber"/>
</DataTemplate>
</xcdg:CellEditor.EditTemplate>
</xcdg:CellEditor>
<xcdg:Column FieldName="Measured" CellEditor="{StaticResource hexCellEditor}" ... />
I am trying a new approach i.e. XAML to make application in xamarin.forms. At this time i am facing an issue to reuse my stack layout which is having a image and label. How i can reuse my layout in different pages using XAML.
You can actually define your custom component in a separate XAML file and then just link the component wherever you need it.
For example a label with image can be grouped together in a dedicated XAML file:
<?xml version="1.0" encoding="utf-8" ?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="UserControls.ImageWithTitle"
VerticalOptions="Center" HorizontalOptions="Center" >
<Label HorizontalOptions="Center"
x:Name="TitleLabel" />
<Image Source="noimage.png" />
</StackLayout>
On the .cs file I've defined a binding for the TitleLabel
public string TitleName
{
get { return TitleLabel.Text; }
set { TitleLabel.Text = value; }
}
So when you include the component on another layout, you can assign the label value directly (or via a binding):
<usercontrols:ImageWithTitle TitleName="Home"/>