Skip to content

Commit 0f3272e

Browse files
committed
Add support for existing IImage loading in AdvancedImage. Close #17
1 parent e4b1e2b commit 0f3272e

File tree

4 files changed

+98
-14
lines changed

4 files changed

+98
-14
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
using System.Globalization;
3+
using Avalonia.Data.Converters;
4+
5+
namespace AsyncImageLoader.Avalonia.Demo.Converters;
6+
7+
public class GetClassNameConverter : IValueConverter {
8+
public static GetClassNameConverter Instance { get; } = new();
9+
10+
/// <inheritdoc />
11+
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) {
12+
if (value is null) {
13+
return "null";
14+
}
15+
16+
return value.GetType().Name;
17+
}
18+
19+
/// <inheritdoc />
20+
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) {
21+
throw new NotSupportedException();
22+
}
23+
}

AsyncImageLoader.Avalonia.Demo/Pages/AdvancedImagePage.axaml

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
55
xmlns:asyncImageLoader="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia"
66
xmlns:services="clr-namespace:AsyncImageLoader.Avalonia.Demo.Services"
7-
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
7+
xmlns:converters="clr-namespace:AsyncImageLoader.Avalonia.Demo.Converters"
8+
mc:Ignorable="d" d:DesignWidth="800"
89
x:Class="AsyncImageLoader.Avalonia.Demo.Pages.AdvancedImagePage">
9-
<Grid ColumnDefinitions="* 8 150 150" RowDefinitions="Auto Auto Auto Auto Auto"
10+
<Grid ColumnDefinitions="* 8 150 150" RowDefinitions="Auto Auto Auto Auto Auto Auto"
1011
HorizontalAlignment="Center">
1112
<TextBlock Grid.Column="2" Grid.Row="0" HorizontalAlignment="Center" Text="AdvancedImage" />
1213
<TextBlock Grid.Column="3" Grid.Row="0" HorizontalAlignment="Center" Text="Image" />
@@ -60,8 +61,32 @@
6061
<asyncImageLoader:AdvancedImage Grid.Row="4" Grid.Column="2"
6162
Width="150" Height="150" CornerRadius="5 10 15 20"
6263
Source="/Assets/cat5.jpg" />
63-
<Border Grid.Row="4" Grid.Column="3" CornerRadius="5 10 15 20" ClipToBounds="True" Width="150" Height="150">
64+
<Border Grid.Row="4" Grid.Column="3" CornerRadius="5 10 15 20" ClipToBounds="True" Width="150" Height="150">
6465
<Image Source="/Assets/cat5.jpg" Width="150" Height="150" />
6566
</Border>
67+
68+
<StackPanel Grid.Row="5" Grid.Column="0" HorizontalAlignment="Left">
69+
<TextBlock TextWrapping="Wrap">
70+
<TextBlock.Text>
71+
You can set CurrentImage property by youself. This sets Source back to null.
72+
</TextBlock.Text>
73+
</TextBlock>
74+
<TextBlock>
75+
<Run>Source: </Run>
76+
<Run Text="{Binding #CurrentImageExample.Source}"></Run>
77+
</TextBlock>
78+
<TextBlock>
79+
<Run>CurrentImage: </Run>
80+
<Run Text="{Binding #CurrentImageExample.CurrentImage, Converter={x:Static converters:GetClassNameConverter.Instance}, Mode=OneWay}" />
81+
</TextBlock>
82+
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
83+
<Button Click="SetSourceButton_OnClick">Set Source</Button>
84+
<Button Click="SetCurrentImageButton_OnClick">Set CurrentImage</Button>
85+
</StackPanel>
86+
</StackPanel>
87+
<asyncImageLoader:AdvancedImage Grid.Row="5" Grid.Column="2"
88+
Name="CurrentImageExample"
89+
Width="150" Height="150"
90+
Source="/Assets/cat5.jpg" />
6691
</Grid>
6792
</UserControl>
Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
1-
using Avalonia;
1+
using System;
2+
using Avalonia;
23
using Avalonia.Controls;
34
using Avalonia.Interactivity;
45
using Avalonia.Markup.Xaml;
6+
using Avalonia.Media.Imaging;
7+
using Avalonia.Platform;
58

69
namespace AsyncImageLoader.Avalonia.Demo.Pages {
710
public partial class AdvancedImagePage : UserControl {
811
public AdvancedImagePage() {
912
InitializeComponent();
1013
}
1114

12-
private void InitializeComponent() {
13-
AvaloniaXamlLoader.Load(this);
14-
}
15-
1615
private void ReloadButton_OnClick(object? sender, RoutedEventArgs e) {
17-
var advancedImage = this.FindControl<AdvancedImage>("ReloadableAdvancedImage");
18-
advancedImage.Source = null;
19-
advancedImage.Source = "https://github.com/AvaloniaUtils/AsyncImageLoader.Avalonia/raw/master/AsyncImageLoader.Avalonia.Demo/Assets/cat0.jpg";
16+
ReloadableAdvancedImage.Source = null;
17+
ReloadableAdvancedImage.Source = "https://github.com/AvaloniaUtils/AsyncImageLoader.Avalonia/raw/master/AsyncImageLoader.Avalonia.Demo/Assets/cat0.jpg";
18+
}
19+
20+
private void SetSourceButton_OnClick(object? sender, RoutedEventArgs e) {
21+
CurrentImageExample.Source = "/Assets/cat5.jpg";
22+
}
23+
24+
private void SetCurrentImageButton_OnClick(object? sender, RoutedEventArgs e) {
25+
using var stream = AssetLoader.Open(new Uri("avares://AsyncImageLoader.Avalonia.Demo/Assets/cat4.jpg", UriKind.RelativeOrAbsolute));
26+
CurrentImageExample.CurrentImage = new Bitmap(stream);
2027
}
2128
}
2229
}

AsyncImageLoader.Avalonia/AdvancedImage.axaml.cs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ public bool IsLoading
142142
public IImage? CurrentImage
143143
{
144144
get => _currentImage;
145-
private set => SetAndRaise(CurrentImageProperty, ref _currentImage, value);
145+
set => SetAndRaise(CurrentImageProperty, ref _currentImage, value);
146146
}
147147

148148
/// <summary>
@@ -169,16 +169,31 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
169169
UpdateImage(change.GetNewValue<string>(), Loader);
170170
else if (change.Property == LoaderProperty && ShouldLoaderChangeTriggerUpdate)
171171
UpdateImage(change.GetNewValue<string>(), Loader);
172+
else if (change.Property == CurrentImageProperty)
173+
ClearSourceIfUserProvideImage();
172174
else if (change.Property == CornerRadiusProperty)
173175
UpdateCornerRadius(change.GetNewValue<CornerRadius>());
174176
else if (change.Property == BoundsProperty && CornerRadius != default) UpdateCornerRadius(CornerRadius);
175177
base.OnPropertyChanged(change);
176178
}
177179

180+
private void ClearSourceIfUserProvideImage() {
181+
if (CurrentImage is not null and not ImageWrapper) {
182+
// User provided image himself
183+
Source = null;
184+
}
185+
}
186+
178187
private async void UpdateImage(string? source, IAsyncImageLoader? loader)
179188
{
180189
_updateCancellationToken?.Cancel();
181190
_updateCancellationToken?.Dispose();
191+
_updateCancellationToken = null;
192+
if (source is null && CurrentImage is not ImageWrapper) {
193+
// User provided image himself
194+
return;
195+
}
196+
182197
var cancellationTokenSource = _updateCancellationToken = new CancellationTokenSource();
183198
IsLoading = true;
184199
CurrentImage = null;
@@ -219,8 +234,8 @@ private async void UpdateImage(string? source, IAsyncImageLoader? loader)
219234

220235
if (cancellationTokenSource.IsCancellationRequested)
221236
return;
222-
CurrentImage = bitmap;
223-
IsLoading = false;
237+
CurrentImage = bitmap is null ? null : new ImageWrapper(bitmap);
238+
IsLoading = false;
224239
}
225240

226241
private void UpdateCornerRadius(CornerRadius radius)
@@ -280,4 +295,18 @@ protected override Size ArrangeOverride(Size finalSize)
280295
? Stretch.CalculateSize(finalSize, CurrentImage.Size)
281296
: base.ArrangeOverride(finalSize);
282297
}
298+
299+
public sealed class ImageWrapper : IImage {
300+
public IImage ImageImplementation { get; }
301+
internal ImageWrapper(IImage imageImplementation) {
302+
ImageImplementation = imageImplementation;
303+
}
304+
/// <inheritdoc />
305+
public void Draw(DrawingContext context, Rect sourceRect, Rect destRect) {
306+
ImageImplementation.Draw(context, sourceRect, destRect);
307+
}
308+
309+
/// <inheritdoc />
310+
public Size Size => ImageImplementation.Size;
311+
}
283312
}

0 commit comments

Comments
 (0)