├── .editorconfig ├── .gitattributes ├── .gitignore ├── Avalonia.PropertyGrid.sln ├── Directory.Build.props ├── Docs └── Images │ ├── ChangeSize.png │ ├── CheckList.png │ ├── CustomObject.png │ ├── DynamicVisibility.png │ ├── Multi-Objects.png │ ├── Styles.png │ ├── custom-label.png │ ├── data-sync.png │ ├── extends.png │ ├── operation-example.png │ ├── painter-demo.png │ ├── self-properties.png │ ├── settings-demo.png │ └── undoredo.png ├── LICENSE ├── README-CHS.md ├── README.md ├── Samples ├── Avalonia.PropertyGrid.Samples.Android │ ├── Avalonia.PropertyGrid.Samples.Android.csproj │ ├── Icon.png │ ├── MainActivity.cs │ ├── Properties │ │ └── AndroidManifest.xml │ └── Resources │ │ ├── AboutResources.txt │ │ ├── drawable-night-v31 │ │ └── avalonia_anim.xml │ │ ├── drawable-v31 │ │ └── avalonia_anim.xml │ │ ├── drawable │ │ └── splash_screen.xml │ │ ├── values-night │ │ └── colors.xml │ │ ├── values-v31 │ │ └── styles.xml │ │ └── values │ │ ├── colors.xml │ │ └── styles.xml ├── Avalonia.PropertyGrid.Samples.Browser │ ├── Avalonia.PropertyGrid.Samples.Browser.csproj │ ├── Program.cs │ ├── Properties │ │ ├── AssemblyInfo.cs │ │ └── launchSettings.json │ ├── runtimeconfig.template.json │ └── wwwroot │ │ ├── app.css │ │ ├── favicon.ico │ │ ├── index.html │ │ └── main.js ├── Avalonia.PropertyGrid.Samples.Desktop │ ├── Avalonia.PropertyGrid.Samples.Desktop.csproj │ ├── Program.cs │ └── app.manifest ├── Avalonia.PropertyGrid.Samples.iOS │ ├── AppDelegate.cs │ ├── Avalonia.PropertyGrid.Samples.iOS.csproj │ ├── Entitlements.plist │ ├── Info.plist │ ├── Main.cs │ └── Resources │ │ └── LaunchScreen.xib ├── Avalonia.PropertyGrid.Samples │ ├── App.axaml │ ├── App.axaml.cs │ ├── Assets │ │ ├── Localizations │ │ │ ├── en-US.json │ │ │ ├── ru-RU.json │ │ │ └── zh-CN.json │ │ ├── avalonia-banner.png │ │ ├── avalonia-logo.ico │ │ ├── country-flags │ │ │ ├── au.png │ │ │ ├── bl.png │ │ │ ├── ca.png │ │ │ ├── cn.png │ │ │ ├── de.png │ │ │ ├── gb.png │ │ │ ├── ua.png │ │ │ └── us.png │ │ └── images │ │ │ ├── colormixer.png │ │ │ ├── home.png │ │ │ └── technology.png │ ├── Avalonia.PropertyGrid.Samples.csproj │ ├── FeatureDemos │ │ ├── Models │ │ │ ├── CancelableObject.cs │ │ │ ├── DynamicVisibilityObject.cs │ │ │ ├── LoginInfo.cs │ │ │ ├── ScriptableObject.cs │ │ │ ├── ScriptableOptions.cs │ │ │ ├── SimpleObject.cs │ │ │ ├── TestExtendsObject.cs │ │ │ ├── TypeDescriptionProvider.cs │ │ │ └── Vector3.cs │ │ ├── ViewModels │ │ │ └── FeatureDemoViewModel.cs │ │ └── Views │ │ │ ├── CountryView.axaml │ │ │ ├── CountryView.axaml.cs │ │ │ ├── FeatureDemoView.axaml │ │ │ ├── FeatureDemoView.axaml.cs │ │ │ ├── TestExtendPropertyGrid.cs │ │ │ ├── Vector3View.axaml │ │ │ └── Vector3View.axaml.cs │ ├── PainterDemo │ │ ├── Models │ │ │ ├── ArrowShape.cs │ │ │ ├── BrushConfiguration.cs │ │ │ ├── EllipseShape.cs │ │ │ ├── FreehandShape.cs │ │ │ ├── LineShape.cs │ │ │ ├── RectangleShape.cs │ │ │ ├── ShapeBase.cs │ │ │ └── StarShape.cs │ │ ├── ViewModel │ │ │ └── PainterViewModel.cs │ │ └── Views │ │ │ ├── GradientStopView.axaml │ │ │ ├── GradientStopView.axaml.cs │ │ │ ├── PainterView.axaml │ │ │ └── PainterView.axaml.cs │ ├── SettingsDemo │ │ ├── Models │ │ │ ├── AboutSettings.cs │ │ │ ├── AccountSettings.cs │ │ │ ├── AppearanceSettings.cs │ │ │ ├── FirewallSettings.cs │ │ │ ├── GeneralSettings.cs │ │ │ └── ThemeSettings.cs │ │ ├── ViewModels │ │ │ └── SettingsViewModel.cs │ │ └── Views │ │ │ ├── SettingsView.axaml │ │ │ └── SettingsView.axaml.cs │ └── Views │ │ ├── MainView.axaml │ │ ├── MainView.axaml.cs │ │ ├── MainWindow.axaml │ │ ├── MainWindow.axaml.cs │ │ └── SampleLocalizationService.cs └── Directory.Packages.props ├── Sources ├── Avalonia.PropertyGrid │ ├── Assets │ │ ├── Images │ │ │ ├── add.png │ │ │ ├── clear.png │ │ │ ├── delete.png │ │ │ ├── new.png │ │ │ └── options.png │ │ └── Localizations │ │ │ ├── en-US.json │ │ │ ├── ru-RU.json │ │ │ └── zh-CN.json │ ├── Avalonia.PropertyGrid.csproj │ ├── Controls │ │ ├── ButtonEdit.axaml │ │ ├── ButtonEdit.axaml.cs │ │ ├── CheckedListEdit.axaml │ │ ├── CheckedListEdit.axaml.cs │ │ ├── CheckedMask.axaml │ │ ├── CheckedMask.axaml.cs │ │ ├── Factories │ │ │ ├── AbstractCellEditFactory.cs │ │ │ └── Builtins │ │ │ │ ├── BooleanCellEditFactory.cs │ │ │ │ ├── CheckedListCellEditFactory.cs │ │ │ │ ├── CollectionCellEditFactory.cs │ │ │ │ ├── ColorCellEditFactory.cs │ │ │ │ ├── CommonCellEditFactory.cs │ │ │ │ ├── DateTimeCellEditFactory.cs │ │ │ │ ├── EnumCellEditFactory.cs │ │ │ │ ├── ExpandableCellEditFactory.cs │ │ │ │ ├── FontFamilyCellEditFactory.cs │ │ │ │ ├── ImageCellEditFactory.cs │ │ │ │ ├── NumericCellEditFactory.cs │ │ │ │ ├── PathCellEditFactory.cs │ │ │ │ ├── ProgressCellEditFactory.cs │ │ │ │ ├── SelectableListCellEditFactory.cs │ │ │ │ ├── StringCellEditFactory.cs │ │ │ │ ├── TimeCellEditFactory.cs │ │ │ │ └── TrackableCellEditFactory.cs │ │ ├── ICellEditFactory.cs │ │ ├── ICellEditFactoryCollection.cs │ │ ├── IPropertyGrid.cs │ │ ├── IPropertyGridCellInfo.cs │ │ ├── IPropertyGridFilterContext.cs │ │ ├── Implements │ │ │ ├── CellEditFactoryCollection.cs │ │ │ ├── PropertyGridCellInfo.cs │ │ │ ├── PropertyGridExpandableCache.cs │ │ │ └── PropertyGridFilterPattern.cs │ │ ├── ListEdit.axaml │ │ ├── ListEdit.axaml.cs │ │ ├── ListElementEdit.axaml │ │ ├── ListElementEdit.axaml.cs │ │ ├── ListElementPlaceholderEdit.axaml │ │ ├── ListElementPlaceholderEdit.axaml.cs │ │ ├── PropertyGrid.axaml │ │ ├── PropertyGrid.axaml.cs │ │ ├── RadioButtonListEdit.axaml │ │ ├── RadioButtonListEdit.axaml.cs │ │ ├── ToggleButtonGroupListEdit.axaml │ │ ├── ToggleButtonGroupListEdit.axaml.cs │ │ ├── TrackableEdit.axaml │ │ └── TrackableEdit.axaml.cs │ ├── Localization │ │ ├── AssemblyJsonAssetLocalizationService.cs │ │ ├── AssetCultureData.cs │ │ ├── LocalizationExtensions.cs │ │ └── LocalizeExtension.cs │ ├── Services │ │ ├── CellEditFactoryService.cs │ │ └── LocalizationService.cs │ ├── Utils │ │ ├── EnumUtils.cs │ │ ├── FontUtils.cs │ │ ├── InverseBooleanConverter.cs │ │ ├── PathBrowserUtils.cs │ │ ├── PropertyObserver.cs │ │ └── TextBlockInlinesUtils.cs │ └── ViewModels │ │ ├── PropertyGridViewModel.cs │ │ ├── ReferencePath.cs │ │ └── SingleSelectListViewModel.cs ├── PropertyModels │ ├── Collections │ │ ├── CheckedList.cs │ │ └── SelectableList.cs │ ├── ComponentModel │ │ ├── AutoCollapseCategoriesAttribute.cs │ │ ├── CancelableCommandRecorder.cs │ │ ├── CheckedMaskModel.cs │ │ ├── ControlClassesAttribute.cs │ │ ├── DataAnnotations │ │ │ ├── DependsOnPropertyAttribute.cs │ │ │ ├── EnumValueAuthorizeAttribute.cs │ │ │ ├── FileNameValidationAttribute.cs │ │ │ ├── FloatingNumberEqualToleranceAttribute.cs │ │ │ ├── ImagePreviewModeAttribute.cs │ │ │ ├── PathBrowsableAttribute.cs │ │ │ ├── ValidationResultExtensions.cs │ │ │ ├── ValidatorUtils.cs │ │ │ └── VisiblityDependencyAttribute.cs │ │ ├── EnumDisplayNameAttribute.cs │ │ ├── ExpandableObjectDisplayModeAttribute.cs │ │ ├── FloatPrecisionAttribute.cs │ │ ├── FormatStringAttribute.cs │ │ ├── ICheckedMaskModel.cs │ │ ├── ICommand.cs │ │ ├── IFilterPattern.cs │ │ ├── INotifyCommandExecuting.cs │ │ ├── INotifyPropertyChanged.cs │ │ ├── INotifyPropertyChanging.cs │ │ ├── IReactiveObject.cs │ │ ├── IntegerIncrementAttribute.cs │ │ ├── ListElementPropertyDescriptor.cs │ │ ├── MultiObjectPropertyDescriptor.cs │ │ ├── MultilineTextAttribute.cs │ │ ├── ObjectCreator.cs │ │ ├── ProgressAttribute.cs │ │ ├── PropertyOperationVisibilityAttribute.cs │ │ ├── ReactiveCommand.cs │ │ ├── SelectableListDisplayModeAttribute.cs │ │ ├── SingleSelectionModeAttribute.cs │ │ ├── TrackableAttribute.cs │ │ ├── UnitAttribute.cs │ │ └── WatermarkAttribute.cs │ ├── Extensions │ │ ├── LinqExtensions.cs │ │ ├── PropertyDescriptorExtensions.cs │ │ ├── StringExtensions.cs │ │ └── TypeExtensions.cs │ ├── Localization │ │ ├── CultureData.cs │ │ └── ILocalizationService.cs │ ├── PropertyModels.csproj │ └── Utils │ │ ├── DecimalConvertUtils.cs │ │ └── PropertyDescriptorBuilder.cs ├── README_NUGET.md └── README_PropertyModels.md ├── UnitTests └── Avalonia.PropertyGrid.UnitTests │ ├── Avalonia.PropertyGrid.UnitTests.csproj │ ├── Model │ ├── UnitTest_DecimalConvert.cs │ └── UnitTest_Utils.cs │ └── Usings.cs └── publish-web.bat /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | indent_style = space 3 | indent_size = 4 4 | 5 | csharp_style_expression_bodied_methods = true 6 | csharp_style_expression_bodied_properties = when_on_single_line 7 | csharp_style_expression_bodied_accessors = true 8 | csharp_style_expression_bodied_indexers = true 9 | csharp_style_expression_bodied_lambdas = true 10 | csharp_style_expression_bodied_operators = true 11 | csharp_style_unused_value_assignment_preference = discard_variable 12 | 13 | dotnet_sort_system_directives_first = true 14 | dotnet_diagnostic.IDE0046.severity = none 15 | 16 | resharper_convert_to_primary_constructor_highlighting = none 17 | csharp_style_prefer_primary_constructors = false 18 | dotnet_diagnostic.IDE0290.severity = none 19 | 20 | resharper_member_can_be_private_global_highlighting = none 21 | resharper_class_never_instantiated_global_highlighting = none 22 | resharper_event_never_subscribed_to_global_highlighting = none 23 | resharper_unused_member_global_highlighting = none 24 | resharper_unused_type_global_highlighting = none 25 | resharper_unused_member_in_super_global_highlighting = none 26 | resharper_not_accessed_field_global_highlighting = none 27 | resharper_member_can_be_protected_global_highlighting = none 28 | resharper_virtual_member_never_overridden_global_highlighting = none 29 | dotnet_diagnostic.IDE0051.severity = none 30 | 31 | resharper_unused_parameter_global_highlighting = none 32 | resharper_unused_parameter_local_highlighting = none 33 | dotnet_diagnostic.IDE0060.severity = none 34 | 35 | resharper_convert_if_statement_to_switch_statement_highlighting = none 36 | dotnet_diagnostic.IDE0010.severity = none 37 | 38 | resharper_unused_method_return_value_global_highlighting = none 39 | dotnet_diagnostic.IDE0058.severity = none 40 | 41 | resharper_arrange_redundant_parentheses_highlighting = none 42 | dotnet_diagnostic.IDE0004.severity = none 43 | 44 | # resharper-specific 45 | resharper_loop_can_be_converted_to_query_highlighting = none 46 | resharper_foreach_can_be_partly_converted_to_query_using_another_get_enumerator_highlighting = none 47 | resharper_arrange_namespace_body_highlighting = none 48 | resharper_base_object_get_hash_code_call_in_get_hash_code_highlighting = none 49 | resharper_invert_if_highlighting = none 50 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.bin filter=lfs diff=lfs merge=lfs -text 2 | *.vsix filter=lfs diff=lfs merge=lfs -text 3 | *.exe filter=lfs diff=lfs merge=lfs -text 4 | *.dll filter=lfs diff=lfs merge=lfs -text 5 | *.dylib filter=lfs diff=lfs merge=lfs -text 6 | *.msi filter=lfs diff=lfs merge=lfs -text 7 | *.zip filter=lfs diff=lfs merge=lfs -text 8 | *.7z filter=lfs diff=lfs merge=lfs -text 9 | *.rar filter=lfs diff=lfs merge=lfs -text 10 | *.pdb filter=lfs diff=lfs merge=lfs -text 11 | *.lib filter=lfs diff=lfs merge=lfs -text 12 | *.so filter=lfs diff=lfs merge=lfs -text 13 | *.pdf filter=lfs diff=lfs merge=lfs -text 14 | *.chm filter=lfs diff=lfs merge=lfs -text 15 | *.pyd filter=lfs diff=lfs merge=lfs -text 16 | *.dmg filter=lfs diff=lfs merge=lfs -text 17 | *.mdb filter=lfs diff=lfs merge=lfs -text 18 | *.psd filter=lfs diff=lfs merge=lfs -text 19 | *.png filter=lfs diff=lfs merge=lfs -text 20 | *.tga filter=lfs diff=lfs merge=lfs -text 21 | *.jpg filter=lfs diff=lfs merge=lfs -text 22 | *.bmp filter=lfs diff=lfs merge=lfs -text 23 | *.mp3 filter=lfs diff=lfs merge=lfs -text 24 | *.mp4 filter=lfs diff=lfs merge=lfs -text 25 | *.mov filter=lfs diff=lfs merge=lfs -text 26 | *.ogg filter=lfs diff=lfs merge=lfs -text 27 | *.svg filter=lfs diff=lfs merge=lfs -text -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | enable 4 | 11.0.0 5 | 6 | 7 | -------------------------------------------------------------------------------- /Docs/Images/ChangeSize.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:4a3276a8e06dfda335308436a4162854a6188cbaa719492b62a555a1735d7614 3 | size 750904 4 | -------------------------------------------------------------------------------- /Docs/Images/CheckList.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:4f447870b6568ff16052ade3de1bd725ea606e3e6a3a6d0728b47dcc847bb4a9 3 | size 62848 4 | -------------------------------------------------------------------------------- /Docs/Images/CustomObject.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:a7001d5c419311ec3f926616aa2c6d90174e48c7c8c63d93af753f1e9829e731 3 | size 302942 4 | -------------------------------------------------------------------------------- /Docs/Images/DynamicVisibility.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:42b82d7eb769f23d10e81176dfcf099725824202a369fc220dc860ac0ff77098 3 | size 240380 4 | -------------------------------------------------------------------------------- /Docs/Images/Multi-Objects.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:66be7457d9fa3b7ef9f10f55b9bd00d512a439d56235c810d27628a2ab77dea6 3 | size 432864 4 | -------------------------------------------------------------------------------- /Docs/Images/Styles.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:2da23d1501aca917bc281cff6956dd2dd77302184754206be72a966b1b77e6ff 3 | size 973646 4 | -------------------------------------------------------------------------------- /Docs/Images/custom-label.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:8a29312167f11e46d2849ec38a011a147b814b32a9553a4ef355580f36dce945 3 | size 47551 4 | -------------------------------------------------------------------------------- /Docs/Images/data-sync.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:9b181a99e5aa6e9d0b5e9edc4a5a68d0a2a298550a1c91f5a974a7f3bce3f443 3 | size 333673 4 | -------------------------------------------------------------------------------- /Docs/Images/extends.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:e1212436015fdb4d9d58d7575b736afb931313a23d7ae430f5f3be7f72842f94 3 | size 325923 4 | -------------------------------------------------------------------------------- /Docs/Images/operation-example.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:7341824fdd7cf2905c54a99cb3775f6dc3dda58c2fac9640f3affcd1ddf7b3c1 3 | size 390274 4 | -------------------------------------------------------------------------------- /Docs/Images/painter-demo.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:dca2b21b2f5a00fcf37bd85c41b7add31a4aa8e92b927a47bc95ecfbc9207e9a 3 | size 344380 4 | -------------------------------------------------------------------------------- /Docs/Images/self-properties.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:18a968df65af9afdf90c565317e18b469ac56bf120e2ae1f760e27bab4c526bd 3 | size 163397 4 | -------------------------------------------------------------------------------- /Docs/Images/settings-demo.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:f8c6c5af64ea8efa3870d4f86a2282b27008bb1cf89435c6b43ca3463b00240a 3 | size 182754 4 | -------------------------------------------------------------------------------- /Docs/Images/undoredo.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:71e68448c23715e4d991207ff4cf9d50bfcb1290cd61e3c068cb22583adc50ec 3 | size 276442 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 bodong 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 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Android/Avalonia.PropertyGrid.Samples.Android.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net8.0-android 5 | 21 6 | enable 7 | com.CompanyName.Avalonia.PropertyGrid.Samples 8 | 1 9 | 1.0 10 | apk 11 | false 12 | Debug;Release;Development 13 | 14 | 15 | 16 | DEBUG;TRACE 17 | 18 | 19 | 20 | 21 | Resources\drawable\Icon.png 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Android/Icon.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:1821e7bd48a6f407bddcbc1fd789132a3d5b6a5b787951114e3360b4bd650c96 3 | size 14349 4 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Android/MainActivity.cs: -------------------------------------------------------------------------------- 1 | using Android.App; 2 | using Android.Content.PM; 3 | using Avalonia.Android; 4 | 5 | namespace Avalonia.PropertyGrid.Samples.Android; 6 | 7 | [Activity( 8 | Label = "Avalonia.PropertyGrid.Samples.Android", 9 | Theme = "@style/MyTheme.NoActionBar", 10 | Icon = "@drawable/icon", 11 | MainLauncher = true, 12 | ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)] 13 | public class MainActivity : AvaloniaMainActivity 14 | { 15 | protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) 16 | { 17 | return base.CustomizeAppBuilder(builder) 18 | .WithInterFont(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Android/Properties/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Android/Resources/AboutResources.txt: -------------------------------------------------------------------------------- 1 | Images, layout descriptions, binary blobs and string dictionaries can be included 2 | in your application as resource files. Various Android APIs are designed to 3 | operate on the resource IDs instead of dealing with images, strings or binary blobs 4 | directly. 5 | 6 | For example, a sample Android app that contains a user interface layout (main.axml), 7 | an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png) 8 | would keep its resources in the "Resources" directory of the application: 9 | 10 | Resources/ 11 | drawable/ 12 | icon.png 13 | 14 | layout/ 15 | main.axml 16 | 17 | values/ 18 | strings.xml 19 | 20 | In order to get the build system to recognize Android resources, set the build action to 21 | "AndroidResource". The native Android APIs do not operate directly with filenames, but 22 | instead operate on resource IDs. When you compile an Android application that uses resources, 23 | the build system will package the resources for distribution and generate a class called "R" 24 | (this is an Android convention) that contains the tokens for each one of the resources 25 | included. For example, for the above Resources layout, this is what the R class would expose: 26 | 27 | public class R { 28 | public class drawable { 29 | public const int icon = 0x123; 30 | } 31 | 32 | public class layout { 33 | public const int main = 0x456; 34 | } 35 | 36 | public class strings { 37 | public const int first_string = 0xabc; 38 | public const int second_string = 0xbcd; 39 | } 40 | } 41 | 42 | You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main 43 | to reference the layout/main.axml file, or R.strings.first_string to reference the first 44 | string in the dictionary file values/strings.xml. -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Android/Resources/drawable-night-v31/avalonia_anim.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | 15 | 16 | 20 | 25 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 42 | 43 | 44 | 45 | 46 | 53 | 54 | 55 | 56 | 57 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Android/Resources/drawable/splash_screen.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Android/Resources/values-night/colors.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | #212121 4 | 5 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Android/Resources/values-v31/styles.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 6 | 7 | 17 | 21 | 22 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Android/Resources/values/colors.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | #FFFFFF 4 | 5 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Android/Resources/values/styles.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Browser/Avalonia.PropertyGrid.Samples.Browser.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net9.0-browser 4 | Exe 5 | true 6 | enable 7 | Debug;Release;Development 8 | browser-wasm 9 | false 10 | 11 | 12 | 13 | DEBUG;TRACE 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Browser/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Avalonia; 3 | using Avalonia.Browser; 4 | using Avalonia.PropertyGrid.Samples; 5 | 6 | internal sealed partial class Program 7 | { 8 | private static Task Main(string[] args) => BuildAvaloniaApp() 9 | .WithInterFont() 10 | .StartBrowserAppAsync("out"); 11 | 12 | public static AppBuilder BuildAvaloniaApp() 13 | => AppBuilder.Configure().WithFont_SourceHanSansCN(); 14 | } -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Browser/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | [assembly: System.Runtime.Versioning.SupportedOSPlatform("browser")] 2 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Browser/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Avalonia.PropertyGrid.Samples.Browser": { 4 | "commandName": "Project", 5 | "launchBrowser": true, 6 | "environmentVariables": { 7 | "ASPNETCORE_ENVIRONMENT": "Development" 8 | }, 9 | "applicationUrl": "https://localhost:7178;http://localhost:5278", 10 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Browser/runtimeconfig.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "wasmHostProperties": { 3 | "perHostConfig": [ 4 | { 5 | "name": "browser", 6 | "host": "browser" 7 | } 8 | ] 9 | } 10 | } -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Browser/wwwroot/app.css: -------------------------------------------------------------------------------- 1 | /* HTML styles for the splash screen */ 2 | .avalonia-splash { 3 | position: absolute; 4 | height: 100%; 5 | width: 100%; 6 | background: white; 7 | font-family: 'Outfit', sans-serif; 8 | justify-content: center; 9 | align-items: center; 10 | display: flex; 11 | pointer-events: none; 12 | } 13 | 14 | /* Light theme styles */ 15 | @media (prefers-color-scheme: light) { 16 | .avalonia-splash { 17 | background: white; 18 | } 19 | 20 | .avalonia-splash h2 { 21 | color: #1b2a4e; 22 | } 23 | 24 | .avalonia-splash a { 25 | color: #0D6EFD; 26 | } 27 | } 28 | 29 | @media (prefers-color-scheme: dark) { 30 | .avalonia-splash { 31 | background: #1b2a4e; 32 | } 33 | 34 | .avalonia-splash h2 { 35 | color: white; 36 | } 37 | 38 | .avalonia-splash a { 39 | color: white; 40 | } 41 | } 42 | 43 | .avalonia-splash h2 { 44 | font-weight: 400; 45 | font-size: 1.5rem; 46 | } 47 | 48 | .avalonia-splash a { 49 | text-decoration: none; 50 | font-size: 2.5rem; 51 | display: block; 52 | } 53 | 54 | .avalonia-splash.splash-close { 55 | transition: opacity 200ms, display 200ms; 56 | display: none; 57 | opacity: 0; 58 | } 59 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Browser/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bodong1987/Avalonia.PropertyGrid/8e1ccd0c7e40ec1f01df6b753315318a3a103d36/Samples/Avalonia.PropertyGrid.Samples.Browser/wwwroot/favicon.ico -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Browser/wwwroot/main.js: -------------------------------------------------------------------------------- 1 | import { dotnet } from './_framework/dotnet.js' 2 | 3 | const is_browser = typeof window != "undefined"; 4 | if (!is_browser) throw new Error(`Expected to be running in a browser`); 5 | 6 | const dotnetRuntime = await dotnet 7 | .withDiagnosticTracing(false) 8 | .withApplicationArgumentsFromQuery() 9 | .create(); 10 | 11 | const config = dotnetRuntime.getConfig(); 12 | 13 | await dotnetRuntime.runMain(config.mainAssemblyName, [globalThis.location.href]); 14 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Desktop/Avalonia.PropertyGrid.Samples.Desktop.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | WinExe 4 | 6 | net8.0;net9.0 7 | enable 8 | true 9 | Debug;Release;Development 10 | 11 | 12 | 13 | DEBUG;TRACE 14 | 15 | 16 | 17 | app.manifest 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Desktop/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia; 3 | using Avalonia.Platform; 4 | 5 | namespace Avalonia.PropertyGrid.Samples.Desktop; 6 | 7 | internal sealed class Program 8 | { 9 | // Initialization code. Don't use any Avalonia, third-party APIs or any 10 | // SynchronizationContext-reliant code before AppMain is called: things aren't initialized 11 | // yet and stuff might break. 12 | [STAThread] 13 | public static void Main(string[] args) => BuildAvaloniaApp() 14 | .StartWithClassicDesktopLifetime(args); 15 | 16 | // Avalonia configuration, don't remove; also used by visual designer. 17 | public static AppBuilder BuildAvaloniaApp() 18 | => AppBuilder.Configure() 19 | .UsePlatformDetect() 20 | .WithInterFont() 21 | .LogToTrace().AfterSetup(builder=> 22 | { 23 | builder.Instance!.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions() 24 | { 25 | StartupScreenIndex = 1, 26 | }); 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.Desktop/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.iOS/AppDelegate.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.iOS; 2 | using Foundation; 3 | 4 | namespace Avalonia.PropertyGrid.Samples.iOS; 5 | 6 | // The UIApplicationDelegate for the application. This class is responsible for launching the 7 | // User Interface of the application, as well as listening (and optionally responding) to 8 | // application events from iOS. 9 | [Register("AppDelegate")] 10 | #pragma warning disable CA1711 // Identifiers should not have incorrect suffix 11 | public partial class AppDelegate : AvaloniaAppDelegate 12 | #pragma warning restore CA1711 // Identifiers should not have incorrect suffix 13 | { 14 | protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) 15 | { 16 | return base.CustomizeAppBuilder(builder) 17 | .WithInterFont(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.iOS/Avalonia.PropertyGrid.Samples.iOS.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0-ios 5 | 13.0 6 | enable 7 | Debug;Release;Development 8 | 9 | 10 | 11 | DEBUG;TRACE 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.iOS/Entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDisplayName 6 | Avalonia.PropertyGrid.Samples 7 | CFBundleIdentifier 8 | companyName.Avalonia.PropertyGrid.Samples 9 | CFBundleShortVersionString 10 | 1.0 11 | CFBundleVersion 12 | 1.0 13 | LSRequiresIPhoneOS 14 | 15 | MinimumOSVersion 16 | 13.0 17 | UIDeviceFamily 18 | 19 | 1 20 | 2 21 | 22 | UILaunchStoryboardName 23 | LaunchScreen 24 | UIRequiredDeviceCapabilities 25 | 26 | armv7 27 | 28 | UISupportedInterfaceOrientations 29 | 30 | UIInterfaceOrientationPortrait 31 | UIInterfaceOrientationPortraitUpsideDown 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.iOS/Main.cs: -------------------------------------------------------------------------------- 1 | using UIKit; 2 | 3 | namespace Avalonia.PropertyGrid.Samples.iOS; 4 | 5 | public class Application 6 | { 7 | // This is the main entry point of the application. 8 | private static void Main(string[] args) 9 | { 10 | // if you want to use a different Application Delegate class from "AppDelegate" 11 | // you can specify it here. 12 | UIApplication.Main(args, null, typeof(AppDelegate)); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples.iOS/Resources/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 21 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/App.axaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | #33000000 16 | #99000000 17 | #FFE6E6E6 18 | #FF000000 19 | 20 | 21 | #33FFFFFF 22 | #99FFFFFF 23 | #FF1F1F1F 24 | #FFFFFFFF 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Assets/Localizations/en-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "Dynamic_Visibility": "Dynamic Visibility", 3 | "Self_s_Properties": "Self's Properties", 4 | "Show_Category": "Show Category", 5 | "Allow_Filter": "Allow Filter", 6 | "Allow_Quick_Filter": "Allow Quick Filter", 7 | "Show_Title": "Show Title", 8 | "Name_Width": "Name Width", 9 | "Show_Style": "Show Style", 10 | "All_Expand": "All Expand", 11 | "Display_Mode": "Display Mode", 12 | "customLabel": "Custom Label", 13 | "Show_Property_Operation": "Show Property Operations", 14 | "CellEdit_Alignment": "CellEdit Alignment", 15 | "ServiceDefaultView": "Service[Default View]", 16 | "ServiceVerticalView": "Service[Vertical View]", 17 | "ServiceHorizontalView": "Service[Horizontal View]", 18 | "CheckedListString": "Checkable String[Default View]", 19 | "CheckedListInt": "Checkable Number", 20 | "CheckedListStringVerticalView": "Checkable String[Vertical View]", 21 | "CheckedListStringHorizontalView": "Checkable String[Horizontal View]", 22 | "PlatformDefaultView": "Platform[Default View]", 23 | "PlatformRadioButtonDefaultView": "Platform[Radio+Default View]", 24 | "PlatformRadioButtonVerticalView": "Platform[Radio+Vertical View]", 25 | "PlatformRadioButtonHorizontalView": "Platform[Radio+Horizontal View]", 26 | "PlatformToggleButtonDefaultView": "Platform[Button+Default View]", 27 | "PlatformToggleButtonVerticalView": "Platform[Button+Vertical View]", 28 | "PlatformToggleButtonHorizontalView": "Platform[Button+Horizontal View]", 29 | "LoginNameToggleGroupModeVerticalView": "Login Name[Button+Vertical View]", 30 | "ArrowShape": "Arrow", 31 | "EllipseShape": "Ellipse", 32 | "LineShape": "Segment", 33 | "RectangleShape": "Rectangle", 34 | "StarShape": "Star", 35 | "CreateRectangle": "Create Rectangle", 36 | "CreateEllipse": "Create Ellipse", 37 | "CreateLine": "Create Line", 38 | "CreateStar": "Create Star", 39 | "CreateArrow": "Create Arrow", 40 | "DeleteShape": "Delete Shape", 41 | "FreehandShape": "Freehand", 42 | "Add_Shapes": "Add Shapes", 43 | "Delete_Shape": "Delete Shape", 44 | "PainterDemo_HelpText": "Select the working mode in the toolbar on the left, right-click to delete the element, click the element in the selection mode to view and edit the element properties, and you can also drag the element." 45 | } -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Assets/avalonia-banner.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:3cf6986fe87c909c5003ff1ff90f821b3f9888e755d49c8c24e71f7e6dc09ac1 3 | size 949838 4 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Assets/avalonia-logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bodong1987/Avalonia.PropertyGrid/8e1ccd0c7e40ec1f01df6b753315318a3a103d36/Samples/Avalonia.PropertyGrid.Samples/Assets/avalonia-logo.ico -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Assets/country-flags/au.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:4cfb3a5cfd1cb5736c41aa4318552b1aa7834cd165773356f98ff78354730f04 3 | size 1643 4 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Assets/country-flags/bl.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:3cea4188fe697208358e1d648688e3856ca615324a20d76c4d0dd602e1121d56 3 | size 167 4 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Assets/country-flags/ca.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:18ce040eff501b5d448989fb9ec168b6a14fc1a31c00aace5c08881c22700126 3 | size 832 4 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Assets/country-flags/cn.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:cd70d32c9a9f6ebeaa821a9df846222ab7540fdb9ce98279fde8efdba5650366 3 | size 755 4 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Assets/country-flags/de.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:91a6912f55fe250dc0e1c82a8cbf3889caa822a763ce8419fd5721d576cbec95 3 | size 106 4 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Assets/country-flags/gb.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:3945b5f183e0729ffb90ee38ff78aba7916e09d172232623d0ffdac6409932e8 3 | size 500 4 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Assets/country-flags/ua.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:010e4ea25f1da4d066a218606867aee772a7f6ad3d1a2370e8306f245759a7a1 3 | size 115 4 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Assets/country-flags/us.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:25be2de75e2d2e55620068642f3225a7f90ff68fad65b6d1dc9d63daeafdbb74 3 | size 756 4 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Assets/images/colormixer.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:e7ca09ed40d4bde1fcd1fa0531fde93188af2567f3f445a8530e27e891ef15cc 3 | size 1218 4 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Assets/images/home.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:91e6dc34364ce7a159442573f12b019ecd7c65dfc19f4f6f47b3a82d0ced85bd 3 | size 1067 4 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Assets/images/technology.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:2b41a318cc211c8b596bf7e015ddcfaa6e44e4188445d8dc57fffcd8d667ca82 3 | size 1383 4 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Avalonia.PropertyGrid.Samples.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net8.0;net9.0 4 | enable 5 | latest 6 | Debug;Release;Development 7 | false 8 | 9 | 10 | 11 | DEBUG;TRACE 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | CountryView.axaml 40 | Code 41 | 42 | 43 | Vector3View.axaml 44 | Code 45 | 46 | 47 | FeatureDemoView.axaml 48 | Code 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/FeatureDemos/Models/CancelableObject.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Windows.Input; 3 | using Avalonia.PropertyGrid.Controls; 4 | using PropertyModels.ComponentModel; 5 | 6 | namespace Avalonia.PropertyGrid.Samples.FeatureDemos.Models 7 | { 8 | public class CancelableObject : SimpleObject 9 | { 10 | private readonly CancelableCommandRecorder _recorder = new(); 11 | 12 | [Browsable(false)] 13 | public bool CanUndo => _recorder.CanUndo; 14 | 15 | [Browsable(false)] 16 | public bool CanRedo => _recorder.CanRedo; 17 | 18 | [Browsable(false)] 19 | public string UndoDescription => _recorder.UndoCommandDescription; 20 | 21 | [Browsable(false)] 22 | public string RedoDescription => _recorder.RedoCommandDescription; 23 | 24 | [Browsable(false)] 25 | public ICommand UndoCommand { get; set; } 26 | 27 | [Browsable(false)] 28 | public ICommand RedoCommand { get; set; } 29 | 30 | [Browsable(false)] 31 | public ICommand ClearCommand { get; set; } 32 | 33 | public CancelableObject(string description) : base(description) 34 | { 35 | UndoCommand = ReactiveCommand.Create(() => _recorder.Undo()); 36 | RedoCommand = ReactiveCommand.Create(() => _recorder.Redo()); 37 | ClearCommand = ReactiveCommand.Create(_recorder.Clear); 38 | 39 | _recorder.OnNewCommandAdded += (s, e) => RefreshFlags(); 40 | _recorder.OnCommandCanceled += (s, e) => RefreshFlags(); 41 | _recorder.OnCommandCleared += (s, e) => RefreshFlags(); 42 | _recorder.OnCommandRedo += (s, e) => RefreshFlags(); 43 | } 44 | 45 | private void RefreshFlags() 46 | { 47 | RaisePropertyChanged(nameof(CanUndo)); 48 | RaisePropertyChanged(nameof(CanRedo)); 49 | RaisePropertyChanged(nameof(UndoDescription)); 50 | RaisePropertyChanged(nameof(RedoDescription)); 51 | } 52 | 53 | public void OnCommandExecuted(object? sender, RoutedCommandExecutedEventArgs e) => _recorder.PushCommand(e.Command); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/FeatureDemos/Models/DynamicVisibilityObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using PropertyModels.ComponentModel; 4 | using PropertyModels.ComponentModel.DataAnnotations; 5 | using PropertyModels.Extensions; 6 | // ReSharper disable AutoPropertyCanBeMadeGetOnly.Global 7 | 8 | namespace Avalonia.PropertyGrid.Samples.FeatureDemos.Models 9 | { 10 | public class DynamicVisibilityObject : ReactiveObject 11 | { 12 | [ConditionTarget] 13 | public bool IsShowPath { get; set; } = true; 14 | 15 | [PropertyVisibilityCondition(nameof(IsShowPath), true)] 16 | [PathBrowsable(Filters = "Image Files(*.jpg;*.png;*.bmp;*.tag)|*.jpg;*.png;*.bmp;*.tag")] 17 | public string Path { get; set; } = string.Empty; 18 | 19 | [ConditionTarget] 20 | public PlatformID Platform { get; set; } = PlatformID.Win32NT; 21 | 22 | [PropertyVisibilityCondition(nameof(Platform), PlatformID.Unix)] 23 | [ConditionTarget] 24 | public string UnixVersion { get; set; } = string.Empty; 25 | 26 | // show more complex conditions... 27 | [Browsable(false)] 28 | [DependsOnProperty(nameof(IsShowPath), nameof(Platform), nameof(UnixVersion))] 29 | [ConditionTarget] 30 | public bool IsShowUnixLoginInfo => IsShowPath && Platform == PlatformID.Unix && UnixVersion.IsNotNullOrEmpty(); 31 | 32 | [PropertyVisibilityCondition(nameof(IsShowUnixLoginInfo), true)] 33 | [TypeConverter(typeof(ExpandableObjectConverter))] 34 | // ReSharper disable once InconsistentNaming 35 | public LoginInfo unixLogInInfo { get; set; } = new(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/FeatureDemos/Models/LoginInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Net.Security; 4 | using System.Security.Cryptography; 5 | using PropertyModels.ComponentModel; 6 | 7 | namespace Avalonia.PropertyGrid.Samples.FeatureDemos.Models 8 | { 9 | public class LoginInfo : MiniReactiveObject 10 | { 11 | [Watermark("Your Login Name")] 12 | public string? UserName { get; set; } 13 | 14 | [PasswordPropertyText(true)] 15 | [Watermark("Your Password")] 16 | public string? Password { get; set; } 17 | 18 | [MultilineText] 19 | public string? HelpText { get; set; } = $"This is multiline Text{Environment.NewLine}Try edit me."; 20 | 21 | public PlatformID ServerType { get; set; } = PlatformID.Unix; 22 | 23 | [ExpandableObjectDisplayMode(IsCategoryVisible = NullableBooleanType.No)] 24 | public EncryptData EncryptPolicy { get; set; } = new(); 25 | } 26 | 27 | [TypeConverter(typeof(ExpandableObjectConverter))] 28 | public class EncryptData : MiniReactiveObject 29 | { 30 | public EncryptionPolicy Policy { get; set; } = EncryptionPolicy.RequireEncryption; 31 | 32 | public RSAEncryptionPaddingMode PaddingMode { get; set; } = RSAEncryptionPaddingMode.Pkcs1; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/FeatureDemos/Models/Vector3.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using PropertyModels.ComponentModel; 3 | // ReSharper disable PropertyCanBeMadeInitOnly.Global 4 | 5 | namespace Avalonia.PropertyGrid.Samples.FeatureDemos.Models 6 | { 7 | [TypeConverter(typeof(ExpandableObjectConverter))] 8 | [ExpandableObjectDisplayMode(IsCategoryVisible = NullableBooleanType.No)] 9 | public class Vector3 : MiniReactiveObject 10 | { 11 | private double _x, _y, _z; 12 | 13 | public double X 14 | { 15 | get => _x; 16 | set => this.RaiseAndSetIfChanged(ref _x, value); 17 | } 18 | 19 | public double Y 20 | { 21 | get => _y; 22 | set => this.RaiseAndSetIfChanged(ref _y, value); 23 | } 24 | 25 | public double Z 26 | { 27 | get => _z; 28 | set => this.RaiseAndSetIfChanged(ref _z, value); 29 | } 30 | 31 | public Vector3() 32 | { 33 | } 34 | 35 | public Vector3(double x, double y, double z) 36 | { 37 | X = x; 38 | Y = y; 39 | Z = z; 40 | } 41 | 42 | public override string ToString() => $"{X},{Y},{Z}"; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/FeatureDemos/Views/CountryView.axaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 6 | 7 | 8 | 23 | 24 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/FeatureDemos/Views/CountryView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls.Primitives; 2 | 3 | namespace Avalonia.PropertyGrid.Samples.FeatureDemos.Views 4 | { 5 | public class CountryView : TemplatedControl; 6 | } 7 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/FeatureDemos/Views/Vector3View.axaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 6 | 7 | 8 | 32 | 33 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/FeatureDemos/Views/Vector3View.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls.Primitives; 2 | 3 | namespace Avalonia.PropertyGrid.Samples.FeatureDemos.Views 4 | { 5 | public class Vector3View : TemplatedControl; 6 | } 7 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/PainterDemo/Models/ArrowShape.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using Avalonia.PropertyGrid.Samples.PainterDemo.ViewModel; 5 | using PropertyModels.ComponentModel; 6 | // ReSharper disable CompareOfFloatsByEqualityOperator 7 | // ReSharper disable PropertyCanBeMadeInitOnly.Global 8 | 9 | namespace Avalonia.PropertyGrid.Samples.PainterDemo.Models; 10 | 11 | [ShapeDescription(ToolMode.CreateArrow)] 12 | public class ArrowShape : ShapeGenericPolygon 13 | { 14 | private double _length = 10; 15 | private double _shaftWidth = 5; 16 | private double _headWidth = 10; 17 | private double _headHeight = 5; 18 | 19 | [Category("Transform")] 20 | [FloatPrecision(0)] 21 | public double Length 22 | { 23 | get => _length; 24 | set => SetProperty(ref _length, value); 25 | } 26 | 27 | [Category("Transform")] 28 | [FloatPrecision(0)] 29 | public double ShaftWidth 30 | { 31 | get => _shaftWidth; 32 | set => SetProperty(ref _shaftWidth, value); 33 | } 34 | 35 | [Category("Transform")] 36 | [FloatPrecision(0)] 37 | public double HeadWidth 38 | { 39 | get => _headWidth; 40 | set => SetProperty(ref _headWidth, value); 41 | } 42 | 43 | [Category("Transform")] 44 | [FloatPrecision(0)] 45 | public double HeadHeight 46 | { 47 | get => _headHeight; 48 | set => SetProperty(ref _headHeight, value); 49 | } 50 | 51 | protected override List GeneratePoints() => CalculateArrowPoints(); 52 | 53 | private List CalculateArrowPoints() 54 | { 55 | var points = new List 56 | { 57 | new(0, -ShaftWidth / 2), // Start of the shaft 58 | new(Length - HeadWidth, -ShaftWidth / 2), // End of the shaft 59 | new(Length - HeadWidth, -HeadHeight / 2), // Top of the arrowhead 60 | new(Length, 0), // Tip of the arrowhead 61 | new(Length - HeadWidth, HeadHeight / 2), // Bottom of the arrowhead 62 | new(Length - HeadWidth, ShaftWidth / 2), // End of the shaft 63 | new(0, ShaftWidth / 2), // Start of the shaft 64 | new(0, -ShaftWidth / 2) // Close the shape 65 | }; 66 | 67 | return points; 68 | } 69 | 70 | protected override void OnFinishCreate(Point endPoint) 71 | { 72 | try 73 | { 74 | BeginBatchUpdate(); 75 | 76 | // Calculate the length of the arrow from start to end point 77 | Length = Math.Sqrt((endPoint.X - CreatingStartX) * (endPoint.X - CreatingStartX) + (endPoint.Y - CreatingStartY) * (endPoint.Y - CreatingStartY)); 78 | 79 | // Set default values for head and shaft dimensions 80 | HeadWidth = Length * 0.2; 81 | HeadHeight = Length * 0.1; 82 | ShaftWidth = Length * 0.05; 83 | 84 | // Set the arrow's position to the starting point 85 | X = CreatingStartX; 86 | Y = CreatingStartY; 87 | } 88 | finally 89 | { 90 | EndBatchUpdate(); 91 | RaisePropertyChanged(nameof(Length)); 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/PainterDemo/Models/EllipseShape.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using Avalonia.Controls.Shapes; 4 | using Avalonia.PropertyGrid.Samples.PainterDemo.ViewModel; 5 | using PropertyModels.ComponentModel; 6 | 7 | // ReSharper disable CompareOfFloatsByEqualityOperator 8 | // ReSharper disable PropertyCanBeMadeInitOnly.Global 9 | 10 | namespace Avalonia.PropertyGrid.Samples.PainterDemo.Models; 11 | 12 | [ShapeDescription(ToolMode.CreateEllipse)] 13 | public class EllipseShape : ShapeGeneric 14 | { 15 | private double _width; 16 | [Category("Transform")] 17 | [FloatPrecision(0)] 18 | public double Width 19 | { 20 | get => _width; 21 | set => SetProperty(ref _width, value); 22 | } 23 | 24 | private double _height; 25 | [Category("Transform")] 26 | [FloatPrecision(0)] 27 | public double Height 28 | { 29 | get => _height; 30 | set => SetProperty(ref _height, value); 31 | } 32 | 33 | protected override void ApplyProperties(Ellipse shape) 34 | { 35 | shape.Width = Width; 36 | shape.Height = Height; 37 | } 38 | 39 | protected override void OnFinishCreate(Point endPoint) 40 | { 41 | try 42 | { 43 | BeginBatchUpdate(); 44 | 45 | X = Math.Min(endPoint.X, CreatingStartX); 46 | Y = Math.Min(endPoint.Y, CreatingStartY); 47 | 48 | _width = Math.Abs(endPoint.X - CreatingStartX); 49 | _height = Math.Abs(endPoint.Y - CreatingStartY); 50 | } 51 | finally 52 | { 53 | EndBatchUpdate(); 54 | RaisePropertyChanged(nameof(Width)); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/PainterDemo/Models/FreehandShape.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using Avalonia.Collections; 3 | using Avalonia.Controls.Shapes; 4 | using Avalonia.PropertyGrid.Samples.PainterDemo.ViewModel; 5 | 6 | namespace Avalonia.PropertyGrid.Samples.PainterDemo.Models; 7 | 8 | [ShapeDescription(ToolMode.Brush)] 9 | public class FreehandShape : ShapeGeneric 10 | { 11 | private BindingList _points = []; 12 | 13 | [Category("Geometry")] 14 | [Browsable(false)] 15 | public BindingList Points 16 | { 17 | get => _points; 18 | set => SetProperty(ref _points, value); 19 | } 20 | 21 | public FreehandShape() 22 | { 23 | FillMode = ShapeFillMode.Blank; 24 | } 25 | 26 | protected override void ApplyProperties(Polyline shape) 27 | { 28 | shape.Points = new AvaloniaList(_points); 29 | } 30 | 31 | protected override void OnFinishCreate(Point endPoint) 32 | { 33 | Points.Add(endPoint - new Point(CreatingStartX, CreatingStartY)); 34 | RaisePropertyChanged(nameof(Points)); 35 | } 36 | } -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/PainterDemo/Models/LineShape.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using Avalonia.Controls.Shapes; 3 | using Avalonia.PropertyGrid.Samples.PainterDemo.ViewModel; 4 | using PropertyModels.ComponentModel; 5 | // ReSharper disable CompareOfFloatsByEqualityOperator 6 | // ReSharper disable PropertyCanBeMadeInitOnly.Global 7 | 8 | namespace Avalonia.PropertyGrid.Samples.PainterDemo.Models; 9 | 10 | [ShapeDescription(ToolMode.CreateLine)] 11 | public class LineShape : ShapeGeneric 12 | { 13 | private double _x2; 14 | private double _y2; 15 | 16 | [Category("Transform")] 17 | [FloatPrecision(0)] 18 | public double X2 19 | { 20 | get => _x2; 21 | set => SetProperty(ref _x2, value); 22 | } 23 | 24 | [Category("Transform")] 25 | [FloatPrecision(0)] 26 | public double Y2 27 | { 28 | get => _y2; 29 | set => SetProperty(ref _y2, value); 30 | } 31 | 32 | public LineShape() 33 | { 34 | IsFillModeVisible = false; 35 | } 36 | 37 | protected override void ApplyProperties(Line shape) 38 | { 39 | shape.StartPoint = new Point(0, 0); 40 | shape.EndPoint = new Point(X2, Y2); 41 | } 42 | 43 | protected override void OnFinishCreate(Point endPoint) 44 | { 45 | X2 = endPoint.X - CreatingStartX; 46 | Y2 = endPoint.Y - CreatingStartY; 47 | } 48 | } -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/PainterDemo/Models/RectangleShape.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using Avalonia.Controls.Shapes; 4 | using Avalonia.PropertyGrid.Samples.PainterDemo.ViewModel; 5 | using PropertyModels.ComponentModel; 6 | 7 | // ReSharper disable CompareOfFloatsByEqualityOperator 8 | // ReSharper disable PropertyCanBeMadeInitOnly.Global 9 | 10 | namespace Avalonia.PropertyGrid.Samples.PainterDemo.Models; 11 | 12 | [ShapeDescription(ToolMode.CreateRectangle)] 13 | public class RectangleShape : ShapeGeneric 14 | { 15 | private double _width; 16 | [Category("Transform")] 17 | [FloatPrecision(0)] 18 | public double Width 19 | { 20 | get => _width; 21 | set => SetProperty(ref _width, value); 22 | } 23 | 24 | private double _height; 25 | [Category("Transform")] 26 | [FloatPrecision(0)] 27 | public double Height 28 | { 29 | get => _height; 30 | set => SetProperty(ref _height, value); 31 | } 32 | 33 | protected override void ApplyProperties(Rectangle shape) 34 | { 35 | shape.Width = Width; 36 | shape.Height = Height; 37 | } 38 | 39 | protected override void OnFinishCreate(Point endPoint) 40 | { 41 | try 42 | { 43 | BeginBatchUpdate(); 44 | 45 | X = Math.Min(endPoint.X, CreatingStartX); 46 | Y = Math.Min(endPoint.Y, CreatingStartY); 47 | 48 | Width = Math.Abs(endPoint.X - CreatingStartX); 49 | Height = Math.Abs(endPoint.Y - CreatingStartY); 50 | } 51 | finally 52 | { 53 | EndBatchUpdate(); 54 | RaisePropertyChanged(nameof(Width)); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/PainterDemo/Models/StarShape.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using Avalonia.PropertyGrid.Samples.PainterDemo.ViewModel; 5 | using PropertyModels.ComponentModel; 6 | // ReSharper disable CompareOfFloatsByEqualityOperator 7 | // ReSharper disable PropertyCanBeMadeInitOnly.Global 8 | 9 | namespace Avalonia.PropertyGrid.Samples.PainterDemo.Models; 10 | 11 | [ShapeDescription(ToolMode.CreateStar)] 12 | public class StarShape : ShapeGenericPolygon 13 | { 14 | private double _radius; 15 | 16 | [Category("Transform")] 17 | [FloatPrecision(0)] 18 | public double Radius 19 | { 20 | get => _radius; 21 | set => SetProperty(ref _radius, value); 22 | } 23 | 24 | protected override List GeneratePoints() => CalculateStarPoints(0, 0, Radius); 25 | 26 | private static List CalculateStarPoints(double centerX, double centerY, double outerRadius) 27 | { 28 | var points = new List(); 29 | const int numPoints = 5; 30 | var innerRadius = outerRadius * 0.5; // Inner radius for the star 31 | 32 | for (var i = 0; i < numPoints * 2; i++) 33 | { 34 | var angle = Math.PI / numPoints * i; 35 | var radius = (i % 2 == 0) ? outerRadius : innerRadius; 36 | points.Add(new Point(centerX + radius * Math.Cos(angle), centerY + radius * Math.Sin(angle))); 37 | } 38 | 39 | return points; 40 | } 41 | 42 | protected override void OnFinishCreate(Point endPoint) 43 | { 44 | try 45 | { 46 | BeginBatchUpdate(); 47 | 48 | Radius = Math.Sqrt((endPoint.X - X) * (endPoint.X - X) + (endPoint.Y - Y) * (endPoint.Y - Y)); 49 | } 50 | finally 51 | { 52 | EndBatchUpdate(); 53 | RaisePropertyChanged(nameof(Radius)); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/PainterDemo/Views/GradientStopView.axaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 6 | 7 | 8 | 23 | 24 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/PainterDemo/Views/GradientStopView.axaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia.Controls; 3 | using Avalonia.Controls.Primitives; 4 | using Avalonia.Media; 5 | using Avalonia.PropertyGrid.Controls; 6 | using Avalonia.PropertyGrid.Controls.Factories; 7 | 8 | namespace Avalonia.PropertyGrid.Samples.PainterDemo.Views; 9 | 10 | public class GradientStopView : TemplatedControl 11 | { 12 | public EventHandler? GradientStopChanged; 13 | 14 | protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) 15 | { 16 | if (change.Property == DataContextProperty) 17 | { 18 | if (change.OldValue is GradientStop oldValue) 19 | oldValue.PropertyChanged -= OnGradientStopValuePropertyChanged; 20 | 21 | if (change.NewValue is GradientStop newValue) 22 | newValue.PropertyChanged += OnGradientStopValuePropertyChanged; 23 | } 24 | 25 | base.OnPropertyChanged(change); 26 | } 27 | 28 | private void OnGradientStopValuePropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) => 29 | GradientStopChanged?.Invoke(sender, e); 30 | } 31 | 32 | internal class GradientStopCellEditFactory : AbstractCellEditFactory 33 | { 34 | public override Control? HandleNewProperty(PropertyCellContext context) 35 | { 36 | if (context.Property.PropertyType != typeof(GradientStop)) return null; 37 | 38 | var value = (context.GetValue() as GradientStop)!; 39 | 40 | var control = new GradientStopView 41 | { 42 | DataContext = new GradientStop(value.Color, value.Offset) // make a copy 43 | }; 44 | 45 | control.GradientStopChanged += (s, e) => 46 | { 47 | var currentValue = (control.DataContext as GradientStop)!; 48 | 49 | // make a copy, so it will save the changed command in command queue... 50 | SetAndRaise(context, control, new GradientStop(currentValue.Color, currentValue.Offset)); 51 | }; 52 | 53 | return control; 54 | } 55 | 56 | 57 | public override bool HandlePropertyChanged(PropertyCellContext context) 58 | { 59 | if (context.Property.PropertyType != typeof(GradientStop)) return false; 60 | 61 | if (context.CellEdit is GradientStopView control) 62 | { 63 | var value = (context.GetValue() as GradientStop)!; 64 | control.DataContext = new GradientStop(value.Color, value.Offset); 65 | return true; 66 | } 67 | 68 | return false; 69 | } 70 | } -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/SettingsDemo/Models/AboutSettings.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using PropertyModels.ComponentModel; 3 | using PropertyModels.ComponentModel.DataAnnotations; 4 | 5 | namespace Avalonia.PropertyGrid.Samples.SettingsDemo.Models; 6 | 7 | public class AboutSettings : ReactiveObject 8 | { 9 | [Category("System Info")] 10 | [DisplayName("OS Version")] 11 | [ReadOnly(true)] 12 | #pragma warning disable CA1822 13 | public string OsVersion => "Windows 10 Build 19044"; 14 | #pragma warning restore CA1822 15 | 16 | [Category("System Info")] 17 | [DisplayName("Manufacturer")] 18 | [ReadOnly(true)] 19 | #pragma warning disable CA1822 20 | public string Manufacturer => "Contoso Electronics"; 21 | #pragma warning restore CA1822 22 | 23 | [Category("License")] 24 | [DisplayName("Activation Status")] 25 | [Description("Check license status online")] 26 | [PathBrowsable(Filters = "Web Link|*.url")] 27 | public string LicenseUrl { get; set; } = "https://contoso.com/activation"; 28 | 29 | [Category("Support")] 30 | [DisplayName("Technical Support")] 31 | [PathBrowsable(Filters = "Web Link|*.url")] 32 | public string SupportUrl { get; set; } = "https://support.contoso.com"; 33 | 34 | } -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/SettingsDemo/Models/AccountSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using PropertyModels.ComponentModel; 4 | 5 | namespace Avalonia.PropertyGrid.Samples.SettingsDemo.Models; 6 | 7 | public class AccountSettings : ReactiveObject 8 | { 9 | [Category("Credentials")] 10 | [DisplayName("Username")] 11 | [ReadOnly(true)] 12 | public string Username { get; set; } = "Admin"; 13 | 14 | [Category("Credentials")] 15 | [DisplayName("Password")] 16 | [PasswordPropertyText(true)] 17 | public string Password { get; set; } = "********"; 18 | 19 | [Category("Security")] 20 | [DisplayName("2FA Enabled")] 21 | public bool TwoFactorEnabled { get; set; } 22 | 23 | [Category("Security")] 24 | [DisplayName("Last Login")] 25 | public DateTime LastLogin { get; set; } = DateTime.Now.AddDays(-2); 26 | } -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/SettingsDemo/Models/AppearanceSettings.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.ComponentModel.DataAnnotations; 3 | using Avalonia.Media; 4 | using PropertyModels.ComponentModel; 5 | using PropertyModels.ComponentModel.DataAnnotations; 6 | 7 | namespace Avalonia.PropertyGrid.Samples.SettingsDemo.Models; 8 | 9 | public class AppearanceSettings : ReactiveObject 10 | { 11 | [Category("Theme")] 12 | [DisplayName("Accent Color")] 13 | public Color AccentColor { get; set; } = Colors.Blue; 14 | 15 | [Category("Theme")] 16 | [DisplayName("Dark Mode")] 17 | [ConditionTarget] 18 | // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global 19 | public bool UseDarkTheme { get; set; } = true; 20 | 21 | [Category("Theme")] 22 | [Range(0.3f, 1.0f)] 23 | [Trackable(0.3f,1.0f)] 24 | public float Transparency { get; set; } = 1.0f; 25 | 26 | [Category("Fonts")] 27 | [DisplayName("Custom Font")] 28 | [ConditionTarget] 29 | public bool UseCustomFont { get; set; } = false; 30 | 31 | [Category("Fonts")] 32 | [DisplayName("System Font")] 33 | [PropertyVisibilityCondition(nameof(UseCustomFont), true)] 34 | public FontFamily SystemFont { get; set; } = FontFamily.Default; 35 | 36 | [Category("Effects")] 37 | [DisplayName("Transparency Effects")] 38 | [DependsOnProperty(nameof(UseDarkTheme))] 39 | public bool EnableTransparencyEffects => UseDarkTheme; 40 | } -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/SettingsDemo/Models/FirewallSettings.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.ComponentModel.DataAnnotations; 3 | using PropertyModels.Collections; 4 | using PropertyModels.ComponentModel; 5 | using PropertyModels.ComponentModel.DataAnnotations; 6 | 7 | namespace Avalonia.PropertyGrid.Samples.SettingsDemo.Models; 8 | 9 | public class FirewallSettings : ReactiveObject 10 | { 11 | [Category("General")] 12 | [DisplayName("Firewall Status")] 13 | public bool IsEnabled { get; set; } = true; 14 | 15 | [Category("Notifications")] 16 | [DisplayName("Block Notifications")] 17 | public bool BlockAllNotifications { get; set; } 18 | 19 | [Category("Rules")] 20 | [DisplayName("Allowed Ports")] 21 | public CheckedList AllowedPorts { get; set; } = new( [80, 443] ); 22 | 23 | [Category("Rules")] 24 | [DisplayName("Custom Port Range")] 25 | [Range(1, 65535)] 26 | public int CustomPortStart { get; set; } = 8000; 27 | 28 | [Range(1, 65535)] 29 | public int CustomPortEnd { get; set; } = 9000; 30 | 31 | [Category("Advanced")] 32 | [DisplayName("Allowed IPs")] 33 | [Description("CIDR format (e.g. 192.168.1.0/24)")] 34 | [CIDRValidation] 35 | public BindingList AllowedIPs { get; set; } = ["192.168.1.0/24"]; 36 | 37 | [Category("Logging")] 38 | [DisplayName("Enable Logging")] 39 | public bool EnableLogging { get; set; } = true; 40 | 41 | [Category("Logging")] 42 | [DisplayName("Log Retention (days)")] 43 | [Range(1, 365)] 44 | [PropertyVisibilityCondition(nameof(EnableLogging), true)] 45 | public int LogRetentionDays { get; set; } = 30; 46 | } 47 | 48 | // ReSharper disable once InconsistentNaming 49 | public class CIDRValidationAttribute : ValidationAttribute 50 | { 51 | protected override ValidationResult? IsValid(object? value, ValidationContext context) 52 | { 53 | if (value is string cidr) 54 | { 55 | #pragma warning disable SYSLIB1045 56 | if (!System.Text.RegularExpressions.Regex.IsMatch(cidr, @"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d{1,2}$")) 57 | #pragma warning restore SYSLIB1045 58 | { 59 | return new ValidationResult("Invalid CIDR format"); 60 | } 61 | } 62 | return ValidationResult.Success; 63 | } 64 | } -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/SettingsDemo/Models/GeneralSettings.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.ComponentModel.DataAnnotations; 3 | using PropertyModels.Collections; 4 | using PropertyModels.ComponentModel; 5 | 6 | namespace Avalonia.PropertyGrid.Samples.SettingsDemo.Models; 7 | 8 | public class GeneralSettings : ReactiveObject 9 | { 10 | [Category("Update")] 11 | [DisplayName("Auto Update")] 12 | [Description("Enable automatic system updates")] 13 | public bool EnableAutoUpdate { get; set; } = true; 14 | 15 | [Category("Update")] 16 | [DisplayName("Update Interval")] 17 | [Range(1, 30)] 18 | public int UpdateCheckIntervalDays { get; set; } = 7; 19 | 20 | [Category("Region")] 21 | [DisplayName("Time Zone")] 22 | public SelectableList TimeZone { get; set; } = new (["UTC", "UTC+08:00", "UTC-05:00", "UTC+01:00"], "UTC+08:00"); 23 | } -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/SettingsDemo/Models/ThemeSettings.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.ComponentModel.DataAnnotations; 3 | using Avalonia.Media; 4 | using PropertyModels.Collections; 5 | using PropertyModels.ComponentModel; 6 | using PropertyModels.ComponentModel.DataAnnotations; 7 | 8 | namespace Avalonia.PropertyGrid.Samples.SettingsDemo.Models; 9 | 10 | public class ThemeSettings : ReactiveObject 11 | { 12 | [Category("Color Scheme")] 13 | [DisplayName("Primary Color")] 14 | public Color PrimaryColor { get; set; } = Color.FromRgb(0, 120, 215); 15 | 16 | [Category("Color Scheme")] 17 | [DisplayName("Secondary Color")] 18 | public Color SecondaryColor { get; set; } = Color.FromRgb(153, 235, 255); 19 | 20 | [Category("Appearance")] 21 | [DisplayName("Theme Mode")] 22 | [SingleSelectionMode(SingleSelectionMode.ToggleButtonGroup)] 23 | public SelectableList ThemeMode { get; set; } = new (["Auto", "Light", "Dark"], "Auto"); 24 | 25 | [Category("Advanced")] 26 | [DisplayName("Custom Font")] 27 | [PropertyVisibilityCondition(nameof(UseCustomFont), true)] 28 | public FontFamily CustomFont { get; set; } = FontFamily.Default; 29 | 30 | [Category("Advanced")] 31 | [DisplayName("Enable Custom Font")] 32 | public bool UseCustomFont { get; set; } 33 | 34 | [Category("Effects")] 35 | [DisplayName("Transparency Level")] 36 | [Range(0.3, 1.0)] 37 | [FloatPrecision(2)] 38 | [Trackable(0.3, 1)] 39 | public double Transparency { get; set; } = 0.8; 40 | } -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/SettingsDemo/ViewModels/SettingsViewModel.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Collections; 2 | using Avalonia.PropertyGrid.Samples.SettingsDemo.Models; 3 | using Avalonia.PropertyGrid.Services; 4 | using PropertyModels.ComponentModel; 5 | 6 | namespace Avalonia.PropertyGrid.Samples.SettingsDemo.ViewModels; 7 | 8 | public class SettingsViewModel : ReactiveObject 9 | { 10 | public AvaloniaList FlatCategories { get; } = []; 11 | 12 | public SettingsViewModel() 13 | { 14 | InitializeCategories(); 15 | 16 | LocalizationService.Default.OnCultureChanged += (sender, args) => 17 | { 18 | foreach (var category in FlatCategories) 19 | { 20 | category.Translate(); 21 | } 22 | }; 23 | } 24 | 25 | private void InitializeCategories() 26 | { 27 | var categories = new[] 28 | { 29 | CreateCategory("General", new GeneralSettings()), 30 | CreateCategory("AppearanceSettings", new AppearanceSettings()), 31 | CreateCategory("Themes", new ThemeSettings()), 32 | CreateCategory("Accounts", new AccountSettings()), 33 | CreateCategory("Firewall", new FirewallSettings()), 34 | CreateCategory("About", new AboutSettings()) 35 | }; 36 | 37 | FlatCategories.AddRange(categories); 38 | } 39 | 40 | private static FlatSettingCategory CreateCategory(string title, object settings) 41 | { 42 | return new FlatSettingCategory(title, settings); 43 | } 44 | } 45 | 46 | public class FlatSettingCategory : ReactiveObject 47 | { 48 | public string Key { get; } 49 | public string Title { get; private set; } 50 | // ReSharper disable once UnusedAutoPropertyAccessor.Global 51 | public object Settings { get; } 52 | 53 | public FlatSettingCategory(string key, object settings) 54 | { 55 | Key = key; 56 | Title = LocalizationService.Default[key]; 57 | Settings = settings; 58 | } 59 | 60 | public void Translate() 61 | { 62 | Title = LocalizationService.Default[Key]; 63 | RaisePropertyChanged(nameof(Title)); 64 | } 65 | } -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/SettingsDemo/Views/SettingsView.axaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/SettingsDemo/Views/SettingsView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.PropertyGrid.Samples.SettingsDemo.ViewModels; 3 | 4 | namespace Avalonia.PropertyGrid.Samples.SettingsDemo.Views; 5 | 6 | public partial class SettingsView : UserControl 7 | { 8 | public SettingsView() 9 | { 10 | InitializeComponent(); 11 | 12 | DataContext = new SettingsViewModel(); 13 | } 14 | } -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Views/MainView.axaml.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Avalonia.Controls; 3 | using Avalonia.PropertyGrid.Services; 4 | using Avalonia.Reactive; 5 | using Avalonia.Styling; 6 | using PropertyModels.Localization; 7 | 8 | namespace Avalonia.PropertyGrid.Samples.Views; 9 | 10 | public partial class MainView : UserControl 11 | { 12 | private readonly List _allCultures = []; 13 | 14 | public ICultureData[] AllCultures => [.. _allCultures]; 15 | 16 | public static readonly StyledProperty CurrentCultureProperty = 17 | AvaloniaProperty.Register( 18 | nameof(CurrentCulture), 19 | defaultValue: LocalizationService.Default.CultureData); 20 | 21 | public ICultureData CurrentCulture 22 | { 23 | get => GetValue(CurrentCultureProperty); 24 | set => SetValue(CurrentCultureProperty, value); 25 | } 26 | 27 | public static string Version => $"v{typeof(Utils.FontUtils).Assembly.GetName().Version?.ToString() ?? "Unknown Version"}"; 28 | 29 | public MainView() 30 | { 31 | LocalizationService.Default.AddExtraService(new SampleLocalizationService()); 32 | _allCultures.AddRange(LocalizationService.Default.GetCultures()); 33 | 34 | InitializeComponent(); 35 | 36 | this.GetObservable(CurrentCultureProperty).Subscribe(new AnonymousObserver(OnCurrentCultureChanged)); 37 | 38 | 39 | ThemeBox.SelectedItem = App.CurrentTheme; 40 | ThemeBox.SelectionChanged += (sender, e) => 41 | { 42 | if (ThemeBox.SelectedItem is ThemeType theme) 43 | { 44 | App.SetThemes(theme); 45 | } 46 | }; 47 | 48 | ThemeVariantsBox.SelectionChanged += (sender, e) => 49 | { 50 | if (ThemeVariantsBox.SelectedItem is ThemeVariant themeVariant) 51 | { 52 | Application.Current!.RequestedThemeVariant = themeVariant; 53 | } 54 | }; 55 | } 56 | 57 | private static void OnCurrentCultureChanged(ICultureData? newCulture) 58 | { 59 | if (newCulture != null) 60 | { 61 | LocalizationService.Default.SelectCulture(newCulture.Culture.Name); 62 | } 63 | } 64 | } 65 | 66 | public enum ThemeType 67 | { 68 | Fluent, 69 | Simple 70 | } -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Views/MainWindow.axaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Views/MainWindow.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace Avalonia.PropertyGrid.Samples.Views; 4 | 5 | public partial class MainWindow : Window 6 | { 7 | public MainWindow() => InitializeComponent(); 8 | } -------------------------------------------------------------------------------- /Samples/Avalonia.PropertyGrid.Samples/Views/SampleLocalizationService.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.PropertyGrid.Localization; 2 | 3 | namespace Avalonia.PropertyGrid.Samples.Views 4 | { 5 | internal class SampleLocalizationService : AssemblyJsonAssetLocalizationService 6 | { 7 | public SampleLocalizationService() 8 | : base(typeof(SampleLocalizationService).Assembly) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Samples/Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | true 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Assets/Images/add.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:c79c171aaee0b40515e2c4da832bd3824ed692a464d42efa1b0b31ca7b147858 3 | size 305 4 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Assets/Images/clear.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:045039873317026be896f22ead78ffcb763e024c23c6c2750d039035cf5e954c 3 | size 1199 4 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Assets/Images/delete.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:fe96c65c3590bf9f5c98ca25c213d9f8c7da0957a32050d5eaba029beb5b687e 3 | size 487 4 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Assets/Images/new.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:b5133133421da495342abfded901c86eed96e1b9af328e8c01fd1034c875e675 3 | size 682 4 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Assets/Images/options.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:87791061d56c5779881aa8c96e870500de9303fa3375de50a47584765cece23b 3 | size 791 4 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Assets/Localizations/en-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "ShowGroup": "Show Category", 3 | "ShowStyle": "Show Style", 4 | "IsCategoryView": "Is Category View", 5 | "AllowQuickFilter": "Allow Quick Filter", 6 | "IgnoreCase": "Ignore Case", 7 | "UseRegex": "Use Regex", 8 | "DisplayMode": "Display Mode", 9 | "ShowTitle": "Show Title", 10 | "CategoryOrder": "Category Order", 11 | "PropertyOrder": "Property Order", 12 | "ExpandAll": "Expand All", 13 | "CollapseAll": "Collapse All", 14 | "InsertNewElement": "Insert a new element before this element", 15 | "RemoveElement": "Remove this element", 16 | "AppendNewElement": "Append a new element", 17 | "ClearAllElements": "Clear this list", 18 | "MainOptionSettingsTooltip": "Choose your display mode and use some shortcuts" 19 | } -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Assets/Localizations/ru-RU.json: -------------------------------------------------------------------------------- 1 | { 2 | "ShowGroup": "Показывать категорию", 3 | "ShowStyle": "Стиль отображения", 4 | "IgnoreCase": "Игнорировать регистр", 5 | "UseRegex": "Использовать Regex", 6 | "Search": "Поиск", 7 | "All": "Все", 8 | "Name": "Название", 9 | "Properties": "Свойства", 10 | "Misc": "Разное", 11 | "{0} Elements": "{0} элементов", 12 | "InsertNewElement": "Вставить элемент перед этим элементом", 13 | "RemoveElement": "Удалить элемент", 14 | "AppendNewElement": "Добавить новый элемент", 15 | "ClearAllElements": "Очистить список", 16 | "Please select some folders": "Пожалуйста, выберите папки", 17 | "Please select a folder": "Пожалуйста, выберите папку", 18 | "Please select some files": "Пожалуйста, выберите файлы", 19 | "Please select a file": "Пожалуйста, выберите файл", 20 | "Remove array element at {0}": "Удалить элемент массива в {0}", 21 | "Clear all elements of the array": "Очистить все элементы массива", 22 | "Insert a new element at {0}": "Вставить новый элемент в {0}", 23 | "Insert a new element at the end of the array": "Вставить новый элемент в конец массива", 24 | "Change {0} form {1} to {2}": "Изменить {0} с {1} на {2}", 25 | "Change {0} selection from {1} to {2}": "Изменить выбор {0} с {1} на {2}", 26 | "ReadOnly": "Только чтение", 27 | "Readonly": "Только чтение" 28 | } -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Assets/Localizations/zh-CN.json: -------------------------------------------------------------------------------- 1 | { 2 | "ShowGroup": "显示分类", 3 | "ShowStyle": "显示风格", 4 | "IsCategoryView": "分类视图", 5 | "AllowQuickFilter": "允许快速过滤", 6 | "IgnoreCase": "忽略大小写", 7 | "UseRegex": "使用正则表达式", 8 | "Search": "搜索", 9 | "DisplayMode": "显示模式", 10 | "Tree": "树形", 11 | "Inline": "内联", 12 | "CategoryOrder": "分类排序", 13 | "PropertyOrder": "属性排序", 14 | "Builtin": "内置", 15 | "Alphabetic": "字母顺序", 16 | "ShowTitle": "显示标题", 17 | "ExpandAll": "全部展开", 18 | "CollapseAll": "全部折叠", 19 | "All": "所有", 20 | "Name": "名称", 21 | "Properties": "属性", 22 | "Misc": "杂项", 23 | "{0} Elements": "{0}个数据", 24 | "InsertNewElement": "在当前元素前新增一个元素", 25 | "RemoveElement": "删除当前元素", 26 | "AppendNewElement": "在尾部增加一个新元素", 27 | "ClearAllElements": "清空整个列表", 28 | "Please select some folders": "请选择文件夹", 29 | "Please select a folder": "请选择一个文件夹", 30 | "Please select some files": "请选择一些文件", 31 | "Please select a file": "请选择一个文件", 32 | "Remove array element at {0}": "从数组{0}处移除一个元素", 33 | "Clear all elements of the array": "清空数组", 34 | "Insert a new element at {0}": "在数组{0}处插入一个新的元素", 35 | "Insert a new element at the end of the array": "在数组尾部新增一个新的元素", 36 | "Change {0} form {1} to {2}": "将属性[{0}]从<{1}>修改为<{2}>", 37 | "Change {0} selection from {1} to {2}": "属性[{0}]选择项从<{1}>变更为<{2}>", 38 | "ReadOnly": "只读", 39 | "Readonly": "只读", 40 | "MainOptionSettingsTooltip": "选择你的显示模式和使用一些快捷功能" 41 | } -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Avalonia.PropertyGrid.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.1;net6.0;net8.0;net9.0 5 | preview 6 | True 7 | bodong.Avalonia.PropertyGrid 8 | 11.3.0.22 9 | bodong 10 | enable 11 | A PropertyGrid control implementation for Avalonia 12 | https://github.com/bodong1987/Avalonia.PropertyGrid 13 | https://github.com/bodong1987/Avalonia.PropertyGrid.git 14 | git 15 | Avalonia;PropertyGrid;AvaloniaControls;AvaloniaSamples 16 | False 17 | Debug;Release;Development 18 | 19 | 20 | 21 | DEBUG;TRACE 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | True 44 | \ 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | BindiListElementPlaceholderEdit.axaml 63 | 64 | 65 | 66 | 67 | bodong.Avalonia.PropertyGrid 68 | bodong.Avalonia.PropertyGrid 69 | MIT 70 | False 71 | README_NUGET.md 72 | True 73 | enable 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/ButtonEdit.axaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 38 | 39 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/CheckedListEdit.axaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 6 | 7 | 8 | 32 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/CheckedMask.axaml: -------------------------------------------------------------------------------- 1 |  7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/Factories/Builtins/BooleanCellEditFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using Avalonia.Controls; 3 | using PropertyModels.ComponentModel; 4 | 5 | namespace Avalonia.PropertyGrid.Controls.Factories.Builtins 6 | { 7 | /// 8 | /// Class BooleanCellEditFactory. 9 | /// Implements the 10 | /// 11 | /// 12 | public class BooleanCellEditFactory : AbstractCellEditFactory 13 | { 14 | /// 15 | /// Gets the import priority. 16 | /// The larger the value, the earlier the object will be processed 17 | /// 18 | /// The import priority. 19 | public override int ImportPriority => base.ImportPriority - 100000; 20 | 21 | /// 22 | /// Handles the new property. 23 | /// 24 | /// The context. 25 | /// Control. 26 | public override Control? HandleNewProperty(PropertyCellContext context) 27 | { 28 | var propertyDescriptor = context.Property; 29 | 30 | if (propertyDescriptor.PropertyType != typeof(bool) && propertyDescriptor.PropertyType != typeof(bool?)) 31 | { 32 | return null; 33 | } 34 | 35 | var control = new CheckBox 36 | { 37 | IsThreeState = propertyDescriptor.PropertyType == typeof(bool?) || propertyDescriptor is MultiObjectPropertyDescriptor 38 | }; 39 | 40 | control.IsCheckedChanged += (s, e) => 41 | { 42 | SetAndRaise(context, control, control.IsChecked); 43 | }; 44 | 45 | return control; 46 | } 47 | 48 | /// 49 | /// Handles the property changed. 50 | /// 51 | /// The context. 52 | /// true if success, false otherwise. 53 | public override bool HandlePropertyChanged(PropertyCellContext context) 54 | { 55 | var propertyDescriptor = context.Property; 56 | var target = context.Target; 57 | var control = context.CellEdit; 58 | 59 | if (propertyDescriptor.PropertyType != typeof(bool) && propertyDescriptor.PropertyType != typeof(bool?)) 60 | { 61 | return false; 62 | } 63 | 64 | Debug.Assert(control != null); 65 | 66 | ValidateProperty(control, propertyDescriptor, target); 67 | 68 | if (control is CheckBox ts) 69 | { 70 | if (ts.IsThreeState) 71 | { 72 | var obj = propertyDescriptor.GetValue(target); 73 | 74 | if (obj != null) 75 | { 76 | ts.IsChecked = (bool)obj; 77 | } 78 | else 79 | { 80 | ts.IsChecked = null; 81 | } 82 | } 83 | else 84 | { 85 | ts.IsChecked = (bool)propertyDescriptor.GetValue(target)!; 86 | } 87 | 88 | return true; 89 | } 90 | 91 | return false; 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/Factories/Builtins/FontFamilyCellEditFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Avalonia.Controls; 3 | using Avalonia.Controls.Templates; 4 | using Avalonia.Data; 5 | using Avalonia.Layout; 6 | using Avalonia.Media; 7 | 8 | namespace Avalonia.PropertyGrid.Controls.Factories.Builtins 9 | { 10 | /// 11 | /// Class FontFamilyCellEditFactory. 12 | /// Implements the 13 | /// 14 | /// 15 | public class FontFamilyCellEditFactory : AbstractCellEditFactory 16 | { 17 | /// 18 | /// Gets the import priority. 19 | /// The larger the value, the earlier the object will be processed 20 | /// 21 | /// The import priority. 22 | public override int ImportPriority => base.ImportPriority - 1000000; 23 | 24 | /// 25 | /// Handles the new property. 26 | /// 27 | /// The context. 28 | /// Control. 29 | public override Control? HandleNewProperty(PropertyCellContext context) 30 | { 31 | var propertyDescriptor = context.Property; 32 | var target = context.Target; 33 | 34 | if (propertyDescriptor.PropertyType != typeof(FontFamily)) 35 | { 36 | return null; 37 | } 38 | 39 | var control = new ComboBox 40 | { 41 | ItemsSource = FontManager.Current.SystemFonts.ToArray(), 42 | HorizontalAlignment = HorizontalAlignment.Stretch, 43 | ItemTemplate = new FuncDataTemplate((value, nameScope) => 44 | new TextBlock 45 | { 46 | [!TextBlock.TextProperty] = new Binding("Name"), 47 | [!TextBlock.FontFamilyProperty] = new Binding() 48 | } 49 | ) 50 | }; 51 | 52 | control.SelectionChanged += (s, e) => 53 | { 54 | var item = control.SelectedItem; 55 | 56 | if (item is FontFamily ff) 57 | { 58 | if (ff != (propertyDescriptor.GetValue(target) as FontFamily)) 59 | { 60 | SetAndRaise(context, control, ff); 61 | } 62 | } 63 | }; 64 | 65 | return control; 66 | } 67 | 68 | /// 69 | /// Handles the property changed. 70 | /// 71 | /// The context. 72 | /// true if success, false otherwise. 73 | public override bool HandlePropertyChanged(PropertyCellContext context) 74 | { 75 | var propertyDescriptor = context.Property; 76 | var target = context.Target; 77 | var control = context.CellEdit!; 78 | 79 | if (propertyDescriptor.PropertyType != typeof(FontFamily)) 80 | { 81 | return false; 82 | } 83 | 84 | ValidateProperty(control, propertyDescriptor, target); 85 | 86 | if (control is ComboBox cb) 87 | { 88 | var value = propertyDescriptor.GetValue(target) as FontFamily; 89 | cb.SelectedItem = value; 90 | return true; 91 | } 92 | 93 | return false; 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/Factories/Builtins/ImageCellEditFactory.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Layout; 3 | using Avalonia.Media; 4 | using PropertyModels.ComponentModel; 5 | using PropertyModels.ComponentModel.DataAnnotations; 6 | using PropertyModels.Extensions; 7 | 8 | namespace Avalonia.PropertyGrid.Controls.Factories.Builtins 9 | { 10 | /// 11 | /// Class ImageCellEditFactory. 12 | /// Implements the 13 | /// 14 | /// 15 | public class ImageCellEditFactory : AbstractCellEditFactory 16 | { 17 | /// 18 | /// Gets the import priority. 19 | /// The larger the value, the earlier the object will be processed 20 | /// 21 | /// The import priority. 22 | public override int ImportPriority => base.ImportPriority - 1000000; 23 | 24 | /// 25 | /// Handles the new property. 26 | /// 27 | /// The context. 28 | /// Control. 29 | public override Control? HandleNewProperty(PropertyCellContext context) 30 | { 31 | var propertyDescriptor = context.Property; 32 | // var target = context.Target; 33 | 34 | if (propertyDescriptor is MultiObjectPropertyDescriptor) 35 | { 36 | return null; 37 | } 38 | 39 | if (propertyDescriptor.PropertyType != typeof(IImage) && !propertyDescriptor.PropertyType.IsImplementFrom()) 40 | { 41 | return null; 42 | } 43 | 44 | var attr = propertyDescriptor.GetCustomAttribute(); 45 | 46 | var control = new Image 47 | { 48 | VerticalAlignment = VerticalAlignment.Center, 49 | HorizontalAlignment = HorizontalAlignment.Center, 50 | Stretch = attr != null ? (Stretch)(int)attr.Stretch : Stretch.Uniform, 51 | StretchDirection = attr != null ? (StretchDirection)(int)attr.StretchDirection : StretchDirection.Both 52 | }; 53 | 54 | return control; 55 | } 56 | 57 | /// 58 | /// Handles the property changed. 59 | /// 60 | /// The context. 61 | /// true if success, false otherwise. 62 | public override bool HandlePropertyChanged(PropertyCellContext context) 63 | { 64 | var propertyDescriptor = context.Property; 65 | var target = context.Target; 66 | var control = context.CellEdit!; 67 | 68 | if (propertyDescriptor.PropertyType != typeof(IImage) && !propertyDescriptor.PropertyType.IsImplementFrom()) 69 | { 70 | return false; 71 | } 72 | 73 | ValidateProperty(control, propertyDescriptor, target); 74 | 75 | if (control is Image imageControl) 76 | { 77 | var imageData = propertyDescriptor.GetValue(target); 78 | 79 | if (imageData == null) 80 | { 81 | imageControl.Source = null; 82 | return false; 83 | } 84 | 85 | if (imageData is IImage iImage) 86 | { 87 | imageControl.Source = iImage; 88 | } 89 | } 90 | 91 | return false; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/Factories/Builtins/ProgressCellEditFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia.Controls; 3 | using PropertyModels.ComponentModel; 4 | using PropertyModels.Extensions; 5 | 6 | namespace Avalonia.PropertyGrid.Controls.Factories.Builtins 7 | { 8 | /// 9 | /// Class ProgressCellEditFactory. 10 | /// Implements the 11 | /// 12 | /// 13 | public class ProgressCellEditFactory : AbstractCellEditFactory 14 | { 15 | /// 16 | /// Gets the import priority. 17 | /// The larger the value, the earlier the object will be processed 18 | /// 19 | /// The import priority. 20 | public override int ImportPriority => base.ImportPriority - 900000; 21 | 22 | /// 23 | /// Handles the new property. 24 | /// 25 | /// The context. 26 | /// Control. 27 | public override Control? HandleNewProperty(PropertyCellContext context) 28 | { 29 | var propertyDescriptor = context.Property; 30 | // var target = context.Target; 31 | 32 | if ((propertyDescriptor.PropertyType != typeof(double) && propertyDescriptor.PropertyType != typeof(float)) || !propertyDescriptor.IsDefined()) 33 | { 34 | return null; 35 | } 36 | 37 | var control = new ProgressBar(); 38 | 39 | var attr = propertyDescriptor.GetCustomAttribute()!; 40 | control.Minimum = attr.Minimum; 41 | control.Maximum = attr.Maximum; 42 | control.ProgressTextFormat = attr.FormatString; 43 | control.ShowProgressText = attr.ShowProgressText; 44 | 45 | return control; 46 | } 47 | 48 | /// 49 | /// Handles the property changed. 50 | /// 51 | /// The context. 52 | /// true if success, false otherwise. 53 | public override bool HandlePropertyChanged(PropertyCellContext context) 54 | { 55 | var propertyDescriptor = context.Property; 56 | var target = context.Target; 57 | var control = context.CellEdit!; 58 | 59 | if ((propertyDescriptor.PropertyType != typeof(double) && propertyDescriptor.PropertyType != typeof(float)) || !propertyDescriptor.IsDefined()) 60 | { 61 | return false; 62 | } 63 | 64 | ValidateProperty(control, propertyDescriptor, target); 65 | 66 | if (control is ProgressBar progressBar) 67 | { 68 | try 69 | { 70 | var v = propertyDescriptor.GetValue(target)!; 71 | 72 | progressBar.Value = Type.GetTypeCode(v.GetType()) switch 73 | { 74 | TypeCode.Single => (float)v, 75 | TypeCode.Double => (double)v, 76 | _ => progressBar.Value 77 | }; 78 | } 79 | catch (Exception ex) 80 | { 81 | DataValidationErrors.SetErrors(control, [ex.Message]); 82 | } 83 | 84 | return true; 85 | } 86 | 87 | return false; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/Factories/Builtins/TimeCellEditFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia.Controls; 3 | 4 | namespace Avalonia.PropertyGrid.Controls.Factories.Builtins 5 | { 6 | /// 7 | /// Class TimeCellEditFactory. 8 | /// Implements the 9 | /// 10 | /// 11 | public class TimeCellEditFactory : AbstractCellEditFactory 12 | { 13 | /// 14 | /// Gets the import priority. 15 | /// The larger the value, the earlier the object will be processed 16 | /// 17 | /// The import priority. 18 | public override int ImportPriority => base.ImportPriority - 100000; 19 | 20 | /// 21 | /// Handles the new property. 22 | /// 23 | /// The context. 24 | /// Control. 25 | public override Control? HandleNewProperty(PropertyCellContext context) 26 | { 27 | var propertyDescriptor = context.Property; 28 | // var target = context.Target; 29 | 30 | var propertyType = propertyDescriptor.PropertyType; 31 | 32 | if (propertyType != typeof(TimeSpan) && propertyType != typeof(TimeSpan?)) 33 | { 34 | return null; 35 | } 36 | 37 | var control = new TimePicker 38 | { 39 | ClockIdentifier = "24HourClock" 40 | }; 41 | 42 | control.SelectedTimeChanged += (s, e) => 43 | { 44 | if (propertyType == typeof(TimeSpan?)) 45 | { 46 | SetAndRaise(context, control, control.SelectedTime); 47 | } 48 | else if (propertyType == typeof(TimeSpan) && control.SelectedTime is not null) 49 | { 50 | SetAndRaise(context, control, control.SelectedTime.Value); 51 | } 52 | }; 53 | 54 | return control; 55 | } 56 | 57 | /// 58 | /// Handles the property changed. 59 | /// 60 | /// The context. 61 | /// true if success, false otherwise. 62 | public override bool HandlePropertyChanged(PropertyCellContext context) 63 | { 64 | var propertyDescriptor = context.Property; 65 | var target = context.Target; 66 | var control = context.CellEdit; 67 | 68 | var propertyType = propertyDescriptor.PropertyType; 69 | 70 | if (propertyType != typeof(TimeSpan) && propertyType != typeof(TimeSpan?)) 71 | { 72 | return false; 73 | } 74 | 75 | if (control is TimePicker tp) 76 | { 77 | if (propertyType == typeof(TimeSpan?)) 78 | { 79 | tp.SelectedTime = propertyDescriptor.GetValue(target) as TimeSpan?; 80 | } 81 | else if (propertyType == typeof(TimeSpan)) 82 | { 83 | var value = propertyDescriptor.GetValue(target); 84 | 85 | if (value != null) 86 | { 87 | tp.SelectedTime = (TimeSpan)value; 88 | } 89 | } 90 | 91 | return true; 92 | } 93 | 94 | return false; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/ICellEditFactoryCollection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Avalonia.Controls; 3 | 4 | namespace Avalonia.PropertyGrid.Controls 5 | { 6 | /// 7 | /// Interface ICellEditFactoryCollection 8 | /// 9 | public interface ICellEditFactoryCollection 10 | { 11 | /// 12 | /// Gets the factories. 13 | /// 14 | /// The factories. 15 | IEnumerable Factories { get; } 16 | 17 | /// 18 | /// Clones the factories. 19 | /// 20 | /// The access token. 21 | /// IEnumerable<ICellEditFactory>. 22 | IEnumerable CloneFactories(object accessToken); 23 | 24 | /// 25 | /// Adds the factory. 26 | /// 27 | /// The factory. 28 | void AddFactory(ICellEditFactory factory); 29 | 30 | /// 31 | /// Removes the factory. 32 | /// 33 | /// The factory. 34 | void RemoveFactory(ICellEditFactory factory); 35 | 36 | /// 37 | /// Builds the property control. 38 | /// 39 | /// The context. 40 | /// Control. 41 | Control? BuildPropertyControl(PropertyCellContext context); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/IPropertyGridFilterContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia.PropertyGrid.ViewModels; 3 | using PropertyModels.ComponentModel; 4 | 5 | namespace Avalonia.PropertyGrid.Controls 6 | { 7 | /// 8 | /// Enum FilterCategory 9 | /// 10 | [Flags] 11 | public enum FilterCategory 12 | { 13 | /// 14 | /// The none 15 | /// 16 | None = 0, 17 | /// 18 | /// The property condition 19 | /// 20 | PropertyCondition = 1 << 0, 21 | /// 22 | /// The category 23 | /// 24 | Category = 1 << 1, 25 | /// 26 | /// The filter 27 | /// 28 | Filter = 1 << 2, 29 | /// 30 | /// The factory 31 | /// 32 | Factory = 1 << 4, 33 | 34 | /// 35 | /// The default 36 | /// 37 | Default = PropertyCondition | Category | Filter | Factory 38 | } 39 | 40 | /// 41 | /// Interface IPropertyGridFilterContext 42 | /// 43 | public interface IPropertyGridFilterContext 44 | { 45 | /// 46 | /// Gets the filter pattern. 47 | /// 48 | /// The filter pattern. 49 | IFilterPattern? FilterPattern { get; } 50 | 51 | /// 52 | /// Gets the fast filter pattern. 53 | /// 54 | /// The fast filter pattern. 55 | ICheckedMaskModel? FastFilterPattern { get; } 56 | 57 | /// 58 | /// Propagates the visibility. 59 | /// 60 | /// The information. 61 | /// The category. 62 | /// The filter text. 63 | /// Indicates whether the filter matches the parent category. 64 | /// PropertyVisibility. 65 | PropertyVisibility PropagateVisibility( 66 | IPropertyGridCellInfo cellInfo, 67 | FilterCategory category = FilterCategory.Default, 68 | string? filterText = null, 69 | bool filterMatchesParentCategory = false); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/Implements/CellEditFactoryCollection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Avalonia.Controls; 4 | using PropertyModels.ComponentModel; 5 | using PropertyModels.Extensions; 6 | 7 | namespace Avalonia.PropertyGrid.Controls.Implements 8 | { 9 | /// 10 | /// Class CellEditFactoryCollection. 11 | /// Implements the 12 | /// 13 | /// 14 | internal class CellEditFactoryCollection : ICellEditFactoryCollection 15 | { 16 | /// 17 | /// The factories 18 | /// 19 | private readonly List _factories = []; 20 | 21 | /// 22 | /// Gets the factories. 23 | /// 24 | /// The factories. 25 | public IEnumerable Factories => [.. _factories]; 26 | 27 | /// 28 | /// Initializes a new instance of the class. 29 | /// 30 | public CellEditFactoryCollection() 31 | { 32 | } 33 | 34 | /// 35 | /// Initializes a new instance of the class. 36 | /// 37 | /// The factories. 38 | public CellEditFactoryCollection(IEnumerable factories) 39 | { 40 | _factories.AddRange(factories); 41 | _factories.Sort((x, y) => Comparer.Default.Compare(y.ImportPriority, x.ImportPriority)); 42 | 43 | foreach (var factory in _factories) 44 | { 45 | factory.Collection = this; 46 | } 47 | } 48 | 49 | /// 50 | /// Clones the factories. 51 | /// 52 | /// The access token. 53 | /// IEnumerable<ICellEditFactory>. 54 | public IEnumerable CloneFactories(object accessToken) 55 | => _factories 56 | .FindAll(x => x.Accept(accessToken)) 57 | .Select(x => x.Clone()) 58 | .Where(x => x != null) 59 | .Select(x => x!); 60 | 61 | /// 62 | /// Adds the factory. 63 | /// 64 | /// The factory. 65 | public void AddFactory(ICellEditFactory factory) 66 | { 67 | factory.Collection = this; 68 | _factories.Add(factory); 69 | _factories.Sort((x, y) => Comparer.Default.Compare(y.ImportPriority, x.ImportPriority)); 70 | } 71 | 72 | /// 73 | /// Removes the factory. 74 | /// 75 | /// The factory. 76 | public void RemoveFactory(ICellEditFactory factory) => _ = _factories.Remove(factory); 77 | 78 | /// 79 | /// Builds the property control. 80 | /// 81 | /// The context. 82 | /// Control. 83 | public Control? BuildPropertyControl(PropertyCellContext context) 84 | { 85 | foreach (var factory in _factories) 86 | { 87 | var control = factory.HandleNewProperty(context); 88 | 89 | if (control != null) 90 | { 91 | var classesAttributes = context.Property.GetCustomAttributes(); 92 | if (classesAttributes.Length > 0) 93 | { 94 | var classes = classesAttributes.SelectMany(a => a.Classes).Distinct(); 95 | control.Classes.AddRange(classes); 96 | } 97 | 98 | context.CellEdit = control; 99 | context.Factory = factory; 100 | 101 | return control; 102 | } 103 | } 104 | 105 | return null; 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/Implements/PropertyGridExpandableCache.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Avalonia.PropertyGrid.Controls.Implements 4 | { 5 | internal class PropertyGridExpandableCache : IExpandableObjectCache 6 | { 7 | private readonly List _targets = []; 8 | 9 | public void Add(object? target) 10 | { 11 | if (!_targets.Contains(target)) 12 | { 13 | _targets.Add(target); 14 | } 15 | } 16 | 17 | public void Clear() => _targets.Clear(); 18 | 19 | public bool IsExists(object? target) => _targets.Contains(target); 20 | 21 | public void Merge(IExpandableObjectCache cache) 22 | { 23 | if (cache is PropertyGridExpandableCache c) 24 | { 25 | foreach (var target in c._targets) 26 | { 27 | Add(target); 28 | } 29 | } 30 | } 31 | 32 | public void Remove(object? target) => _ = _targets.Remove(target); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/Implements/PropertyGridFilterPattern.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Text.RegularExpressions; 4 | using Avalonia.PropertyGrid.Services; 5 | using PropertyModels.ComponentModel; 6 | using PropertyModels.Extensions; 7 | 8 | namespace Avalonia.PropertyGrid.Controls.Implements 9 | { 10 | internal class PropertyGridFilterPattern : MiniReactiveObject, IFilterPattern 11 | { 12 | private Regex? _cachedRegex; 13 | 14 | public string? FilterText 15 | { 16 | get; 17 | set => this.RaiseAndSetIfChanged(ref field, value); 18 | } 19 | 20 | public bool UseRegex 21 | { 22 | get; 23 | set => this.RaiseAndSetIfChanged(ref field, value); 24 | } 25 | public bool IgnoreCase 26 | { 27 | get; 28 | set => this.RaiseAndSetIfChanged(ref field, value); 29 | } = true; 30 | 31 | /// 32 | /// Gets the quick filter. 33 | /// 34 | /// The quick filter. 35 | public ICheckedMaskModel? QuickFilter 36 | { 37 | get; 38 | set => this.RaiseAndSetIfChanged(ref field, value); 39 | } 40 | 41 | public PropertyGridFilterPattern() => PropertyChanged += OnPropertyChanged; 42 | 43 | private void OnPropertyChanged(object? sender, PropertyChangedEventArgs e) 44 | { 45 | if (e.PropertyName == nameof(FilterText) && UseRegex && FilterText.IsNotNullOrEmpty()) 46 | { 47 | _cachedRegex = null; 48 | try 49 | { 50 | _cachedRegex = new Regex(FilterText.Trim()); 51 | } 52 | catch 53 | { 54 | // ignored 55 | } 56 | } 57 | } 58 | 59 | public bool Match(PropertyDescriptor propertyDescriptor, object? context) 60 | { 61 | var displayName = LocalizationService.Default[propertyDescriptor.DisplayName]; 62 | 63 | if (UseRegex && _cachedRegex != null) 64 | { 65 | return _cachedRegex.IsMatch(displayName); 66 | } 67 | 68 | return FilterText.IsNullOrEmpty() || displayName.Contains(FilterText, IgnoreCase ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/ListEdit.axaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | 83 | 84 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/ListElementEdit.axaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 66 | 67 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/ListElementEdit.axaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Input; 2 | using Avalonia.Controls.Primitives; 3 | 4 | namespace Avalonia.PropertyGrid.Controls 5 | { 6 | /// 7 | /// Class ListElementEdit. 8 | /// Implements the 9 | /// 10 | /// 11 | public class ListElementEdit : TemplatedControl 12 | { 13 | /// 14 | /// The insert command property 15 | /// 16 | public static readonly DirectProperty InsertCommandProperty = 17 | AvaloniaProperty.RegisterDirect( 18 | nameof(InsertCommand), 19 | o => o.InsertCommand!, 20 | (o, v) => o.InsertCommand = v); 21 | 22 | /// 23 | /// Gets or sets the insert command. 24 | /// 25 | /// The insert command. 26 | public ICommand? InsertCommand 27 | { 28 | get; 29 | set => SetAndRaise(InsertCommandProperty!, ref field, value); 30 | } 31 | 32 | /// 33 | /// The remove command property 34 | /// 35 | public static readonly DirectProperty RemoveCommandProperty = 36 | AvaloniaProperty.RegisterDirect( 37 | nameof(RemoveCommand), 38 | o => o.RemoveCommand!, 39 | (o, v) => o.RemoveCommand = v); 40 | 41 | /// 42 | /// Gets or sets the remove command. 43 | /// 44 | /// The remove command. 45 | public ICommand? RemoveCommand 46 | { 47 | get; 48 | set => SetAndRaise(RemoveCommandProperty!, ref field, value); 49 | } 50 | 51 | /// 52 | /// Initializes a new instance of the class. 53 | /// 54 | public ListElementEdit() 55 | { 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/ListElementPlaceholderEdit.axaml: -------------------------------------------------------------------------------- 1 |  7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/ListElementPlaceholderEdit.axaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using Avalonia.Controls; 4 | 5 | namespace Avalonia.PropertyGrid.Controls 6 | { 7 | /// 8 | /// Class ListElementPlaceholderEdit. 9 | /// Implements the 10 | /// 11 | /// 12 | public partial class ListElementPlaceholderEdit : UserControl 13 | { 14 | private PropertyCellContext? _context; 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | public ListElementPlaceholderEdit() => InitializeComponent(); 20 | 21 | /// 22 | /// Called when [property changed]. 23 | /// 24 | /// The change. 25 | protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) 26 | { 27 | base.OnPropertyChanged(change); 28 | 29 | if (change.Property == DataContextProperty) 30 | { 31 | OnDataDescPropertyChanged(change.OldValue as ListElementDataDesc, change.NewValue as ListElementDataDesc); 32 | } 33 | } 34 | 35 | // ReSharper disable once RedundantOverriddenMember 36 | /// 37 | /// Called when the property changes. 38 | /// 39 | /// The event args. 40 | protected override void OnDataContextChanged(EventArgs e) => base.OnDataContextChanged(e); 41 | 42 | private void OnDataDescPropertyChanged(ListElementDataDesc? oldValue, ListElementDataDesc? value) 43 | { 44 | if (oldValue != null) 45 | { 46 | oldValue.ValueChanged -= OnElementValueChanged; 47 | } 48 | 49 | MainBorder.Child = null; 50 | 51 | if (value == null) 52 | { 53 | return; 54 | } 55 | 56 | value.ValueChanged += OnElementValueChanged; 57 | 58 | Debug.Assert(value.Context != null); 59 | Debug.Assert(value.Context.Root != null); 60 | 61 | _context = new PropertyCellContext(value.Context, value.List, value.Property); 62 | 63 | var control = _context.GetCellEditFactoryCollection().BuildPropertyControl(_context); 64 | if (control != null) 65 | { 66 | control.Margin = new Thickness(2, 2); 67 | 68 | MainBorder.Child = control; 69 | 70 | Debug.Assert(_context.Factory != null); 71 | 72 | _context.Factory!.HandleReadOnlyStateChanged(control, _context.IsReadOnly || value.IsReadOnly); 73 | 74 | _ = _context.Factory.HandlePropertyChanged(_context); 75 | } 76 | } 77 | 78 | 79 | private void OnElementValueChanged(object? sender, EventArgs e) 80 | { 81 | if (DataContext is not ListElementDataDesc) 82 | { 83 | return; 84 | } 85 | 86 | if (_context is { Factory: not null }) 87 | { 88 | Debug.Assert(_context != null); 89 | Debug.Assert(_context!.CellEdit != null); 90 | 91 | _ = _context.Factory.HandlePropertyChanged(_context); 92 | } 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/RadioButtonListEdit.axaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 6 | 7 | 8 | 36 | 37 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/ToggleButtonGroupListEdit.axaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 6 | 7 | 8 | 38 | 39 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Controls/TrackableEdit.axaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 50 | 51 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Localization/AssetCultureData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using Avalonia.Platform; 5 | using PropertyModels.Localization; 6 | 7 | namespace Avalonia.PropertyGrid.Localization 8 | { 9 | internal class AssetCultureData : AbstractCultureData 10 | { 11 | public AssetCultureData(Uri uri, bool autoLoad = false) 12 | : base(uri) 13 | { 14 | if (autoLoad) 15 | { 16 | _ = Reload(); 17 | } 18 | } 19 | 20 | public sealed override bool Reload() 21 | { 22 | try 23 | { 24 | using (var stream = AssetLoader.Open(Path)) 25 | { 26 | using var sr = new StreamReader(stream, Encoding.UTF8); 27 | var tempDict = ReadJsonStringDictionary(sr.ReadToEnd()); 28 | 29 | LocalTexts = tempDict; 30 | } 31 | 32 | return LocalTexts != null; 33 | } 34 | catch 35 | { 36 | return false; 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Localization/LocalizationExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia.Controls; 3 | using Avalonia.Data; 4 | using Avalonia.PropertyGrid.Services; 5 | using PropertyModels.ComponentModel; 6 | 7 | namespace Avalonia.PropertyGrid.Localization 8 | { 9 | /// 10 | /// Class LocalizationExtensions. 11 | /// 12 | public static class LocalizationExtensions 13 | { 14 | /// 15 | /// Sets the localize binding. 16 | /// 17 | /// The control. 18 | /// The property. 19 | /// The name. 20 | /// The mode. 21 | public static void SetLocalizeBinding(this Control control, AvaloniaProperty property, string name, BindingMode mode = BindingMode.Default) 22 | { 23 | var source = new LocalizedDataModel(name); 24 | var binding = new Binding 25 | { 26 | Source = source, 27 | Path = nameof(source.Value), 28 | Mode = mode 29 | }; 30 | 31 | _ = control.Bind(property, binding); 32 | control.DataContext = source; 33 | } 34 | } 35 | 36 | internal class LocalizedDataModel : ReactiveObject 37 | { 38 | // ReSharper disable once MemberCanBePrivate.Global 39 | public readonly string Name; 40 | 41 | public string Value 42 | { 43 | get 44 | { 45 | var localizeService = LocalizationService.Default; 46 | 47 | // in design mode, service maybe unavailable... 48 | return localizeService[Name]; 49 | } 50 | } 51 | 52 | public LocalizedDataModel(string name) 53 | { 54 | Name = name; 55 | 56 | var localizeService = LocalizationService.Default; 57 | 58 | localizeService.OnCultureChanged += OnCultureChanged; 59 | } 60 | 61 | private void OnCultureChanged(object? sender, EventArgs e) => RaisePropertyChanged(nameof(Value)); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Localization/LocalizeExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia.Data; 3 | using Avalonia.Markup.Xaml; 4 | using Avalonia.Markup.Xaml.MarkupExtensions; 5 | using Avalonia.PropertyGrid.Services; 6 | 7 | namespace Avalonia.PropertyGrid.Localization 8 | { 9 | /// 10 | /// Class LocalizeExtension. 11 | /// Implements the 12 | /// 13 | /// 14 | public class LocalizeExtension : MarkupExtension 15 | { 16 | /// 17 | /// Gets or sets the key. 18 | /// 19 | /// The key. 20 | // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global 21 | public string Key { get; set; } 22 | /// 23 | /// Gets or sets the context. 24 | /// 25 | /// The context. 26 | // ReSharper disable once UnusedAutoPropertyAccessor.Global 27 | public string? Context { get; set; } 28 | 29 | /// 30 | /// Initializes a new instance of the class. 31 | /// 32 | /// The key. 33 | public LocalizeExtension(string key) => Key = key; 34 | 35 | /// 36 | /// Provides the value. 37 | /// 38 | /// The service provider. 39 | /// System.Object. 40 | public override object ProvideValue(IServiceProvider serviceProvider) 41 | { 42 | var keyToUse = Key; 43 | 44 | if (!string.IsNullOrWhiteSpace(Context)) 45 | { 46 | keyToUse = $"{Context}/{Key}"; 47 | } 48 | 49 | var binding = new ReflectionBindingExtension($"[{keyToUse}]") 50 | { 51 | Mode = BindingMode.OneWay, 52 | Source = LocalizationService.Default 53 | }; 54 | 55 | return binding.ProvideValue(serviceProvider); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Services/CellEditFactoryService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia.PropertyGrid.Controls; 3 | using Avalonia.PropertyGrid.Controls.Implements; 4 | using PropertyModels.Extensions; 5 | 6 | namespace Avalonia.PropertyGrid.Services 7 | { 8 | /// 9 | /// Class CellEditFactoryService. 10 | /// 11 | public static class CellEditFactoryService 12 | { 13 | /// 14 | /// The default 15 | /// 16 | public static readonly ICellEditFactoryCollection Default = new CellEditFactoryCollection(); 17 | 18 | /// 19 | /// Initializes static members of the class. 20 | /// 21 | static CellEditFactoryService() 22 | { 23 | foreach (var type in typeof(CellEditFactoryService).Assembly.GetTypes()) 24 | { 25 | if (type is { IsClass: true, IsAbstract: false } && type.IsImplementFrom()) 26 | { 27 | Default.AddFactory((Activator.CreateInstance(type) as ICellEditFactory)!); 28 | } 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Services/LocalizationService.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.PropertyGrid.Localization; 2 | using PropertyModels.Localization; 3 | 4 | namespace Avalonia.PropertyGrid.Services 5 | { 6 | /// 7 | /// Class LocalizationService. 8 | /// 9 | public static class LocalizationService 10 | { 11 | /// 12 | /// The default 13 | /// 14 | public static readonly ILocalizationService Default = new AssemblyJsonAssetLocalizationService(typeof(LocalizationService).Assembly); 15 | 16 | static LocalizationService() 17 | { 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Utils/FontUtils.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Media; 2 | 3 | namespace Avalonia.PropertyGrid.Utils 4 | { 5 | /// 6 | /// Class FontUtils. 7 | /// 8 | public static class FontUtils 9 | { 10 | /// 11 | /// Gets the default font family. 12 | /// Change this property can change the default TextBox's Font 13 | /// so it can display complex characters correctly. 14 | /// 15 | /// The default font family. 16 | // ReSharper disable once StringLiteralTypo 17 | public static FontFamily DefaultFontFamily => new("Microsoft YaHei,Simsun,苹方-简,宋体-简"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Utils/InverseBooleanConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Avalonia.Data.Converters; 4 | 5 | namespace Avalonia.PropertyGrid.Utils 6 | { 7 | /// 8 | /// A value converter that inverts a boolean value. 9 | /// 10 | public class InverseBooleanConverter : IValueConverter 11 | { 12 | /// 13 | /// Converts a boolean value to its inverse. 14 | /// 15 | /// The value produced by the binding source. 16 | /// The type of the binding target property. 17 | /// The converter parameter to use. 18 | /// The culture to use in the converter. 19 | /// 20 | /// A converted value. If the method returns null, the valid null value is used. 21 | /// 22 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 23 | { 24 | if (value is bool booleanValue) 25 | { 26 | return !booleanValue; 27 | } 28 | 29 | return AvaloniaProperty.UnsetValue; 30 | } 31 | 32 | /// 33 | /// Converts a value back to its inverse. 34 | /// 35 | /// The value that is produced by the binding target. 36 | /// The type to convert to. 37 | /// The converter parameter to use. 38 | /// The culture to use in the converter. 39 | /// 40 | /// A converted value. If the method returns null, the valid null value is used. 41 | /// 42 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) 43 | { 44 | if (value is bool booleanValue) 45 | { 46 | return !booleanValue; 47 | } 48 | 49 | return AvaloniaProperty.UnsetValue; 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/Utils/PropertyObserver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Avalonia.PropertyGrid.Utils; 4 | 5 | /// 6 | public class PropertyObserver : IObserver 7 | { 8 | private readonly Action _action; 9 | 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// The to perform. 14 | public PropertyObserver(Action action) 15 | { 16 | _action = action; 17 | } 18 | 19 | /// 20 | public void OnNext(T value) => _action(value); 21 | 22 | /// 23 | public void OnError(Exception error) { } 24 | 25 | /// 26 | public void OnCompleted() { } 27 | } -------------------------------------------------------------------------------- /Sources/Avalonia.PropertyGrid/ViewModels/ReferencePath.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Avalonia.PropertyGrid.ViewModels 4 | { 5 | /// 6 | /// Class ReferencePath. 7 | /// 8 | public class ReferencePath 9 | { 10 | /// 11 | /// The paths 12 | /// 13 | public readonly Stack Paths = new(); 14 | 15 | /// 16 | /// Gets the count. 17 | /// 18 | /// The count. 19 | public int Count => Paths.Count; 20 | 21 | /// 22 | /// Begins the scope. 23 | /// 24 | /// The scope. 25 | public void BeginScope(string scope) => Paths.Push(scope); 26 | 27 | /// 28 | /// Ends the scope. 29 | /// 30 | public void EndScope() => _ = Paths.Pop(); 31 | 32 | /// 33 | /// Returns a that represents this instance. 34 | /// 35 | /// A that represents this instance. 36 | public override string ToString() => string.Join(", ", [.. Paths]); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/AutoCollapseCategoriesAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace PropertyModels.ComponentModel 5 | { 6 | /// 7 | /// Attribute to specify categories that should be automatically collapsed. 8 | /// 9 | [AttributeUsage(AttributeTargets.Class)] 10 | public class AutoCollapseCategoriesAttribute : Attribute 11 | { 12 | /// 13 | /// Gets the set of category names that should be automatically collapsed. 14 | /// 15 | public readonly HashSet CategoryNames; 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// The category names to be automatically collapsed. 21 | public AutoCollapseCategoriesAttribute(params string[] categoryNames) 22 | { 23 | CategoryNames = new HashSet(categoryNames); 24 | } 25 | 26 | /// 27 | /// Determines whether the specified category should be automatically collapsed. 28 | /// 29 | /// The name of the category to check. 30 | /// true if the category should be collapsed; otherwise, false. 31 | public virtual bool ShouldAutoCollapse(string categoryName) => CategoryNames.Contains(categoryName); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/ControlClassesAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PropertyModels.ComponentModel; 4 | 5 | /// 6 | /// Defines the Classes of generated control. 7 | /// 8 | [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] 9 | public class ControlClassesAttribute : Attribute 10 | { 11 | /// 12 | /// The Classes to be injected to generated control. 13 | /// 14 | public readonly string[] Classes; 15 | 16 | /// 17 | /// Initializes a new instance of the class 18 | /// 19 | /// 20 | public ControlClassesAttribute(params string[] classes) 21 | { 22 | Classes = classes; 23 | } 24 | } -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/DataAnnotations/DependsOnPropertyAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PropertyModels.ComponentModel.DataAnnotations 4 | { 5 | /// 6 | /// Class DependsOnPropertyAttribute. 7 | /// Implements the 8 | /// 9 | /// 10 | [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] 11 | public class DependsOnPropertyAttribute : Attribute 12 | { 13 | /// 14 | /// The dependency properties 15 | /// 16 | public readonly string[] DependencyProperties; 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | /// The property names. 22 | public DependsOnPropertyAttribute(params string[] propertyNames) 23 | { 24 | DependencyProperties = propertyNames; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/DataAnnotations/FileNameValidationAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.IO; 3 | using System.Runtime.CompilerServices; 4 | 5 | namespace PropertyModels.ComponentModel.DataAnnotations 6 | { 7 | /// 8 | /// Class FileNameValidationAttribute. 9 | /// Implements the 10 | /// 11 | /// 12 | public class FileNameValidationAttribute : ValidationAttribute 13 | { 14 | /// 15 | /// Validates the specified value with respect to the current validation attribute. 16 | /// 17 | /// The value to validate. 18 | /// The context information about the validation operation. 19 | /// An instance of the class. 20 | protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) 21 | { 22 | if (value is string name) 23 | { 24 | return IsValidFileName(name) ? ValidationResult.Success : new ValidationResult($"[{validationContext.DisplayName}]{name} is not an valid file name."); 25 | } 26 | 27 | return new ValidationResult($"{validationContext.DisplayName} is not an valid file name."); 28 | } 29 | 30 | /// 31 | /// Determines whether [is valid file name] [the specified filename]. 32 | /// 33 | /// The filename. 34 | /// true if [is valid file name] [the specified filename]; otherwise, false. 35 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 36 | public static bool IsValidFileName(string filename) => !(filename.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/DataAnnotations/FloatingNumberEqualToleranceAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PropertyModels.ComponentModel.DataAnnotations; 4 | 5 | /// 6 | /// You can use this tag to mark the tolerance value of a floating point number. When the change difference is less than this value, it is considered that there is no change. 7 | /// 8 | [AttributeUsage(AttributeTargets.Field|AttributeTargets.Property)] 9 | public class FloatingNumberEqualToleranceAttribute : Attribute 10 | { 11 | /// 12 | /// value 13 | /// 14 | public float Tolerance { get; } 15 | 16 | /// 17 | /// constructor 18 | /// 19 | /// 20 | public FloatingNumberEqualToleranceAttribute(float tolerance = 0.0001f) 21 | { 22 | Tolerance = tolerance; 23 | } 24 | } -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/DataAnnotations/ImagePreviewModeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | // ReSharper disable UnusedAutoPropertyAccessor.Global 3 | 4 | namespace PropertyModels.ComponentModel.DataAnnotations 5 | { 6 | /// 7 | /// Specifies how the content is resized to fill its allocated space. 8 | /// 9 | public enum StretchType 10 | { 11 | /// 12 | /// The content preserves its original size. 13 | /// 14 | None, 15 | 16 | /// 17 | /// The content is resized to fill the destination dimensions. The aspect ratio is not preserved. 18 | /// 19 | Fill, 20 | 21 | /// 22 | /// The content is resized to fit in the destination dimensions while preserving its native aspect ratio. 23 | /// 24 | Uniform, 25 | 26 | /// 27 | /// The content is resized to completely fill the destination rectangle while preserving its native aspect ratio. 28 | /// A portion of the content may not be visible if the aspect ratio of the content does not match the aspect ratio of the allocated space. 29 | /// 30 | UniformToFill 31 | } 32 | 33 | /// 34 | /// Specifies the direction in which content is scaled. 35 | /// 36 | public enum StretchDirectionType 37 | { 38 | /// 39 | /// Only scales the content upwards when the content is smaller than the available space. 40 | /// If the content is larger, no scaling downwards is done. 41 | /// 42 | UpOnly, 43 | 44 | /// 45 | /// Only scales the content downwards when the content is larger than the available space. 46 | /// If the content is smaller, no scaling upwards is done. 47 | /// 48 | DownOnly, 49 | 50 | /// 51 | /// Always stretches to fit the available space according to the stretch mode. 52 | /// 53 | Both 54 | } 55 | 56 | /// 57 | /// Attribute to specify the image preview mode, including stretch and stretch direction. 58 | /// 59 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] 60 | public class ImagePreviewModeAttribute : Attribute 61 | { 62 | /// 63 | /// Gets or sets the stretch mode. 64 | /// 65 | public StretchType Stretch { get; set; } 66 | 67 | /// 68 | /// Gets or sets the stretch direction. 69 | /// 70 | // ReSharper disable once UnusedAutoPropertyAccessor.Global 71 | public StretchDirectionType StretchDirection { get; set; } 72 | } 73 | } -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/DataAnnotations/ValidationResultExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.Linq; 3 | 4 | namespace PropertyModels.ComponentModel.DataAnnotations 5 | { 6 | /// 7 | /// Class ValidationResultExtensions. 8 | /// 9 | public static class ValidationResultExtensions 10 | { 11 | /// 12 | /// Determines whether the specified validation result is success. 13 | /// 14 | /// The validation result. 15 | /// true if the specified validation result is success; otherwise, false. 16 | public static bool IsSuccess(this ValidationResult validationResult) => !IsFailure(validationResult); 17 | 18 | /// 19 | /// Determines whether the specified validation result is failure. 20 | /// 21 | /// The validation result. 22 | /// true if the specified validation result is failure; otherwise, false. 23 | public static bool IsFailure(this ValidationResult? validationResult) 24 | => validationResult != null 25 | && validationResult != ValidationResult.Success 26 | && !string.IsNullOrEmpty(validationResult.ErrorMessage); 27 | 28 | /// 29 | /// Gets the display message. 30 | /// 31 | /// The validation result. 32 | /// string. 33 | public static string GetDisplayMessage(this ValidationResult? validationResult) 34 | { 35 | if (validationResult == null) 36 | { 37 | return "Success"; 38 | } 39 | 40 | if (validationResult.MemberNames.Any()) 41 | { 42 | return $"{validationResult.ErrorMessage}:{string.Join(",", validationResult.MemberNames)}"; 43 | } 44 | 45 | return validationResult.ErrorMessage ?? ""; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/ExpandableObjectDisplayModeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | // ReSharper disable UnusedAutoPropertyAccessor.Global 3 | 4 | namespace PropertyModels.ComponentModel; 5 | 6 | /// 7 | /// instead of bool? in attribute 8 | /// 9 | public enum NullableBooleanType 10 | { 11 | /// 12 | /// bool? 13 | /// 14 | Undefined = 0, 15 | /// 16 | /// Yes 17 | /// 18 | Yes = 1, 19 | /// 20 | /// No 21 | /// 22 | No = -1 23 | } 24 | 25 | /// 26 | /// used to custom expandable object display mode 27 | /// 28 | [AttributeUsage(AttributeTargets.All)] 29 | public class ExpandableObjectDisplayModeAttribute : Attribute 30 | { 31 | /// 32 | /// use category mode ? 33 | /// null means use root config 34 | /// 35 | public NullableBooleanType IsCategoryVisible { get; set; } 36 | 37 | /// 38 | /// is in tree view mode 39 | /// null means use root config 40 | /// 41 | public NullableBooleanType IsTreeMode { get; set; } 42 | 43 | /// 44 | /// if category use builtin order/ only valid when IsCategoryVisible 45 | /// null means use root config 46 | /// 47 | public NullableBooleanType IsCategoryBuiltinOrder { get; set; } 48 | 49 | /// 50 | /// if property use builtin order 51 | /// null means use root config 52 | /// 53 | public NullableBooleanType IsPropertyBuiltinOrder { get; set; } 54 | } -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/FloatPrecisionAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PropertyModels.ComponentModel 4 | { 5 | /// 6 | /// Class FloatPrecisionAttribute. 7 | /// Use this attribute to define float value precision 8 | /// Implements the 9 | /// 10 | /// 11 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] 12 | public class FloatPrecisionAttribute : Attribute 13 | { 14 | /// 15 | /// The increment 16 | /// 17 | public readonly decimal Increment; 18 | 19 | /// 20 | /// The format string 21 | /// 22 | public readonly string FormatString; 23 | 24 | /// 25 | /// Initializes a new instance of the class. 26 | /// 27 | /// The precision. 28 | public FloatPrecisionAttribute(int precision = 2) 29 | { 30 | decimal v = 1; 31 | for (var i = 0; i < precision; ++i) 32 | { 33 | v *= (decimal)0.1; 34 | } 35 | 36 | Increment = v; 37 | 38 | // ReSharper disable once UseStringInterpolation 39 | FormatString = string.Format("{{0:0.{0}}}", new string('0', precision)); 40 | } 41 | 42 | /// 43 | /// Initializes a new instance of the class. 44 | /// 45 | /// The increment. 46 | /// The format string. 47 | public FloatPrecisionAttribute(decimal increment = (decimal)0.01, string formatString = "{0:0.00}") 48 | { 49 | Increment = increment; 50 | FormatString = formatString; 51 | } 52 | 53 | /// 54 | /// Initializes a new instance of the class. 55 | /// 56 | /// The increment. 57 | /// The format string. 58 | public FloatPrecisionAttribute(double increment, string formatString) : 59 | this((decimal)increment, formatString) 60 | { 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/FormatStringAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PropertyModels.ComponentModel 4 | { 5 | /// 6 | /// Class FormatStringAttribute. 7 | /// Implements the 8 | /// 9 | /// 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] 11 | public class FormatStringAttribute : Attribute 12 | { 13 | /// 14 | /// The format string 15 | /// 16 | public readonly string FormatString; 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | /// The format string. 22 | public FormatStringAttribute(string formatString) 23 | { 24 | FormatString = formatString; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/ICheckedMaskModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PropertyModels.ComponentModel 4 | { 5 | /// 6 | /// Interface ICheckedMaskModel 7 | /// Implements the 8 | /// 9 | /// 10 | public interface ICheckedMaskModel : IReactiveObject 11 | { 12 | /// 13 | /// Gets a value indicating whether this instance is all checked. 14 | /// 15 | /// true if this instance is all checked; otherwise, false. 16 | bool IsAllChecked { get; } 17 | 18 | /// 19 | /// Gets all. 20 | /// 21 | /// All. 22 | string All { get; } 23 | 24 | /// 25 | /// Gets the masks. 26 | /// 27 | /// The masks. 28 | string[] Masks { get; } 29 | 30 | /// 31 | /// Occurs when [check changed]. 32 | /// 33 | event EventHandler CheckChanged; 34 | 35 | /// 36 | /// Determines whether the specified mask is checked. 37 | /// 38 | /// The mask. 39 | /// true if the specified mask is checked; otherwise, false. 40 | bool IsChecked(string mask); 41 | 42 | /// 43 | /// Checks the specified mask. 44 | /// 45 | /// The mask. 46 | void Check(string mask); 47 | 48 | /// 49 | /// Uns the check. 50 | /// 51 | /// The mask. 52 | void UnCheck(string mask); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/IFilterPattern.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace PropertyModels.ComponentModel 4 | { 5 | /// 6 | /// Interface IFilterPattern 7 | /// Implements the 8 | /// 9 | /// 10 | public interface IFilterPattern : IReactiveObject 11 | { 12 | /// 13 | /// Gets or sets the filter text. 14 | /// 15 | /// The filter text. 16 | string? FilterText { get; set; } 17 | 18 | /// 19 | /// Gets or sets a value indicating whether [use regex]. 20 | /// 21 | /// true if [use regex]; otherwise, false. 22 | bool UseRegex { get; set; } 23 | 24 | /// 25 | /// Gets or sets a value indicating whether [ignore case]. 26 | /// 27 | /// true if [ignore case]; otherwise, false. 28 | bool IgnoreCase { get; set; } 29 | 30 | /// 31 | /// Gets the quick filter. 32 | /// 33 | /// The quick filter. 34 | ICheckedMaskModel? QuickFilter { get; } 35 | 36 | /// 37 | /// Matches the specified property descriptor. 38 | /// 39 | /// The property descriptor. 40 | /// The context. 41 | /// true if success, false otherwise. 42 | // ReSharper disable once UnusedParameter.Global 43 | bool Match(PropertyDescriptor propertyDescriptor, object? context); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/INotifyCommandExecuting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | 4 | namespace PropertyModels.ComponentModel 5 | { 6 | /// 7 | /// Interface INotifyCommandExecuting 8 | /// 9 | public interface INotifyCommandExecuting 10 | { 11 | /// 12 | /// Occurs when [command executing]. 13 | /// 14 | event EventHandler CommandExecuting; 15 | 16 | /// 17 | /// Raises the command executing. 18 | /// 19 | /// The instance containing the event data. 20 | void RaiseCommandExecuting(CommandExecutingEventArgs eventArgs); 21 | } 22 | 23 | /// 24 | /// Class CommandExecutingEventArgs. 25 | /// Implements the 26 | /// 27 | /// 28 | public class CommandExecutingEventArgs : CancelEventArgs 29 | { 30 | /// 31 | /// The command 32 | /// 33 | public readonly ICancelableCommand Command; 34 | 35 | /// 36 | /// The target 37 | /// 38 | public readonly object Target; 39 | 40 | /// 41 | /// The property 42 | /// 43 | public readonly PropertyDescriptor Property; 44 | 45 | /// 46 | /// The old value 47 | /// 48 | public readonly object? OldValue; 49 | 50 | /// 51 | /// Creates new value. 52 | /// 53 | public readonly object? NewValue; 54 | 55 | /// 56 | /// The context 57 | /// 58 | public readonly object? Context; 59 | 60 | /// 61 | /// Initializes a new instance of the class. 62 | /// 63 | /// The command. 64 | /// The target. 65 | /// The property. 66 | /// The old value. 67 | /// The new value. 68 | /// The context. 69 | public CommandExecutingEventArgs(ICancelableCommand command, object target, PropertyDescriptor property, object? oldValue, object? newValue, object? context) 70 | { 71 | Command = command; 72 | Target = target; 73 | Property = property; 74 | OldValue = oldValue; 75 | NewValue = newValue; 76 | Context = context; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/INotifyPropertyChanged.cs: -------------------------------------------------------------------------------- 1 | namespace PropertyModels.ComponentModel 2 | { 3 | /// 4 | /// Interface INotifyPropertyChanged 5 | /// Extends the 6 | /// 7 | /// 8 | public interface INotifyPropertyChanged : System.ComponentModel.INotifyPropertyChanged 9 | { 10 | /// 11 | /// Raises the property changed. 12 | /// 13 | /// Name of the property. 14 | void RaisePropertyChanged(string propertyName); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/INotifyPropertyChanging.cs: -------------------------------------------------------------------------------- 1 | namespace PropertyModels.ComponentModel 2 | { 3 | /// 4 | /// Interface INotifyPropertyChanging 5 | /// Implements the 6 | /// 7 | /// 8 | public interface INotifyPropertyChanging : System.ComponentModel.INotifyPropertyChanging 9 | { 10 | /// 11 | /// Raises the property changing. 12 | /// 13 | /// Name of the property. 14 | void RaisePropertyChanging(string propertyName); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/IntegerIncrementAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PropertyModels.ComponentModel 4 | { 5 | /// 6 | /// Class IntegerIncrementAttribute. 7 | /// Implements the 8 | /// 9 | /// 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] 11 | public class IntegerIncrementAttribute : Attribute 12 | { 13 | /// 14 | /// The increment 15 | /// 16 | public readonly int Increment; 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | /// The increment. 22 | public IntegerIncrementAttribute(int increment) 23 | { 24 | Increment = increment; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/MultilineTextAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PropertyModels.ComponentModel 4 | { 5 | /// 6 | /// Class MultilineTextAttribute. 7 | /// Implements the 8 | /// 9 | /// 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] 11 | public class MultilineTextAttribute : Attribute 12 | { 13 | /// 14 | /// The is multiline 15 | /// 16 | public readonly bool IsMultiline; 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | /// if set to true [is multiline]. 22 | public MultilineTextAttribute(bool isMultiline = true) 23 | { 24 | IsMultiline = isMultiline; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/ObjectCreator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PropertyModels.ComponentModel 4 | { 5 | /// 6 | /// Class ObjectCreator. 7 | /// 8 | public static class ObjectCreator 9 | { 10 | /// 11 | /// Creates this instance. 12 | /// 13 | /// 14 | /// The arguments. 15 | /// T. 16 | public static T? Create(params object[] args) => (T?)Create(typeof(T), args); 17 | 18 | /// 19 | /// Creates the specified type. 20 | /// 21 | /// The type. 22 | /// The arguments. 23 | /// System.Object. 24 | public static object? Create(Type type, params object[] args) 25 | { 26 | if (type == typeof(string)) 27 | { 28 | return ""; 29 | } 30 | 31 | return type.IsAbstract ? null : Activator.CreateInstance(type, args); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/ProgressAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PropertyModels.ComponentModel 4 | { 5 | /// 6 | /// Class ProgressAttribute. 7 | /// Implements the 8 | /// 9 | /// 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] 11 | public class ProgressAttribute : Attribute 12 | { 13 | /// 14 | /// The minimum 15 | /// 16 | public readonly double Minimum; 17 | 18 | /// 19 | /// The maximum 20 | /// 21 | public readonly double Maximum; 22 | 23 | /// 24 | /// The format string 25 | /// 26 | public readonly string FormatString; 27 | 28 | /// 29 | /// Gets or sets a value indicating whether [show progress text]. 30 | /// 31 | /// true if [show progress text]; otherwise, false. 32 | // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global 33 | public bool ShowProgressText { get; set; } = true; 34 | 35 | /// 36 | /// Initializes a new instance of the class. 37 | /// 38 | /// The minimum. 39 | /// The maximum. 40 | /// The format string. 41 | public ProgressAttribute(double min = 0, double max = 100, string formatString = "{1:0}%") 42 | { 43 | Minimum = min; 44 | Maximum = max; 45 | FormatString = formatString; 46 | } 47 | 48 | /// 49 | /// Initializes a new instance of the class. 50 | /// 51 | /// The format string. 52 | public ProgressAttribute(string formatString) 53 | { 54 | FormatString = formatString; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/PropertyOperationVisibilityAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PropertyModels.ComponentModel; 4 | 5 | /// 6 | /// set property extra operation visibility 7 | /// 8 | public enum PropertyOperationVisibility 9 | { 10 | /// 11 | /// Default 12 | /// 13 | Default, 14 | 15 | /// 16 | /// All Visible 17 | /// 18 | Visible, 19 | 20 | /// 21 | /// All Hidden 22 | /// 23 | Hidden 24 | } 25 | 26 | /// 27 | /// set property operation visibility 28 | /// 29 | [AttributeUsage(AttributeTargets.Field|AttributeTargets.Property)] 30 | public class PropertyOperationVisibilityAttribute : Attribute 31 | { 32 | /// 33 | /// visibility 34 | /// 35 | public readonly PropertyOperationVisibility Visibility; 36 | 37 | /// 38 | /// constructor 39 | /// 40 | /// 41 | public PropertyOperationVisibilityAttribute(PropertyOperationVisibility visibility = PropertyOperationVisibility.Default) 42 | { 43 | Visibility = visibility; 44 | } 45 | } -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/SelectableListDisplayModeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PropertyModels.ComponentModel; 4 | 5 | /// 6 | /// selectable list display mode 7 | /// specify the show mode of the elements in items 8 | /// 9 | public enum SelectableListDisplayMode 10 | { 11 | /// 12 | /// same as AutoWrap/ like grid layout/ WrapPanel 13 | /// 14 | Default, 15 | /// 16 | /// one line first, auto start new line 17 | /// 18 | AutoWrap, 19 | 20 | /// 21 | /// one element in a row 22 | /// 23 | Vertical, 24 | 25 | /// 26 | /// always in one row 27 | /// 28 | Horizontal 29 | } 30 | 31 | /// 32 | /// set property display mode 33 | /// 34 | [AttributeUsage(AttributeTargets.Property|AttributeTargets.Field)] 35 | public class SelectableListDisplayModeAttribute : Attribute 36 | { 37 | /// 38 | /// display mode for checked list 39 | /// 40 | public readonly SelectableListDisplayMode DisplayMode; 41 | 42 | /// 43 | /// constructor 44 | /// 45 | /// 46 | public SelectableListDisplayModeAttribute(SelectableListDisplayMode displayMode) 47 | { 48 | DisplayMode = displayMode; 49 | } 50 | } -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/SingleSelectionModeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | // ReSharper disable UnusedAutoPropertyAccessor.Global 3 | 4 | namespace PropertyModels.ComponentModel; 5 | 6 | /// 7 | /// selection mode, used for normal enum type or ISelectableList 8 | /// 9 | public enum SingleSelectionMode 10 | { 11 | /// 12 | /// default 13 | /// 14 | Default, 15 | /// 16 | /// default/combobox 17 | /// 18 | ComboBox = Default, 19 | /// 20 | /// radio 21 | /// 22 | RadioButton, 23 | /// 24 | /// toggle button group 25 | /// 26 | ToggleButtonGroup 27 | } 28 | 29 | /// 30 | /// set select mode 31 | /// 32 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] 33 | public class SingleSelectionModeAttribute : Attribute 34 | { 35 | /// 36 | /// Mode 37 | /// 38 | public readonly SingleSelectionMode Mode; 39 | 40 | /// 41 | /// min width for each element 42 | /// 43 | public double ElementMinWidth { get; set; } 44 | 45 | /// 46 | /// min height for each element 47 | /// 48 | public double ElementMinHeight { get; set; } 49 | 50 | /// 51 | /// construct this instance 52 | /// 53 | /// 54 | public SingleSelectionModeAttribute(SingleSelectionMode mode) 55 | { 56 | Mode = mode; 57 | } 58 | } -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/TrackableAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | // ReSharper disable AutoPropertyCanBeMadeGetOnly.Global 3 | 4 | namespace PropertyModels.ComponentModel 5 | { 6 | /// 7 | /// Class TrackableAttribute. 8 | /// Implements the 9 | /// 10 | /// 11 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] 12 | public class TrackableAttribute : Attribute 13 | { 14 | /// 15 | /// The minimum 16 | /// 17 | public readonly double Minimum; 18 | 19 | /// 20 | /// The maximum 21 | /// 22 | public readonly double Maximum; 23 | 24 | /// 25 | /// Gets or sets the increment. 26 | /// 27 | /// The increment. 28 | public double Increment { get; set; } = 0.01; 29 | 30 | /// 31 | /// Gets or sets the format string. 32 | /// 33 | /// The format string. 34 | public string FormatString { get; set; } = "{0:0.00}"; 35 | 36 | /// 37 | /// Allow spin 38 | /// 39 | public bool AllowSpin { get; set; } = false; 40 | 41 | /// 42 | /// Show button spinner 43 | /// 44 | public bool ShowButtonSpinner { get; set; } = false; 45 | 46 | /// 47 | /// Initializes a new instance of the class. 48 | /// 49 | /// The minimum. 50 | /// The maximum. 51 | public TrackableAttribute(double min = 0, double max = 100) 52 | { 53 | Minimum = min; 54 | Maximum = max; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/UnitAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PropertyModels.ComponentModel 4 | { 5 | /// 6 | /// Class UnitAttribute. 7 | /// Implements the 8 | /// 9 | /// 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] 11 | public class UnitAttribute : Attribute 12 | { 13 | /// 14 | /// The unit 15 | /// 16 | public readonly string Unit; 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | /// The unit. 22 | public UnitAttribute(string unit) 23 | { 24 | Unit = unit; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Sources/PropertyModels/ComponentModel/WatermarkAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PropertyModels.ComponentModel 4 | { 5 | /// 6 | /// Class WatermarkAttribute. 7 | /// Implements the 8 | /// 9 | /// 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] 11 | public class WatermarkAttribute : Attribute 12 | { 13 | /// 14 | /// The watermark 15 | /// 16 | public readonly string Watermark; 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | /// The watermark. 22 | public WatermarkAttribute(string watermark) 23 | { 24 | Watermark = watermark; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/PropertyModels/Extensions/PropertyDescriptorExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace PropertyModels.Extensions; 2 | 3 | using System.ComponentModel; 4 | using System.Reflection; 5 | 6 | /// 7 | /// Extension class for s. 8 | /// 9 | public static class PropertyDescriptorExtensions 10 | { 11 | /// 12 | /// Determines whether [is expandable type] [the specified property]. 13 | /// 14 | /// The property. 15 | /// true if [is expandable type] [the specified property]; otherwise, false. 16 | public static bool IsExpandableType(this PropertyDescriptor property) 17 | { 18 | if (!property.PropertyType.IsClass) 19 | { 20 | return false; 21 | } 22 | 23 | var attr = property.GetCustomAttribute(); 24 | 25 | if (attr?.GetConverterType()!.IsChildOf() == true) 26 | { 27 | return true; 28 | } 29 | 30 | attr = property.PropertyType.GetCustomAttribute(); 31 | 32 | return attr?.GetConverterType()!.IsChildOf() == true; 33 | } 34 | } -------------------------------------------------------------------------------- /Sources/PropertyModels/Localization/ILocalizationService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using PropertyModels.ComponentModel; 4 | 5 | namespace PropertyModels.Localization 6 | { 7 | /// 8 | /// Interface ICultureData 9 | /// 10 | public interface ICultureData 11 | { 12 | /// 13 | /// Gets the culture. 14 | /// 15 | /// The culture. 16 | CultureInfo Culture { get; } 17 | 18 | /// 19 | /// Gets the path. 20 | /// 21 | /// The path. 22 | Uri Path { get; } 23 | 24 | /// 25 | /// Gets the with the specified key. 26 | /// 27 | /// The key. 28 | /// System.String. 29 | string this[string key] { get; } 30 | 31 | /// 32 | /// Gets a value indicating whether this instance is loaded. 33 | /// 34 | /// true if this instance is loaded; otherwise, false. 35 | bool IsLoaded { get; } 36 | 37 | /// 38 | /// Reloads this instance. 39 | /// 40 | /// true if reload success, false otherwise. 41 | bool Reload(); 42 | 43 | /// 44 | /// Unload all data, release memory 45 | /// 46 | void Unload(); 47 | } 48 | 49 | /// 50 | /// Interface ILocalizationService 51 | /// Implements the 52 | /// 53 | /// 54 | public interface ILocalizationService : IReactiveObject 55 | { 56 | /// 57 | /// Gets or sets the culture data. 58 | /// 59 | /// The culture data. 60 | ICultureData CultureData { get; } 61 | 62 | /// 63 | /// Gets the with the specified key. 64 | /// 65 | /// The key. 66 | /// System.String. 67 | string this[string key] { get; } 68 | 69 | /// 70 | /// Occurs when [on culture changed]. 71 | /// 72 | event EventHandler OnCultureChanged; 73 | 74 | /// 75 | /// Gets the extra services. 76 | /// 77 | /// ILocalizationService[]. 78 | ILocalizationService[] GetExtraServices(); 79 | 80 | /// 81 | /// Adds the extra service. 82 | /// 83 | /// The service. 84 | void AddExtraService(ILocalizationService service); 85 | 86 | /// 87 | /// Removes the extra service. 88 | /// 89 | /// The service. 90 | void RemoveExtraService(ILocalizationService service); 91 | 92 | /// 93 | /// Gets the cultures. 94 | /// 95 | /// ICultureData[]. 96 | ICultureData[] GetCultures(); 97 | 98 | /// 99 | /// Selects the culture. 100 | /// 101 | /// Name of the culture. 102 | void SelectCulture(string cultureName); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /Sources/PropertyModels/PropertyModels.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.1;net6.0;net8.0;net9.0 5 | preview 6 | bodong 7 | 11.3.0.21 8 | MIT 9 | True 10 | enable 11 | True 12 | bodong.$(AssemblyName) 13 | bodong.$(AssemblyName) 14 | Some simple object model class libraries, originally used in the Avalonia.PropertyGrid project, were later split into an independent package in order to achieve the separation of data and presentation. 15 | https://github.com/bodong1987/Avalonia.PropertyGrid 16 | https://github.com/bodong1987/Avalonia.PropertyGrid.git 17 | git 18 | Avalonia;PropertyGrid;AvaloniaControls;ObjectModel;ComponentModel 19 | README_PropertyModels.md 20 | Debug;Release;Development 21 | 22 | 23 | 24 | DEBUG;TRACE 25 | 26 | 27 | 28 | 29 | True 30 | \ 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Sources/README_NUGET.md: -------------------------------------------------------------------------------- 1 | # Avalonia.PropertyGrid 2 | This is a PropertyGrid implementation for Avalonia, you can use it in Avalonia Applications. 3 | Its main features are: 4 | * Support automatic analysis of class's Properties like DevExpress's PropertyGridControl and display and edit 5 | * Support simultaneous editing of multiple objects in one PropertyGrid 6 | * Support custom types that implement the ICustomTypeDescriptor interface or TypeDescriptionProvider 7 | * Support custom property label controls 8 | * Support custom property cell edit 9 | * Support for additional property operation areas and their custom operations 10 | * Support array editing, support for creating, inserting, deleting and clearing in the control 11 | * Support data verification 12 | * Support Built-in undo and redo framework 13 | * Support global `ReadOnly` setting 14 | * Support for automatically adjusting the visibility of properties based on conditions 15 | * Support path picking 16 | * Support three display modes: category-based, alphabetical sorting and builtin sorting 17 | * Support text filtering, regular expression filtering, and supports ignoring case settings 18 | * Support fast filtering by Category 19 | * Support data automatic reloading 20 | * Support automatic expansion of sub-objects 21 | * Support adjust the width of the property name and property value by drag the title 22 | * Support localization and realtime change language without restart 23 | * Support web 24 | * Depend on https://www.nuget.org/packages/bodong.PropertyModels 25 | 26 | Check more information here: https://github.com/bodong1987/Avalonia.PropertyGrid 27 | 28 | → View Online Demo: 29 | https://bodong1987.github.io/Avalonia.PropertyGrid/ 30 | 31 | 32 | # Avalonia.PropertyGrid中文说明 33 | 这是一个用于Avalonia的PropertyGrid实现,可以在Avalonia应用程序中使用。 34 | 其主要功能包括: 35 | * 支持自动分析类的属性(类似于DevExpress的PropertyGridControl)并显示和编辑 36 | * 支持在一个PropertyGrid中同时编辑多个对象 37 | * 支持实现ICustomTypeDescriptor接口或TypeDescriptionProvider的自定义类型 38 | * 支持自定义属性标签的控件 39 | * 支持自定义任意属性的栅格编辑器(Cell Edit) 40 | * 支持额外的属性操作区及其自定义操作 41 | * 支持数组编辑,支持数组在控件中创建、插入、删除和清除 42 | * 支持数据验证 43 | * 支持内置的撤销和重做框架 44 | * 支持全局`只读`设置 45 | * 支持根据条件自动调整属性的可见性 46 | * 支持文件路径选择 47 | * 支持三种显示模式:基于类别、按字母排序和内置排序 48 | * 支持文本过滤、正则表达式过滤,并支持忽略大小写设置 49 | * 支持按类别快速过滤 50 | * 支持数据自动重新加载 51 | * 支持子对象的自动展开 52 | * 支持通过拖动标题调整属性名称和属性值的宽度 53 | * 支持本地化和实时更改语言而无需重启 54 | * 支持Web 55 | 56 | 查看更多信息: https://github.com/bodong1987/Avalonia.PropertyGrid 57 | 58 | → 查看在线示例: 59 | https://bodong1987.github.io/Avalonia.PropertyGrid/ 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /Sources/README_PropertyModels.md: -------------------------------------------------------------------------------- 1 | # PropertyModels 2 | Some simple object model class libraries, originally used in the Avalonia.PropertyGrid project, were later split into an independent package in order to achieve the separation of data and presentation. 3 | 4 | Check more information here: 5 | https://github.com/bodong1987/Avalonia.PropertyGrid 6 | 7 | → View Online Demo: 8 | https://bodong1987.github.io/Avalonia.PropertyGrid/ 9 | 10 | -------------------------------------------------------------------------------- /UnitTests/Avalonia.PropertyGrid.UnitTests/Avalonia.PropertyGrid.UnitTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | 7 | false 8 | true 9 | disable 10 | preview 11 | Debug;Release;Development 12 | 13 | 14 | 15 | DEBUG;TRACE 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | all 24 | runtime; build; native; contentfiles; analyzers; buildtransitive 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /UnitTests/Avalonia.PropertyGrid.UnitTests/Usings.cs: -------------------------------------------------------------------------------- 1 | global using Microsoft.VisualStudio.TestTools.UnitTesting; -------------------------------------------------------------------------------- /publish-web.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM Save the current directory 3 | set "current_dir=%cd%" 4 | 5 | REM Navigate to the target directory 6 | cd /d "%current_dir%\Samples\Avalonia.PropertyGrid.Samples.Browser" 7 | 8 | REM Check for the --clean argument 9 | if "%1"=="--clean" ( 10 | echo Cleaning bin and obj directories... 11 | rd /s /q "bin" 12 | rd /s /q "obj" 13 | ) 14 | 15 | REM Execute the dotnet publish command 16 | dotnet publish 17 | 18 | REM Check if the publish was successful 19 | if %errorlevel% neq 0 ( 20 | echo Publish failed, exiting script. 21 | exit /b %errorlevel% 22 | ) 23 | 24 | REM Navigate to the publish directory 25 | cd /d "%current_dir%\Samples\Avalonia.PropertyGrid.Samples.Browser\bin\Release\net9.0-browser\publish\wwwroot" 26 | 27 | REM Recursively delete all .br and .gz files 28 | for /r %%i in (*.br *.gz) do del "%%i" 29 | 30 | REM Open the directory in Windows Explorer 31 | explorer . 32 | 33 | echo Operation completed. --------------------------------------------------------------------------------