Browse Source

Add scroll bar & slider buttons

pull/1132/head
Eli Arbel 9 years ago
parent
commit
aee42bad6c
  1. 24
      src/Avalonia.Controls/Primitives/RangeBase.cs
  2. 103
      src/Avalonia.Controls/Primitives/ScrollBar.cs
  3. 102
      src/Avalonia.Controls/Primitives/Track.cs
  4. 4
      src/Avalonia.Controls/ScrollViewer.cs
  5. 38
      src/Avalonia.Controls/Slider.cs
  6. 158
      src/Avalonia.Themes.Default/ScrollBar.xaml
  7. 2
      src/Avalonia.Themes.Default/ScrollViewer.xaml
  8. 26
      src/Avalonia.Themes.Default/Slider.xaml
  9. 5
      tests/Avalonia.Controls.UnitTests/Primitives/ScrollBarTests.cs
  10. 6
      tests/Avalonia.Controls.UnitTests/Primitives/TrackTests.cs
  11. 9
      tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs

24
src/Avalonia.Controls/Primitives/RangeBase.cs

@ -38,6 +38,18 @@ namespace Avalonia.Controls.Primitives
o => o.Value,
(o, v) => o.Value = v);
/// <summary>
/// Defines the <see cref="SmallChange"/> property.
/// </summary>
public static readonly StyledProperty<double> SmallChangeProperty =
AvaloniaProperty.Register<RangeBase, double>(nameof(SmallChange), 0.1);
/// <summary>
/// Defines the <see cref="LargeChange"/> property.
/// </summary>
public static readonly StyledProperty<double> LargeChangeProperty =
AvaloniaProperty.Register<RangeBase, double>(nameof(LargeChange), 1);
private double _minimum;
private double _maximum = 100.0;
private double _value;
@ -103,6 +115,18 @@ namespace Avalonia.Controls.Primitives
}
}
public double SmallChange
{
get => GetValue(SmallChangeProperty);
set => SetValue(SmallChangeProperty, value);
}
public double LargeChange
{
get => GetValue(LargeChangeProperty);
set => SetValue(LargeChangeProperty, value);
}
/// <summary>
/// Throws an exception if the double valus is NaN or Inf.
/// </summary>

103
src/Avalonia.Controls/Primitives/ScrollBar.cs

@ -5,6 +5,7 @@ using System;
using System.Reactive;
using System.Reactive.Linq;
using Avalonia.Data;
using Avalonia.Interactivity;
namespace Avalonia.Controls.Primitives
{
@ -31,13 +32,18 @@ namespace Avalonia.Controls.Primitives
public static readonly StyledProperty<Orientation> OrientationProperty =
AvaloniaProperty.Register<ScrollBar, Orientation>(nameof(Orientation));
private Button _lineUpButton;
private Button _lineDownButton;
private Button _pageUpButton;
private Button _pageDownButton;
/// <summary>
/// Initializes static members of the <see cref="ScrollBar"/> class.
/// </summary>
static ScrollBar()
{
PseudoClass(OrientationProperty, o => o == Avalonia.Controls.Orientation.Vertical, ":vertical");
PseudoClass(OrientationProperty, o => o == Avalonia.Controls.Orientation.Horizontal, ":horizontal");
PseudoClass(OrientationProperty, o => o == Orientation.Vertical, ":vertical");
PseudoClass(OrientationProperty, o => o == Orientation.Horizontal, ":horizontal");
}
/// <summary>
@ -97,12 +103,101 @@ namespace Avalonia.Controls.Primitives
return false;
case ScrollBarVisibility.Auto:
var viewportSize = ViewportSize;
return double.IsNaN(viewportSize) || viewportSize < Maximum - Minimum;
return double.IsNaN(ViewportSize) || Maximum > 0;
default:
throw new InvalidOperationException("Invalid value for ScrollBar.Visibility.");
}
}
protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
{
base.OnTemplateApplied(e);
if (_lineUpButton != null)
{
_lineUpButton.Click -= LineUpClick;
}
if (_lineDownButton != null)
{
_lineDownButton.Click -= LineDownClick;
}
if (_pageUpButton != null)
{
_pageUpButton.Click -= PageUpClick;
}
if (_pageDownButton != null)
{
_pageDownButton.Click -= PageDownClick;
}
_lineUpButton = e.NameScope.Find<Button>("PART_LineUpButton");
_lineDownButton = e.NameScope.Find<Button>("PART_LineDownButton");
_pageUpButton = e.NameScope.Find<Button>("PART_PageUpButton");
_pageDownButton = e.NameScope.Find<Button>("PART_PageDownButton");
if (_lineUpButton != null)
{
_lineUpButton.Click += LineUpClick;
}
if (_lineDownButton != null)
{
_lineDownButton.Click += LineDownClick;
}
if (_pageUpButton != null)
{
_pageUpButton.Click += PageUpClick;
}
if (_pageDownButton != null)
{
_pageDownButton.Click += PageDownClick;
}
}
private void LineUpClick(object sender, RoutedEventArgs e)
{
SmallDecrement();
}
private void LineDownClick(object sender, RoutedEventArgs e)
{
SmallIncrement();
}
private void PageUpClick(object sender, RoutedEventArgs e)
{
LargeDecrement();
}
private void PageDownClick(object sender, RoutedEventArgs e)
{
LargeIncrement();
}
private void SmallDecrement()
{
Value = Math.Max(Value - SmallChange * ViewportSize, Minimum);
}
private void SmallIncrement()
{
Value = Math.Min(Value + SmallChange * ViewportSize, Maximum);
}
private void LargeDecrement()
{
Value = Math.Max(Value - LargeChange * ViewportSize, Minimum);
}
private void LargeIncrement()
{
Value = Math.Min(Value + LargeChange * ViewportSize, Maximum);
}
}
}

102
src/Avalonia.Controls/Primitives/Track.cs

@ -10,7 +10,7 @@ namespace Avalonia.Controls.Primitives
public class Track : Control
{
public static readonly DirectProperty<Track, double> MinimumProperty =
RangeBase.MinimumProperty.AddOwner<Track>(o => o.Minimum, (o,v) => o.Minimum = v);
RangeBase.MinimumProperty.AddOwner<Track>(o => o.Minimum, (o, v) => o.Minimum = v);
public static readonly DirectProperty<Track, double> MaximumProperty =
RangeBase.MaximumProperty.AddOwner<Track>(o => o.Maximum, (o, v) => o.Maximum = v);
@ -25,7 +25,13 @@ namespace Avalonia.Controls.Primitives
ScrollBar.OrientationProperty.AddOwner<Track>();
public static readonly StyledProperty<Thumb> ThumbProperty =
AvaloniaProperty.Register<Track, Thumb>("Thumb");
AvaloniaProperty.Register<Track, Thumb>(nameof(Thumb));
public static readonly StyledProperty<Button> IncreaseButtonProperty =
AvaloniaProperty.Register<Track, Button>(nameof(IncreaseButton));
public static readonly StyledProperty<Button> DecreaseButtonProperty =
AvaloniaProperty.Register<Track, Button>(nameof(DecreaseButton));
private double _minimum;
private double _maximum = 100.0;
@ -34,6 +40,8 @@ namespace Avalonia.Controls.Primitives
static Track()
{
ThumbProperty.Changed.AddClassHandler<Track>(x => x.ThumbChanged);
IncreaseButtonProperty.Changed.AddClassHandler<Track>(x => x.ButtonChanged);
DecreaseButtonProperty.Changed.AddClassHandler<Track>(x => x.ButtonChanged);
AffectsArrange(MinimumProperty, MaximumProperty, ValueProperty, OrientationProperty);
}
@ -74,6 +82,18 @@ namespace Avalonia.Controls.Primitives
set { SetValue(ThumbProperty, value); }
}
public Button IncreaseButton
{
get { return GetValue(IncreaseButtonProperty); }
set { SetValue(IncreaseButtonProperty, value); }
}
public Button DecreaseButton
{
get { return GetValue(DecreaseButtonProperty); }
set { SetValue(DecreaseButtonProperty, value); }
}
protected override Size MeasureOverride(Size availableSize)
{
var thumb = Thumb;
@ -98,34 +118,54 @@ namespace Avalonia.Controls.Primitives
protected override Size ArrangeOverride(Size finalSize)
{
var thumb = Thumb;
var increaseButton = IncreaseButton;
var decreaseButton = DecreaseButton;
if (thumb != null)
var range = Maximum - Minimum;
var offset = Math.Min(Value - Minimum, range);
var viewportSize = ViewportSize;
var extent = range + viewportSize;
if (Orientation == Orientation.Horizontal)
{
var range = Maximum - Minimum;
var thumbFraction = ViewportSize / range;
var valueFraction = (Value - Minimum) / range;
var thumbWidth = double.IsNaN(viewportSize) ? finalSize.Width : finalSize.Width * viewportSize / extent;
var remaining = finalSize.Width - thumbWidth;
var firstWidth = range <= 0 ? 0 : remaining * offset / range;
if (double.IsNaN(valueFraction) || double.IsInfinity(valueFraction))
if (decreaseButton != null)
{
valueFraction = 0;
thumbFraction = 1;
decreaseButton.Arrange(new Rect(0, 0, firstWidth, finalSize.Height));
}
else if (double.IsNaN(thumbFraction) || double.IsInfinity(thumbFraction))
if (thumb != null)
{
thumbFraction = 0;
thumb.Arrange(new Rect(firstWidth, 0, thumbWidth, finalSize.Height));
}
if (Orientation == Orientation.Horizontal)
if (increaseButton != null)
{
var width = Math.Max(finalSize.Width * thumbFraction, thumb.MinWidth);
var x = (finalSize.Width - width) * valueFraction;
thumb.Arrange(new Rect(x, 0, width, finalSize.Height));
increaseButton.Arrange(new Rect(firstWidth + thumbWidth, 0, remaining - firstWidth, finalSize.Height));
}
else
}
else
{
var thumbHeight = double.IsNaN(viewportSize) ? finalSize.Height : finalSize.Height * viewportSize / extent;
var remaining = finalSize.Height - thumbHeight;
var firstHeight = range <= 0 ? 0 : remaining * offset / range;
if (decreaseButton != null)
{
var height = Math.Max(finalSize.Height * thumbFraction, thumb.MinHeight);
var y = (finalSize.Height - height) * valueFraction;
thumb.Arrange(new Rect(0, y, finalSize.Width, height));
decreaseButton.Arrange(new Rect(0, 0, finalSize.Width, firstHeight));
}
if (thumb != null)
{
thumb.Arrange(new Rect(0, firstHeight, finalSize.Width, thumbHeight));
}
if (increaseButton != null)
{
increaseButton.Arrange(new Rect(0, firstHeight + thumbHeight, finalSize.Width, remaining - firstHeight));
}
}
@ -140,10 +180,10 @@ namespace Avalonia.Controls.Primitives
if (oldThumb != null)
{
oldThumb.DragDelta -= ThumbDragged;
}
LogicalChildren.Clear();
VisualChildren.Clear();
LogicalChildren.Remove(oldThumb);
VisualChildren.Remove(oldThumb);
}
if (newThumb != null)
{
@ -153,6 +193,24 @@ namespace Avalonia.Controls.Primitives
}
}
private void ButtonChanged(AvaloniaPropertyChangedEventArgs e)
{
var oldButton = (Button)e.OldValue;
var newButton = (Button)e.NewValue;
if (oldButton != null)
{
LogicalChildren.Remove(oldButton);
VisualChildren.Remove(oldButton);
}
if (newButton != null)
{
LogicalChildren.Add(newButton);
VisualChildren.Add(newButton);
}
}
private void ThumbDragged(object sender, VectorEventArgs e)
{
double range = Maximum - Minimum;

4
src/Avalonia.Controls/ScrollViewer.cs

@ -275,7 +275,7 @@ namespace Avalonia.Controls
/// </summary>
protected double HorizontalScrollBarViewportSize
{
get { return Max((_viewport.Width / _extent.Width) * (_extent.Width - _viewport.Width), 0); }
get { return _viewport.Width; }
}
/// <summary>
@ -308,7 +308,7 @@ namespace Avalonia.Controls
/// </summary>
protected double VerticalScrollBarViewportSize
{
get { return Max((_viewport.Height / _extent.Height) * (_extent.Height - _viewport.Height), 0); }
get { return _viewport.Height; }
}
/// <summary>

38
src/Avalonia.Controls/Slider.cs

@ -33,6 +33,8 @@ namespace Avalonia.Controls
// Slider required parts
private Track _track;
private Button _decreaseButton;
private Button _increaseButton;
/// <summary>
/// Initializes static members of the <see cref="Slider"/> class.
@ -83,7 +85,39 @@ namespace Avalonia.Controls
/// <inheritdoc/>
protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
{
_track = e.NameScope.Get<Track>("PART_Track");
if (_decreaseButton != null)
{
_decreaseButton.Click -= DecreaseClick;
}
if (_increaseButton != null)
{
_increaseButton.Click -= IncreaseClick;
}
_decreaseButton = e.NameScope.Find<Button>("PART_DecreaseButton");
_track = e.NameScope.Find<Track>("PART_Track");
_increaseButton = e.NameScope.Find<Button>("PART_IncreaseButton");
if (_decreaseButton != null)
{
_decreaseButton.Click += DecreaseClick;
}
if (_increaseButton != null)
{
_increaseButton.Click += IncreaseClick;
}
}
private void DecreaseClick(object sender, RoutedEventArgs e)
{
Value = Math.Max(Value - LargeChange, Minimum);
}
private void IncreaseClick(object sender, RoutedEventArgs e)
{
Value = Math.Min(Value + LargeChange, Maximum);
}
/// <summary>
@ -101,7 +135,7 @@ namespace Avalonia.Controls
protected virtual void OnThumbDragDelta(VectorEventArgs e)
{
Thumb thumb = e.Source as Thumb;
if (thumb != null && _track.Thumb == thumb)
if (thumb != null && _track?.Thumb == thumb)
{
MoveToNextTick(_track.Value);
}

158
src/Avalonia.Themes.Default/ScrollBar.xaml

@ -1,35 +1,127 @@
<Styles xmlns="https://github.com/avaloniaui">
<Style Selector="ScrollBar">
<Setter Property="Template">
<ControlTemplate>
<Border Background="{StyleResource ThemeControlMidBrush}">
<Track Minimum="{TemplateBinding Minimum}"
Maximum="{TemplateBinding Maximum}"
Value="{TemplateBinding Path=Value, Mode=TwoWay}"
ViewportSize="{TemplateBinding ViewportSize}"
Orientation="{TemplateBinding Orientation}">
<Thumb Name="thumb">
<Thumb.Template>
<ControlTemplate>
<Border Background="{StyleResource ThemeControlDarkBrush}"/>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Track>
</Border>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="ScrollBar:horizontal">
<Setter Property="Height" Value="10"/>
</Style>
<Style Selector="ScrollBar:horizontal /template/ Thumb#thumb">
<Setter Property="MinWidth" Value="10"/>
</Style>
<Style Selector="ScrollBar:vertical">
<Setter Property="Width" Value="10"/>
</Style>
<Style Selector="ScrollBar:vertical /template/ Thumb#thumb">
<Setter Property="MinHeight" Value="10"/>
</Style>
<Style Selector="ScrollBar">
<Setter Property="Template">
<ControlTemplate>
<Border Background="{StyleResource ThemeControlMidBrush}">
<Grid RowDefinitions="10,*,10">
<RepeatButton Name="PART_LineUpButton"
Classes="repeat"
Grid.Row="0"
Grid.Column="0">
<Path Data="M 0,4 C0,4 0,6 0,6 0,6 3.5,2.5 3.5,2.5 3.5,2.5 7,6 7,6 7,6 7,4 7,4 7,4 3.5,0.5 3.5,0.5 3.5,0.5 0,4 0,4 z"
Stretch="Uniform"
Fill="Gray" />
</RepeatButton>
<Track Grid.Row="1"
Grid.Column="1"
Minimum="{TemplateBinding Minimum}"
Maximum="{TemplateBinding Maximum}"
Value="{TemplateBinding Path=Value, Mode=TwoWay}"
ViewportSize="{TemplateBinding ViewportSize}"
Orientation="{TemplateBinding Orientation}">
<Track.DecreaseButton>
<RepeatButton Name="PART_PageUpButton"
Classes="repeattrack" />
</Track.DecreaseButton>
<Track.IncreaseButton>
<RepeatButton Name="PART_PageDownButton"
Classes="repeattrack" />
</Track.IncreaseButton>
<Thumb Name="thumb">
<Thumb.Template>
<ControlTemplate>
<Border Background="{StyleResource ThemeControlDarkBrush}" />
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Track>
<RepeatButton Name="PART_LineDownButton"
Classes="repeat"
Grid.Row="2"
Grid.Column="2">
<Path Data="M 0,2.5 C0,2.5 0,0.5 0,0.5 0,0.5 3.5,4 3.5,4 3.5,4 7,0.5 7,0.5 7,0.5 7,2.5 7,2.5 7,2.5 3.5,6 3.5,6 3.5,6 0,2.5 0,2.5 z"
Stretch="Uniform"
Fill="Gray" />
</RepeatButton>
</Grid>
</Border>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="ScrollBar:horizontal">
<Setter Property="Height"
Value="10" />
<Setter Property="Template">
<ControlTemplate>
<Border Background="{StyleResource ThemeControlMidBrush}">
<Grid ColumnDefinitions="10,*,10">
<RepeatButton Name="PART_LineUpButton"
Classes="repeat"
Grid.Row="0"
Grid.Column="0">
<Path Data="M 3.18,7 C3.18,7 5,7 5,7 5,7 1.81,3.5 1.81,3.5 1.81,3.5 5,0 5,0 5,0 3.18,0 3.18,0 3.18,0 0,3.5 0,3.5 0,3.5 3.18,7 3.18,7 z"
Stretch="Uniform"
Fill="Gray" />
</RepeatButton>
<Track Grid.Row="1"
Grid.Column="1"
Minimum="{TemplateBinding Minimum}"
Maximum="{TemplateBinding Maximum}"
Value="{TemplateBinding Path=Value, Mode=TwoWay}"
ViewportSize="{TemplateBinding ViewportSize}"
Orientation="{TemplateBinding Orientation}">
<Track.DecreaseButton>
<RepeatButton Name="PART_PageUpButton"
Classes="repeattrack" />
</Track.DecreaseButton>
<Track.IncreaseButton>
<RepeatButton Name="PART_PageDownButton"
Classes="repeattrack" />
</Track.IncreaseButton>
<Thumb Name="thumb">
<Thumb.Template>
<ControlTemplate>
<Border Background="{StyleResource ThemeControlDarkBrush}" />
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Track>
<RepeatButton Name="PART_LineDownButton"
Classes="repeat"
Grid.Row="2"
Grid.Column="2">
<Path Data="M 1.81,7 C1.81,7 0,7 0,7 0,7 3.18,3.5 3.18,3.5 3.18,3.5 0,0 0,0 0,0 1.81,0 1.81,0 1.81,0 5,3.5 5,3.5 5,3.5 1.81,7 1.81,7 z"
Stretch="Uniform"
Fill="Gray" />
</RepeatButton>
</Grid>
</Border>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="ScrollBar:horizontal /template/ Thumb#thumb">
<Setter Property="MinWidth"
Value="10" />
</Style>
<Style Selector="ScrollBar:vertical">
<Setter Property="Width"
Value="10" />
</Style>
<Style Selector="ScrollBar:vertical /template/ Thumb#thumb">
<Setter Property="MinHeight"
Value="10" />
</Style>
<Style Selector="ScrollBar /template/ RepeatButton.repeat">
<Setter Property="Padding"
Value="2" />
<Setter Property="BorderThickness"
Value="0" />
</Style>
<Style Selector="ScrollBar /template/ RepeatButton.repeattrack">
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}" />
</ControlTemplate>
</Setter>
</Style>
</Styles>

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

@ -1,4 +1,6 @@
<Style xmlns="https://github.com/avaloniaui" Selector="ScrollViewer">
<Setter Property="Background"
Value="Transparent" />
<Setter Property="Template">
<ControlTemplate>
<Grid ColumnDefinitions="*,Auto" RowDefinitions="*,Auto">

26
src/Avalonia.Themes.Default/Slider.xaml

@ -12,6 +12,14 @@
</Grid.RowDefinitions>
<Border Name="TrackBackground" Grid.Row="1" Height="4" Margin="6,0" VerticalAlignment="Center"/>
<Track Name="PART_Track" Grid.Row="1">
<Track.DecreaseButton>
<RepeatButton Name="PART_DecreaseButton"
Classes="repeattrack" />
</Track.DecreaseButton>
<Track.IncreaseButton>
<RepeatButton Name="PART_IncreaseButton"
Classes="repeattrack" />
</Track.IncreaseButton>
<Thumb MinWidth="20" MinHeight="20">
<Thumb.Template>
<ControlTemplate>
@ -39,6 +47,14 @@
</Grid.ColumnDefinitions>
<Border Name="TrackBackground" Grid.Column="1" Width="4" Margin="0,6" HorizontalAlignment="Center"/>
<Track Name="PART_Track" Grid.Column="1">
<Track.DecreaseButton>
<RepeatButton Name="PART_DecreaseButton"
Classes="repeattrack" />
</Track.DecreaseButton>
<Track.IncreaseButton>
<RepeatButton Name="PART_IncreaseButton"
Classes="repeattrack" />
</Track.IncreaseButton>
<Thumb MinWidth="20" MinHeight="20">
<Thumb.Template>
<ControlTemplate>
@ -62,5 +78,13 @@
<Style Selector="Slider /template/ Border#TrackBackground">
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderLightBrush}"/>
</Style>
</Style>
<Style Selector="Slider /template/ RepeatButton.repeattrack">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}" />
</ControlTemplate>
</Setter>
</Style>
</Styles>

5
tests/Avalonia.Controls.UnitTests/Primitives/ScrollBarTests.cs

@ -65,9 +65,8 @@ namespace Avalonia.Controls.UnitTests.Primitives
var target = new ScrollBar();
target.Visibility = ScrollBarVisibility.Auto;
target.Minimum = 0;
target.Maximum = 100;
target.ViewportSize = 100;
target.ViewportSize = 1;
target.Maximum = 0;
Assert.False(target.IsVisible);
}

6
tests/Avalonia.Controls.UnitTests/Primitives/TrackTests.cs

@ -69,7 +69,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
target.Measure(new Size(100, 100));
target.Arrange(new Rect(0, 0, 100, 100));
Assert.Equal(new Rect(25, 0, 50, 12), thumb.Bounds);
Assert.Equal(new Rect(33, 0, 34, 12), thumb.Bounds);
}
[Fact]
@ -85,7 +85,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
Thumb = thumb,
Orientation = Orientation.Vertical,
Minimum = 100,
Maximum = 300,
Maximum = 200,
Value = 150,
ViewportSize = 50,
Width = 12,
@ -94,7 +94,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
target.Measure(new Size(100, 100));
target.Arrange(new Rect(0, 0, 100, 100));
Assert.Equal(new Rect(0, 18, 12, 25), thumb.Bounds);
Assert.Equal(new Rect(0, 33, 12, 34), thumb.Bounds);
}
[Fact]

9
tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs

@ -173,6 +173,15 @@ namespace Avalonia.Layout.UnitTests
It.IsAny<IReadOnlyList<FormattedTextStyleSpan>>()))
.Returns(new FormattedTextMock("TEST"));
var streamGeometry = new Mock<IStreamGeometryImpl>();
streamGeometry.Setup(x =>
x.Open())
.Returns(new Mock<IStreamGeometryContextImpl>().Object);
renderInterface.Setup(x =>
x.CreateStreamGeometry())
.Returns(streamGeometry.Object);
var windowImpl = new Mock<IWindowImpl>();
Size clientSize = default(Size);

Loading…
Cancel
Save