Skip to content

Commit

Permalink
Added waiting block feature in Avalonia 11 C# sample.
Browse files Browse the repository at this point in the history
kekyo committed Jul 8, 2023
1 parent dde5595 commit d349a97
Showing 6 changed files with 190 additions and 32 deletions.
41 changes: 41 additions & 0 deletions playground/EpoxyHello.Avalonia11/Controls/WaitingBlock.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!--
////////////////////////////////////////////////////////////////////////////
//
// Epoxy - An independent flexible XAML MVVM library for .NET
// Copyright (c) Kouji Matsui (@kozy_kekyo, @[email protected])
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
-->
<UserControl
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:EpoxyHello.Avalonia11.Controls"
mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"
x:Class="EpoxyHello.Avalonia11.Controls.WaitingBlock">

<UniformGrid Rows="3" Columns="3">
<Rectangle Fill="{Binding CellBrushes[0]}" />
<Rectangle Fill="{Binding CellBrushes[1]}" />
<Rectangle Fill="{Binding CellBrushes[2]}" />
<Rectangle Fill="{Binding CellBrushes[7]}" />
<Rectangle Fill="{x:Static Brushes.Transparent}" />
<Rectangle Fill="{Binding CellBrushes[3]}" />
<Rectangle Fill="{Binding CellBrushes[6]}" />
<Rectangle Fill="{Binding CellBrushes[5]}" />
<Rectangle Fill="{Binding CellBrushes[4]}" />
</UniformGrid>
</UserControl>
91 changes: 91 additions & 0 deletions playground/EpoxyHello.Avalonia11/Controls/WaitingBlock.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
////////////////////////////////////////////////////////////////////////////
//
// Epoxy - An independent flexible XAML MVVM library for .NET
// Copyright (c) Kouji Matsui (@kozy_kekyo, @[email protected])
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////

using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Epoxy;
using Epoxy.Supplemental;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;

namespace EpoxyHello.Avalonia11.Controls;

/// <summary>
/// Interaction logic for WaitingBlock.xaml
/// </summary>
public sealed partial class WaitingBlock : UserControl
{
public static readonly AvaloniaProperty CellBrushesProperty =
AvaloniaProperty.Register<WaitingBlock, ObservableCollection<IImmutableSolidColorBrush>?>(
"CellBrushes");

private int currentPosition;
private Timer timer;

public WaitingBlock()
{
InitializeComponent();
this.DataContext = this;

this.CellBrushes = Enumerable.Range(0, 8).
Select(_ => Brushes.Gray).
ToObservableCollection();

this.timer = new Timer(async _ =>
{
if (await UIThread.TryBind())
{
this.CellBrushes[this.currentPosition] = Brushes.Gray;
if (++this.currentPosition >= this.CellBrushes.Count)
{
this.currentPosition = 0;
}
this.CellBrushes[this.currentPosition] = Brushes.Red;
}
},
null,
TimeSpan.Zero,
TimeSpan.Zero);
}

private void InitializeComponent() =>
AvaloniaXamlLoader.Load(this);

protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
this.timer.Change(TimeSpan.Zero, TimeSpan.FromMilliseconds(300));
}

protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
this.timer.Change(TimeSpan.Zero, TimeSpan.Zero);
base.OnDetachedFromVisualTree(e);
}

public ObservableCollection<IImmutableSolidColorBrush>? CellBrushes
{
get => (ObservableCollection<IImmutableSolidColorBrush>?)GetValue(CellBrushesProperty);
set => SetValue(CellBrushesProperty, value);
}
}
2 changes: 2 additions & 0 deletions playground/EpoxyHello.Avalonia11/EpoxyHello.Avalonia11.csproj
Original file line number Diff line number Diff line change
@@ -6,13 +6,15 @@
<TargetFrameworks>net48;net6.0;net7.0</TargetFrameworks>
<IncludeAvaloniaGenerators>true</IncludeAvaloniaGenerators>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="All" />
<PackageReference Include="Avalonia" Version="11.0.0" />
<PackageReference Include="Avalonia.Desktop" Version="11.0.0" />
<PackageReference Include="Avalonia.Diagnostics" Version="11.0.0" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Epoxy.Core.Avalonia11\Epoxy.Core.Avalonia11.csproj" />
<ProjectReference Include="..\..\src\Epoxy.Avalonia11\Epoxy.Avalonia11.csproj" />
61 changes: 38 additions & 23 deletions playground/EpoxyHello.Avalonia11/ViewModels/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
@@ -17,18 +17,18 @@
//
////////////////////////////////////////////////////////////////////////////

#nullable enable
using Epoxy;

using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

using Avalonia.Controls;
using Avalonia.Media.Imaging;

using Epoxy;
using EpoxyHello.Models;
using EpoxyHello.Avalonia11.Controls;

namespace EpoxyHello.Avalonia11.ViewModels;

@@ -43,6 +43,8 @@ public sealed class MainWindowViewModel

public Command Fetch { get; }

public Pile<Panel> IndicatorPile { get; } = Pile.Factory.Create<Panel>();

public MainWindowViewModel()
{
// A handler for window opened
@@ -55,36 +57,49 @@ public MainWindowViewModel()
// A handler for fetch button
this.Fetch = Command.Factory.Create(async () =>
{
// Disable button
this.IsEnabled = false;

try
// Temporary rent Grid children accessor
await this.IndicatorPile.RentAsync(async indicator =>
{
// Uses The Cat API
var cats = await TheCatAPI.FetchTheCatsAsync(10);
// Show WaitingBlock control
var waitingBlock = new WaitingBlock();
indicator.Children.Add(waitingBlock);

this.Items.Clear();
try
{
// Uses The Cat API
var cats = await TheCatAPI.FetchTheCatsAsync(10);

static async ValueTask<Bitmap?> FetchImageAsync(Uri url) =>
new Bitmap(new MemoryStream(await TheCatAPI.FetchImageAsync(url)));
this.Items.Clear();

foreach (var cat in cats)
{
if (cat.Url is { } url)
static async ValueTask<Bitmap?> FetchImageAsync(Uri url) =>
new Bitmap(new MemoryStream(await TheCatAPI.FetchImageAsync(url)));

foreach (var cat in cats)
{
var bleed = cat?.Bleeds.FirstOrDefault();
this.Items.Add(new ItemViewModel
if (cat.Url is { } url)
{
Title = bleed?.Description ?? bleed?.Temperament ?? "(No comment)",
Score = bleed?.Intelligence ?? 5,
Image = await FetchImageAsync(url)
});
var bleed = cat?.Bleeds.FirstOrDefault();
this.Items.Add(new ItemViewModel
{
Title = bleed?.Description ?? bleed?.Temperament ?? "(No comment)",
Score = bleed?.Intelligence ?? 5,
Image = await FetchImageAsync(url)
});
}
}
}
}
finally
{
this.IsEnabled = true;
}
finally
{
// Hide WaitingBlock control
indicator.Children.Remove(waitingBlock);

// Re-enable button
this.IsEnabled = true;
}
});
});
}
}
6 changes: 6 additions & 0 deletions playground/EpoxyHello.Avalonia11/Views/MainWindow.axaml
Original file line number Diff line number Diff line change
@@ -65,6 +65,12 @@
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Grid Width="50" Height="50"
Margin="0,0,30,30"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
epoxy:Anchor.Pile="{Binding IndicatorPile}">
</Grid>
</Grid>
</DockPanel>
</Window>
21 changes: 12 additions & 9 deletions playground/EpoxyHello.Wpf/Controls/WaitingBlock.xaml.cs
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@
//
////////////////////////////////////////////////////////////////////////////

using Epoxy;
using Epoxy.Supplemental;
using System;
using System.Collections.ObjectModel;
@@ -51,16 +52,18 @@ public WaitingBlock()
Select(_ => Brushes.Gray).
ToObservableCollection();

this.timer = new Timer(_ => Dispatcher.BeginInvoke(
new EventHandler((s, e) =>
this.timer = new Timer(async _ =>
{
this.CellBrushes[this.currentPosition] = Brushes.Gray;
if (++this.currentPosition >= this.CellBrushes.Count)
if (await UIThread.TryBind())
{
this.currentPosition = 0;
this.CellBrushes[this.currentPosition] = Brushes.Gray;
if (++this.currentPosition >= this.CellBrushes.Count)
{
this.currentPosition = 0;
}
this.CellBrushes[this.currentPosition] = Brushes.Red;
}
this.CellBrushes[this.currentPosition] = Brushes.Red;
}), this, EventArgs.Empty),
},
null,
TimeSpan.Zero,
TimeSpan.Zero);
@@ -80,9 +83,9 @@ protected override void OnVisualParentChanged(DependencyObject oldParent)
}
}

public ObservableCollection<SolidColorBrush> CellBrushes
public ObservableCollection<SolidColorBrush>? CellBrushes
{
get => (ObservableCollection<SolidColorBrush>)GetValue(CellBrushesProperty);
get => (ObservableCollection<SolidColorBrush>?)GetValue(CellBrushesProperty);
set => SetValue(CellBrushesProperty, value);
}
}

0 comments on commit d349a97

Please sign in to comment.