├── gif.gif ├── src ├── key.snk ├── Directory.Build.props ├── Breakpoints.Avalonia │ ├── Xmlns.cs │ ├── ResponsivityBreakpoints.axaml │ ├── ResponsivityBreakpoints.axaml.cs │ ├── Controls │ │ ├── Breakpoint.axaml │ │ ├── TemplatedBreakpoint.axaml │ │ ├── Breakpoint.cs │ │ ├── TemplatedBreakpoint.cs │ │ └── Breakpoints.cs │ ├── Nullables.cs │ ├── Breakpoints.Avalonia.csproj │ ├── Collections │ │ └── BreakpointList.cs │ └── Markup │ │ └── BreakpointExtension.cs ├── Breakpoints.Avalonia.Xmlns │ ├── Xmlns.cs │ └── Breakpoints.Avalonia.Xmlns.csproj ├── Breakpoints.Avalonia.TestApp │ ├── UserControl1.axaml.cs │ ├── App.axaml │ ├── App.axaml.cs │ ├── Program.cs │ ├── app.manifest │ ├── Breakpoints.Avalonia.TestApp.csproj │ ├── MainWindow.axaml.cs │ ├── MainWindow.axaml │ └── UserControl1.axaml ├── Breakpoints.Avalonia.sln └── .editorconfig ├── LICENSE ├── .gitignore └── README.md /gif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AVVI94/Breakpoints.Avalonia/HEAD/gif.gif -------------------------------------------------------------------------------- /src/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AVVI94/Breakpoints.Avalonia/HEAD/src/key.snk -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | enable 4 | 11.0.10 5 | Latest 6 | 2.3 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia/Xmlns.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Metadata; 2 | [assembly: XmlnsDefinition("https://github.com/AVVI94", "AVVI94.Breakpoints.Avalonia")] 3 | [assembly: XmlnsDefinition("https://github.com/AVVI94", "AVVI94.Breakpoints.Avalonia.Controls")] 4 | [assembly: XmlnsDefinition("https://github.com/AVVI94", "AVVI94.Breakpoints.Avalonia.Markup")] 5 | -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia.Xmlns/Xmlns.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Metadata; 2 | [assembly: XmlnsDefinition("https://github.com/avaloniaui", "AVVI94.Breakpoints.Avalonia")] 3 | [assembly: XmlnsDefinition("https://github.com/avaloniaui", "AVVI94.Breakpoints.Avalonia.Controls")] 4 | [assembly: XmlnsDefinition("https://github.com/avaloniaui", "AVVI94.Breakpoints.Avalonia.Markup")] 5 | -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia.TestApp/UserControl1.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Markup.Xaml; 4 | using System.Diagnostics; 5 | using System.Threading; 6 | 7 | namespace Breakpoints.Avalonia.TestApp; 8 | 9 | public partial class UserControl1 : UserControl 10 | { 11 | public UserControl1() 12 | { 13 | InitializeComponent(); 14 | } 15 | } -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia.TestApp/App.axaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia/ResponsivityBreakpoints.axaml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia/ResponsivityBreakpoints.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Markup.Xaml; 3 | using Avalonia.Styling; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Text; 7 | 8 | namespace AVVI94.Breakpoints.Avalonia; 9 | 10 | public class ResponsivityBreakpoints : Styles 11 | { 12 | public ResponsivityBreakpoints() 13 | { 14 | AvaloniaXamlLoader.Load(this); 15 | } 16 | 17 | public ResponsivityBreakpoints(IResourceHost owner) : base(owner) 18 | { 19 | AvaloniaXamlLoader.Load(this); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia.Xmlns/Breakpoints.Avalonia.Xmlns.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | True 6 | ..\key.snk 7 | True 8 | Jan Král 9 | AVVI94.$(RootNamespace) 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia.TestApp/App.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls.ApplicationLifetimes; 3 | using Avalonia.Markup.Xaml; 4 | 5 | namespace Breakpoints.Avalonia.TestApp 6 | { 7 | public partial class App : Application 8 | { 9 | public override void Initialize() 10 | { 11 | AvaloniaXamlLoader.Load(this); 12 | } 13 | 14 | public override void OnFrameworkInitializationCompleted() 15 | { 16 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) 17 | { 18 | desktop.MainWindow = new MainWindow(); 19 | } 20 | 21 | base.OnFrameworkInitializationCompleted(); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia/Controls/Breakpoint.axaml: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia.TestApp/Program.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using System; 3 | 4 | namespace Breakpoints.Avalonia.TestApp 5 | { 6 | internal class Program 7 | { 8 | // Initialization code. Don't use any Avalonia, third-party APIs or any 9 | // SynchronizationContext-reliant code before AppMain is called: things aren't initialized 10 | // yet and stuff might break. 11 | [STAThread] 12 | public static void Main(string[] args) => BuildAvaloniaApp() 13 | .StartWithClassicDesktopLifetime(args); 14 | 15 | // Avalonia configuration, don't remove; also used by visual designer. 16 | public static AppBuilder BuildAvaloniaApp() 17 | => AppBuilder.Configure() 18 | .UsePlatformDetect() 19 | .WithInterFont() 20 | .LogToTrace(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia/Controls/TemplatedBreakpoint.axaml: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia.TestApp/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Jan Král 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia.TestApp/Breakpoints.Avalonia.TestApp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | WinExe 4 | net8.0 5 | enable 6 | true 7 | app.manifest 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia/Nullables.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace System.Diagnostics.CodeAnalysis; 6 | 7 | /// Specifies that an output will not be null even if the corresponding type allows it. Specifies that an input argument was not null when the call returns. 8 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] 9 | internal sealed class NotNullAttribute : Attribute; 10 | 11 | /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. 12 | [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] 13 | internal sealed class NotNullWhenAttribute : Attribute 14 | { 15 | /// Initializes the attribute with the specified return value condition. 16 | /// 17 | /// The return value condition. If the method returns this value, the associated parameter will not be null. 18 | /// 19 | public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; 20 | 21 | /// Gets the return value condition. 22 | public bool ReturnValue { get; } 23 | } 24 | -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia/Breakpoints.Avalonia.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | True 6 | True 7 | False 8 | $(AssemblyName) 9 | Jan Král 10 | Breakpoints.Avalonia is a library for Avalonia UI (https://avaloniaui.net/) that provides responsive design capabilities using breakpoints. It allows you to define different UI layouts and behaviors based on the size of the application window. 11 | https://github.com/AVVI94/Breakpoints.Avalonia 12 | README.md 13 | https://github.com/AVVI94/Breakpoints.Avalonia 14 | true 15 | ..\key.snk 16 | AVVI94.Breakpoints.Avalonia 17 | $(RootNamespace) 18 | Avalonia, breakpoints, responsivity, responsive, desktop 19 | 20 | 21 | 22 | 23 | True 24 | \ 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia.TestApp/MainWindow.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using AVVI94.Breakpoints.Avalonia.Collections; 3 | using System; 4 | using System.Diagnostics; 5 | 6 | namespace Breakpoints.Avalonia.TestApp 7 | { 8 | public partial class MainWindow : Window 9 | { 10 | public MainWindow() 11 | { 12 | InitializeComponent(); 13 | BreakpointList bp = [ 14 | ("XS", 600), 15 | ("S", 800), 16 | ("M", 1000), 17 | ("L", 1200), 18 | ("XL", 1400), 19 | ("XXL", 1600) 20 | ]; 21 | AVVI94.Breakpoints.Avalonia.Controls.Breakpoints.SetValues(this, bp); 22 | 23 | GridInfoTextBox.Text = """ 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | """; 35 | } 36 | 37 | bool flag = false; 38 | private void Button_Click(object? sender, global::Avalonia.Interactivity.RoutedEventArgs e) 39 | { 40 | var button = (Button)sender!; 41 | if(flag) 42 | { 43 | ((StackPanel)button.Parent!).Children.RemoveAt(((StackPanel)button.Parent).Children.Count - 1); 44 | flag = false; 45 | } 46 | else 47 | { 48 | ((StackPanel)button.Parent!).Children.Add(new UserControl1()); 49 | flag = true; 50 | } 51 | 52 | GC.Collect(); 53 | GC.WaitForPendingFinalizers(); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio Version 17 3 | VisualStudioVersion = 17.11.35312.102 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{838EF520-3CF7-447D-B1CD-AF3468F41DEC}" 6 | ProjectSection(SolutionItems) = preProject 7 | .editorconfig = .editorconfig 8 | Directory.Build.props = Directory.Build.props 9 | ..\README.md = ..\README.md 10 | EndProjectSection 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Breakpoints.Avalonia", "Breakpoints.Avalonia\Breakpoints.Avalonia.csproj", "{D444E0FE-960B-4B38-9ED8-5740DAE5A2CD}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Breakpoints.Avalonia.TestApp", "Breakpoints.Avalonia.TestApp\Breakpoints.Avalonia.TestApp.csproj", "{D74723CE-B5C8-4845-A8A5-54E50FEBA4BB}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Breakpoints.Avalonia.Xmlns", "Breakpoints.Avalonia.Xmlns\Breakpoints.Avalonia.Xmlns.csproj", "{DB2989BC-0EDD-4DF9-92B8-CD8F3D456F73}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Release|Any CPU = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {D444E0FE-960B-4B38-9ED8-5740DAE5A2CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {D444E0FE-960B-4B38-9ED8-5740DAE5A2CD}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {D444E0FE-960B-4B38-9ED8-5740DAE5A2CD}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {D444E0FE-960B-4B38-9ED8-5740DAE5A2CD}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {D74723CE-B5C8-4845-A8A5-54E50FEBA4BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {D74723CE-B5C8-4845-A8A5-54E50FEBA4BB}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {D74723CE-B5C8-4845-A8A5-54E50FEBA4BB}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {D74723CE-B5C8-4845-A8A5-54E50FEBA4BB}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {DB2989BC-0EDD-4DF9-92B8-CD8F3D456F73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {DB2989BC-0EDD-4DF9-92B8-CD8F3D456F73}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {DB2989BC-0EDD-4DF9-92B8-CD8F3D456F73}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {DB2989BC-0EDD-4DF9-92B8-CD8F3D456F73}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {5063A987-1D2E-4643-A985-424CACF6671D} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia/Collections/BreakpointList.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Avalonia = global::Avalonia; 3 | using BP = AVVI94.Breakpoints.Avalonia.Controls.Breakpoints; 4 | using NsBreakpoints = AVVI94.Breakpoints.Avalonia; 5 | 6 | namespace AVVI94.Breakpoints.Avalonia.Collections; 7 | 8 | using System; 9 | using System.Collections; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | 13 | /// 14 | /// An ordered list of breakpoints with keys and values 15 | /// 16 | public sealed class BreakpointList : IEnumerable, IEnumerable> 17 | { 18 | private readonly Dictionary _keyValuePairs = []; 19 | private readonly SortedSet<(double Value, string Key)> _sortedValues = []; 20 | 21 | /// 22 | /// Provides a read-only view of the items in the list 23 | /// 24 | public IReadOnlyDictionary Items => _keyValuePairs; 25 | /// 26 | /// Provides a read-only view of the breakpoints in the list sorted from min to max. 27 | /// 28 | public IEnumerable<(double Value, string Key)> SortedItems => _sortedValues; 29 | 30 | /// 31 | /// Add a new key-value pair to the list 32 | /// 33 | /// Breakpoint name 34 | /// Breakpoint value 35 | /// Thrown if the breakpoint name or value is already present in the collection. 36 | public void Add(string key, double value) 37 | { 38 | if (_keyValuePairs.ContainsKey(key)) 39 | throw new ArgumentException("The key already exists."); 40 | 41 | if (!_sortedValues.Add((value, key))) 42 | throw new ArgumentException("The value already exists."); 43 | 44 | _keyValuePairs[key] = value; 45 | } 46 | 47 | /// 48 | /// Add a new key-value pair to the list, inteded to be used with collection initializers 49 | /// 50 | /// Breakpoint 51 | public void Add((string Key, double Value) item) => Add(item.Key, item.Value); 52 | 53 | /// 54 | /// Try to get the value of a breakpoint 55 | /// 56 | /// Breakpoint name 57 | /// [OUT] Value of the breakpoint 58 | /// 59 | public bool TryGetValue(string key, out double value) => _keyValuePairs.TryGetValue(key, out value); 60 | 61 | /// 62 | /// Remove a breakpoint from the list 63 | /// 64 | /// Name of the breakpoint 65 | /// 66 | public bool Remove(string key) 67 | { 68 | if (_keyValuePairs.TryGetValue(key, out double value)) 69 | { 70 | _keyValuePairs.Remove(key); 71 | _sortedValues.Remove((value, key)); 72 | return true; 73 | } 74 | return false; 75 | } 76 | 77 | /// 78 | /// Get or set the value of a breakpoint 79 | /// 80 | /// Name of the breakpoint 81 | /// Value of the breakpoint 82 | public double this[string key] 83 | { 84 | get => _keyValuePairs[key]; 85 | set 86 | { 87 | if (_keyValuePairs.ContainsKey(key)) 88 | { 89 | var oldValue = _keyValuePairs[key]; 90 | _sortedValues.Remove((oldValue, key)); 91 | _keyValuePairs[key] = value; 92 | _sortedValues.Add((value, key)); 93 | } 94 | else 95 | { 96 | Add(key, value); 97 | } 98 | } 99 | } 100 | /// 101 | /// Get the key-value pair at the specified index 102 | /// 103 | /// Breakpoint index 104 | /// 105 | /// 106 | public (string Key, double Value) this[int index] 107 | { 108 | get 109 | { 110 | if (index < 0 || index >= _sortedValues.Count) 111 | throw new IndexOutOfRangeException(); 112 | 113 | var item = _sortedValues.ElementAt(index); 114 | return (item.Key, item.Value); 115 | } 116 | } 117 | /// 118 | /// Number of breakpoints in the list 119 | /// 120 | public int Count => _keyValuePairs.Count; 121 | 122 | /// 123 | /// Find the next breakpoint with a value greater than the specified value. 124 | /// 125 | /// Searched value 126 | /// Breakpoint name and value or if no next breakpoint was found. 127 | public KeyValuePair? FindNext(double value) 128 | { 129 | var next = _sortedValues.FirstOrDefault(x => x.Value > value); 130 | return next == default ? null : new(next.Key, next.Value); 131 | } 132 | 133 | /// 134 | /// Find the previous breakpoint with a value less than the specified value. 135 | /// 136 | /// Searched value 137 | /// 138 | /// Breakpoint name and value or if no previous breakpoint was found. 139 | /// 140 | public KeyValuePair? FindPrevious(double value) 141 | { 142 | var previous = _sortedValues.LastOrDefault(x => x.Value < value); 143 | return previous == default ? null : new(previous.Key, previous.Value); 144 | } 145 | 146 | public KeyValuePair? FindCurrent(double value) 147 | { 148 | var current = _sortedValues.LastOrDefault(x => value >= x.Value); 149 | return current == default ? FindNext(value) ?? FindPrevious(value) : new(current.Key, current.Value); 150 | } 151 | 152 | /// 153 | /// Get an enumerator for the breakpoints. Implemented mainly for collection initializers. 154 | /// 155 | public IEnumerator GetEnumerator() 156 | { 157 | return ((IEnumerable)Items).GetEnumerator(); 158 | } 159 | 160 | IEnumerator> IEnumerable>.GetEnumerator() 161 | { 162 | return Items.GetEnumerator(); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/Breakpoints.Avalonia.TestApp/MainWindow.axaml: -------------------------------------------------------------------------------- 1 | 13 | 14 | 16 |