Reputation: 667
I'm developing an Avalonia App using ReactiveUI and MVVM. I want to display an image from a web URL, what would be the best course of action to achieve this ? I have setup the following Binding :
this.OneWayBind(
ViewModel,
vm => vm.UserProfileImageUrl,
v => v.ProfileImage.Source,
ImageConverter
).DisposeWith(disposables);
And Binding adapter :
private IImage ImageConverter(string arg)
{
}
But I don't know how to implement the Binding adapter to download the image without blocking the UI. Is there some tool like Glide on Android ?
Thank you in advance,
Upvotes: 4
Views: 7313
Reputation: 2489
I'd recommend AsyncImageLoader.Avalonia, It can handle Async based downloads without much overhead and with added features including Disk and Memory based caching of the results and "ready" properties which will allow you to display loading spinners for downloading images.
You can find a basic example of using it here, but for brevity to show you the power. I'll paste the line of the resultant axaml for once everything is setup:
<Image asyncImageLoader:ImageLoader.Source="https://github.com/AvaloniaUtils/AsyncImageLoader.Avalonia/raw/master/AsyncImageLoader.Avalonia.Demo/Assets/cat2.jpg" />
The added benefits being that you don't need any special handling in your View or View Model. You can bind Source to a property that figures out the URL and do everything with just strings such as concatenation etc.
Upvotes: 7
Reputation: 8281
You can download and store the Image in your ViewModel asynchronously, or using the download complete event for example like this:
public class MainWindowViewModel : ViewModelBase
{
private string chessboardUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d5/Chess_Board.svg/2000px-Chess_Board.svg.png";
public string ChessboardUrl
{
get => chessboardUrl;
set {
this.RaiseAndSetIfChanged(ref chessboardUrl, value);
DownloadImage(ChessboardUrl);
System.Diagnostics.Debug.WriteLine(ChessboardUrl);
}
}
private Avalonia.Media.Imaging.Bitmap chessboard = null;
public Avalonia.Media.Imaging.Bitmap Chessboard
{
get => chessboard;
set => this.RaiseAndSetIfChanged(ref chessboard, value);
}
public MainWindowViewModel()
{
DownloadImage(ChessboardUrl);
}
public void DownloadImage(string url)
{
using (WebClient client = new WebClient())
{
client.DownloadDataAsync(new Uri(url));
client.DownloadDataCompleted += DownloadComplete;
}
}
private void DownloadComplete(object sender, DownloadDataCompletedEventArgs e)
{
try
{
byte[] bytes = e.Result;
Stream stream = new MemoryStream(bytes);
var image = new Avalonia.Media.Imaging.Bitmap(stream);
Chessboard = image;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex);
Chessboard = null; // Could not download...
}
}
}
Then you can easily bind to the Url and the associated image. For example like this from the XAML (with appropriate DataContext):
<StackPanel>
<Image Source="{Binding Chessboard}"
Width="200"
Height="200"
Name="MyImage"></Image>
<TextBox Text="{Binding ChessboardUrl}"></TextBox>
</StackPanel>
Upvotes: 6