diff --git a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml
index f90a0c4658..a49616e543 100644
--- a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml
+++ b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml
@@ -51,6 +51,11 @@
Width="200"
Margin="0,0,0,8"
FilterMode="None"/>
+
+
diff --git a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
index f9d6a72a3a..574cc79a7d 100644
--- a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
@@ -92,13 +92,28 @@ namespace ControlCatalog.Pages
}
public StateData[] States { get; private set; }
+ private LinkedList[] BuildAllSentences()
+ {
+ return new string[]
+ {
+ "Hello world",
+ "No this is Patrick",
+ "Never gonna give you up",
+ "How does one patch KDE2 under FreeBSD"
+ }
+ .Select(x => new LinkedList(x.Split(' ')))
+ .ToArray();
+ }
+ public LinkedList[] Sentences { get; private set; }
+
public AutoCompleteBoxPage()
{
this.InitializeComponent();
States = BuildAllStates();
+ Sentences = BuildAllSentences();
- foreach (AutoCompleteBox box in GetAllAutoCompleteBox())
+ foreach (AutoCompleteBox box in GetAllAutoCompleteBox().Where(x => x.Name != "CustomAutocompleteBox"))
{
box.Items = States;
}
@@ -116,6 +131,11 @@ namespace ControlCatalog.Pages
var asyncBox = this.FindControl("AsyncBox");
asyncBox.AsyncPopulator = PopulateAsync;
+
+ var customAutocompleteBox = this.FindControl("CustomAutocompleteBox");
+ customAutocompleteBox.Items = Sentences.SelectMany(x => x);
+ customAutocompleteBox.TextFilter = LastWordContains;
+ customAutocompleteBox.TextSelector = AppendWord;
}
private IEnumerable GetAllAutoCompleteBox()
{
@@ -137,6 +157,42 @@ namespace ControlCatalog.Pages
.ToList();
}
+ private bool LastWordContains(string searchText, string item)
+ {
+ var words = searchText.Split(' ');
+ var options = Sentences.Select(x => x.First).ToArray();
+ for (var i = 0; i < words.Length; ++i)
+ {
+ var word = words[i];
+ for (var j = 0; j < options.Length; ++j)
+ {
+ var option = options[j];
+ if (option == null)
+ continue;
+
+ if (i == words.Length - 1)
+ {
+ options[j] = option.Value.ToLower().Contains(word.ToLower()) ? option : null;
+ }
+ else
+ {
+ options[j] = option.Value.Equals(word, StringComparison.InvariantCultureIgnoreCase) ? option.Next : null;
+ }
+ }
+ }
+
+ return options.Any(x => x != null && x.Value == item);
+ }
+ private string AppendWord(string text, string item)
+ {
+ string[] parts = text.Split(' ');
+ if (parts.Length == 0)
+ return item;
+
+ parts[parts.Length - 1] = item;
+ return string.Join(" ", parts);
+ }
+
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
diff --git a/samples/RenderDemo/MainWindow.xaml b/samples/RenderDemo/MainWindow.xaml
index 770960d7c4..93fbe5e412 100644
--- a/samples/RenderDemo/MainWindow.xaml
+++ b/samples/RenderDemo/MainWindow.xaml
@@ -3,8 +3,8 @@
x:Class="RenderDemo.MainWindow"
Title="AvaloniaUI Rendering Test"
xmlns:pages="clr-namespace:RenderDemo.Pages"
- Width="800"
- Height="600">
+ Width="{Binding Width, Mode=TwoWay}"
+ Height="{Binding Height, Mode=TwoWay}">
diff --git a/samples/RenderDemo/ViewModels/MainWindowViewModel.cs b/samples/RenderDemo/ViewModels/MainWindowViewModel.cs
index d2d789a687..eda5e80530 100644
--- a/samples/RenderDemo/ViewModels/MainWindowViewModel.cs
+++ b/samples/RenderDemo/ViewModels/MainWindowViewModel.cs
@@ -1,5 +1,6 @@
-using System;
-using System.Reactive;
+using System.Reactive;
+using System.Threading.Tasks;
+
using ReactiveUI;
namespace RenderDemo.ViewModels
@@ -8,26 +9,61 @@ namespace RenderDemo.ViewModels
{
private bool drawDirtyRects = false;
private bool drawFps = true;
+ private double width = 800;
+ private double height = 600;
public MainWindowViewModel()
{
ToggleDrawDirtyRects = ReactiveCommand.Create(() => DrawDirtyRects = !DrawDirtyRects);
ToggleDrawFps = ReactiveCommand.Create(() => DrawFps = !DrawFps);
+ ResizeWindow = ReactiveCommand.CreateFromTask(ResizeWindowAsync);
}
public bool DrawDirtyRects
{
- get { return drawDirtyRects; }
- set { this.RaiseAndSetIfChanged(ref drawDirtyRects, value); }
+ get => drawDirtyRects;
+ set => this.RaiseAndSetIfChanged(ref drawDirtyRects, value);
}
public bool DrawFps
{
- get { return drawFps; }
- set { this.RaiseAndSetIfChanged(ref drawFps, value); }
+ get => drawFps;
+ set => this.RaiseAndSetIfChanged(ref drawFps, value);
+ }
+
+ public double Width
+ {
+ get => width;
+ set => this.RaiseAndSetIfChanged(ref width, value);
+ }
+
+ public double Height
+ {
+ get => height;
+ set => this.RaiseAndSetIfChanged(ref height, value);
}
public ReactiveCommand ToggleDrawDirtyRects { get; }
public ReactiveCommand ToggleDrawFps { get; }
+ public ReactiveCommand ResizeWindow { get; }
+
+ private async Task ResizeWindowAsync()
+ {
+ for (int i = 0; i < 30; i++)
+ {
+ Width += 10;
+ Height += 5;
+ await Task.Delay(10);
+ }
+
+ await Task.Delay(10);
+
+ for (int i = 0; i < 30; i++)
+ {
+ Width -= 10;
+ Height -= 5;
+ await Task.Delay(10);
+ }
+ }
}
}
diff --git a/src/Avalonia.Controls.DataGrid/DataGrid.cs b/src/Avalonia.Controls.DataGrid/DataGrid.cs
index 9ca0b91523..7c57ea3db9 100644
--- a/src/Avalonia.Controls.DataGrid/DataGrid.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGrid.cs
@@ -24,12 +24,14 @@ using Avalonia.Input.Platform;
using System.ComponentModel.DataAnnotations;
using Avalonia.Controls.Utils;
using Avalonia.Layout;
+using Avalonia.Controls.Metadata;
namespace Avalonia.Controls
{
///
/// Displays data in a customizable grid.
///
+ [PseudoClasses(":invalid")]
public partial class DataGrid : TemplatedControl
{
private const string DATAGRID_elementRowsPresenterName = "PART_RowsPresenter";
diff --git a/src/Avalonia.Controls.DataGrid/DataGridCell.cs b/src/Avalonia.Controls.DataGrid/DataGridCell.cs
index e5fbfa1a81..445dc541a7 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridCell.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridCell.cs
@@ -3,6 +3,7 @@
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
+using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Input;
@@ -12,6 +13,7 @@ namespace Avalonia.Controls
///
/// Represents an individual cell.
///
+ [PseudoClasses(":selected", ":current", ":edited", ":invalid")]
public class DataGridCell : ContentControl
{
private const string DATAGRIDCELL_elementRightGridLine = "PART_RightGridLine";
diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs b/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs
index 25aae99942..856d1f6566 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs
@@ -14,12 +14,14 @@ using Avalonia.Utilities;
using System;
using Avalonia.Controls.Utils;
using Avalonia.Controls.Mixins;
+using Avalonia.Controls.Metadata;
namespace Avalonia.Controls
{
///
/// Represents an individual column header.
///
+ [PseudoClasses(":dragIndicator", ":pressed", ":sortascending", ":sortdescending")]
public class DataGridColumnHeader : ContentControl
{
private enum DragMode
diff --git a/src/Avalonia.Controls.DataGrid/DataGridRow.cs b/src/Avalonia.Controls.DataGrid/DataGridRow.cs
index d5ce8dba75..c3562c53a4 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridRow.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridRow.cs
@@ -3,6 +3,7 @@
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
+using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates;
@@ -20,6 +21,7 @@ namespace Avalonia.Controls
///
/// Represents a row.
///
+ [PseudoClasses(":selected", ":editing", ":invalid")]
public class DataGridRow : TemplatedControl
{
diff --git a/src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs b/src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs
index 0833247439..1e03b134b1 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs
@@ -3,6 +3,7 @@
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
+using Avalonia.Controls.Metadata;
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
@@ -13,6 +14,7 @@ using System.Reactive.Linq;
namespace Avalonia.Controls
{
+ [PseudoClasses(":pressed", ":current", ":expanded")]
public class DataGridRowGroupHeader : TemplatedControl
{
private const string DATAGRIDROWGROUPHEADER_expanderButton = "ExpanderButton";
diff --git a/src/Avalonia.Controls.DataGrid/DataGridRowHeader.cs b/src/Avalonia.Controls.DataGrid/DataGridRowHeader.cs
index 8f8b1742ba..0cd3589a57 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridRowHeader.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridRowHeader.cs
@@ -3,6 +3,7 @@
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
+using Avalonia.Controls.Metadata;
using Avalonia.Input;
using Avalonia.Media;
using System.Diagnostics;
@@ -12,6 +13,7 @@ namespace Avalonia.Controls.Primitives
///
/// Represents an individual row header.
///
+ [PseudoClasses(":invalid", ":selected", ":editing", ":current")]
public class DataGridRowHeader : ContentControl
{
private const string DATAGRIDROWHEADER_elementRootName = "PART_Root";
diff --git a/src/Avalonia.Controls/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox.cs
index c164f282e8..bfd633c947 100644
--- a/src/Avalonia.Controls/AutoCompleteBox.cs
+++ b/src/Avalonia.Controls/AutoCompleteBox.cs
@@ -14,6 +14,7 @@ using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Collections;
+using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Controls.Utils;
@@ -30,6 +31,7 @@ namespace Avalonia.Controls
///
/// event.
///
+ [PseudoClasses(":dropdownopen")]
public class PopulatedEventArgs : EventArgs
{
///
@@ -225,6 +227,27 @@ namespace Avalonia.Controls
Custom = 13,
}
+ ///
+ /// Represents the selector used by the
+ /// control to
+ /// determine how the specified text should be modified with an item.
+ ///
+ ///
+ /// Modified text that will be used by the
+ /// .
+ ///
+ /// The string used as the basis for filtering.
+ ///
+ /// The selected item that should be combined with the
+ /// parameter.
+ ///
+ ///
+ /// The type used for filtering the
+ /// .
+ /// This type can be either a string or an object.
+ ///
+ public delegate string AutoCompleteSelector(string search, T item);
+
///
/// Represents a control that provides a text box for user input and a
/// drop-down that contains possible matches based on the input in the text
@@ -362,6 +385,9 @@ namespace Avalonia.Controls
private AutoCompleteFilterPredicate