Hello, In my code I use an ObservableCollection<MyPictureClass> as the image source.
When I initially load the page, it reflects the images in the initial get from my database. However if the user adds an image to the database, and I re-build the ObservableCollection<MyPictureClass> the displayed Carousel doesn't reflect the new images, I have to exit the page, and return to it.
Here is my code.
/// <summary>
/// Says the cheese.
/// </summary>
internal void SayCheese(ref TemplateCarouselView control)
{
try
{
RefreshPagePhotos();
control.ItemsSource = lPhotos;
OnPropertyChanged(nameof(lPhotos));
}
catch (Exception ex)
{
DebugTools.LogException(ex);
}
return;
}
//block the update until done with the Camera code. Then rebuild the image collection.
private async void RefreshPagePhotos()
{
await CoreGlobals.dbSemaphore.WaitAsync();
await RefreshPhotos();
}
//Refresh the collection of images.
private async Task RefreshPhotos()
{
if (MyWeapon.Id >= 0)
{
lPhotos = await PhotoRepo.GetItemByParentID(MyWeapon.Id, (int)RecordCatagory.Item, (int)RecordType.Type).ConfigureAwait(true);
OnPropertyChanged("lPhotos");
}
}
My template for the carousel is pretty intense, so I've included it here (perhaps there's something here that's causing the problem?
public partial class TemplateCarouselView : SfCarousel
{
public DataTemplate dt;
public TemplateCarouselView()
{
try
{
HeightRequest = 350;
ItemHeight = 350;
ItemSpacing = 2;
ItemWidth = 250;
ViewMode = ViewMode.Default;
WidthRequest = 400;
Offset = 1;
dt = new DataTemplate(() =>
{
var keyLayout = new StackLayout();
var bindPhoto = new Binding()
{
Converter = new FillImageFromBytes(),
Path = "Image"
};
var bindLocalPath = new Binding()
{
Converter = new FillImageFromBytes(),
Path = "."
};
var tgRec = new TapGestureRecognizer()
{
CommandParameter = bindLocalPath,
NumberOfTapsRequired = 1
};
tgRec.Tapped += async (s, e) =>
{
if (ActionList != null)
{
var act = await Application.Current.MainPage.DisplayActionSheet(
StringTools.GetStringResource("szPhotoOptions"),
null,
StringTools.GetStringResource("szOK"),
ActionList.ToArray());
await TapHandler.ImageTapHandler((Photos)((TappedEventArgs)e).Parameter, act, KeyButton, ParentObject);
}
};
//tgRec.SetBinding(TapGestureRecognizer.CommandProperty, bindTapped);
tgRec.SetBinding(TapGestureRecognizer.CommandParameterProperty, ".");
keyLayout.GestureRecognizers.Add(tgRec);
var img = new Image()
{
Aspect = Aspect.AspectFit,
HeightRequest = 350,
WidthRequest = 250,
};
img.SetBinding(Image.SourceProperty, bindPhoto);
var lblFileName = new Label()
{
HorizontalTextAlignment = TextAlignment.Center,
};
lblFileName.SetBinding(Label.TextProperty, "FileName");
keyLayout.Children.Add(img);
keyLayout.Children.Add(lblFileName);
return new ViewCell { View = keyLayout };
});
}
catch (Exception ex)
{
DebugTools.LogException(ex);
}
ItemTemplate = dt;
}
/// <summary>
/// The action list property
/// </summary>
public static readonly BindableProperty ActionListProperty = BindableProperty.Create(nameof(ActionList), typeof(List<string>), typeof(List<string>));
/// <summary>
/// Gets or sets the action list.
/// </summary>
/// <value>
/// The action list.
/// </value>
public List<string> ActionList
{
get
{
return (List<string>)GetValue(ActionListProperty);
}
set
{
SetValue(ActionListProperty, value);
}
}
/// <summary>
/// The parent object property
/// </summary>
public static readonly BindableProperty ParentObjectProperty = BindableProperty.Create(nameof(ParentObject), typeof(Object), typeof(Object));
/// <summary>
/// Gets or sets the parent object.
/// </summary>
/// <value>
/// The parent object.
/// </value>
public Object ParentObject
{
get
{
return (Object)GetValue(ParentObjectProperty);
}
set
{
SetValue(ParentObjectProperty, value);
}
}
/// <summary>
/// The key button property
/// </summary>
public static readonly BindableProperty KeyButtonProperty = BindableProperty.Create(nameof(KeyButton), typeof(ImageButton), typeof(ImageButton));
/// <summary>
/// Gets or sets the key button.
/// </summary>
/// <value>
/// The key button.
/// </value>
public ImageButton KeyButton
{
get
{
return (ImageButton)GetValue(KeyButtonProperty);
}
set
{
SetValue(KeyButtonProperty, value);
}
}
}
The additional bits I've added are for various controls that I link in to interfacing with this control.
When a user taps on an image there are a series of actions that are displayed for managing the images. There is also a "Key Image" that is an image button who's tap gesture recognizer initiates the camera function.
Since the Camera code is executing properly, and my semaphore process is functioning as expected (the camera code releases the semaphore when the image has been added to the database.)
I have tried this by just recreating the collection, by calling OnPropertyChanged("lPhotos"), and in this method, passing a pointer to the control, and reassigning the ItemSource with the new one.
How can I force the control to redraw it's self?
Cheers!