Browse Source

Merge branch 'master' into compiled-bindings-fixes

pull/4454/head
Steven Kirk 6 years ago
committed by GitHub
parent
commit
af2c23cc1f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      build/ReactiveUI.props
  2. 2
      build/SharedVersion.props
  3. 2
      samples/ControlCatalog/App.xaml
  4. 5
      samples/ControlCatalog/Pages/ContextMenuPage.xaml
  5. 6
      samples/ControlCatalog/Pages/MenuPage.xaml
  6. 3
      samples/RenderDemo/MainWindow.xaml
  7. 92
      samples/RenderDemo/Pages/WriteableBitmapPage.cs
  8. 6
      src/Avalonia.Base/ApiCompatBaseline.txt
  9. 4
      src/Avalonia.Base/AvaloniaObject.cs
  10. 6
      src/Avalonia.Base/AvaloniaProperty.cs
  11. 25
      src/Avalonia.Base/DirectProperty.cs
  12. 39
      src/Avalonia.Base/DirectPropertyBase.cs
  13. 2
      src/Avalonia.Controls/Repeater/ItemsRepeaterElementIndexChangedEventArgs.cs
  14. 17
      src/Avalonia.Controls/Repeater/ViewportManager.cs
  15. 2
      src/Avalonia.Controls/Window.cs
  16. 11
      src/Avalonia.Controls/WindowBase.cs
  17. 10
      src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs
  18. 4
      src/Avalonia.ReactiveUI/AutoDataTemplateBindingHook.cs
  19. 22
      src/Avalonia.ReactiveUI/RoutedViewHost.cs
  20. 2
      src/Avalonia.Styling/Styling/PropertySetterBindingInstance.cs
  21. 2
      src/Avalonia.Themes.Default/Window.xaml
  22. 2
      src/Avalonia.Themes.Fluent/ContextMenu.xaml
  23. 14
      src/Avalonia.Themes.Fluent/MenuItem.xaml
  24. 12
      src/Avalonia.Visuals/ApiCompatBaseline.txt
  25. 21
      src/Avalonia.Visuals/Media/Imaging/Bitmap.cs
  26. 33
      src/Avalonia.Visuals/Media/Imaging/WriteableBitmap.cs
  27. 21
      src/Avalonia.Visuals/Platform/AlphaFormat.cs
  28. 19
      src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs
  29. 9
      src/Skia/Avalonia.Skia/ImmutableBitmap.cs
  30. 16
      src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
  31. 22
      src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs
  32. 10
      src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs
  33. 17
      src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs
  34. 17
      src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs
  35. 4
      src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs
  36. 9
      src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs
  37. 99
      src/Windows/Avalonia.Win32/WindowImpl.cs
  38. 23
      tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_DataValidation.cs
  39. 6
      tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Direct.cs
  40. 105
      tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Metadata.cs
  41. 29
      tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_SetValue.cs
  42. 3
      tests/Avalonia.Base.UnitTests/DirectPropertyTests.cs
  43. 8
      tests/Avalonia.Benchmarks/NullRenderingPlatform.cs
  44. 81
      tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs
  45. 76
      tests/Avalonia.ReactiveUI.UnitTests/RoutedViewHostTest.cs
  46. 2
      tests/Avalonia.RenderTests/Media/BitmapTests.cs
  47. 15
      tests/Avalonia.Styling.UnitTests/SetterTests.cs
  48. 8
      tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs
  49. 6
      tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs

2
build/ReactiveUI.props

@ -1,5 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="ReactiveUI" Version="10.3.6" />
<PackageReference Include="ReactiveUI" Version="11.5.17" />
</ItemGroup>
</Project>

2
build/SharedVersion.props

@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Product>Avalonia</Product>
<Version>0.9.999</Version>
<Version>0.10.999</Version>
<Copyright>Copyright 2020 &#169; The AvaloniaUI Project</Copyright>
<PackageProjectUrl>https://avaloniaui.net</PackageProjectUrl>
<RepositoryUrl>https://github.com/AvaloniaUI/Avalonia/</RepositoryUrl>

2
samples/ControlCatalog/App.xaml

@ -11,7 +11,7 @@
<Setter Property="FontSize" Value="14" />
</Style>
<Style Selector="TextBlock.h3">
<Setter Property="FontSize" Value="10" />
<Setter Property="FontSize" Value="12" />
</Style>
<StyleInclude Source="/SideBar.xaml"/>
</Application.Styles>

5
samples/ControlCatalog/Pages/ContextMenuPage.xaml

@ -14,13 +14,14 @@
Padding="48,48,48,48">
<Border.ContextMenu>
<ContextMenu>
<MenuItem Header="Standard _Menu Item"/>
<MenuItem Header="Standard _Menu Item" InputGesture="Ctrl+A" />
<MenuItem Header="_Disabled Menu Item" IsEnabled="False" InputGesture="Ctrl+D" />
<Separator/>
<MenuItem Header="Menu with _Submenu">
<MenuItem Header="Submenu _1"/>
<MenuItem Header="Submenu _2"/>
</MenuItem>
<MenuItem Header="Menu Item with _Icon">
<MenuItem Header="Menu Item with _Icon" InputGesture="Ctrl+Shift+B">
<MenuItem.Icon>
<Image Source="/Assets/github_icon.png"/>
</MenuItem.Icon>

6
samples/ControlCatalog/Pages/MenuPage.xaml

@ -16,13 +16,17 @@
<TextBlock Classes="h3" Margin="4 8">Defined in XAML</TextBlock>
<Menu>
<MenuItem Header="_First">
<MenuItem Header="Standard _Menu Item" InputGesture="Ctrl+A"/>
<MenuItem Header="Standard _Menu Item" InputGesture="Ctrl+A" />
<MenuItem Header="_Disabled Menu Item" IsEnabled="False" InputGesture="Ctrl+D" />
<Separator/>
<MenuItem Header="Menu with _Submenu">
<MenuItem Header="Submenu _1"/>
<MenuItem Header="Submenu _2 with Submenu">
<MenuItem Header="Submenu Level 2" />
</MenuItem>
<MenuItem Header="Submenu _3 with Submenu Disabled" IsEnabled="False">
<MenuItem Header="Submenu Level 2" />
</MenuItem>
</MenuItem>
<MenuItem Header="Menu Item with _Icon" InputGesture="Ctrl+Shift+B">
<MenuItem.Icon>

3
samples/RenderDemo/MainWindow.xaml

@ -44,6 +44,9 @@
<TabItem Header="RenderTargetBitmap">
<pages:RenderTargetBitmapPage/>
</TabItem>
<TabItem Header="WriteableBitmap">
<pages:WriteableBitmapPage/>
</TabItem>
<TabItem Header="GlyphRun">
<pages:GlyphRunPage/>
</TabItem>

92
samples/RenderDemo/Pages/WriteableBitmapPage.cs

@ -0,0 +1,92 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Controls;
using Avalonia.LogicalTree;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Media.Immutable;
using Avalonia.Platform;
using Avalonia.Threading;
namespace RenderDemo.Pages
{
public class WriteableBitmapPage : Control
{
private WriteableBitmap _unpremulBitmap;
private WriteableBitmap _premulBitmap;
private readonly Stopwatch _st = Stopwatch.StartNew();
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
_unpremulBitmap = new WriteableBitmap(new PixelSize(256, 256), new Vector(96, 96), PixelFormat.Bgra8888, AlphaFormat.Unpremul);
_premulBitmap = new WriteableBitmap(new PixelSize(256, 256), new Vector(96, 96), PixelFormat.Bgra8888, AlphaFormat.Premul);
base.OnAttachedToLogicalTree(e);
}
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{
base.OnDetachedFromLogicalTree(e);
_unpremulBitmap?.Dispose();
_unpremulBitmap = null;
_premulBitmap?.Dispose();
_unpremulBitmap = null;
}
public override void Render(DrawingContext context)
{
void FillPixels(WriteableBitmap bitmap, byte fillAlpha, bool premul)
{
using (var fb = bitmap.Lock())
{
var data = new int[fb.Size.Width * fb.Size.Height];
for (int y = 0; y < fb.Size.Height; y++)
{
for (int x = 0; x < fb.Size.Width; x++)
{
var color = new Color(fillAlpha, 0, 255, 0);
if (premul)
{
byte r = (byte) (color.R * color.A / 255);
byte g = (byte) (color.G * color.A / 255);
byte b = (byte) (color.B * color.A / 255);
color = new Color(fillAlpha, r, g, b);
}
data[y * fb.Size.Width + x] = (int) color.ToUint32();
}
}
Marshal.Copy(data, 0, fb.Address, fb.Size.Width * fb.Size.Height);
}
}
base.Render(context);
byte alpha = (byte)((_st.ElapsedMilliseconds / 10) % 256);
FillPixels(_unpremulBitmap, alpha, false);
FillPixels(_premulBitmap, alpha, true);
context.FillRectangle(Brushes.Red, new Rect(0, 0, 256 * 3, 256));
context.DrawImage(_unpremulBitmap,
new Rect(0, 0, 256, 256),
new Rect(0, 0, 256, 256));
context.DrawImage(_premulBitmap,
new Rect(0, 0, 256, 256),
new Rect(256, 0, 256, 256));
context.FillRectangle(new ImmutableSolidColorBrush(Colors.Lime, alpha / 255d), new Rect(512, 0, 256, 256));
Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background);
}
}
}

6
src/Avalonia.Base/ApiCompatBaseline.txt

@ -0,0 +1,6 @@
Compat issues with assembly Avalonia.Base:
MembersMustExist : Member 'public void Avalonia.DirectProperty<TOwner, TValue>..ctor(System.String, System.Func<TOwner, TValue>, System.Action<TOwner, TValue>, Avalonia.DirectPropertyMetadata<TValue>, System.Boolean)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'protected void Avalonia.DirectPropertyBase<TValue>..ctor(Avalonia.AvaloniaProperty, System.Type, Avalonia.PropertyMetadata, System.Boolean)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'protected void Avalonia.DirectPropertyBase<TValue>..ctor(System.String, System.Type, Avalonia.PropertyMetadata, System.Boolean)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public System.Boolean Avalonia.DirectPropertyBase<TValue>.IsDataValidationEnabled.get()' does not exist in the implementation but it does exist in the contract.
Total Issues: 4

4
src/Avalonia.Base/AvaloniaObject.cs

@ -806,7 +806,9 @@ namespace Avalonia
break;
}
if (p.IsDataValidationEnabled)
var metadata = p.GetMetadata(GetType());
if (metadata.EnableDataValidation == true)
{
UpdateDataValidation(property, value);
}

6
src/Avalonia.Base/AvaloniaProperty.cs

@ -369,14 +369,14 @@ namespace Avalonia
var metadata = new DirectPropertyMetadata<TValue>(
unsetValue: unsetValue,
defaultBindingMode: defaultBindingMode);
defaultBindingMode: defaultBindingMode,
enableDataValidation: enableDataValidation);
var result = new DirectProperty<TOwner, TValue>(
name,
getter,
setter,
metadata,
enableDataValidation);
metadata);
AvaloniaPropertyRegistry.Instance.Register(typeof(TOwner), result);
return result;
}

25
src/Avalonia.Base/DirectProperty.cs

@ -23,16 +23,12 @@ namespace Avalonia
/// <param name="getter">Gets the current value of the property.</param>
/// <param name="setter">Sets the value of the property. May be null.</param>
/// <param name="metadata">The property metadata.</param>
/// <param name="enableDataValidation">
/// Whether the property is interested in data validation.
/// </param>
public DirectProperty(
string name,
Func<TOwner, TValue> getter,
Action<TOwner, TValue> setter,
DirectPropertyMetadata<TValue> metadata,
bool enableDataValidation)
: base(name, typeof(TOwner), metadata, enableDataValidation)
DirectPropertyMetadata<TValue> metadata)
: base(name, typeof(TOwner), metadata)
{
Contract.Requires<ArgumentNullException>(getter != null);
@ -47,16 +43,12 @@ namespace Avalonia
/// <param name="getter">Gets the current value of the property.</param>
/// <param name="setter">Sets the value of the property. May be null.</param>
/// <param name="metadata">Optional overridden metadata.</param>
/// <param name="enableDataValidation">
/// Whether the property is interested in data validation.
/// </param>
private DirectProperty(
DirectPropertyBase<TValue> source,
Func<TOwner, TValue> getter,
Action<TOwner, TValue> setter,
DirectPropertyMetadata<TValue> metadata,
bool enableDataValidation)
: base(source, typeof(TOwner), metadata, enableDataValidation)
DirectPropertyMetadata<TValue> metadata)
: base(source, typeof(TOwner), metadata)
{
Contract.Requires<ArgumentNullException>(getter != null);
@ -107,7 +99,8 @@ namespace Avalonia
{
var metadata = new DirectPropertyMetadata<TValue>(
unsetValue: unsetValue,
defaultBindingMode: defaultBindingMode);
defaultBindingMode: defaultBindingMode,
enableDataValidation: enableDataValidation);
metadata.Merge(GetMetadata<TOwner>(), this);
@ -115,8 +108,7 @@ namespace Avalonia
(DirectPropertyBase<TValue>)this,
getter,
setter,
metadata,
enableDataValidation);
metadata);
AvaloniaPropertyRegistry.Instance.Register(typeof(TNewOwner), result);
return result;
@ -155,8 +147,7 @@ namespace Avalonia
this,
getter,
setter,
metadata,
enableDataValidation);
metadata);
AvaloniaPropertyRegistry.Instance.Register(typeof(TNewOwner), result);
return result;

39
src/Avalonia.Base/DirectPropertyBase.cs

@ -23,17 +23,12 @@ namespace Avalonia
/// <param name="name">The name of the property.</param>
/// <param name="ownerType">The type of the class that registers the property.</param>
/// <param name="metadata">The property metadata.</param>
/// <param name="enableDataValidation">
/// Whether the property is interested in data validation.
/// </param>
protected DirectPropertyBase(
string name,
Type ownerType,
PropertyMetadata metadata,
bool enableDataValidation)
PropertyMetadata metadata)
: base(name, ownerType, metadata)
{
IsDataValidationEnabled = enableDataValidation;
}
/// <summary>
@ -42,17 +37,12 @@ namespace Avalonia
/// <param name="source">The property to copy.</param>
/// <param name="ownerType">The new owner type.</param>
/// <param name="metadata">Optional overridden metadata.</param>
/// <param name="enableDataValidation">
/// Whether the property is interested in data validation.
/// </param>
protected DirectPropertyBase(
AvaloniaProperty source,
Type ownerType,
PropertyMetadata metadata,
bool enableDataValidation)
PropertyMetadata metadata)
: base(source, ownerType, metadata)
{
IsDataValidationEnabled = enableDataValidation;
}
/// <summary>
@ -60,11 +50,6 @@ namespace Avalonia
/// </summary>
public abstract Type Owner { get; }
/// <summary>
/// Gets a value that indicates whether data validation is enabled for the property.
/// </summary>
public bool IsDataValidationEnabled { get; }
/// <summary>
/// Gets the value of the property on the instance.
/// </summary>
@ -102,6 +87,26 @@ namespace Avalonia
return (DirectPropertyMetadata<TValue>)base.GetMetadata(type);
}
/// <summary>
/// Overrides the metadata for the property on the specified type.
/// </summary>
/// <typeparam name="T">The type.</typeparam>
/// <param name="metadata">The metadata.</param>
public void OverrideMetadata<T>(DirectPropertyMetadata<TValue> metadata) where T : IAvaloniaObject
{
base.OverrideMetadata(typeof(T), metadata);
}
/// <summary>
/// Overrides the metadata for the property on the specified type.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="metadata">The metadata.</param>
public void OverrideMetadata(Type type, DirectPropertyMetadata<TValue> metadata)
{
base.OverrideMetadata(type, metadata);
}
/// <inheritdoc/>
public override void Accept<TData>(IAvaloniaPropertyVisitor<TData> vistor, ref TData data)
{

2
src/Avalonia.Controls/Repeater/ItemsRepeaterElementIndexChangedEventArgs.cs

@ -34,7 +34,7 @@ namespace Avalonia.Controls
/// </summary>
public int OldIndex { get; private set; }
internal void Update(IControl element, int newIndex, int oldIndex)
internal void Update(IControl element, int oldIndex, int newIndex)
{
Element = element;
NewIndex = newIndex;

17
src/Avalonia.Controls/Repeater/ViewportManager.cs

@ -350,11 +350,14 @@ namespace Avalonia.Controls
}
// Make sure that only the target child can be the anchor during the bring into view operation.
foreach (var child in _owner.Children)
if (_scroller is object)
{
if (child != targetChild)
foreach (var child in _owner.Children)
{
_scroller.UnregisterAnchorCandidate(child);
if (child != targetChild)
{
_scroller.UnregisterAnchorCandidate(child);
}
}
}
@ -469,13 +472,7 @@ namespace Avalonia.Controls
parent = parent.VisualParent;
}
if (_scroller == null)
{
// We usually update the viewport in the post arrange handler. But, since we don't have
// a scroller, let's do it now.
UpdateViewport(Rect.Empty);
}
else if (!_managingViewportDisabled)
if (!_managingViewportDisabled)
{
_owner.EffectiveViewportChanged += OnEffectiveViewportChanged;
_effectiveViewportChangedSubscribed = true;

2
src/Avalonia.Controls/Window.cs

@ -652,8 +652,8 @@ namespace Avalonia.Controls
PlatformImpl?.Show();
Renderer?.Start();
SetWindowStartupLocation(Owner?.PlatformImpl);
}
SetWindowStartupLocation(Owner?.PlatformImpl);
OnOpened(EventArgs.Empty);
}

11
src/Avalonia.Controls/WindowBase.cs

@ -39,6 +39,7 @@ namespace Avalonia.Controls
public static readonly StyledProperty<bool> TopmostProperty =
AvaloniaProperty.Register<WindowBase, bool>(nameof(Topmost));
private int _autoSizing;
private bool _hasExecutedInitialLayoutPass;
private bool _isActive;
private bool _ignoreVisibilityChange;
@ -97,11 +98,7 @@ namespace Avalonia.Controls
/// <summary>
/// Whether an auto-size operation is in progress.
/// </summary>
protected bool AutoSizing
{
get;
private set;
}
protected bool AutoSizing => _autoSizing > 0;
/// <summary>
/// Gets or sets the owner of the window.
@ -186,8 +183,8 @@ namespace Avalonia.Controls
/// </remarks>
protected IDisposable BeginAutoSizing()
{
AutoSizing = true;
return Disposable.Create(() => AutoSizing = false);
++_autoSizing;
return Disposable.Create(() => --_autoSizing);
}
/// <summary>

10
src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs

@ -21,7 +21,11 @@ namespace Avalonia.Headless
public IEnumerable<string> InstalledFontNames { get; } = new[] { "Tahoma" };
public bool SupportsIndividualRoundRects => throw new NotImplementedException();
public bool SupportsIndividualRoundRects => false;
public AlphaFormat DefaultAlphaFormat => AlphaFormat.Premul;
public PixelFormat DefaultPixelFormat => PixelFormat.Rgba8888;
public IFormattedTextImpl CreateFormattedText(string text, Typeface typeface, double fontSize, TextAlignment textAlignment, TextWrapping wrapping, Size constraint, IReadOnlyList<FormattedTextStyleSpan> spans)
{
@ -51,7 +55,7 @@ namespace Avalonia.Headless
return new HeadlessBitmapStub(size, dpi);
}
public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null)
public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat format, AlphaFormat alphaFormat)
{
return new HeadlessBitmapStub(size, dpi);
}
@ -66,7 +70,7 @@ namespace Avalonia.Headless
return new HeadlessBitmapStub(new Size(1, 1), new Vector(96, 96));
}
public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride)
public IBitmapImpl LoadBitmap(PixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride)
{
return new HeadlessBitmapStub(new Size(1, 1), new Vector(96, 96));
}

4
src/Avalonia.ReactiveUI/AutoDataTemplateBindingHook.cs

@ -48,6 +48,10 @@ namespace Avalonia.ReactiveUI
if (itemsControl.ItemTemplate != null)
return true;
if (itemsControl.DataTemplates != null &&
itemsControl.DataTemplates.Count > 0)
return true;
itemsControl.ItemTemplate = DefaultItemTemplate;
return true;
}

22
src/Avalonia.ReactiveUI/RoutedViewHost.cs

@ -65,8 +65,15 @@ namespace Avalonia.ReactiveUI
{
this.WhenActivated(disposables =>
{
this.WhenAnyObservable(x => x.Router.CurrentViewModel)
.DistinctUntilChanged()
var routerRemoved = this
.WhenAnyValue(x => x.Router)
.Where(router => router == null)
.Cast<object>();
this.WhenAnyValue(x => x.Router)
.Where(router => router != null)
.SelectMany(router => router.CurrentViewModel)
.Merge(routerRemoved)
.Subscribe(NavigateToViewModel)
.DisposeWith(disposables);
});
@ -92,6 +99,13 @@ namespace Avalonia.ReactiveUI
/// <param name="viewModel">ViewModel to which the user navigates.</param>
private void NavigateToViewModel(object viewModel)
{
if (Router == null)
{
this.Log().Warn("Router property is null. Falling back to default content.");
Content = DefaultContent;
return;
}
if (viewModel == null)
{
this.Log().Info("ViewModel is null. Falling back to default content.");
@ -110,8 +124,8 @@ namespace Avalonia.ReactiveUI
this.Log().Info($"Ready to show {viewInstance} with autowired {viewModel}.");
viewInstance.ViewModel = viewModel;
if (viewInstance is IStyledElement styled)
styled.DataContext = viewModel;
if (viewInstance is IDataContextProvider provider)
provider.DataContext = viewModel;
Content = viewInstance;
}
}

2
src/Avalonia.Styling/Styling/PropertySetterBindingInstance.cs

@ -164,7 +164,7 @@ namespace Avalonia.Styling
private void ConvertAndPublishNext(object? value)
{
_value = value is T v ? v : BindingValue<T>.FromUntyped(value);
_value = BindingValue<T>.FromUntyped(value);
if (_isActive)
{

2
src/Avalonia.Themes.Default/Window.xaml

@ -2,7 +2,7 @@
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/>
<Setter Property="TransparencyBackgroundFallback" Value="{DynamicResource HighlightForegroundColor}" />
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
<Setter Property="FontSize" Value="{DynamicResource FontSizeSmall}"/>
<Setter Property="FontSize" Value="{DynamicResource FontSizeNormal}"/>
<Setter Property="Template">
<ControlTemplate>
<Panel>

2
src/Avalonia.Themes.Fluent/ContextMenu.xaml

@ -9,6 +9,8 @@
<Border.ContextMenu>
<ContextMenu>
<MenuItem Header="Standard _Menu Item" />
<MenuItem Header="Disabled"
IsEnabled="False" />
<Separator />
<MenuItem Header="Menu with _Submenu">
<MenuItem Header="Submenu _1" />

14
src/Avalonia.Themes.Fluent/MenuItem.xaml

@ -8,6 +8,8 @@
Height="200">
<Menu VerticalAlignment="Top">
<MenuItem Header="File">
<MenuItem Header="Disabled"
IsEnabled="False" />
<MenuItem Header="New"
InputGesture="Ctrl+N">
<MenuItem Header="XML" />
@ -83,7 +85,6 @@
Content="{TemplateBinding Header}"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
TextBlock.Foreground="{TemplateBinding Foreground}"
Grid.Column="1">
<ContentPresenter.DataTemplates>
<DataTemplate DataType="sys:String">
@ -213,6 +214,9 @@
<Style Selector="MenuItem:selected /template/ Border#PART_LayoutRoot">
<Setter Property="Background" Value="{DynamicResource MenuFlyoutItemBackgroundPointerOver}" />
</Style>
<Style Selector="MenuItem:selected /template/ ContentPresenter#PART_HeaderPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource MenuFlyoutItemForegroundPointerOver}" />
</Style>
<Style Selector="MenuItem:selected /template/ TextBlock#PART_InputGestureText">
<Setter Property="Foreground" Value="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForegroundPointerOver}" />
</Style>
@ -224,6 +228,9 @@
<Style Selector="MenuItem:pressed /template/ Border#PART_LayoutRoot:pointerover">
<Setter Property="Background" Value="{DynamicResource MenuFlyoutItemBackgroundPressed}" />
</Style>
<Style Selector="MenuItem:pressed /template/ Border#PART_LayoutRoot:pointerover ContentPresenter#PART_HeaderPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource MenuFlyoutItemForegroundPressed}" />
</Style>
<Style Selector="MenuItem:pressed /template/ Border#PART_LayoutRoot:pointerover TextBlock#PART_InputGestureText">
<Setter Property="Foreground" Value="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForegroundPressed}" />
</Style>
@ -231,9 +238,12 @@
<Setter Property="Fill" Value="{DynamicResource MenuFlyoutSubItemChevronPressed}" />
</Style>
<Style Selector="MenuItem:disabled">
<Style Selector="MenuItem:disabled /template/ Border#PART_LayoutRoot">
<Setter Property="Background" Value="{DynamicResource MenuFlyoutItemBackgroundDisabled}" />
</Style>
<Style Selector="MenuItem:disabled /template/ ContentPresenter#PART_HeaderPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource MenuFlyoutItemForegroundDisabled}" />
</Style>
<Style Selector="MenuItem:disabled /template/ TextBlock#PART_InputGestureText">
<Setter Property="Foreground" Value="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForegroundDisabled}" />
</Style>

12
src/Avalonia.Visuals/ApiCompatBaseline.txt

@ -1,4 +1,14 @@
Compat issues with assembly Avalonia.Visuals:
EnumValuesMustMatch : Enum value 'Avalonia.Media.FontStyle Avalonia.Media.FontStyle.Italic' is (System.Int32)1 in the implementation but (System.Int32)2 in the contract.
EnumValuesMustMatch : Enum value 'Avalonia.Media.FontStyle Avalonia.Media.FontStyle.Oblique' is (System.Int32)2 in the implementation but (System.Int32)1 in the contract.
Total Issues: 2
InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.AlphaFormat Avalonia.Platform.IPlatformRenderInterface.DefaultAlphaFormat' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.PixelFormat Avalonia.Platform.IPlatformRenderInterface.DefaultPixelFormat' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IWriteableBitmapImpl Avalonia.Platform.IPlatformRenderInterface.CreateWriteableBitmap(Avalonia.PixelSize, Avalonia.Vector, Avalonia.Platform.PixelFormat, Avalonia.Platform.AlphaFormat)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IWriteableBitmapImpl Avalonia.Platform.IPlatformRenderInterface.CreateWriteableBitmap(Avalonia.PixelSize, Avalonia.Vector, System.Nullable<Avalonia.Platform.PixelFormat>)' is present in the contract but not in the implementation.
MembersMustExist : Member 'public Avalonia.Platform.IWriteableBitmapImpl Avalonia.Platform.IPlatformRenderInterface.CreateWriteableBitmap(Avalonia.PixelSize, Avalonia.Vector, System.Nullable<Avalonia.Platform.PixelFormat>)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.AlphaFormat Avalonia.Platform.IPlatformRenderInterface.DefaultAlphaFormat.get()' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.PixelFormat Avalonia.Platform.IPlatformRenderInterface.DefaultPixelFormat.get()' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IBitmapImpl Avalonia.Platform.IPlatformRenderInterface.LoadBitmap(Avalonia.Platform.PixelFormat, Avalonia.Platform.AlphaFormat, System.IntPtr, Avalonia.PixelSize, Avalonia.Vector, System.Int32)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IBitmapImpl Avalonia.Platform.IPlatformRenderInterface.LoadBitmap(Avalonia.Platform.PixelFormat, System.IntPtr, Avalonia.PixelSize, Avalonia.Vector, System.Int32)' is present in the contract but not in the implementation.
MembersMustExist : Member 'public Avalonia.Platform.IBitmapImpl Avalonia.Platform.IPlatformRenderInterface.LoadBitmap(Avalonia.Platform.PixelFormat, System.IntPtr, Avalonia.PixelSize, Avalonia.Vector, System.Int32)' does not exist in the implementation but it does exist in the contract.
Total Issues: 12

21
src/Avalonia.Visuals/Media/Imaging/Bitmap.cs

@ -99,14 +99,33 @@ namespace Avalonia.Media.Imaging
/// Initializes a new instance of the <see cref="Bitmap"/> class.
/// </summary>
/// <param name="format">The pixel format.</param>
/// <param name="alphaFormat">The alpha format.</param>
/// <param name="data">The pointer to the source bytes.</param>
/// <param name="size">The size of the bitmap in device pixels.</param>
/// <param name="dpi">The DPI of the bitmap.</param>
/// <param name="stride">The number of bytes per row.</param>
[Obsolete("Use overload taking an AlphaFormat.")]
public Bitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride)
{
var ri = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
PlatformImpl = RefCountable.Create(AvaloniaLocator.Current.GetService<IPlatformRenderInterface>()
.LoadBitmap(format, ri.DefaultAlphaFormat, data, size, dpi, stride));
}
/// <summary>
/// Initializes a new instance of the <see cref="Bitmap"/> class.
/// </summary>
/// <param name="format">The pixel format.</param>
/// <param name="alphaFormat">The alpha format.</param>
/// <param name="data">The pointer to the source bytes.</param>
/// <param name="size">The size of the bitmap in device pixels.</param>
/// <param name="dpi">The DPI of the bitmap.</param>
/// <param name="stride">The number of bytes per row.</param>
public Bitmap(PixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride)
{
PlatformImpl = RefCountable.Create(AvaloniaLocator.Current.GetService<IPlatformRenderInterface>()
.LoadBitmap(format, data, size, dpi, stride));
.LoadBitmap(format, alphaFormat, data, size, dpi, stride));
}
/// <inheritdoc/>

33
src/Avalonia.Visuals/Media/Imaging/WriteableBitmap.cs

@ -1,4 +1,5 @@
using Avalonia.Platform;
using System;
using Avalonia.Platform;
namespace Avalonia.Media.Imaging
{
@ -14,11 +15,35 @@ namespace Avalonia.Media.Imaging
/// <param name="dpi">The DPI of the bitmap.</param>
/// <param name="format">The pixel format (optional).</param>
/// <returns>An <see cref="IWriteableBitmapImpl"/>.</returns>
public WriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null)
: base(AvaloniaLocator.Current.GetService<IPlatformRenderInterface>().CreateWriteableBitmap(size, dpi, format))
[Obsolete("Use overload taking an AlphaFormat.")]
public WriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null)
: base(CreatePlatformImpl(size, dpi, format, null))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="WriteableBitmap"/> class.
/// </summary>
/// <param name="size">The size of the bitmap in device pixels.</param>
/// <param name="dpi">The DPI of the bitmap.</param>
/// <param name="format">The pixel format (optional).</param>
/// <param name="alphaFormat">The alpha format (optional).</param>
/// <returns>An <see cref="IWriteableBitmapImpl"/>.</returns>
public WriteableBitmap(PixelSize size, Vector dpi, PixelFormat format, AlphaFormat alphaFormat)
: base(CreatePlatformImpl(size, dpi, format, alphaFormat))
{
}
public ILockedFramebuffer Lock() => ((IWriteableBitmapImpl) PlatformImpl.Item).Lock();
private static IBitmapImpl CreatePlatformImpl(PixelSize size, in Vector dpi, PixelFormat? format, AlphaFormat? alphaFormat)
{
var ri = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
PixelFormat finalFormat = format ?? ri.DefaultPixelFormat;
AlphaFormat finalAlphaFormat = alphaFormat ?? ri.DefaultAlphaFormat;
return ri.CreateWriteableBitmap(size, dpi, finalFormat, finalAlphaFormat);
}
}
}

21
src/Avalonia.Visuals/Platform/AlphaFormat.cs

@ -0,0 +1,21 @@
namespace Avalonia.Platform
{
/// <summary>
/// Describes how to interpret the alpha component of a pixel.
/// </summary>
public enum AlphaFormat
{
/// <summary>
/// All pixels have their alpha premultiplied in their color components.
/// </summary>
Premul,
/// <summary>
/// All pixels have their color components stored without any regard to the alpha. e.g. this is the default configuration for PNG images.
/// </summary>
Unpremul,
/// <summary>
/// All pixels are stored as opaque.
/// </summary>
Opaque
}
}

19
src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs

@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using System.IO;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Visuals.Media.Imaging;
namespace Avalonia.Platform
@ -82,9 +81,10 @@ namespace Avalonia.Platform
/// </summary>
/// <param name="size">The size of the bitmap in device pixels.</param>
/// <param name="dpi">The DPI of the bitmap.</param>
/// <param name="format">Pixel format (optional).</param>
/// <param name="format">Pixel format.</param>
/// <param name="alphaFormat">Alpha format .</param>
/// <returns>An <see cref="IWriteableBitmapImpl"/>.</returns>
IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null);
IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat format, AlphaFormat alphaFormat);
/// <summary>
/// Loads a bitmap implementation from a file..
@ -124,12 +124,13 @@ namespace Avalonia.Platform
/// Loads a bitmap implementation from a pixels in memory.
/// </summary>
/// <param name="format">The pixel format.</param>
/// <param name="alphaFormat">The alpha format.</param>
/// <param name="data">The pointer to source bytes.</param>
/// <param name="size">The size of the bitmap in device pixels.</param>
/// <param name="dpi">The DPI of the bitmap.</param>
/// <param name="stride">The number of bytes per row.</param>
/// <returns>An <see cref="IBitmapImpl"/>.</returns>
IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride);
IBitmapImpl LoadBitmap(PixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride);
/// <summary>
/// Creates a platform implementation of a glyph run.
@ -140,5 +141,15 @@ namespace Avalonia.Platform
IGlyphRunImpl CreateGlyphRun(GlyphRun glyphRun, out double width);
bool SupportsIndividualRoundRects { get; }
/// <summary>
/// Default <see cref="AlphaFormat"/> used on this platform.
/// </summary>
public AlphaFormat DefaultAlphaFormat { get; }
/// <summary>
/// Default <see cref="PixelFormat"/> used on this platform.
/// </summary>
public PixelFormat DefaultPixelFormat { get; }
}
}

9
src/Skia/Avalonia.Skia/ImmutableBitmap.cs

@ -85,10 +85,6 @@ namespace Avalonia.Skia
if (bmp.Width != desired.Width || bmp.Height != desired.Height)
{
if (bmp.Height != bmp.Width)
{
}
var scaledBmp = bmp.Resize(desired, interpolationMode.ToSKFilterQuality());
bmp.Dispose();
bmp = scaledBmp;
@ -116,10 +112,11 @@ namespace Avalonia.Skia
/// <param name="dpi">DPI of the bitmap.</param>
/// <param name="stride">Stride of data pixels.</param>
/// <param name="format">Format of data pixels.</param>
/// <param name="alphaFormat">Alpha format of data pixels.</param>
/// <param name="data">Data pixels.</param>
public ImmutableBitmap(PixelSize size, Vector dpi, int stride, PixelFormat format, IntPtr data)
public ImmutableBitmap(PixelSize size, Vector dpi, int stride, PixelFormat format, AlphaFormat alphaFormat, IntPtr data)
{
var imageInfo = new SKImageInfo(size.Width, size.Height, format.ToSkColorType(), SKAlphaType.Premul);
var imageInfo = new SKImageInfo(size.Width, size.Height, format.ToSkColorType(), alphaFormat.ToSkAlphaType());
_image = SKImage.FromPixelCopy(imageInfo, data, stride);

16
src/Skia/Avalonia.Skia/PlatformRenderInterface.cs

@ -2,11 +2,9 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Linq;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Imaging;
using Avalonia.Platform;
@ -24,6 +22,8 @@ namespace Avalonia.Skia
public PlatformRenderInterface(ISkiaGpu skiaGpu, long? maxResourceBytes = null)
{
DefaultPixelFormat = SKImageInfo.PlatformColorType.ToPixelFormat();
if (skiaGpu != null)
{
_skiaGpu = skiaGpu;
@ -76,9 +76,9 @@ namespace Avalonia.Skia
}
/// <inheritdoc />
public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride)
public IBitmapImpl LoadBitmap(PixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride)
{
return new ImmutableBitmap(size, dpi, stride, format, data);
return new ImmutableBitmap(size, dpi, stride, format, alphaFormat, data);
}
/// <inheritdoc />
@ -152,9 +152,9 @@ namespace Avalonia.Skia
}
/// <inheritdoc />
public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null)
public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat format, AlphaFormat alphaFormat)
{
return new WriteableBitmapImpl(size, dpi, format);
return new WriteableBitmapImpl(size, dpi, format, alphaFormat);
}
private static readonly SKFont s_font = new SKFont
@ -267,5 +267,9 @@ namespace Avalonia.Skia
}
public bool SupportsIndividualRoundRects => true;
public AlphaFormat DefaultAlphaFormat => AlphaFormat.Premul;
public PixelFormat DefaultPixelFormat { get; }
}
}

22
src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs

@ -105,6 +105,28 @@ namespace Avalonia.Skia
throw new ArgumentException("Unknown pixel format: " + fmt);
}
public static SKAlphaType ToSkAlphaType(this AlphaFormat fmt)
{
return fmt switch
{
AlphaFormat.Premul => SKAlphaType.Premul,
AlphaFormat.Unpremul => SKAlphaType.Unpremul,
AlphaFormat.Opaque => SKAlphaType.Opaque,
_ => throw new ArgumentException($"Unknown alpha format: {fmt}")
};
}
public static AlphaFormat ToAlphaFormat(this SKAlphaType fmt)
{
return fmt switch
{
SKAlphaType.Premul => AlphaFormat.Premul,
SKAlphaType.Unpremul => AlphaFormat.Unpremul,
SKAlphaType.Opaque => AlphaFormat.Opaque,
_ => throw new ArgumentException($"Unknown alpha format: {fmt}")
};
}
public static SKShaderTileMode ToSKShaderTileMode(this Media.GradientSpreadMethod m)
{
switch (m)

10
src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs

@ -22,12 +22,14 @@ namespace Avalonia.Skia
/// <param name="size">The size of the bitmap in device pixels.</param>
/// <param name="dpi">The DPI of the bitmap.</param>
/// <param name="format">The pixel format.</param>
public WriteableBitmapImpl(PixelSize size, Vector dpi, PixelFormat? format = null)
/// <param name="alphaFormat">The alpha format.</param>
public WriteableBitmapImpl(PixelSize size, Vector dpi, PixelFormat format, AlphaFormat alphaFormat)
{
PixelSize = size;
Dpi = dpi;
var colorType = PixelFormatHelper.ResolveColorType(format);
SKColorType colorType = format.ToSkColorType();
SKAlphaType alphaType = alphaFormat.ToSkAlphaType();
var runtimePlatform = AvaloniaLocator.Current?.GetService<IRuntimePlatform>();
@ -35,14 +37,14 @@ namespace Avalonia.Skia
{
_bitmap = new SKBitmap();
var nfo = new SKImageInfo(size.Width, size.Height, colorType, SKAlphaType.Premul);
var nfo = new SKImageInfo(size.Width, size.Height, colorType, alphaType);
var blob = runtimePlatform.AllocBlob(nfo.BytesSize);
_bitmap.InstallPixels(nfo, blob.Address, nfo.RowBytes, s_releaseDelegate, blob);
}
else
{
_bitmap = new SKBitmap(size.Width, size.Height, colorType, SKAlphaType.Premul);
_bitmap = new SKBitmap(size.Width, size.Height, colorType, alphaType);
}
_bitmap.Erase(SKColor.Empty);

17
src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs

@ -115,11 +115,6 @@ namespace Avalonia.Direct2D1
SharpDX.Configuration.EnableReleaseOnFinalizer = true;
}
public IBitmapImpl CreateBitmap(PixelSize size, Vector dpi)
{
return new WicBitmapImpl(size, dpi);
}
public IFormattedTextImpl CreateFormattedText(
string text,
Typeface typeface,
@ -171,9 +166,9 @@ namespace Avalonia.Direct2D1
return new WicRenderTargetBitmapImpl(size, dpi);
}
public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null)
public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat format, AlphaFormat alphaFormat)
{
return new WriteableWicBitmapImpl(size, dpi, format);
return new WriteableWicBitmapImpl(size, dpi, format, alphaFormat);
}
public IGeometryImpl CreateEllipseGeometry(Rect rect) => new EllipseGeometryImpl(rect);
@ -213,9 +208,9 @@ namespace Avalonia.Direct2D1
}
/// <inheritdoc />
public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride)
public IBitmapImpl LoadBitmap(PixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride)
{
return new WicBitmapImpl(format, data, size, dpi, stride);
return new WicBitmapImpl(format, alphaFormat, data, size, dpi, stride);
}
public IGlyphRunImpl CreateGlyphRun(GlyphRun glyphRun, out double width)
@ -266,5 +261,9 @@ namespace Avalonia.Direct2D1
}
public bool SupportsIndividualRoundRects => false;
public AlphaFormat DefaultAlphaFormat => AlphaFormat.Premul;
public PixelFormat DefaultPixelFormat => PixelFormat.Bgra8888;
}
}

17
src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs

@ -1,9 +1,9 @@
using System;
using System.IO;
using System.Security.Cryptography;
using Avalonia.Win32.Interop;
using SharpDX.WIC;
using APixelFormat = Avalonia.Platform.PixelFormat;
using AlphaFormat = Avalonia.Platform.AlphaFormat;
using D2DBitmap = SharpDX.Direct2D1.Bitmap;
namespace Avalonia.Direct2D1.Media
@ -73,29 +73,34 @@ namespace Avalonia.Direct2D1.Media
/// <param name="size">The size of the bitmap in device pixels.</param>
/// <param name="dpi">The DPI of the bitmap.</param>
/// <param name="pixelFormat">Pixel format</param>
public WicBitmapImpl(PixelSize size, Vector dpi, APixelFormat? pixelFormat = null)
/// <param name="alphaFormat">Alpha format.</param>
public WicBitmapImpl(PixelSize size, Vector dpi, APixelFormat? pixelFormat = null, AlphaFormat? alphaFormat = null)
{
if (!pixelFormat.HasValue)
{
pixelFormat = APixelFormat.Bgra8888;
}
if (!alphaFormat.HasValue)
{
alphaFormat = AlphaFormat.Premul;
}
PixelFormat = pixelFormat;
WicImpl = new Bitmap(
Direct2D1Platform.ImagingFactory,
size.Width,
size.Height,
pixelFormat.Value.ToWic(),
pixelFormat.Value.ToWic(alphaFormat.Value),
BitmapCreateCacheOption.CacheOnLoad);
Dpi = dpi;
}
public WicBitmapImpl(APixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride)
public WicBitmapImpl(APixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride)
{
WicImpl = new Bitmap(Direct2D1Platform.ImagingFactory, size.Width, size.Height, format.ToWic(), BitmapCreateCacheOption.CacheOnDemand);
WicImpl = new Bitmap(Direct2D1Platform.ImagingFactory, size.Width, size.Height, format.ToWic(alphaFormat), BitmapCreateCacheOption.CacheOnDemand);
WicImpl.SetResolution(dpi.X, dpi.Y);
PixelFormat = format;
Dpi = dpi;

4
src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs

@ -7,8 +7,8 @@ namespace Avalonia.Direct2D1.Media.Imaging
{
class WriteableWicBitmapImpl : WicBitmapImpl, IWriteableBitmapImpl
{
public WriteableWicBitmapImpl(PixelSize size, Vector dpi, PixelFormat? pixelFormat)
: base(size, dpi, pixelFormat)
public WriteableWicBitmapImpl(PixelSize size, Vector dpi, PixelFormat? pixelFormat, AlphaFormat? alphaFormat)
: base(size, dpi, pixelFormat, alphaFormat)
{
}

9
src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs

@ -1,5 +1,6 @@
using System;
using System.Linq;
using Avalonia.Platform;
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.Mathematics.Interop;
@ -89,14 +90,16 @@ namespace Avalonia.Direct2D1
return CapStyle.Triangle;
}
public static Guid ToWic(this Platform.PixelFormat format)
public static Guid ToWic(this Platform.PixelFormat format, Platform.AlphaFormat alphaFormat)
{
bool isPremul = alphaFormat == AlphaFormat.Premul;
if (format == Platform.PixelFormat.Rgb565)
return SharpDX.WIC.PixelFormat.Format16bppBGR565;
if (format == Platform.PixelFormat.Bgra8888)
return SharpDX.WIC.PixelFormat.Format32bppPBGRA;
return isPremul ? SharpDX.WIC.PixelFormat.Format32bppPBGRA : SharpDX.WIC.PixelFormat.Format32bppBGRA;
if (format == Platform.PixelFormat.Rgba8888)
return SharpDX.WIC.PixelFormat.Format32bppPRGBA;
return isPremul ? SharpDX.WIC.PixelFormat.Format32bppPRGBA : SharpDX.WIC.PixelFormat.Format32bppRGBA;
throw new ArgumentException("Unknown pixel format");
}

99
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -6,7 +6,6 @@ using Avalonia.Controls;
using Avalonia.Controls.Platform;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Media;
using Avalonia.OpenGL;
using Avalonia.Platform;
using Avalonia.Rendering;
@ -230,28 +229,104 @@ namespace Avalonia.Win32
private WindowTransparencyLevel EnableBlur(WindowTransparencyLevel transparencyLevel)
{
bool canUseTransparency = false;
bool canUseAcrylic = false;
if (Win32Platform.WindowsVersion.Major >= 10)
if (Win32Platform.WindowsVersion.Major >= 6)
{
canUseTransparency = true;
if (Win32Platform.WindowsVersion.Major > 10 || Win32Platform.WindowsVersion.Build >= 19628)
if (DwmIsCompositionEnabled(out var compositionEnabled) != 0 || !compositionEnabled)
{
return WindowTransparencyLevel.None;
}
else if (Win32Platform.WindowsVersion.Major >= 10)
{
return Win10EnableBlur(transparencyLevel);
}
else if (Win32Platform.WindowsVersion.Minor >= 2)
{
return Win8xEnableBlur(transparencyLevel);
}
else
{
canUseAcrylic = true;
return Win7EnableBlur(transparencyLevel);
}
}
else
{
return WindowTransparencyLevel.None;
}
}
if (!canUseTransparency || DwmIsCompositionEnabled(out var compositionEnabled) != 0 || !compositionEnabled)
private WindowTransparencyLevel Win7EnableBlur(WindowTransparencyLevel transparencyLevel)
{
if (transparencyLevel == WindowTransparencyLevel.AcrylicBlur)
{
transparencyLevel = WindowTransparencyLevel.Blur;
}
var blurInfo = new DWM_BLURBEHIND(false);
if (transparencyLevel == WindowTransparencyLevel.Blur)
{
blurInfo = new DWM_BLURBEHIND(true);
}
DwmEnableBlurBehindWindow(_hwnd, ref blurInfo);
if (transparencyLevel == WindowTransparencyLevel.Transparent)
{
return WindowTransparencyLevel.None;
}
else
{
return transparencyLevel;
}
}
private WindowTransparencyLevel Win8xEnableBlur(WindowTransparencyLevel transparencyLevel)
{
var accent = new AccentPolicy();
var accentStructSize = Marshal.SizeOf(accent);
if (transparencyLevel == WindowTransparencyLevel.AcrylicBlur)
{
transparencyLevel = WindowTransparencyLevel.Blur;
}
if (transparencyLevel == WindowTransparencyLevel.Transparent)
{
accent.AccentState = AccentState.ACCENT_ENABLE_BLURBEHIND;
}
else
{
accent.AccentState = AccentState.ACCENT_DISABLED;
}
var accentPtr = Marshal.AllocHGlobal(accentStructSize);
Marshal.StructureToPtr(accent, accentPtr, false);
var data = new WindowCompositionAttributeData();
data.Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY;
data.SizeOfData = accentStructSize;
data.Data = accentPtr;
SetWindowCompositionAttribute(_hwnd, ref data);
Marshal.FreeHGlobal(accentPtr);
if (transparencyLevel >= WindowTransparencyLevel.Blur)
{
Win7EnableBlur(transparencyLevel);
}
return transparencyLevel;
}
private WindowTransparencyLevel Win10EnableBlur(WindowTransparencyLevel transparencyLevel)
{
bool canUseAcrylic = Win32Platform.WindowsVersion.Major > 10 || Win32Platform.WindowsVersion.Build >= 19628;
var accent = new AccentPolicy();
var accentStructSize = Marshal.SizeOf(accent);
if(transparencyLevel == WindowTransparencyLevel.AcrylicBlur && !canUseAcrylic)
if (transparencyLevel == WindowTransparencyLevel.AcrylicBlur && !canUseAcrylic)
{
transparencyLevel = WindowTransparencyLevel.Blur;
}
@ -291,7 +366,7 @@ namespace Avalonia.Win32
SetWindowCompositionAttribute(_hwnd, ref data);
Marshal.FreeHGlobal(accentPtr);
Marshal.FreeHGlobal(accentPtr);
return transparencyLevel;
}

23
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_DataValidation.cs

@ -62,6 +62,20 @@ namespace Avalonia.Base.UnitTests
Assert.Equal(7, result[3].Value);
}
[Fact]
public void Binding_Overridden_Validated_Direct_Property_Calls_UpdateDataValidation()
{
var target = new Class2();
var source = new Subject<BindingValue<int>>();
// Class2 overrides `NonValidatedDirectProperty`'s metadata to enable data validation.
target.Bind(Class1.NonValidatedDirectProperty, source);
source.OnNext(1);
var result = target.Notifications.Cast<BindingValue<int>>().ToList();
Assert.Equal(1, result.Count);
}
[Fact]
public void Bound_Validated_Direct_String_Property_Can_Be_Set_To_Null()
{
@ -150,6 +164,15 @@ namespace Avalonia.Base.UnitTests
}
}
private class Class2 : Class1
{
static Class2()
{
NonValidatedDirectProperty.OverrideMetadata<Class2>(
new DirectPropertyMetadata<int>(enableDataValidation: true));
}
}
public class ViewModel : NotifyingBase
{
private string _stringValue;

6
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Direct.cs

@ -547,8 +547,7 @@ namespace Avalonia.Base.UnitTests
"foo",
o => "foo",
null,
new DirectPropertyMetadata<string>(defaultBindingMode: BindingMode.TwoWay),
false);
new DirectPropertyMetadata<string>(defaultBindingMode: BindingMode.TwoWay));
var bar = foo.AddOwner<Class2>(o => "bar");
Assert.Equal(BindingMode.TwoWay, bar.GetMetadata<Class1>().DefaultBindingMode);
@ -562,8 +561,7 @@ namespace Avalonia.Base.UnitTests
"foo",
o => "foo",
null,
new DirectPropertyMetadata<string>(defaultBindingMode: BindingMode.TwoWay),
false);
new DirectPropertyMetadata<string>(defaultBindingMode: BindingMode.TwoWay));
var bar = foo.AddOwner<Class2>(o => "bar", defaultBindingMode: BindingMode.OneWayToSource);
Assert.Equal(BindingMode.TwoWay, bar.GetMetadata<Class1>().DefaultBindingMode);

105
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Metadata.cs

@ -1,5 +1,4 @@
using System.Linq;
using System.Reactive.Linq;
using System.Runtime.CompilerServices;
using Xunit;
namespace Avalonia.Base.UnitTests
@ -9,57 +8,101 @@ namespace Avalonia.Base.UnitTests
public AvaloniaObjectTests_Metadata()
{
// Ensure properties are registered.
AvaloniaProperty p;
p = Class1.FooProperty;
p = Class2.BarProperty;
p = AttachedOwner.AttachedProperty;
RuntimeHelpers.RunClassConstructor(typeof(Class1).TypeHandle);
RuntimeHelpers.RunClassConstructor(typeof(Class2).TypeHandle);
RuntimeHelpers.RunClassConstructor(typeof(Class3).TypeHandle);
}
[Fact]
public void IsSet_Returns_False_For_Unset_Property()
public class StyledProperty : AvaloniaObjectTests_Metadata
{
var target = new Class1();
[Fact]
public void Default_Value_Can_Be_Overridden_In_Derived_Class()
{
var baseValue = Class1.StyledProperty.GetDefaultValue(typeof(Class1));
var derivedValue = Class1.StyledProperty.GetDefaultValue(typeof(Class2));
Assert.False(target.IsSet(Class1.FooProperty));
}
[Fact]
public void IsSet_Returns_False_For_Set_Property()
{
var target = new Class1();
Assert.Equal("foo", baseValue);
Assert.Equal("bar", derivedValue);
}
target.SetValue(Class1.FooProperty, "foo");
[Fact]
public void Default_Value_Can_Be_Overridden_In_AddOwnered_Property()
{
var baseValue = Class1.StyledProperty.GetDefaultValue(typeof(Class1));
var addOwneredValue = Class1.StyledProperty.GetDefaultValue(typeof(Class3));
Assert.True(target.IsSet(Class1.FooProperty));
Assert.Equal("foo", baseValue);
Assert.Equal("baz", addOwneredValue);
}
}
[Fact]
public void IsSet_Returns_False_For_Cleared_Property()
public class DirectProperty : AvaloniaObjectTests_Metadata
{
var target = new Class1();
[Fact]
public void Unset_Value_Can_Be_Overridden_In_Derived_Class()
{
var baseValue = Class1.DirectProperty.GetUnsetValue(typeof(Class1));
var derivedValue = Class1.DirectProperty.GetUnsetValue(typeof(Class2));
target.SetValue(Class1.FooProperty, "foo");
target.SetValue(Class1.FooProperty, AvaloniaProperty.UnsetValue);
Assert.Equal("foo", baseValue);
Assert.Equal("bar", derivedValue);
}
Assert.False(target.IsSet(Class1.FooProperty));
[Fact]
public void Unset_Value_Can_Be_Overridden_In_AddOwnered_Property()
{
var baseValue = Class1.DirectProperty.GetUnsetValue(typeof(Class1));
var addOwneredValue = Class3.DirectProperty.GetUnsetValue(typeof(Class3));
Assert.Equal("foo", baseValue);
Assert.Equal("baz", addOwneredValue);
}
}
private class Class1 : AvaloniaObject
{
public static readonly StyledProperty<string> FooProperty =
AvaloniaProperty.Register<Class1, string>("Foo");
public static readonly StyledProperty<string> StyledProperty =
AvaloniaProperty.Register<Class1, string>("Styled", "foo");
public static readonly DirectProperty<Class1, string> DirectProperty =
AvaloniaProperty.RegisterDirect<Class1, string>("Styled", o => o.Direct, unsetValue: "foo");
private string _direct;
public string Direct
{
get => _direct;
}
}
private class Class2 : Class1
{
public static readonly StyledProperty<string> BarProperty =
AvaloniaProperty.Register<Class2, string>("Bar");
static Class2()
{
StyledProperty.OverrideDefaultValue<Class2>("bar");
DirectProperty.OverrideMetadata<Class2>(new DirectPropertyMetadata<string>("bar"));
}
}
private class AttachedOwner
private class Class3 : AvaloniaObject
{
public static readonly AttachedProperty<string> AttachedProperty =
AvaloniaProperty.RegisterAttached<AttachedOwner, Class1, string>("Attached");
public static readonly StyledProperty<string> StyledProperty =
Class1.StyledProperty.AddOwner<Class3>();
public static readonly DirectProperty<Class3, string> DirectProperty =
Class1.DirectProperty.AddOwner<Class3>(o => o.Direct, unsetValue: "baz");
private string _direct;
static Class3()
{
StyledProperty.OverrideDefaultValue<Class3>("baz");
}
public string Direct
{
get => _direct;
}
}
}
}

29
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_SetValue.cs

@ -39,6 +39,35 @@ namespace Avalonia.Base.UnitTests
Assert.Equal(1, raised);
}
[Fact]
public void IsSet_Returns_False_For_Unset_Property()
{
var target = new Class1();
Assert.False(target.IsSet(Class1.FooProperty));
}
[Fact]
public void IsSet_Returns_False_For_Set_Property()
{
var target = new Class1();
target.SetValue(Class1.FooProperty, "foo");
Assert.True(target.IsSet(Class1.FooProperty));
}
[Fact]
public void IsSet_Returns_False_For_Cleared_Property()
{
var target = new Class1();
target.SetValue(Class1.FooProperty, "foo");
target.SetValue(Class1.FooProperty, AvaloniaProperty.UnsetValue);
Assert.False(target.IsSet(Class1.FooProperty));
}
[Fact]
public void SetValue_Sets_Value()
{

3
tests/Avalonia.Base.UnitTests/DirectPropertyTests.cs

@ -11,8 +11,7 @@ namespace Avalonia.Base.UnitTests
"test",
o => null,
null,
new DirectPropertyMetadata<string>(),
false);
new DirectPropertyMetadata<string>());
Assert.True(target.IsDirect);
}

8
tests/Avalonia.Benchmarks/NullRenderingPlatform.cs

@ -46,7 +46,7 @@ namespace Avalonia.Benchmarks
throw new NotImplementedException();
}
public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null)
public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat format, AlphaFormat alphaFormat)
{
throw new NotImplementedException();
}
@ -61,7 +61,7 @@ namespace Avalonia.Benchmarks
throw new NotImplementedException();
}
public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride)
public IBitmapImpl LoadBitmap(PixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride)
{
throw new NotImplementedException();
}
@ -94,5 +94,9 @@ namespace Avalonia.Benchmarks
}
public bool SupportsIndividualRoundRects => true;
public AlphaFormat DefaultAlphaFormat => AlphaFormat.Premul;
public PixelFormat DefaultPixelFormat => PixelFormat.Rgba8888;
}
}

81
tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs

@ -28,10 +28,17 @@ namespace Avalonia.ReactiveUI.UnitTests
public class ExampleView : ReactiveUserControl<ExampleViewModel>
{
public ItemsControl List { get; } = new ItemsControl();
public ItemsControl List { get; } = new ItemsControl
{
Template = GetTemplate()
};
public ExampleView()
public ExampleView(Action<ItemsControl> adjustItemsControl = null)
{
adjustItemsControl?.Invoke(List);
List.ApplyTemplate();
List.Presenter.ApplyTemplate();
Content = List;
ViewModel = new ExampleViewModel();
this.OneWayBind(ViewModel, x => x.Items, x => x.List.Items);
@ -50,18 +57,15 @@ namespace Avalonia.ReactiveUI.UnitTests
{
var view = new ExampleView();
Assert.NotNull(view.List.ItemTemplate);
Assert.IsType<FuncDataTemplate<object>>(view.List.ItemTemplate);
}
[Fact]
public void Should_Use_View_Model_View_Host_As_Data_Template()
public void Should_Use_ViewModelViewHost_As_Data_Template_By_Default()
{
var view = new ExampleView();
view.ViewModel.Items.Add(new NestedViewModel());
view.List.Template = GetTemplate();
view.List.ApplyTemplate();
view.List.Presenter.ApplyTemplate();
var child = view.List.Presenter.Panel.Children[0];
var container = (ContentPresenter) child;
container.UpdateChild();
@ -70,16 +74,11 @@ namespace Avalonia.ReactiveUI.UnitTests
}
[Fact]
public void Should_Resolve_And_Embedd_Appropriate_View_Model()
public void ViewModelViewHost_Should_Resolve_And_Embedd_Appropriate_View_Model()
{
var view = new ExampleView();
var root = new TestRoot { Child = view };
view.ViewModel.Items.Add(new NestedViewModel());
view.List.Template = GetTemplate();
view.List.ApplyTemplate();
view.List.Presenter.ApplyTemplate();
var child = view.List.Presenter.Panel.Children[0];
var container = (ContentPresenter) child;
container.UpdateChild();
@ -93,19 +92,55 @@ namespace Avalonia.ReactiveUI.UnitTests
Assert.IsType<string>(host.DataContext);
}
private FuncControlTemplate GetTemplate()
[Fact]
public void Should_Not_Override_Data_Template_Binding_When_Item_Template_Is_Set()
{
var view = new ExampleView(control => control.ItemTemplate = GetItemTemplate());
Assert.NotNull(view.List.ItemTemplate);
Assert.IsType<FuncDataTemplate<TextBlock>>(view.List.ItemTemplate);
}
[Fact]
public void Should_Not_Use_View_Model_View_Host_When_Item_Template_Is_Set()
{
var view = new ExampleView(control => control.ItemTemplate = GetItemTemplate());
view.ViewModel.Items.Add(new NestedViewModel());
var child = view.List.Presenter.Panel.Children[0];
var container = (ContentPresenter) child;
container.UpdateChild();
Assert.IsType<TextBlock>(container.Child);
}
[Fact]
public void Should_Not_Use_View_Model_View_Host_When_Data_Templates_Are_Not_Empty()
{
var view = new ExampleView(control => control.DataTemplates.Add(GetItemTemplate()));
view.ViewModel.Items.Add(new NestedViewModel());
var child = view.List.Presenter.Panel.Children[0];
var container = (ContentPresenter) child;
container.UpdateChild();
Assert.IsType<TextBlock>(container.Child);
}
private static FuncDataTemplate GetItemTemplate()
{
return new FuncDataTemplate<TextBlock>((parent, scope) => new TextBlock());
}
private static FuncControlTemplate GetTemplate()
{
return new FuncControlTemplate<ItemsControl>((parent, scope) =>
return new FuncControlTemplate<ItemsControl>((parent, scope) => new Border
{
return new Border
Background = new Media.SolidColorBrush(0xffffffff),
Child = new ItemsPresenter
{
Background = new Media.SolidColorBrush(0xffffffff),
Child = new ItemsPresenter
{
Name = "PART_ItemsPresenter",
[~ItemsPresenter.ItemsProperty] = parent[~ItemsControl.ItemsProperty],
}.RegisterInNameScope(scope)
};
Name = "PART_ItemsPresenter",
[~ItemsPresenter.ItemsProperty] = parent[~ItemsControl.ItemsProperty],
}.RegisterInNameScope(scope)
});
}
}

76
tests/Avalonia.ReactiveUI.UnitTests/RoutedViewHostTest.cs

@ -62,51 +62,85 @@ namespace Avalonia.ReactiveUI.UnitTests
PageTransition = null
};
var root = new TestRoot
{
Child = host
var root = new TestRoot
{
Child = host
};
Assert.NotNull(host.Content);
Assert.Equal(typeof(TextBlock), host.Content.GetType());
Assert.IsType<TextBlock>(host.Content);
Assert.Equal(defaultContent, host.Content);
var first = new FirstRoutableViewModel();
screen.Router.Navigate
.Execute(first)
.Subscribe();
screen.Router.Navigate.Execute(first).Subscribe();
Assert.NotNull(host.Content);
Assert.Equal(typeof(FirstRoutableView), host.Content.GetType());
Assert.IsType<FirstRoutableView>(host.Content);
Assert.Equal(first, ((FirstRoutableView)host.Content).DataContext);
Assert.Equal(first, ((FirstRoutableView)host.Content).ViewModel);
var second = new SecondRoutableViewModel();
screen.Router.Navigate
.Execute(second)
.Subscribe();
screen.Router.Navigate.Execute(second).Subscribe();
Assert.NotNull(host.Content);
Assert.Equal(typeof(SecondRoutableView), host.Content.GetType());
Assert.IsType<SecondRoutableView>(host.Content);
Assert.Equal(second, ((SecondRoutableView)host.Content).DataContext);
Assert.Equal(second, ((SecondRoutableView)host.Content).ViewModel);
screen.Router.NavigateBack
.Execute(Unit.Default)
.Subscribe();
screen.Router.NavigateBack.Execute(Unit.Default).Subscribe();
Assert.NotNull(host.Content);
Assert.Equal(typeof(FirstRoutableView), host.Content.GetType());
Assert.IsType<FirstRoutableView>(host.Content);
Assert.Equal(first, ((FirstRoutableView)host.Content).DataContext);
Assert.Equal(first, ((FirstRoutableView)host.Content).ViewModel);
screen.Router.NavigateBack
.Execute(Unit.Default)
.Subscribe();
screen.Router.NavigateBack.Execute(Unit.Default).Subscribe();
Assert.NotNull(host.Content);
Assert.IsType<TextBlock>(host.Content);
Assert.Equal(defaultContent, host.Content);
}
[Fact]
public void RoutedViewHost_Should_Show_Default_Content_When_Router_Is_Null()
{
var screen = new ScreenViewModel();
var defaultContent = new TextBlock();
var host = new RoutedViewHost
{
DefaultContent = defaultContent,
PageTransition = null,
Router = null
};
var root = new TestRoot
{
Child = host
};
Assert.NotNull(host.Content);
Assert.Equal(typeof(TextBlock), host.Content.GetType());
Assert.Equal(defaultContent, host.Content);
host.Router = screen.Router;
Assert.NotNull(host.Content);
Assert.Equal(defaultContent, host.Content);
var first = new FirstRoutableViewModel();
screen.Router.Navigate.Execute(first).Subscribe();
Assert.NotNull(host.Content);
Assert.IsType<FirstRoutableView>(host.Content);
host.Router = null;
Assert.NotNull(host.Content);
Assert.Equal(defaultContent, host.Content);
host.Router = screen.Router;
Assert.NotNull(host.Content);
Assert.IsType<FirstRoutableView>(host.Content);
}
}
}
}

2
tests/Avalonia.RenderTests/Media/BitmapTests.cs

@ -81,7 +81,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
ctx.PopOpacity();
}
var bmp = new Bitmap(fmt, fb.Address, fb.Size, new Vector(96, 96), fb.RowBytes);
var bmp = new Bitmap(fmt, AlphaFormat.Premul, fb.Address, fb.Size, new Vector(96, 96), fb.RowBytes);
fb.Deallocate();
using (var rtb = new RenderTargetBitmap(new PixelSize(100, 100), new Vector(96, 96)))
{

15
tests/Avalonia.Styling.UnitTests/SetterTests.cs

@ -35,6 +35,21 @@ namespace Avalonia.Styling.UnitTests
Assert.Equal("foo", control.Text);
}
[Fact]
public void Setter_Should_Handle_Binding_Producing_UnsetValue()
{
var control = new TextBlock();
var subject = new BehaviorSubject<object>(AvaloniaProperty.UnsetValue);
var descriptor = InstancedBinding.OneWay(subject);
var binding = Mock.Of<IBinding>(x => x.Initiate(control, TextBlock.TagProperty, null, false) == descriptor);
var style = Mock.Of<IStyle>();
var setter = new Setter(TextBlock.TagProperty, binding);
setter.Instance(control).Start(false);
Assert.Equal("", control.Text);
}
[Fact]
public void Setter_Should_Materialize_Template_To_Property()
{

8
tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs

@ -55,7 +55,8 @@ namespace Avalonia.UnitTests
public IWriteableBitmapImpl CreateWriteableBitmap(
PixelSize size,
Vector dpi,
PixelFormat? format = default(PixelFormat?))
PixelFormat format,
AlphaFormat alphaFormat)
{
throw new NotImplementedException();
}
@ -87,6 +88,7 @@ namespace Avalonia.UnitTests
public IBitmapImpl LoadBitmap(
PixelFormat format,
AlphaFormat alphaFormat,
IntPtr data,
PixelSize size,
Vector dpi,
@ -102,5 +104,9 @@ namespace Avalonia.UnitTests
}
public bool SupportsIndividualRoundRects { get; set; }
public AlphaFormat DefaultAlphaFormat => AlphaFormat.Premul;
public PixelFormat DefaultPixelFormat => PixelFormat.Rgba8888;
}
}

6
tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs

@ -47,7 +47,7 @@ namespace Avalonia.Visuals.UnitTests.VisualTree
throw new NotImplementedException();
}
public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride)
public IBitmapImpl LoadBitmap(PixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride)
{
throw new NotImplementedException();
}
@ -58,13 +58,15 @@ namespace Avalonia.Visuals.UnitTests.VisualTree
}
public bool SupportsIndividualRoundRects { get; set; }
public AlphaFormat DefaultAlphaFormat { get; }
public PixelFormat DefaultPixelFormat { get; }
public IFontManagerImpl CreateFontManager()
{
return new MockFontManagerImpl();
}
public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? fmt)
public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat fmt, AlphaFormat alphaFormat)
{
throw new NotImplementedException();
}

Loading…
Cancel
Save