Sfoglia il codice sorgente

Added PseudoClassesAttribute.

And apply it to our controls. Can be used by designers to add auto-completion support for pseudoclasses.
Steven Kirk 5 anni fa
parent
commit
58c333b6f1
37 ha cambiato i file con 97 aggiunte e 5 eliminazioni
  1. 2 0
      src/Avalonia.Controls.DataGrid/DataGrid.cs
  2. 2 0
      src/Avalonia.Controls.DataGrid/DataGridCell.cs
  3. 2 0
      src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs
  4. 2 0
      src/Avalonia.Controls.DataGrid/DataGridRow.cs
  5. 2 0
      src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs
  6. 2 0
      src/Avalonia.Controls.DataGrid/DataGridRowHeader.cs
  7. 2 0
      src/Avalonia.Controls/AutoCompleteBox.cs
  8. 2 0
      src/Avalonia.Controls/Button.cs
  9. 2 0
      src/Avalonia.Controls/ButtonSpinner.cs
  10. 2 0
      src/Avalonia.Controls/Calendar/CalendarButton.cs
  11. 2 0
      src/Avalonia.Controls/Calendar/CalendarDayButton.cs
  12. 2 0
      src/Avalonia.Controls/Calendar/CalendarItem.cs
  13. 2 0
      src/Avalonia.Controls/Chrome/CaptionButtons.cs
  14. 2 0
      src/Avalonia.Controls/Chrome/TitleBar.cs
  15. 2 0
      src/Avalonia.Controls/DataValidationErrors.cs
  16. 3 1
      src/Avalonia.Controls/DateTimePickers/DatePicker.cs
  17. 3 1
      src/Avalonia.Controls/DateTimePickers/TimePicker.cs
  18. 2 1
      src/Avalonia.Controls/Expander.cs
  19. 2 0
      src/Avalonia.Controls/ItemsControl.cs
  20. 2 0
      src/Avalonia.Controls/ListBoxItem.cs
  21. 2 0
      src/Avalonia.Controls/MenuItem.cs
  22. 2 0
      src/Avalonia.Controls/Notifications/NotificationCard.cs
  23. 2 0
      src/Avalonia.Controls/Notifications/WindowNotificationManager.cs
  24. 2 0
      src/Avalonia.Controls/Primitives/ScrollBar.cs
  25. 2 0
      src/Avalonia.Controls/Primitives/Thumb.cs
  26. 2 0
      src/Avalonia.Controls/Primitives/ToggleButton.cs
  27. 2 0
      src/Avalonia.Controls/Primitives/Track.cs
  28. 2 0
      src/Avalonia.Controls/ProgressBar.cs
  29. 2 0
      src/Avalonia.Controls/Slider.cs
  30. 6 1
      src/Avalonia.Controls/SplitView.cs
  31. 2 0
      src/Avalonia.Controls/TabItem.cs
  32. 2 0
      src/Avalonia.Controls/TextBox.cs
  33. 3 1
      src/Avalonia.Controls/ToggleSwitch.cs
  34. 2 0
      src/Avalonia.Controls/ToolTip.cs
  35. 2 0
      src/Avalonia.Controls/TreeViewItem.cs
  36. 2 0
      src/Avalonia.Input/InputElement.cs
  37. 18 0
      src/Avalonia.Styling/Controls/Metadata/PseudoClassesAttribute.cs

+ 2 - 0
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
 {
     /// <summary>
     /// Displays data in a customizable grid.
     /// </summary>
+    [PseudoClasses(":invalid")]
     public partial class DataGrid : TemplatedControl
     {
         private const string DATAGRID_elementRowsPresenterName = "PART_RowsPresenter";

+ 2 - 0
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
     /// <summary>
     /// Represents an individual <see cref="T:Avalonia.Controls.DataGrid" /> cell.
     /// </summary>
+    [PseudoClasses(":selected", ":current", ":edited", ":invalid")]
     public class DataGridCell : ContentControl
     {
         private const string DATAGRIDCELL_elementRightGridLine = "PART_RightGridLine";

+ 2 - 0
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
 {
     /// <summary>
     /// Represents an individual <see cref="T:Avalonia.Controls.DataGrid" /> column header.
     /// </summary>
+    [PseudoClasses(":dragIndicator", ":pressed", ":sortascending", ":sortdescending")]
     public class DataGridColumnHeader : ContentControl
     {
         private enum DragMode

+ 2 - 0
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
     /// <summary>
     /// Represents a <see cref="T:Avalonia.Controls.DataGrid" /> row.
     /// </summary>
+    [PseudoClasses(":selected", ":editing", ":invalid")]
     public class DataGridRow : TemplatedControl
     {
 

+ 2 - 0
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";

+ 2 - 0
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
     /// <summary>
     /// Represents an individual <see cref="T:Avalonia.Controls.DataGrid" /> row header. 
     /// </summary>
+    [PseudoClasses(":invalid", ":selected", ":editing", ":current")]
     public class DataGridRowHeader : ContentControl
     {
         private const string DATAGRIDROWHEADER_elementRootName = "PART_Root";

+ 2 - 0
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
     /// <see cref="E:Avalonia.Controls.AutoCompleteBox.Populated" />
     /// event.
     /// </summary>
+    [PseudoClasses(":dropdownopen")]
     public class PopulatedEventArgs : EventArgs
     {
         /// <summary>

+ 2 - 0
src/Avalonia.Controls/Button.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Linq;
 using System.Windows.Input;
+using Avalonia.Controls.Metadata;
 using Avalonia.Data;
 using Avalonia.Input;
 using Avalonia.Interactivity;
@@ -28,6 +29,7 @@ namespace Avalonia.Controls
     /// <summary>
     /// A button control.
     /// </summary>
+    [PseudoClasses(":pressed")]
     public class Button : ContentControl
     {
         /// <summary>

+ 2 - 0
src/Avalonia.Controls/ButtonSpinner.cs

@@ -1,4 +1,5 @@
 using System;
+using Avalonia.Controls.Metadata;
 using Avalonia.Controls.Primitives;
 using Avalonia.Data;
 using Avalonia.Input;
@@ -15,6 +16,7 @@ namespace Avalonia.Controls
     /// <summary>
     /// Represents a spinner control that includes two Buttons.
     /// </summary>
+    [PseudoClasses(":left", ":right")]
     public class ButtonSpinner : Spinner
     {
         /// <summary>

+ 2 - 0
src/Avalonia.Controls/Calendar/CalendarButton.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 System;
 
@@ -12,6 +13,7 @@ namespace Avalonia.Controls.Primitives
     /// Represents a button on a
     /// <see cref="T:Avalonia.Controls.Calendar" />.
     /// </summary>
+    [PseudoClasses(":selected", ":inactive", ":btnfocused")]
     public sealed class CalendarButton : Button
     {
         /// <summary>

+ 2 - 0
src/Avalonia.Controls/Calendar/CalendarDayButton.cs

@@ -5,10 +5,12 @@
 
 using System;
 using System.Globalization;
+using Avalonia.Controls.Metadata;
 using Avalonia.Input;
 
 namespace Avalonia.Controls.Primitives
 {
+    [PseudoClasses(":pressed", ":disabled", ":selected", ":inactive", ":today", ":blackout", ":dayfocused")]
     public sealed class CalendarDayButton : Button
     {
         /// <summary>

+ 2 - 0
src/Avalonia.Controls/Calendar/CalendarItem.cs

@@ -7,6 +7,7 @@ using System;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Globalization;
+using Avalonia.Controls.Metadata;
 using Avalonia.Data;
 using Avalonia.Input;
 using Avalonia.Interactivity;
@@ -18,6 +19,7 @@ namespace Avalonia.Controls.Primitives
     /// Represents the currently displayed month or year on a
     /// <see cref="T:Avalonia.Controls.Calendar" />.
     /// </summary>
+    [PseudoClasses(":calendardisabled")]
     public sealed class CalendarItem : TemplatedControl
     {
         /// <summary>

+ 2 - 0
src/Avalonia.Controls/Chrome/CaptionButtons.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Reactive.Disposables;
+using Avalonia.Controls.Metadata;
 using Avalonia.Controls.Primitives;
 
 #nullable enable
@@ -9,6 +10,7 @@ namespace Avalonia.Controls.Chrome
     /// <summary>
     /// Draws window minimize / maximize / close buttons in a <see cref="TitleBar"/> when managed client decorations are enabled.
     /// </summary>
+    [PseudoClasses(":minimized", ":normal", ":maximized", ":fullscreen")]
     public class CaptionButtons : TemplatedControl
     {
         private CompositeDisposable? _disposables;

+ 2 - 0
src/Avalonia.Controls/Chrome/TitleBar.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Reactive.Disposables;
+using Avalonia.Controls.Metadata;
 using Avalonia.Controls.Primitives;
 
 #nullable enable
@@ -9,6 +10,7 @@ namespace Avalonia.Controls.Chrome
     /// <summary>
     /// Draws a titlebar when managed client decorations are enabled.
     /// </summary>
+    [PseudoClasses(":minimized", ":normal", ":maximized", ":fullscreen")]
     public class TitleBar : TemplatedControl
     {
         private CompositeDisposable? _disposables;

+ 2 - 0
src/Avalonia.Controls/DataValidationErrors.cs

@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Reactive.Linq;
+using Avalonia.Controls.Metadata;
 using Avalonia.Controls.Templates;
 using Avalonia.Data;
 
@@ -14,6 +15,7 @@ namespace Avalonia.Controls
     /// <remarks>
     /// You will probably only want to create instances inside of control templates.
     /// </remarks>
+    [PseudoClasses(":error")]
     public class DataValidationErrors : ContentControl
     {
         /// <summary>

+ 3 - 1
src/Avalonia.Controls/DateTimePickers/DatePicker.cs

@@ -1,4 +1,5 @@
-using Avalonia.Controls.Primitives;
+using Avalonia.Controls.Metadata;
+using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Shapes;
 using Avalonia.Controls.Templates;
 using Avalonia.Interactivity;
@@ -11,6 +12,7 @@ namespace Avalonia.Controls
     /// <summary>
     /// A control to allow the user to select a date
     /// </summary>
+    [PseudoClasses(":hasnodate")]
     public class DatePicker : TemplatedControl
     {
         /// <summary>

+ 3 - 1
src/Avalonia.Controls/DateTimePickers/TimePicker.cs

@@ -1,4 +1,5 @@
-using Avalonia.Controls.Primitives;
+using Avalonia.Controls.Metadata;
+using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Shapes;
 using Avalonia.Controls.Templates;
 using System;
@@ -9,6 +10,7 @@ namespace Avalonia.Controls
     /// <summary>
     /// A control to allow the user to select a time
     /// </summary>
+    [PseudoClasses(":hasnotime")]
     public class TimePicker : TemplatedControl
     {
         /// <summary>

+ 2 - 1
src/Avalonia.Controls/Expander.cs

@@ -1,6 +1,6 @@
 using Avalonia.Animation;
+using Avalonia.Controls.Metadata;
 using Avalonia.Controls.Primitives;
-using Avalonia.Data;
 
 namespace Avalonia.Controls
 {
@@ -12,6 +12,7 @@ namespace Avalonia.Controls
         Right
     }
 
+    [PseudoClasses(":expanded", ":up", ":down", ":left", ":right")]
     public class Expander : HeaderedContentControl
     {
         public static readonly StyledProperty<IPageTransition> ContentTransitionProperty =

+ 2 - 0
src/Avalonia.Controls/ItemsControl.cs

@@ -4,6 +4,7 @@ using System.Collections.Generic;
 using System.Collections.Specialized;
 using Avalonia.Collections;
 using Avalonia.Controls.Generators;
+using Avalonia.Controls.Metadata;
 using Avalonia.Controls.Presenters;
 using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Templates;
@@ -18,6 +19,7 @@ namespace Avalonia.Controls
     /// <summary>
     /// Displays a collection of items.
     /// </summary>
+    [PseudoClasses(":empty", ":singleitem")]
     public class ItemsControl : TemplatedControl, IItemsPresenterHost, ICollectionChangedListener
     {
         /// <summary>

+ 2 - 0
src/Avalonia.Controls/ListBoxItem.cs

@@ -1,3 +1,4 @@
+using Avalonia.Controls.Metadata;
 using Avalonia.Controls.Mixins;
 using Avalonia.Input;
 
@@ -6,6 +7,7 @@ namespace Avalonia.Controls
     /// <summary>
     /// A selectable item in a <see cref="ListBox"/>.
     /// </summary>
+    [PseudoClasses(":pressed", ":selected")]
     public class ListBoxItem : ContentControl, ISelectable
     {
         /// <summary>

+ 2 - 0
src/Avalonia.Controls/MenuItem.cs

@@ -4,6 +4,7 @@ using System.Linq;
 using System.Reactive.Linq;
 using System.Windows.Input;
 using Avalonia.Controls.Generators;
+using Avalonia.Controls.Metadata;
 using Avalonia.Controls.Mixins;
 using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Templates;
@@ -20,6 +21,7 @@ namespace Avalonia.Controls
     /// <summary>
     /// A menu item control.
     /// </summary>
+    [PseudoClasses(":separator", ":icon", ":open", ":pressed", ":selected")]
     public class MenuItem : HeaderedSelectingItemsControl, IMenuItem, ISelectable
     {
         /// <summary>

+ 2 - 0
src/Avalonia.Controls/Notifications/NotificationCard.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Linq;
 using System.Reactive.Linq;
+using Avalonia.Controls.Metadata;
 using Avalonia.Interactivity;
 using Avalonia.LogicalTree;
 
@@ -9,6 +10,7 @@ namespace Avalonia.Controls.Notifications
     /// <summary>
     /// Control that represents and displays a notification.
     /// </summary>
+    [PseudoClasses(":error", ":information", ":success", ":warning")]
     public class NotificationCard : ContentControl
     {
         private bool _isClosed;

+ 2 - 0
src/Avalonia.Controls/Notifications/WindowNotificationManager.cs

@@ -7,12 +7,14 @@ using Avalonia.Controls.Primitives;
 using Avalonia.Rendering;
 using Avalonia.Data;
 using Avalonia.VisualTree;
+using Avalonia.Controls.Metadata;
 
 namespace Avalonia.Controls.Notifications
 {
     /// <summary>
     /// An <see cref="INotificationManager"/> that displays notifications in a <see cref="Window"/>.
     /// </summary>
+    [PseudoClasses(":topleft", ":topright", ":bottomleft", ":bottomright")]
     public class WindowNotificationManager : TemplatedControl, IManagedNotificationManager, ICustomSimpleHitTest
     {
         private IList _items;

+ 2 - 0
src/Avalonia.Controls/Primitives/ScrollBar.cs

@@ -4,6 +4,7 @@ using Avalonia.Interactivity;
 using Avalonia.Input;
 using Avalonia.Layout;
 using Avalonia.Threading;
+using Avalonia.Controls.Metadata;
 
 namespace Avalonia.Controls.Primitives
 {
@@ -21,6 +22,7 @@ namespace Avalonia.Controls.Primitives
     /// <summary>
     /// A scrollbar control.
     /// </summary>
+    [PseudoClasses(":vertical", ":horizontal")]
     public class ScrollBar : RangeBase
     {
         /// <summary>

+ 2 - 0
src/Avalonia.Controls/Primitives/Thumb.cs

@@ -1,9 +1,11 @@
 using System;
+using Avalonia.Controls.Metadata;
 using Avalonia.Input;
 using Avalonia.Interactivity;
 
 namespace Avalonia.Controls.Primitives
 {
+    [PseudoClasses(":pressed")]
     public class Thumb : TemplatedControl
     {
         public static readonly RoutedEvent<VectorEventArgs> DragStartedEvent =

+ 2 - 0
src/Avalonia.Controls/Primitives/ToggleButton.cs

@@ -1,4 +1,5 @@
 using System;
+using Avalonia.Controls.Metadata;
 using Avalonia.Data;
 using Avalonia.Interactivity;
 
@@ -7,6 +8,7 @@ namespace Avalonia.Controls.Primitives
     /// <summary>
     /// Represents a control that a user can select (check) or clear (uncheck). Base class for controls that can switch states.
     /// </summary>
+    [PseudoClasses(":checked", ":unchecked", ":indeterminate")]
     public class ToggleButton : Button
     {
         /// <summary>

+ 2 - 0
src/Avalonia.Controls/Primitives/Track.cs

@@ -4,6 +4,7 @@
 // Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
 
 using System;
+using Avalonia.Controls.Metadata;
 using Avalonia.Data;
 using Avalonia.Input;
 using Avalonia.Layout;
@@ -12,6 +13,7 @@ using Avalonia.Utilities;
 
 namespace Avalonia.Controls.Primitives
 {
+    [PseudoClasses(":vertical", ":horizontal")]
     public class Track : Control
     {
         public static readonly DirectProperty<Track, double> MinimumProperty =

+ 2 - 0
src/Avalonia.Controls/ProgressBar.cs

@@ -1,4 +1,5 @@
 using System;
+using Avalonia.Controls.Metadata;
 using Avalonia.Controls.Primitives;
 using Avalonia.Layout;
 using Avalonia.Media;
@@ -8,6 +9,7 @@ namespace Avalonia.Controls
     /// <summary>
     /// A control used to indicate the progress of an operation.
     /// </summary>
+    [PseudoClasses(":vertical", ":horizontal", ":indeterminate")]
     public class ProgressBar : RangeBase
     {
         public class ProgressBarTemplateProperties : AvaloniaObject

+ 2 - 0
src/Avalonia.Controls/Slider.cs

@@ -1,5 +1,6 @@
 using System;
 using Avalonia.Collections;
+using Avalonia.Controls.Metadata;
 using Avalonia.Controls.Mixins;
 using Avalonia.Controls.Primitives;
 using Avalonia.Input;
@@ -39,6 +40,7 @@ namespace Avalonia.Controls
     /// <summary>
     /// A control that lets the user select from a range of values by moving a Thumb control along a Track.
     /// </summary>
+    [PseudoClasses(":vertical", ":horizontal", ":pressed")]
     public class Slider : RangeBase
     {
         /// <summary>

+ 6 - 1
src/Avalonia.Controls/SplitView.cs

@@ -1,4 +1,5 @@
-using Avalonia.Controls.Primitives;
+using Avalonia.Controls.Metadata;
+using Avalonia.Controls.Primitives;
 using Avalonia.Input;
 using Avalonia.Input.Raw;
 using Avalonia.Interactivity;
@@ -73,6 +74,10 @@ namespace Avalonia.Controls
     /// <summary>
     /// A control with two views: A collapsible pane and an area for content
     /// </summary>
+    [PseudoClasses(":open", ":closed")]
+    [PseudoClasses(":compactoverlay", ":compactinline", ":overlay", ":inline")]
+    [PseudoClasses(":left", ":right")]
+    [PseudoClasses(":lightdismiss")]
     public class SplitView : TemplatedControl
     {
         /*

+ 2 - 0
src/Avalonia.Controls/TabItem.cs

@@ -1,3 +1,4 @@
+using Avalonia.Controls.Metadata;
 using Avalonia.Controls.Mixins;
 using Avalonia.Controls.Primitives;
 
@@ -6,6 +7,7 @@ namespace Avalonia.Controls
     /// <summary>
     /// An item in  a <see cref="TabStrip"/> or <see cref="TabControl"/>.
     /// </summary>
+    [PseudoClasses(":pressed", ":selected")]
     public class TabItem : HeaderedContentControl, ISelectable
     {
         /// <summary>

+ 2 - 0
src/Avalonia.Controls/TextBox.cs

@@ -13,9 +13,11 @@ using Avalonia.Metadata;
 using Avalonia.Data;
 using Avalonia.Layout;
 using Avalonia.Utilities;
+using Avalonia.Controls.Metadata;
 
 namespace Avalonia.Controls
 {
+    [PseudoClasses(":empty")]
     public class TextBox : TemplatedControl, UndoRedoHelper<TextBox.UndoRedoState>.IUndoRedoHost
     {
         public static KeyGesture CutGesture { get; } = AvaloniaLocator.Current

+ 3 - 1
src/Avalonia.Controls/ToggleSwitch.cs

@@ -1,4 +1,5 @@
-using Avalonia.Controls.Presenters;
+using Avalonia.Controls.Metadata;
+using Avalonia.Controls.Presenters;
 using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Templates;
 using Avalonia.LogicalTree;
@@ -8,6 +9,7 @@ namespace Avalonia.Controls
     /// <summary>
     /// A Toggle Switch control.
     /// </summary>
+    [PseudoClasses(":dragging")]
     public class ToggleSwitch : ToggleButton
     {
         private Panel _knobsPanel;

+ 2 - 0
src/Avalonia.Controls/ToolTip.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Reactive.Linq;
+using Avalonia.Controls.Metadata;
 using Avalonia.Controls.Primitives;
 using Avalonia.VisualTree;
 
@@ -14,6 +15,7 @@ namespace Avalonia.Controls
     /// To add a tooltip to a control, use the <see cref="TipProperty"/> attached property,
     /// assigning the content that you want displayed.
     /// </remarks>
+    [PseudoClasses(":open")]
     public class ToolTip : ContentControl
     {
         /// <summary>

+ 2 - 0
src/Avalonia.Controls/TreeViewItem.cs

@@ -1,5 +1,6 @@
 using System.Linq;
 using Avalonia.Controls.Generators;
+using Avalonia.Controls.Metadata;
 using Avalonia.Controls.Mixins;
 using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Templates;
@@ -11,6 +12,7 @@ namespace Avalonia.Controls
     /// <summary>
     /// An item in a <see cref="TreeView"/>.
     /// </summary>
+    [PseudoClasses(":pressed", ":selected")]
     public class TreeViewItem : HeaderedItemsControl, ISelectable
     {
         /// <summary>

+ 2 - 0
src/Avalonia.Input/InputElement.cs

@@ -2,6 +2,7 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using Avalonia.Controls;
+using Avalonia.Controls.Metadata;
 using Avalonia.Data;
 using Avalonia.Input.GestureRecognizers;
 using Avalonia.Interactivity;
@@ -12,6 +13,7 @@ namespace Avalonia.Input
     /// <summary>
     /// Implements input-related functionality for a control.
     /// </summary>
+    [PseudoClasses(":disabled", ":focus", ":focus-visible", ":pointerover")]
     public class InputElement : Interactive, IInputElement
     {
         /// <summary>

+ 18 - 0
src/Avalonia.Styling/Controls/Metadata/PseudoClassesAttribute.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+
+#nullable enable
+
+namespace Avalonia.Controls.Metadata
+{
+    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+    public class PseudoClassesAttribute : Attribute
+    {
+        public PseudoClassesAttribute(params string[] pseudoClasses)
+        {
+            PseudoClasses = pseudoClasses;
+        }
+
+        public IReadOnlyList<string> PseudoClasses { get; }
+    }
+}