ImageGalleryControl 未触发
Posted
技术标签:
【中文标题】ImageGalleryControl 未触发【英文标题】:ImageGalleryControl not triggering 【发布时间】:2018-09-13 23:04:52 【问题描述】:我正在尝试从服务器下载以字节为单位的图像,但图像不会显示。我得到一个正确的字节数组并调整它的大小。它可以从相机添加图片,但从互联网添加图片时不起作用。
我已确认图像已正确保存并正确下载,因为我可以复制字节数组并使用字节数组字符串显示它。
我在调试时发现了比较这两种方法的问题,在execturepickcommand
中它触发了我的"ItemSourceChanged"
方法,但在AddImages
方法中没有触发。
收藏
public class ImageGalleryPageModel
public ObservableCollection<ImageModel> Images
get return images;
private ObservableCollection<ImageModel> images = new ObservableCollection<ImageModel>();
这可以从这个类中添加图片
private async Task ExecutePickCommand()
MediaFile file = await CrossMedia.Current.PickPhotoAsync();
if (file == null)
return;
byte[] imageAsBytes;
using (MemoryStream memoryStream = new MemoryStream())
file.GetStream().CopyTo(memoryStream);
file.Dispose();
imageAsBytes = memoryStream.ToArray();
if (imageAsBytes.Length > 0)
IImageResizer resizer = DependencyService.Get<IImageResizer>();
imageAsBytes = resizer.ResizeImage(imageAsBytes, 1080, 1080);
ImageSource imageSource = ImageSource.FromStream(() => new MemoryStream(imageAsBytes));
Images.Add(new ImageModel Source = imageSource, OrgImage = imageAsBytes );
然后我下载图像并将它们放入集合中,
private void AddTheImages(int imageIssueId)
var imageData = App.Client.GetImage(imageIssueId);
byte[] imageAsBytes = imageData.Item1;
if (imageAsBytes.Length > 0)
IImageResizer resizer = DependencyService.Get<IImageResizer>();
imageAsBytes = resizer.ResizeImage(imageAsBytes, 1080, 1080);
ImageSource imageSource = ImageSource.FromStream(() => new MemoryStream(imageAsBytes));
ImageGalleryViewModel.Images.Add(new ImageModel Source = imageSource, OrgImage = imageAsBytes );
Xaml
<freshMvvm:FreshBaseContentPage NavigationPage.HasNavigationBar="False"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:freshMvvm="clr-namespace:FreshMvvm;assembly=FreshMvvm"
xmlns:converters="clr-namespace:ASFT.Converters;assembly=ASFT"
xmlns:controls="clr-namespace:ASFT.Controls;assembly=ASFT"
x:Class="ASFT.Pages.IssuePage"
Padding="4,25,4,4"
x:Name="IssuePages">
...
<!--PictureGallery-->
<Label Text="IMAGES"
HorizontalTextAlignment="Start"
VerticalTextAlignment="Center"
Style="StaticResource Labelfont"
TextColor="White" />
<Grid BindingContext="Binding ImageGalleryViewModel">
<Grid.RowDefinitions>
<RowDefinition Height="128" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<controls:ImageGalleryControl Grid.Row="0"
ItemsSource="Binding Images">
<controls:ImageGalleryControl.ItemTemplate>
<DataTemplate>
<Image Source="Binding Source"
Aspect="AspectFit">
<Image.GestureRecognizers>
<TapGestureRecognizer
Command="Binding Path=BindingContext.PreviewImageCommand, Source=x:Reference IssuePages"
CommandParameter="Binding ImageId" />
</Image.GestureRecognizers>
</Image>
</DataTemplate>
</controls:ImageGalleryControl.ItemTemplate>
</controls:ImageGalleryControl>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Text="Add photo"
Command="Binding CameraCommand" />
<Button Grid.Column="1"
Text="Pick photo"
Command="Binding PickCommand" />
</Grid>
</Grid>
<Label Grid.Column="0"
Grid.Row="3"
Grid.ColumnSpan="3"
Text="Binding ImageText"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"
TextColor="White" />
...
</freshMvvm:FreshBaseContentPage>
这是控件,它是未触发的 itemsourcechanged。
private readonly StackLayout imageStack;
public ImageGalleryControl()
this.Orientation = ScrollOrientation.Horizontal;
imageStack = new StackLayout
Orientation = StackOrientation.Horizontal
;
this.Content = imageStack;
public new IList<View> Children
get return imageStack.Children;
public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create<ImageGalleryControl, IList>
(
view => view.ItemsSource,
default(IList),
BindingMode.TwoWay,
propertyChanging: (bindableObject, oldValue, newValue) =>
((ImageGalleryControl)bindableObject).ItemsSourceChanging();
,
propertyChanged: (bindableObject, oldValue, newValue) =>
((ImageGalleryControl)bindableObject).ItemsSourceChanged(bindableObject, oldValue, newValue);
);
public IList ItemsSource
get return (IList)GetValue(ItemsSourceProperty);
set SetValue(ItemsSourceProperty, value);
private void ItemsSourceChanging()
if (ItemsSource == null)
return;
private void CreateNewItem(IList newItem)
View view = (View)ItemTemplate.CreateContent();
if (view is BindableObject bindableObject)
bindableObject.BindingContext = newItem;
imageStack.Children.Add(view);
private void ItemsSourceChanged(BindableObject bindable, IList oldValue, IList newValue)
if (ItemsSource == null)
return;
if (newValue is INotifyCollectionChanged notifyCollection)
notifyCollection.CollectionChanged += (sender, args) =>
if (args.NewItems != null)
if (args.NewItems.Count > 0)
foreach (object newItem in args.NewItems)
View view = (View)ItemTemplate.CreateContent();
if (view is BindableObject bindableObject)
bindableObject.BindingContext = newItem;
imageStack.Children.Add(view);
else
imageStack.Children.Clear();
foreach (object item in ItemsSource)
View view = (View)ItemTemplate.CreateContent();
BindableObject bindableObject = (BindableObject) view;
if (bindableObject != null)
bindableObject.BindingContext = item;
imageStack.Children.Add(view);
if (args.OldItems != null)
// not supported
;
public DataTemplate ItemTemplate
get;
set;
public static readonly BindableProperty SelectedItemProperty =
BindableProperty.Create<ImageGalleryControl, object>
(
view => view.SelectedItem,
null,
BindingMode.TwoWay,
propertyChanged: (bindable, oldValue, newValue) =>
((ImageGalleryControl)bindable).UpdateSelectedIndex();
);
public object SelectedItem
get return GetValue(SelectedItemProperty);
set SetValue(SelectedItemProperty, value);
private void UpdateSelectedIndex()
if (SelectedItem == BindingContext)
return;
SelectedIndex = Children
.Select(c => c.BindingContext)
.ToList()
.IndexOf(SelectedItem);
public static readonly BindableProperty SelectedIndexProperty =
BindableProperty.Create<ImageGalleryControl, int>
(
carousel => carousel.SelectedIndex,
0,
BindingMode.TwoWay,
propertyChanged: (bindable, oldValue, newValue) =>
((ImageGalleryControl)bindable).UpdateSelectedItem();
);
public int SelectedIndex
get return (int)GetValue(SelectedIndexProperty);
set SetValue(SelectedIndexProperty, value);
private void UpdateSelectedItem()
SelectedItem = SelectedIndex > -1 ? Children[SelectedIndex].BindingContext : null;
【问题讨论】:
在没有调整大小的情况下可以工作吗?尝试将下载的图像保存到磁盘并打开它 - 可能你的字节有问题 没有 reziser 就无法工作,字节没有问题,我在一个页面上测试了它们,该页面采用字节数组并将其转换为图像,完美显示图像但是当excat 相同的数组进入集合 你试过网络客户端下载图片吗? var webClient = new WebClient(); byte[] imageBytes = webClient.DownloadData("google.com/images/logos/ps_logo2.png"); 不确定这里是否有用。 是的,也试过了。不知道为什么,为什么添加图像的一种情况有效而另一种无效。它们几乎相同。唯一的区别是我从互联网上获取另一个文件,从手机摄像头获取另一个文件。 您是否 100% 确定将它们添加到同一 ImageGalleryPageModel 实例中? 【参考方案1】:-
尝试为图像属性引发 Propertychanged 事件,例如:PropertyChanged(nameof(Images))。
然后,为了验证您在同一个 ViewModel 实例上,您可以订阅页面中的 BindingContextChanged 事件并验证您的 VM 对象是否正在更改。
我建议使用 ObservableCollection 作为:
public ObservableCollection<> Images get;set; = new ObservableCollection<>();
使用通用 ImageModel。 你不需要私有字段,它没有多大意义。
【讨论】:
嘿老兄,感谢您的回答。但这是一篇将近 3 年的帖子,哈哈,我已经改进了很久,可以编写更好的代码,甚至 Xamarin 也有了很大的改进。无论如何都接受了你的答案 m8以上是关于ImageGalleryControl 未触发的主要内容,如果未能解决你的问题,请参考以下文章