├── .editorconfig
├── .gitattributes
├── .github
├── FUNDING.yml
├── stale.yml
└── workflows
│ └── build.yml
├── .gitignore
├── .nuke
├── build.schema.json
└── parameters.json
├── DataBox.sln
├── LICENSE.TXT
├── README.md
├── azure-pipelines.yml
├── build.cmd
├── build.ps1
├── build.sh
├── build
├── Avalonia.Desktop.props
├── Avalonia.Diagnostics.props
├── Avalonia.ReactiveUI.props
├── Avalonia.Themes.Fluent.props
├── Avalonia.props
├── Base.props
├── ReferenceAssemblies.props
├── SignAssembly.props
├── SourceLink.props
├── XUnit.props
├── build
│ ├── Build.cs
│ └── _build.csproj
└── databox.public.snk
├── global.json
├── nuget.config
├── samples
├── DataBoxDataVirtualizationDemo
│ ├── App.axaml
│ ├── App.axaml.cs
│ ├── DataBoxDataVirtualizationDemo.csproj
│ ├── MainWindow.axaml
│ ├── MainWindow.axaml.cs
│ ├── Program.cs
│ └── ViewModels
│ │ ├── ItemProvider.cs
│ │ ├── ItemViewModel.cs
│ │ ├── MainWindowViewModel.cs
│ │ └── ViewModelBase.cs
├── DataBoxDemo
│ ├── App.axaml
│ ├── App.axaml.cs
│ ├── DataBoxDemo.csproj
│ ├── MainWindow.axaml
│ ├── MainWindow.axaml.cs
│ ├── Program.cs
│ └── ViewModels
│ │ ├── ItemViewModel.cs
│ │ ├── MainWindowViewModel.cs
│ │ └── ViewModelBase.cs
├── VirtualPanelDemo.NetCore
│ ├── Assets
│ │ └── avalonia-logo.ico
│ ├── Program.cs
│ └── VirtualPanelDemo.NetCore.csproj
└── VirtualPanelDemo
│ ├── App.axaml
│ ├── App.axaml.cs
│ ├── MainView.axaml
│ ├── MainView.axaml.cs
│ ├── MainWindow.axaml
│ ├── MainWindow.axaml.cs
│ ├── ViewModels
│ ├── ItemProvider.cs
│ └── MainWindowViewModel.cs
│ └── VirtualPanelDemo.csproj
├── src
├── DataBox.DataVirtualization
│ ├── AsyncVirtualizingCollection.cs
│ ├── DataBox.DataVirtualization.csproj
│ ├── DataPage.cs
│ ├── DataWrapper.cs
│ ├── IItemsProvider.cs
│ ├── LICENSE
│ ├── README.txt
│ └── VirtualizingCollection.cs
├── DataBox
│ ├── Automation
│ │ └── Peers
│ │ │ ├── DataBoxAutomationPeer.cs
│ │ │ ├── DataBoxCellAutomationPeer.cs
│ │ │ ├── DataBoxColumnHeaderAutomationPeer.cs
│ │ │ ├── DataBoxColumnHeadersPresenterAutomationPeer.cs
│ │ │ └── DataBoxRowAutomationPeer.cs
│ ├── Columns
│ │ ├── DataBoxAutoCompleteColumn.cs
│ │ ├── DataBoxBoundColumn.cs
│ │ ├── DataBoxButtonColumn.cs
│ │ ├── DataBoxCheckBoxColumn.cs
│ │ ├── DataBoxContentColumn.cs
│ │ ├── DataBoxDateColumn.cs
│ │ ├── DataBoxEntryColumn.cs
│ │ ├── DataBoxItemsColumn.cs
│ │ ├── DataBoxLabelColumn.cs
│ │ ├── DataBoxNumericColumn.cs
│ │ ├── DataBoxProgressColumn.cs
│ │ ├── DataBoxRangeColumn.cs
│ │ ├── DataBoxSliderColumn.cs
│ │ ├── DataBoxSwitchColumn.cs
│ │ ├── DataBoxTemplateColumn.cs
│ │ ├── DataBoxTextColumn.cs
│ │ ├── DataBoxTimeColumn.cs
│ │ └── DataBoxToggleColumn.cs
│ ├── Controls
│ │ └── DataBoxPanel.cs
│ ├── DataBox.cs
│ ├── DataBox.csproj
│ ├── DataBoxCell.cs
│ ├── DataBoxColumn.cs
│ ├── DataBoxColumnHeader.cs
│ ├── DataBoxGridLinesVisibility.cs
│ ├── DataBoxRow.cs
│ ├── Primitives
│ │ ├── ActionObserver.cs
│ │ ├── DataBoxCellsPresenter.cs
│ │ ├── DataBoxColumnHeadersPresenter.cs
│ │ ├── DataBoxRowsPresenter.cs
│ │ └── Layout
│ │ │ ├── DataBoxCellsLayout.cs
│ │ │ └── DataBoxRowsLayout.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── Themes
│ │ ├── Accents
│ │ └── Fluent.axaml
│ │ ├── Controls
│ │ ├── DataBox.axaml
│ │ ├── DataBoxCell.axaml
│ │ ├── DataBoxCellsPresenter.axaml
│ │ ├── DataBoxColumnHeader.axaml
│ │ ├── DataBoxColumnHeadersPresenter.axaml
│ │ ├── DataBoxPanel.axaml
│ │ ├── DataBoxRow.axaml
│ │ └── DataBoxRowsPresenter.axaml
│ │ ├── DataBoxFluentTheme.axaml
│ │ └── DataBoxFluentTheme.axaml.cs
└── VirtualPanel
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── VirtualPanel.cs
│ └── VirtualPanel.csproj
└── tests
└── DataBox.UnitTests
├── DataBox.UnitTests.csproj
└── Properties
└── AssemblyInfo.cs
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | # Default settings:
7 | # A newline ending every file
8 | # Use 4 spaces as indentation
9 | [*]
10 | insert_final_newline = true
11 | indent_style = space
12 | indent_size = 4
13 |
14 | # C# files
15 | [*.cs]
16 | # New line preferences
17 | csharp_new_line_before_open_brace = all
18 | csharp_new_line_before_else = true
19 | csharp_new_line_before_catch = true
20 | csharp_new_line_before_finally = true
21 | csharp_new_line_before_members_in_object_initializers = true
22 | csharp_new_line_before_members_in_anonymous_types = true
23 | csharp_new_line_between_query_expression_clauses = true
24 |
25 | # Indentation preferences
26 | csharp_indent_block_contents = true
27 | csharp_indent_braces = false
28 | csharp_indent_case_contents = true
29 | csharp_indent_switch_labels = true
30 | csharp_indent_labels = one_less_than_current
31 |
32 | # avoid this. unless absolutely necessary
33 | dotnet_style_qualification_for_field = false:suggestion
34 | dotnet_style_qualification_for_property = false:suggestion
35 | dotnet_style_qualification_for_method = false:suggestion
36 | dotnet_style_qualification_for_event = false:suggestion
37 |
38 | # prefer var
39 | csharp_style_var_for_built_in_types = true
40 | csharp_style_var_when_type_is_apparent = true
41 | csharp_style_var_elsewhere = true:suggestion
42 |
43 | # use language keywords instead of BCL types
44 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
45 | dotnet_style_predefined_type_for_member_access = true:suggestion
46 |
47 | # name all constant fields using PascalCase
48 | dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
49 | dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
50 | dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
51 |
52 | dotnet_naming_symbols.constant_fields.applicable_kinds = field
53 | dotnet_naming_symbols.constant_fields.required_modifiers = const
54 |
55 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case
56 |
57 | # static fields should have s_ prefix
58 | dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion
59 | dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields
60 | dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style
61 |
62 | dotnet_naming_symbols.static_fields.applicable_kinds = field
63 | dotnet_naming_symbols.static_fields.required_modifiers = static
64 |
65 | dotnet_naming_style.static_prefix_style.required_prefix = s_
66 | dotnet_naming_style.static_prefix_style.capitalization = camel_case
67 |
68 | # internal and private fields should be _camelCase
69 | dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
70 | dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
71 | dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
72 |
73 | dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
74 | dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
75 |
76 | dotnet_naming_style.camel_case_underscore_style.required_prefix = _
77 | dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
78 |
79 | # use accessibility modifiers
80 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
81 |
82 | # Code style defaults
83 | dotnet_sort_system_directives_first = true
84 | csharp_preserve_single_line_blocks = true
85 | csharp_preserve_single_line_statements = false
86 |
87 | # Expression-level preferences
88 | dotnet_style_object_initializer = true:suggestion
89 | dotnet_style_collection_initializer = true:suggestion
90 | dotnet_style_explicit_tuple_names = true:suggestion
91 | dotnet_style_coalesce_expression = true:suggestion
92 | dotnet_style_null_propagation = true:suggestion
93 |
94 | # Expression-bodied members
95 | csharp_style_expression_bodied_methods = false:none
96 | csharp_style_expression_bodied_constructors = false:none
97 | csharp_style_expression_bodied_operators = false:none
98 | csharp_style_expression_bodied_properties = true:none
99 | csharp_style_expression_bodied_indexers = true:none
100 | csharp_style_expression_bodied_accessors = true:none
101 |
102 | # Pattern matching
103 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
104 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
105 | csharp_style_inlined_variable_declaration = true:suggestion
106 |
107 | # Null checking preferences
108 | csharp_style_throw_expression = true:suggestion
109 | csharp_style_conditional_delegate_call = true:suggestion
110 |
111 | # Space preferences
112 | csharp_space_after_cast = false
113 | csharp_space_after_colon_in_inheritance_clause = true
114 | csharp_space_after_comma = true
115 | csharp_space_after_dot = false
116 | csharp_space_after_keywords_in_control_flow_statements = true
117 | csharp_space_after_semicolon_in_for_statement = true
118 | csharp_space_around_binary_operators = before_and_after
119 | csharp_space_around_declaration_statements = do_not_ignore
120 | csharp_space_before_colon_in_inheritance_clause = true
121 | csharp_space_before_comma = false
122 | csharp_space_before_dot = false
123 | csharp_space_before_open_square_brackets = false
124 | csharp_space_before_semicolon_in_for_statement = false
125 | csharp_space_between_empty_square_brackets = false
126 | csharp_space_between_method_call_empty_parameter_list_parentheses = false
127 | csharp_space_between_method_call_name_and_opening_parenthesis = false
128 | csharp_space_between_method_call_parameter_list_parentheses = false
129 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
130 | csharp_space_between_method_declaration_name_and_open_parenthesis = false
131 | csharp_space_between_method_declaration_parameter_list_parentheses = false
132 | csharp_space_between_parentheses = false
133 | csharp_space_between_square_brackets = false
134 |
135 | # Xaml files
136 | [*.{xaml,axaml}]
137 | indent_style = space
138 | indent_size = 2
139 |
140 | # Xml project files
141 | [*.{csproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}]
142 | indent_size = 2
143 |
144 | # Xml build files
145 | [*.builds]
146 | indent_size = 2
147 |
148 | # Xml files
149 | [*.{xml,stylecop,resx,ruleset}]
150 | indent_size = 2
151 |
152 | # Xml config files
153 | [*.{props,targets,config,nuspec}]
154 | indent_size = 2
155 |
156 | # Shell scripts
157 | [*.sh]
158 | end_of_line = lf
159 | [*.{cmd, bat}]
160 | end_of_line = crlf
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [wieslawsoltes]
2 |
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | # https://probot.github.io/apps/stale/
2 |
3 | # Number of days of inactivity before an issue becomes stale
4 | daysUntilStale: 60
5 |
6 | # Number of days of inactivity before a stale issue is closed
7 | daysUntilClose: 7
8 |
9 | # Issues with these labels will never be considered stale
10 | exemptLabels:
11 | - pinned
12 | - security
13 |
14 | # Label to use when marking an issue as stale
15 | staleLabel: stale
16 |
17 | # Comment to post when marking an issue as stale. Set to `false` to disable
18 | markComment: >
19 | This issue has been automatically marked as stale because it has not had
20 | recent activity. It will be closed if no further activity occurs. Thank you
21 | for your contributions.
22 |
23 | # Comment to post when closing a stale issue. Set to `false` to disable
24 | closeComment: true
25 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | - release/*
8 | pull_request:
9 | branches:
10 | - main
11 |
12 | jobs:
13 | build:
14 | strategy:
15 | matrix:
16 | os: [ubuntu-latest, windows-latest, macos-latest]
17 | name: Build ${{ matrix.os }}
18 | runs-on: ${{ matrix.os }}
19 |
20 | steps:
21 | - uses: actions/checkout@v1
22 | - name: Setup .NET Core
23 | uses: actions/setup-dotnet@v1
24 | - name: Install wasm-tools
25 | run: dotnet workload install wasm-tools
26 | - name: Build Release
27 | run: dotnet build --configuration Release
28 | - name: Test Release
29 | run: dotnet test --configuration Release
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
289 |
--------------------------------------------------------------------------------
/.nuke/build.schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-04/schema#",
3 | "title": "Build Schema",
4 | "$ref": "#/definitions/build",
5 | "definitions": {
6 | "build": {
7 | "type": "object",
8 | "properties": {
9 | "Configuration": {
10 | "type": "string",
11 | "description": "configuration"
12 | },
13 | "Continue": {
14 | "type": "boolean",
15 | "description": "Indicates to continue a previously failed build attempt"
16 | },
17 | "Help": {
18 | "type": "boolean",
19 | "description": "Shows the help text for this build assembly"
20 | },
21 | "Host": {
22 | "type": "string",
23 | "description": "Host for execution. Default is 'automatic'",
24 | "enum": [
25 | "AppVeyor",
26 | "AzurePipelines",
27 | "Bamboo",
28 | "Bitrise",
29 | "GitHubActions",
30 | "GitLab",
31 | "Jenkins",
32 | "Rider",
33 | "SpaceAutomation",
34 | "TeamCity",
35 | "Terminal",
36 | "TravisCI",
37 | "VisualStudio",
38 | "VSCode"
39 | ]
40 | },
41 | "NoLogo": {
42 | "type": "boolean",
43 | "description": "Disables displaying the NUKE logo"
44 | },
45 | "Partition": {
46 | "type": "string",
47 | "description": "Partition to use on CI"
48 | },
49 | "Plan": {
50 | "type": "boolean",
51 | "description": "Shows the execution plan (HTML)"
52 | },
53 | "Profile": {
54 | "type": "array",
55 | "description": "Defines the profiles to load",
56 | "items": {
57 | "type": "string"
58 | }
59 | },
60 | "PublishFramework": {
61 | "type": "string",
62 | "description": "publish-framework"
63 | },
64 | "PublishProject": {
65 | "type": "string",
66 | "description": "publish-project"
67 | },
68 | "PublishRuntime": {
69 | "type": "string",
70 | "description": "publish-runtime"
71 | },
72 | "PublishSelfContained": {
73 | "type": "boolean",
74 | "description": "publish-self-contained"
75 | },
76 | "Root": {
77 | "type": "string",
78 | "description": "Root directory during build execution"
79 | },
80 | "Skip": {
81 | "type": "array",
82 | "description": "List of targets to be skipped. Empty list skips all dependencies",
83 | "items": {
84 | "type": "string",
85 | "enum": [
86 | "Clean",
87 | "Compile",
88 | "Pack",
89 | "Publish",
90 | "Restore",
91 | "Test"
92 | ]
93 | }
94 | },
95 | "Solution": {
96 | "type": "string",
97 | "description": "Path to a solution file that is automatically loaded"
98 | },
99 | "Target": {
100 | "type": "array",
101 | "description": "List of targets to be invoked. Default is '{default_target}'",
102 | "items": {
103 | "type": "string",
104 | "enum": [
105 | "Clean",
106 | "Compile",
107 | "Pack",
108 | "Publish",
109 | "Restore",
110 | "Test"
111 | ]
112 | }
113 | },
114 | "Verbosity": {
115 | "type": "string",
116 | "description": "Logging verbosity during build execution. Default is 'Normal'",
117 | "enum": [
118 | "Minimal",
119 | "Normal",
120 | "Quiet",
121 | "Verbose"
122 | ]
123 | },
124 | "VersionSuffix": {
125 | "type": "string",
126 | "description": "version-suffix"
127 | }
128 | }
129 | }
130 | }
131 | }
--------------------------------------------------------------------------------
/.nuke/parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./build.schema.json",
3 | "Solution": "DataBox.sln"
4 | }
--------------------------------------------------------------------------------
/DataBox.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataBoxDemo", "samples\DataBoxDemo\DataBoxDemo.csproj", "{D9D964C6-72D8-4009-910D-6DA99BA9D30F}"
4 | EndProject
5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataBox", "src\DataBox\DataBox.csproj", "{00120A66-65E2-4D26-A117-51BA40C2F844}"
6 | EndProject
7 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{BFAAFDC6-9A28-4F70-9C21-F6DF50786C70}"
8 | ProjectSection(SolutionItems) = preProject
9 | .editorconfig = .editorconfig
10 | azure-pipelines.yml = azure-pipelines.yml
11 | build.ps1 = build.ps1
12 | build.sh = build.sh
13 | global.json = global.json
14 | build\databox.public.snk = build\databox.public.snk
15 | EndProjectSection
16 | EndProject
17 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "git", "git", "{17E6165A-4614-435A-8BBE-55A8C850F21B}"
18 | ProjectSection(SolutionItems) = preProject
19 | .gitattributes = .gitattributes
20 | .gitignore = .gitignore
21 | EndProjectSection
22 | EndProject
23 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuget", "nuget", "{94B631C1-E35B-462E-8D52-90BF04F72ECB}"
24 | ProjectSection(SolutionItems) = preProject
25 | nuget.config = nuget.config
26 | EndProjectSection
27 | EndProject
28 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "props", "props", "{BFAD5779-6E04-463F-9A38-6D78CEFC6E09}"
29 | ProjectSection(SolutionItems) = preProject
30 | build\Avalonia.Desktop.props = build\Avalonia.Desktop.props
31 | build\Avalonia.Diagnostics.props = build\Avalonia.Diagnostics.props
32 | build\Avalonia.props = build\Avalonia.props
33 | build\Avalonia.ReactiveUI.props = build\Avalonia.ReactiveUI.props
34 | build\Base.props = build\Base.props
35 | build\ReferenceAssemblies.props = build\ReferenceAssemblies.props
36 | build\SignAssembly.props = build\SignAssembly.props
37 | build\SourceLink.props = build\SourceLink.props
38 | build\XUnit.props = build\XUnit.props
39 | build\Avalonia.Themes.Fluent.props = build\Avalonia.Themes.Fluent.props
40 | EndProjectSection
41 | EndProject
42 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{4E19FF9C-17EE-4AFA-9317-7C949FB3C66A}"
43 | ProjectSection(SolutionItems) = preProject
44 | LICENSE.TXT = LICENSE.TXT
45 | README.md = README.md
46 | EndProjectSection
47 | EndProject
48 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{3B564AD4-C507-43DC-8711-38320FB3B679}"
49 | EndProject
50 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D7275F04-303E-4385-B806-08726C572D6D}"
51 | EndProject
52 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{491007E3-8E11-4236-A724-ED7AC78FF726}"
53 | EndProject
54 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataBox.UnitTests", "tests\DataBox.UnitTests\DataBox.UnitTests.csproj", "{85FA5761-009D-4072-9C86-7CCFE1B14CE3}"
55 | EndProject
56 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_build", "build\build\_build.csproj", "{185AA19E-8CAC-4539-BD28-8199E348AC40}"
57 | EndProject
58 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataBox.DataVirtualization", "src\DataBox.DataVirtualization\DataBox.DataVirtualization.csproj", "{8AD8D915-14C1-49E5-AB33-792C63DF2379}"
59 | EndProject
60 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataBoxDataVirtualizationDemo", "samples\DataBoxDataVirtualizationDemo\DataBoxDataVirtualizationDemo.csproj", "{51696845-5450-4A14-9368-E1063B6B14B5}"
61 | EndProject
62 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPanel", "src\VirtualPanel\VirtualPanel.csproj", "{2C2535BC-38DB-4FFF-BD30-ABAED465E7D7}"
63 | EndProject
64 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPanelDemo.NetCore", "samples\VirtualPanelDemo.NetCore\VirtualPanelDemo.NetCore.csproj", "{7396717D-036A-4F90-9120-4755F44C6310}"
65 | EndProject
66 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPanelDemo", "samples\VirtualPanelDemo\VirtualPanelDemo.csproj", "{CBA4D84C-45CC-4E37-9E16-F95E1CEF5DC4}"
67 | EndProject
68 | Global
69 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
70 | Debug|Any CPU = Debug|Any CPU
71 | Release|Any CPU = Release|Any CPU
72 | EndGlobalSection
73 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
74 | {D9D964C6-72D8-4009-910D-6DA99BA9D30F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
75 | {D9D964C6-72D8-4009-910D-6DA99BA9D30F}.Debug|Any CPU.Build.0 = Debug|Any CPU
76 | {D9D964C6-72D8-4009-910D-6DA99BA9D30F}.Release|Any CPU.ActiveCfg = Release|Any CPU
77 | {D9D964C6-72D8-4009-910D-6DA99BA9D30F}.Release|Any CPU.Build.0 = Release|Any CPU
78 | {00120A66-65E2-4D26-A117-51BA40C2F844}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
79 | {00120A66-65E2-4D26-A117-51BA40C2F844}.Debug|Any CPU.Build.0 = Debug|Any CPU
80 | {00120A66-65E2-4D26-A117-51BA40C2F844}.Release|Any CPU.ActiveCfg = Release|Any CPU
81 | {00120A66-65E2-4D26-A117-51BA40C2F844}.Release|Any CPU.Build.0 = Release|Any CPU
82 | {85FA5761-009D-4072-9C86-7CCFE1B14CE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
83 | {85FA5761-009D-4072-9C86-7CCFE1B14CE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
84 | {85FA5761-009D-4072-9C86-7CCFE1B14CE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
85 | {85FA5761-009D-4072-9C86-7CCFE1B14CE3}.Release|Any CPU.Build.0 = Release|Any CPU
86 | {185AA19E-8CAC-4539-BD28-8199E348AC40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
87 | {185AA19E-8CAC-4539-BD28-8199E348AC40}.Debug|Any CPU.Build.0 = Debug|Any CPU
88 | {185AA19E-8CAC-4539-BD28-8199E348AC40}.Release|Any CPU.ActiveCfg = Release|Any CPU
89 | {185AA19E-8CAC-4539-BD28-8199E348AC40}.Release|Any CPU.Build.0 = Release|Any CPU
90 | {8AD8D915-14C1-49E5-AB33-792C63DF2379}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
91 | {8AD8D915-14C1-49E5-AB33-792C63DF2379}.Debug|Any CPU.Build.0 = Debug|Any CPU
92 | {8AD8D915-14C1-49E5-AB33-792C63DF2379}.Release|Any CPU.ActiveCfg = Release|Any CPU
93 | {8AD8D915-14C1-49E5-AB33-792C63DF2379}.Release|Any CPU.Build.0 = Release|Any CPU
94 | {51696845-5450-4A14-9368-E1063B6B14B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
95 | {51696845-5450-4A14-9368-E1063B6B14B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
96 | {51696845-5450-4A14-9368-E1063B6B14B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
97 | {51696845-5450-4A14-9368-E1063B6B14B5}.Release|Any CPU.Build.0 = Release|Any CPU
98 | {2C2535BC-38DB-4FFF-BD30-ABAED465E7D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
99 | {2C2535BC-38DB-4FFF-BD30-ABAED465E7D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
100 | {2C2535BC-38DB-4FFF-BD30-ABAED465E7D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
101 | {2C2535BC-38DB-4FFF-BD30-ABAED465E7D7}.Release|Any CPU.Build.0 = Release|Any CPU
102 | {7396717D-036A-4F90-9120-4755F44C6310}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
103 | {7396717D-036A-4F90-9120-4755F44C6310}.Debug|Any CPU.Build.0 = Debug|Any CPU
104 | {7396717D-036A-4F90-9120-4755F44C6310}.Release|Any CPU.ActiveCfg = Release|Any CPU
105 | {7396717D-036A-4F90-9120-4755F44C6310}.Release|Any CPU.Build.0 = Release|Any CPU
106 | {CBA4D84C-45CC-4E37-9E16-F95E1CEF5DC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
107 | {CBA4D84C-45CC-4E37-9E16-F95E1CEF5DC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
108 | {CBA4D84C-45CC-4E37-9E16-F95E1CEF5DC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
109 | {CBA4D84C-45CC-4E37-9E16-F95E1CEF5DC4}.Release|Any CPU.Build.0 = Release|Any CPU
110 | EndGlobalSection
111 | GlobalSection(NestedProjects) = preSolution
112 | {17E6165A-4614-435A-8BBE-55A8C850F21B} = {BFAAFDC6-9A28-4F70-9C21-F6DF50786C70}
113 | {94B631C1-E35B-462E-8D52-90BF04F72ECB} = {BFAAFDC6-9A28-4F70-9C21-F6DF50786C70}
114 | {BFAD5779-6E04-463F-9A38-6D78CEFC6E09} = {BFAAFDC6-9A28-4F70-9C21-F6DF50786C70}
115 | {D9D964C6-72D8-4009-910D-6DA99BA9D30F} = {3B564AD4-C507-43DC-8711-38320FB3B679}
116 | {00120A66-65E2-4D26-A117-51BA40C2F844} = {D7275F04-303E-4385-B806-08726C572D6D}
117 | {85FA5761-009D-4072-9C86-7CCFE1B14CE3} = {491007E3-8E11-4236-A724-ED7AC78FF726}
118 | {185AA19E-8CAC-4539-BD28-8199E348AC40} = {BFAAFDC6-9A28-4F70-9C21-F6DF50786C70}
119 | {8AD8D915-14C1-49E5-AB33-792C63DF2379} = {D7275F04-303E-4385-B806-08726C572D6D}
120 | {51696845-5450-4A14-9368-E1063B6B14B5} = {3B564AD4-C507-43DC-8711-38320FB3B679}
121 | {2C2535BC-38DB-4FFF-BD30-ABAED465E7D7} = {D7275F04-303E-4385-B806-08726C572D6D}
122 | {7396717D-036A-4F90-9120-4755F44C6310} = {3B564AD4-C507-43DC-8711-38320FB3B679}
123 | {CBA4D84C-45CC-4E37-9E16-F95E1CEF5DC4} = {3B564AD4-C507-43DC-8711-38320FB3B679}
124 | EndGlobalSection
125 | EndGlobal
126 |
--------------------------------------------------------------------------------
/LICENSE.TXT:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Wiesław Šoltés
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DataBox
2 |
3 | [](https://dev.azure.com/wieslawsoltes/GitHub/_build/latest?definitionId=103&repoName=wieslawsoltes%2FDataBox&branchName=main)
4 | [](https://github.com/wieslawsoltes/DataBox/actions/workflows/build.yml)
5 |
6 | [](https://www.nuget.org/packages/DataBox)
7 | [](https://www.nuget.org/packages/DataBox)
8 |
9 | A DataGrid control based on ListBox control.
10 |
11 | 
12 |
13 | ## Building DataBox
14 |
15 | First, clone the repository or download the latest zip.
16 | ```
17 | git clone https://github.com/wieslawsoltes/DataBox.git
18 | ```
19 |
20 | ### Build on Windows using script
21 |
22 | * [.NET Core](https://www.microsoft.com/net/download?initial-os=windows).
23 |
24 | Open up a command-prompt and execute the commands:
25 | ```
26 | .\build.ps1
27 | ```
28 |
29 | ### Build on Linux using script
30 |
31 | * [.NET Core](https://www.microsoft.com/net/download?initial-os=linux).
32 |
33 | Open up a terminal prompt and execute the commands:
34 | ```
35 | ./build.sh
36 | ```
37 |
38 | ### Build on OSX using script
39 |
40 | * [.NET Core](https://www.microsoft.com/net/download?initial-os=macos).
41 |
42 | Open up a terminal prompt and execute the commands:
43 | ```
44 | ./build.sh
45 | ```
46 |
47 | ## NuGet
48 |
49 | DataBox is delivered as a NuGet package.
50 |
51 | You can find the packages here [NuGet](https://www.nuget.org/packages/DataBox/) and install the package like this:
52 |
53 | `Install-Package DataBox`
54 |
55 | ### Package Sources
56 |
57 | * https://api.nuget.org/v3/index.json
58 | * https://www.myget.org/F/avalonia-ci/api/v2
59 |
60 | ## Resources
61 |
62 | * [GitHub source code repository.](https://github.com/wieslawsoltes/DataBox)
63 |
64 | ## License
65 |
66 | DataBox is licensed under the [MIT license](LICENSE.TXT).
67 |
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | name: $(date:yyyyMMdd)$(rev:-rr)
2 |
3 | resources:
4 | repositories:
5 | - repository: templates
6 | endpoint: wieslawsoltes
7 | type: github
8 | name: wieslawsoltes/BuildTemplates
9 | ref: refs/tags/v2.0.0
10 |
11 | variables:
12 | BuildConfiguration: 'Release'
13 | BuildPlatform: 'Any CPU'
14 | PublishFramework: 'net9.0'
15 | PublishProject: 'DataBoxDemo'
16 | PublishRuntime: ''
17 |
18 | jobs:
19 | - template: Test-PowerShell.yml@templates
20 | parameters:
21 | name: 'Test_Windows'
22 | vmImage: 'windows-2022'
23 | BuildConfiguration: ${{ variables.BuildConfiguration }}
24 |
25 | - template: Test-Bash.yml@templates
26 | parameters:
27 | name: 'Test_Linux'
28 | vmImage: 'ubuntu-20.04'
29 | BuildConfiguration: ${{ variables.BuildConfiguration }}
30 |
31 | - template: Test-Bash.yml@templates
32 | parameters:
33 | name: 'Test_macOS'
34 | vmImage: 'macOS-14'
35 | BuildConfiguration: ${{ variables.BuildConfiguration }}
36 |
37 | - template: Pack-MyGet.yml@templates
38 | parameters:
39 | name: 'Pack_MyGet'
40 | vmImage: 'windows-2022'
41 | BuildConfiguration: ${{ variables.BuildConfiguration }}
42 |
43 | - template: Pack-NuGet.yml@templates
44 | parameters:
45 | name: 'Pack_NuGet'
46 | vmImage: 'windows-2022'
47 | BuildConfiguration: ${{ variables.BuildConfiguration }}
48 |
--------------------------------------------------------------------------------
/build.cmd:
--------------------------------------------------------------------------------
1 | :; set -eo pipefail
2 | :; SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
3 | :; ${SCRIPT_DIR}/build.sh "$@"
4 | :; exit $?
5 |
6 | @ECHO OFF
7 | powershell -ExecutionPolicy ByPass -NoProfile -File "%~dp0build.ps1" %*
8 |
--------------------------------------------------------------------------------
/build.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding()]
2 | Param(
3 | [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
4 | [string[]]$BuildArguments
5 | )
6 |
7 | Write-Output "PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)"
8 |
9 | Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { Write-Error $_ -ErrorAction Continue; exit 1 }
10 | $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
11 |
12 | ###########################################################################
13 | # CONFIGURATION
14 | ###########################################################################
15 |
16 | $BuildProjectFile = "$PSScriptRoot\build\build\_build.csproj"
17 | $TempDirectory = "$PSScriptRoot\\.nuke\temp"
18 |
19 | $DotNetGlobalFile = "$PSScriptRoot\\global.json"
20 | $DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1"
21 | $DotNetChannel = "Current"
22 |
23 | $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1
24 | $env:DOTNET_CLI_TELEMETRY_OPTOUT = 1
25 | $env:DOTNET_MULTILEVEL_LOOKUP = 0
26 |
27 | ###########################################################################
28 | # EXECUTION
29 | ###########################################################################
30 |
31 | function ExecSafe([scriptblock] $cmd) {
32 | & $cmd
33 | if ($LASTEXITCODE) { exit $LASTEXITCODE }
34 | }
35 |
36 | # If dotnet CLI is installed globally and it matches requested version, use for execution
37 | if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and `
38 | $(dotnet --version) -and $LASTEXITCODE -eq 0) {
39 | $env:DOTNET_EXE = (Get-Command "dotnet").Path
40 | }
41 | else {
42 | # Download install script
43 | $DotNetInstallFile = "$TempDirectory\dotnet-install.ps1"
44 | New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null
45 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
46 | (New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile)
47 |
48 | # If global.json exists, load expected version
49 | if (Test-Path $DotNetGlobalFile) {
50 | $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json)
51 | if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) {
52 | $DotNetVersion = $DotNetGlobal.sdk.version
53 | }
54 | }
55 |
56 | # Install by channel or version
57 | $DotNetDirectory = "$TempDirectory\dotnet-win"
58 | if (!(Test-Path variable:DotNetVersion)) {
59 | ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }
60 | } else {
61 | ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }
62 | }
63 | $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
64 | }
65 |
66 | Write-Output "Microsoft (R) .NET Core SDK version $(& $env:DOTNET_EXE --version)"
67 |
68 | ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet }
69 | ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments }
70 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | bash --version 2>&1 | head -n 1
4 |
5 | set -eo pipefail
6 | SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
7 |
8 | ###########################################################################
9 | # CONFIGURATION
10 | ###########################################################################
11 |
12 | BUILD_PROJECT_FILE="$SCRIPT_DIR/build/build/_build.csproj"
13 | TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp"
14 |
15 | DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json"
16 | DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh"
17 | DOTNET_CHANNEL="Current"
18 |
19 | export DOTNET_CLI_TELEMETRY_OPTOUT=1
20 | export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
21 | export DOTNET_MULTILEVEL_LOOKUP=0
22 |
23 | ###########################################################################
24 | # EXECUTION
25 | ###########################################################################
26 |
27 | function FirstJsonValue {
28 | perl -nle 'print $1 if m{"'"$1"'": "([^"]+)",?}' <<< "${@:2}"
29 | }
30 |
31 | # If dotnet CLI is installed globally and it matches requested version, use for execution
32 | if [ -x "$(command -v dotnet)" ] && dotnet --version &>/dev/null; then
33 | export DOTNET_EXE="$(command -v dotnet)"
34 | else
35 | # Download install script
36 | DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh"
37 | mkdir -p "$TEMP_DIRECTORY"
38 | curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL"
39 | chmod +x "$DOTNET_INSTALL_FILE"
40 |
41 | # If global.json exists, load expected version
42 | if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then
43 | DOTNET_VERSION=$(FirstJsonValue "version" "$(cat "$DOTNET_GLOBAL_FILE")")
44 | if [[ "$DOTNET_VERSION" == "" ]]; then
45 | unset DOTNET_VERSION
46 | fi
47 | fi
48 |
49 | # Install by channel or version
50 | DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix"
51 | if [[ -z ${DOTNET_VERSION+x} ]]; then
52 | "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path
53 | else
54 | "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path
55 | fi
56 | export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet"
57 | fi
58 |
59 | echo "Microsoft (R) .NET Core SDK version $("$DOTNET_EXE" --version)"
60 |
61 | "$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet
62 | "$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@"
63 |
--------------------------------------------------------------------------------
/build/Avalonia.Desktop.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/build/Avalonia.Diagnostics.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/build/Avalonia.ReactiveUI.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/build/Avalonia.Themes.Fluent.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/build/Avalonia.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/build/Base.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | 11.2.0
4 |
5 | Wiesław Šoltés
6 | Wiesław Šoltés
7 | Copyright © Wiesław Šoltés 2024
8 | MIT
9 | https://github.com/wieslawsoltes/DataBox
10 |
11 |
12 | latest
13 | preview
14 |
15 |
16 |
--------------------------------------------------------------------------------
/build/ReferenceAssemblies.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/build/SignAssembly.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | True
5 | $(MSBuildThisFileDirectory)\databox.public.snk
6 | false
7 | true
8 |
9 |
10 |
--------------------------------------------------------------------------------
/build/SourceLink.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 | false
5 | true
6 | embedded
7 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
8 |
9 |
10 | true
11 |
12 |
13 | true
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/build/XUnit.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/build/build/Build.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Nuke.Common;
3 | using Nuke.Common.Git;
4 | using Nuke.Common.ProjectModel;
5 | using Nuke.Common.Tools.DotNet;
6 | using Nuke.Common.IO;
7 | using static Nuke.Common.IO.FileSystemTasks;
8 | using static Nuke.Common.IO.PathConstruction;
9 | using static Nuke.Common.Tools.DotNet.DotNetTasks;
10 |
11 | class Build : NukeBuild
12 | {
13 | public static int Main() => Execute(x => x.Compile);
14 |
15 | [Solution]
16 | readonly Solution Solution;
17 |
18 | [GitRepository]
19 | readonly GitRepository GitRepository;
20 |
21 | [Parameter("configuration")]
22 | public string Configuration { get; set; }
23 |
24 | [Parameter("version-suffix")]
25 | public string VersionSuffix { get; set; }
26 |
27 | [Parameter("publish-framework")]
28 | public string PublishFramework { get; set; }
29 |
30 | [Parameter("publish-runtime")]
31 | public string PublishRuntime { get; set; }
32 |
33 | [Parameter("publish-project")]
34 | public string PublishProject { get; set; }
35 |
36 | [Parameter("publish-self-contained")]
37 | public bool PublishSelfContained { get; set; } = true;
38 |
39 | AbsolutePath SourceDirectory => RootDirectory / "src";
40 |
41 | AbsolutePath TestsDirectory => RootDirectory / "tests";
42 |
43 | AbsolutePath ArtifactsDirectory => RootDirectory / "artifacts";
44 |
45 | protected override void OnBuildInitialized()
46 | {
47 | Configuration = Configuration ?? "Release";
48 | VersionSuffix = VersionSuffix ?? "";
49 | }
50 |
51 | private void DeleteDirectories(IReadOnlyCollection directories)
52 | {
53 | foreach (var directory in directories)
54 | {
55 | DeleteDirectory(directory);
56 | }
57 | }
58 |
59 | Target Clean => _ => _
60 | .Executes(() =>
61 | {
62 | DeleteDirectories(GlobDirectories(SourceDirectory, "**/bin", "**/obj"));
63 | DeleteDirectories(GlobDirectories(TestsDirectory, "**/bin", "**/obj"));
64 | EnsureCleanDirectory(ArtifactsDirectory);
65 | });
66 |
67 | Target Restore => _ => _
68 | .DependsOn(Clean)
69 | .Executes(() =>
70 | {
71 | DotNetRestore(s => s
72 | .SetProjectFile(Solution));
73 | });
74 |
75 | Target Compile => _ => _
76 | .DependsOn(Restore)
77 | .Executes(() =>
78 | {
79 | DotNetBuild(s => s
80 | .SetProjectFile(Solution)
81 | .SetConfiguration(Configuration)
82 | .SetVersionSuffix(VersionSuffix)
83 | .EnableNoRestore());
84 | });
85 |
86 | Target Test => _ => _
87 | .DependsOn(Compile)
88 | .Executes(() =>
89 | {
90 | DotNetTest(s => s
91 | .SetProjectFile(Solution)
92 | .SetConfiguration(Configuration)
93 | .SetLoggers("trx")
94 | .SetResultsDirectory(ArtifactsDirectory / "TestResults")
95 | .EnableNoBuild()
96 | .EnableNoRestore());
97 | });
98 |
99 | Target Pack => _ => _
100 | .DependsOn(Test)
101 | .Executes(() =>
102 | {
103 | DotNetPack(s => s
104 | .SetProject(Solution)
105 | .SetConfiguration(Configuration)
106 | .SetVersionSuffix(VersionSuffix)
107 | .SetOutputDirectory(ArtifactsDirectory / "NuGet")
108 | .EnableNoBuild()
109 | .EnableNoRestore());
110 | });
111 |
112 | Target Publish => _ => _
113 | .DependsOn(Test)
114 | .Requires(() => PublishRuntime)
115 | .Requires(() => PublishFramework)
116 | .Requires(() => PublishProject)
117 | .Executes(() =>
118 | {
119 | DotNetPublish(s => s
120 | .SetProject(Solution.GetProject(PublishProject))
121 | .SetConfiguration(Configuration)
122 | .SetVersionSuffix(VersionSuffix)
123 | .SetFramework(PublishFramework)
124 | .SetRuntime(PublishRuntime)
125 | .SetSelfContained(PublishSelfContained)
126 | .SetOutput(ArtifactsDirectory / "Publish" / PublishProject + "-" + PublishFramework + "-" + PublishRuntime));
127 | });
128 | }
129 |
--------------------------------------------------------------------------------
/build/build/_build.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net9.0
6 | false
7 | False
8 | CS0649;CS0169
9 | 1
10 | true
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/build/databox.public.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wieslawsoltes/DataBox/316c5de320064ebf429002def9b05e389cb97aed/build/databox.public.snk
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "9.0.100",
4 | "rollForward": "latestMinor",
5 | "allowPrerelease": true
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/nuget.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/samples/DataBoxDataVirtualizationDemo/App.axaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/samples/DataBoxDataVirtualizationDemo/App.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls.ApplicationLifetimes;
3 | using Avalonia.Markup.Xaml;
4 | using DataBoxDataVirtualizationDemo.ViewModels;
5 |
6 | namespace DataBoxDataVirtualizationDemo;
7 |
8 | public class App : Application
9 | {
10 | public override void Initialize()
11 | {
12 | AvaloniaXamlLoader.Load(this);
13 | }
14 |
15 | public override void OnFrameworkInitializationCompleted()
16 | {
17 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
18 | {
19 | desktop.MainWindow = new MainWindow
20 | {
21 | DataContext = new MainWindowViewModel(2_000_000, 100)
22 | };
23 | }
24 |
25 | base.OnFrameworkInitializationCompleted();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/samples/DataBoxDataVirtualizationDemo/DataBoxDataVirtualizationDemo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Exe
4 |
5 |
6 | WinExe
7 |
8 |
9 | net9.0
10 | False
11 | enable
12 | Debug;Release
13 | AnyCPU;x64
14 |
15 |
16 |
17 | true
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | all
40 | runtime; build; native; contentfiles; analyzers; buildtransitive
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/samples/DataBoxDataVirtualizationDemo/MainWindow.axaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 |
19 |
21 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
53 |
54 |
56 |
57 |
58 |
59 |
60 |
63 |
66 |
67 |
68 |
69 |
71 |
72 |
73 |
74 |
75 |
77 |
80 |
81 |
82 |
83 |
85 |
86 |
87 |
88 |
89 |
91 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
106 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/samples/DataBoxDataVirtualizationDemo/MainWindow.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Markup.Xaml;
4 | using Avalonia.Rendering;
5 |
6 | namespace DataBoxDataVirtualizationDemo;
7 |
8 | public partial class MainWindow : Window
9 | {
10 | public MainWindow()
11 | {
12 | InitializeComponent();
13 | #if DEBUG
14 | this.AttachDevTools();
15 | #endif
16 | RendererDiagnostics.DebugOverlays = RendererDebugOverlays.Fps;
17 | }
18 |
19 | private void InitializeComponent()
20 | {
21 | AvaloniaXamlLoader.Load(this);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/samples/DataBoxDataVirtualizationDemo/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Avalonia;
3 | using Avalonia.ReactiveUI;
4 |
5 | namespace DataBoxDataVirtualizationDemo;
6 |
7 | class Program
8 | {
9 | [STAThread]
10 | public static void Main(string[] args) => BuildAvaloniaApp()
11 | .StartWithClassicDesktopLifetime(args);
12 |
13 | public static AppBuilder BuildAvaloniaApp()
14 | => AppBuilder.Configure()
15 | .UsePlatformDetect()
16 | .LogToTrace()
17 | .UseReactiveUI();
18 | }
19 |
--------------------------------------------------------------------------------
/samples/DataBoxDataVirtualizationDemo/ViewModels/ItemProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using DataVirtualization;
4 |
5 | namespace DataBoxDataVirtualizationDemo.ViewModels;
6 |
7 | public class ItemProvider : IItemsProvider
8 | {
9 | private readonly int _count;
10 |
11 | public ItemProvider(int count)
12 | {
13 | _count = count;
14 | }
15 |
16 | public int FetchCount()
17 | {
18 | return _count;
19 | }
20 |
21 | private ItemViewModel CreateItem(int index)
22 | {
23 | return new ItemViewModel(
24 | $"Item {index}-1",
25 | $"Item {index}-2",
26 | $"Item {index}-3",
27 | Random.Shared.NextDouble() > 0.5,
28 | index,
29 | //Random.Shared.Next(24, 100));
30 | double.NaN);
31 | }
32 |
33 | public IList FetchRange(int startIndex, int pageCount, out int overallCount)
34 | {
35 | var result = new List();
36 | var endIndex = startIndex + pageCount;
37 |
38 | overallCount = _count;
39 |
40 | for (var i = startIndex; i < endIndex; i++)
41 | {
42 | result.Add(CreateItem(i));
43 | }
44 |
45 | return result;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/samples/DataBoxDataVirtualizationDemo/ViewModels/ItemViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace DataBoxDataVirtualizationDemo.ViewModels;
2 |
3 | public partial class ItemViewModel : ViewModelBase
4 | {
5 | [Reactive]
6 | public partial string Column1 { get; set; }
7 |
8 | [Reactive]
9 | public partial string Column2 { get; set; }
10 |
11 | [Reactive]
12 | public partial string Column3 { get; set; }
13 |
14 | [Reactive]
15 | public partial bool Column4 { get; set; }
16 |
17 | [Reactive]
18 | public partial int Column5 { get; set; }
19 |
20 | [Reactive]
21 | public partial double Height { get; set; }
22 |
23 | public ItemViewModel(string column1, string column2, string column3, bool column4, int column5, double height)
24 | {
25 | _column1 = column1;
26 | _column2 = column2;
27 | _column3 = column3;
28 | _column4 = column4;
29 | _column5 = column5;
30 | _height = height;
31 | }
32 |
33 | public override string ToString()
34 | {
35 | return $"{_column5}";
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/samples/DataBoxDataVirtualizationDemo/ViewModels/MainWindowViewModel.cs:
--------------------------------------------------------------------------------
1 | using DataVirtualization;
2 |
3 | namespace DataBoxDataVirtualizationDemo.ViewModels;
4 |
5 | public partial class MainWindowViewModel : ViewModelBase
6 | {
7 | [Reactive]
8 | public partial AsyncVirtualizingCollection? Items { get; set; }
9 |
10 | public MainWindowViewModel(int count, int pageSize)
11 | {
12 | Items = new AsyncVirtualizingCollection(
13 | new ItemProvider(count),
14 | pageSize,
15 | 5000);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/samples/DataBoxDataVirtualizationDemo/ViewModels/ViewModelBase.cs:
--------------------------------------------------------------------------------
1 | using ReactiveUI;
2 |
3 | namespace DataBoxDataVirtualizationDemo.ViewModels;
4 |
5 | public class ViewModelBase : ReactiveObject
6 | {
7 | }
8 |
--------------------------------------------------------------------------------
/samples/DataBoxDemo/App.axaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/samples/DataBoxDemo/App.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls.ApplicationLifetimes;
3 | using Avalonia.Markup.Xaml;
4 | using DataBoxDemo.ViewModels;
5 |
6 | namespace DataBoxDemo;
7 |
8 | public class App : Application
9 | {
10 | public override void Initialize()
11 | {
12 | AvaloniaXamlLoader.Load(this);
13 | }
14 |
15 | public override void OnFrameworkInitializationCompleted()
16 | {
17 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
18 | {
19 | desktop.MainWindow = new MainWindow
20 | {
21 | DataContext = new MainWindowViewModel(),
22 | };
23 | }
24 |
25 | base.OnFrameworkInitializationCompleted();
26 | }
27 | }
--------------------------------------------------------------------------------
/samples/DataBoxDemo/DataBoxDemo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Exe
4 |
5 |
6 | WinExe
7 |
8 |
9 | net9.0
10 | False
11 | enable
12 | Debug;Release
13 | AnyCPU;x64
14 |
15 |
16 |
17 | true
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | all
39 | runtime; build; native; contentfiles; analyzers; buildtransitive
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/samples/DataBoxDemo/MainWindow.axaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
22 |
23 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
57 |
58 |
63 |
64 |
65 |
68 |
69 |
70 |
71 |
76 |
77 |
78 |
81 |
82 |
83 |
84 |
89 |
90 |
91 |
94 |
95 |
96 |
97 |
105 |
112 |
113 |
114 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/samples/DataBoxDemo/MainWindow.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Markup.Xaml;
4 | using Avalonia.Rendering;
5 |
6 | namespace DataBoxDemo;
7 |
8 | public partial class MainWindow : Window
9 | {
10 | public MainWindow()
11 | {
12 | InitializeComponent();
13 | #if DEBUG
14 | this.AttachDevTools();
15 | #endif
16 | RendererDiagnostics.DebugOverlays = RendererDebugOverlays.Fps;
17 | }
18 |
19 | private void InitializeComponent()
20 | {
21 | AvaloniaXamlLoader.Load(this);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/samples/DataBoxDemo/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Avalonia;
3 | using Avalonia.ReactiveUI;
4 |
5 | namespace DataBoxDemo;
6 |
7 | class Program
8 | {
9 | [STAThread]
10 | public static void Main(string[] args) => BuildAvaloniaApp()
11 | .StartWithClassicDesktopLifetime(args);
12 |
13 | public static AppBuilder BuildAvaloniaApp()
14 | => AppBuilder.Configure()
15 | .UsePlatformDetect()
16 | .LogToTrace()
17 | .UseReactiveUI();
18 | }
--------------------------------------------------------------------------------
/samples/DataBoxDemo/ViewModels/ItemViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace DataBoxDemo.ViewModels;
2 |
3 | public partial class ItemViewModel : ViewModelBase
4 | {
5 | [Reactive]
6 | public partial string Column1 { get; set; }
7 |
8 | [Reactive]
9 | public partial string Column2 { get; set; }
10 |
11 | [Reactive]
12 | public partial string Column3 { get; set; }
13 |
14 | [Reactive]
15 | public partial bool Column4 { get; set; }
16 |
17 | [Reactive]
18 | public partial int Column5 { get; set; }
19 |
20 | [Reactive]
21 | public partial double Height { get; set; }
22 |
23 | public ItemViewModel(string column1, string column2, string column3, bool column4, int column5, double height)
24 | {
25 | _column1 = column1;
26 | _column2 = column2;
27 | _column3 = column3;
28 | _column4 = column4;
29 | _column5 = column5;
30 | _height = height;
31 | }
32 |
33 | public override string ToString()
34 | {
35 | return $"{_column5}";
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/samples/DataBoxDemo/ViewModels/MainWindowViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.ObjectModel;
4 | using System.ComponentModel;
5 | using System.Linq;
6 | using System.Reactive.Linq;
7 | using System.Reactive.Subjects;
8 | using System.Threading.Tasks;
9 | using System.Windows.Input;
10 | using DynamicData;
11 | using DynamicData.Binding;
12 | using ReactiveUI;
13 |
14 | namespace DataBoxDemo.ViewModels;
15 |
16 | public partial class MainWindowViewModel : ViewModelBase
17 | {
18 | private readonly SourceList _itemsSourceList;
19 | private ReadOnlyObservableCollection? _items;
20 | private readonly Subject> _comparerSubject;
21 | private IDisposable? _subscription;
22 | private bool _isSortingEnabled;
23 |
24 | public ReadOnlyObservableCollection? Items => _items;
25 |
26 | [Reactive]
27 | public partial ItemViewModel? SelectedItem { get; set; }
28 |
29 | [Reactive]
30 | public partial ListSortDirection? SortingStateColumn1 { get; set; }
31 |
32 | [Reactive]
33 | public partial ListSortDirection? SortingStateColumn2 { get; set; }
34 |
35 | [Reactive]
36 | public partial ListSortDirection? SortingStateColumn3 { get; set; }
37 |
38 | [Reactive]
39 | public partial ListSortDirection? SortingStateColumn4 { get; set; }
40 |
41 | [Reactive]
42 | public partial ListSortDirection? SortingStateColumn5 { get; set; }
43 |
44 | public ICommand SortCommand { get; }
45 |
46 | public ICommand AddItemCommand { get; }
47 |
48 | public ICommand InsertItemCommand { get; }
49 |
50 | public ICommand RemoveItemCommand { get; }
51 |
52 | public ICommand SelectFirstItemCommand { get; }
53 |
54 | public MainWindowViewModel()
55 | {
56 | var totalItems = 10_000;
57 | var rand = new Random();
58 | var items = new List();
59 |
60 | for (var i = 0; i < totalItems; i++)
61 | {
62 | items.Add(CreateItem(i));
63 | }
64 |
65 | ItemViewModel CreateItem(int index)
66 | {
67 | return new ItemViewModel(
68 | $"Item {index}-1",
69 | $"Item {index}-2",
70 | $"Item {index}-3",
71 | rand.NextDouble() > 0.5,
72 | index,
73 | //rand.Next(24, 100));
74 | double.NaN);
75 | }
76 |
77 | _itemsSourceList = new SourceList();
78 | _itemsSourceList.AddRange(items);
79 |
80 | _comparerSubject = new Subject>();
81 | _isSortingEnabled = false;
82 | SortingStateColumn5 = ListSortDirection.Ascending;
83 | EnableSort(x => x.Column5, SortingStateColumn5);
84 |
85 | SortCommand = ReactiveCommand.CreateFromTask(async sortMemberPath =>
86 | {
87 | await Task.Run(() =>
88 | {
89 | Sort(sortMemberPath);
90 | });
91 | });
92 |
93 | InsertItemCommand = ReactiveCommand.Create(() =>
94 | {
95 | if (_items is null)
96 | {
97 | return;
98 | }
99 | var index = _items.Count;
100 | var item = CreateItem(index);
101 | _itemsSourceList.Insert(0, item);
102 | });
103 |
104 | AddItemCommand = ReactiveCommand.Create(() =>
105 | {
106 | if (_items is null)
107 | {
108 | return;
109 | }
110 | var index = _items.Count;
111 | var item = CreateItem(index);
112 | _itemsSourceList.Add(item);
113 | });
114 |
115 | RemoveItemCommand = ReactiveCommand.Create((item) =>
116 | {
117 | if (item is not null)
118 | {
119 | _itemsSourceList.Remove(item);
120 | }
121 | });
122 |
123 | SelectFirstItemCommand = ReactiveCommand.Create(() =>
124 | {
125 | if (_items is null)
126 | {
127 | return;
128 | }
129 | SelectedItem = _items.FirstOrDefault();
130 | });
131 | }
132 |
133 | private IObservable> GetSortObservable(IComparer comparer)
134 | {
135 | return _itemsSourceList!
136 | .Connect()
137 | .ObserveOn(RxApp.MainThreadScheduler)
138 | .Sort(comparer, comparerChanged: _comparerSubject)
139 | .Bind(out _items);
140 | }
141 |
142 | private IObservable> GetDefaultObservable()
143 | {
144 | return _itemsSourceList!
145 | .Connect()
146 | .ObserveOn(RxApp.MainThreadScheduler)
147 | .Bind(out _items);
148 | }
149 |
150 | private void EnableSort(Func expression, ListSortDirection? listSortDirection)
151 | {
152 | var sortExpressionComparer = listSortDirection == ListSortDirection.Ascending
153 | ? SortExpressionComparer.Ascending(expression)
154 | : SortExpressionComparer.Descending(expression);
155 |
156 | if (!_isSortingEnabled)
157 | {
158 | _subscription?.Dispose();
159 | _subscription = GetSortObservable(sortExpressionComparer).Subscribe();
160 | _isSortingEnabled = true;
161 | this.RaisePropertyChanged(nameof(Items));
162 | }
163 | else
164 | {
165 | _comparerSubject.OnNext(sortExpressionComparer);
166 | }
167 | }
168 |
169 | private void DisableSort()
170 | {
171 | if (_isSortingEnabled)
172 | {
173 | _subscription?.Dispose();
174 | _subscription = GetDefaultObservable().Subscribe();
175 | _isSortingEnabled = false;
176 | this.RaisePropertyChanged(nameof(Items));
177 | }
178 | }
179 |
180 | private void Sort(string? sortMemberPath)
181 | {
182 | switch (sortMemberPath)
183 | {
184 | case null:
185 | DisableSort();
186 | break;
187 | case "Column1":
188 | EnableSort(x => x.Column1, SortingStateColumn1);
189 | break;
190 | case "Column2":
191 | EnableSort(x => x.Column2, SortingStateColumn2);
192 | break;
193 | case "Column3":
194 | EnableSort(x => x.Column3, SortingStateColumn3);
195 | break;
196 | case "Column4":
197 | EnableSort(x => x.Column4, SortingStateColumn4);
198 | break;
199 | case "Column5":
200 | EnableSort(x => x.Column5, SortingStateColumn5);
201 | break;
202 | }
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/samples/DataBoxDemo/ViewModels/ViewModelBase.cs:
--------------------------------------------------------------------------------
1 | using ReactiveUI;
2 |
3 | namespace DataBoxDemo.ViewModels;
4 |
5 | public class ViewModelBase : ReactiveObject
6 | {
7 | }
--------------------------------------------------------------------------------
/samples/VirtualPanelDemo.NetCore/Assets/avalonia-logo.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wieslawsoltes/DataBox/316c5de320064ebf429002def9b05e389cb97aed/samples/VirtualPanelDemo.NetCore/Assets/avalonia-logo.ico
--------------------------------------------------------------------------------
/samples/VirtualPanelDemo.NetCore/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Avalonia;
3 | using Avalonia.Controls.ApplicationLifetimes;
4 | using Avalonia.ReactiveUI;
5 |
6 | namespace VirtualPanelDemo.NetCore
7 | {
8 | class Program
9 | {
10 | // Initialization code. Don't use any Avalonia, third-party APIs or any
11 | // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
12 | // yet and stuff might break.
13 | [STAThread]
14 | public static void Main(string[] args) => BuildAvaloniaApp()
15 | .StartWithClassicDesktopLifetime(args);
16 |
17 | // Avalonia configuration, don't remove; also used by visual designer.
18 | public static AppBuilder BuildAvaloniaApp()
19 | => AppBuilder.Configure()
20 | .UsePlatformDetect()
21 | .LogToTrace()
22 | .UseReactiveUI();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/samples/VirtualPanelDemo.NetCore/VirtualPanelDemo.NetCore.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Exe
4 |
5 |
6 | WinExe
7 |
8 |
9 | net9.0
10 | False
11 | enable
12 | Debug;Release
13 | AnyCPU;x64
14 | preview
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/samples/VirtualPanelDemo/App.axaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/samples/VirtualPanelDemo/App.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls.ApplicationLifetimes;
3 | using Avalonia.Markup.Xaml;
4 |
5 | namespace VirtualPanelDemo;
6 |
7 | public class App : Application
8 | {
9 | public override void Initialize()
10 | {
11 | AvaloniaXamlLoader.Load(this);
12 | }
13 |
14 | public override void OnFrameworkInitializationCompleted()
15 | {
16 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
17 | {
18 | desktop.MainWindow = new MainWindow();
19 | }
20 | else if (ApplicationLifetime is ISingleViewApplicationLifetime single)
21 | {
22 | single.MainView = new MainView();
23 | }
24 |
25 | base.OnFrameworkInitializationCompleted();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/samples/VirtualPanelDemo/MainView.axaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
32 |
35 |
36 |
37 |
44 |
45 |
46 |
47 |
48 |
49 |
51 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/samples/VirtualPanelDemo/MainView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Markup.Xaml;
3 | using VirtualPanelDemo.ViewModels;
4 |
5 | namespace VirtualPanelDemo;
6 |
7 | public partial class MainView : UserControl
8 | {
9 | public MainView()
10 | {
11 | InitializeComponent();
12 |
13 | var vm = new MainWindowViewModel(2_000_000_000, 100, 100, 100);
14 |
15 | DataContext = vm;
16 |
17 | var vp = this.FindControl("VirtualPanel");
18 |
19 | if (vm.Items is { })
20 | {
21 | vm.Items.CollectionChanged += (_, _) =>
22 | {
23 | vp?.InvalidateMeasure();
24 | };
25 | }
26 | }
27 |
28 | private void InitializeComponent()
29 | {
30 | AvaloniaXamlLoader.Load(this);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/samples/VirtualPanelDemo/MainWindow.axaml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/samples/VirtualPanelDemo/MainWindow.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Markup.Xaml;
4 | using Avalonia.Rendering;
5 | using VirtualPanelDemo.ViewModels;
6 |
7 | namespace VirtualPanelDemo;
8 |
9 | public partial class MainWindow : Window
10 | {
11 | public MainWindow()
12 | {
13 | InitializeComponent();
14 | #if DEBUG
15 | this.AttachDevTools();
16 | #endif
17 | //RendererDiagnostics.DebugOverlays = RendererDebugOverlays.Fps | RendererDebugOverlays.LayoutTimeGraph | RendererDebugOverlays.RenderTimeGraph;
18 | RendererDiagnostics.DebugOverlays = RendererDebugOverlays.Fps;
19 | }
20 |
21 | private void InitializeComponent()
22 | {
23 | AvaloniaXamlLoader.Load(this);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/samples/VirtualPanelDemo/ViewModels/ItemProvider.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using DataVirtualization;
3 |
4 | namespace VirtualPanelDemo.ViewModels
5 | {
6 | public class ItemProvider(int count) : IItemsProvider
7 | {
8 | public int FetchCount()
9 | {
10 | return count;
11 | }
12 |
13 | public IList FetchRange(int startIndex, int pageCount, out int overallCount)
14 | {
15 | var result = new List();
16 | var endIndex = startIndex + pageCount;
17 |
18 | overallCount = count;
19 |
20 | for (var i = startIndex; i < endIndex; i++)
21 | {
22 | //result.Add($"Item {i}");
23 | result.Add($"{i}");
24 | }
25 |
26 | return result;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/samples/VirtualPanelDemo/ViewModels/MainWindowViewModel.cs:
--------------------------------------------------------------------------------
1 | using DataVirtualization;
2 | using ReactiveUI;
3 |
4 | namespace VirtualPanelDemo.ViewModels;
5 |
6 | public partial class MainWindowViewModel : ReactiveObject
7 | {
8 | [Reactive]
9 | public partial AsyncVirtualizingCollection? Items { get; set; }
10 |
11 | [Reactive]
12 | public partial double ItemHeight { get; set; }
13 |
14 | [Reactive]
15 | public partial double ItemWidth { get; set; }
16 |
17 | public int Count { get; }
18 |
19 | public MainWindowViewModel(int count, int pageSize, int itemHeight, int itemWidth)
20 | {
21 | Items = new AsyncVirtualizingCollection(new ItemProvider(count), pageSize, 5000);
22 | ItemHeight = itemHeight;
23 | ItemWidth = itemWidth;
24 | Count = count;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/samples/VirtualPanelDemo/VirtualPanelDemo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net9.0
4 | Library
5 | False
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | all
28 | runtime; build; native; contentfiles; analyzers; buildtransitive
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/DataBox.DataVirtualization/AsyncVirtualizingCollection.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Collections.Specialized;
3 | using System.ComponentModel;
4 | using System.Threading;
5 |
6 | namespace DataVirtualization
7 | {
8 | ///
9 | /// Derived VirtualizingCollection, performing loading asynchronously.
10 | ///
11 | /// The type of items in the collection
12 | public class AsyncVirtualizingCollection : VirtualizingCollection, INotifyCollectionChanged, INotifyPropertyChanged where T : class
13 | {
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | /// The items provider.
18 | /// Size of the page.
19 | /// The page timeout.
20 | public AsyncVirtualizingCollection(IItemsProvider itemsProvider, int pageSize, int pageTimeout)
21 | : base(itemsProvider, pageSize, pageTimeout)
22 | {
23 | SynchronizationContext = SynchronizationContext.Current;
24 | }
25 |
26 | #region SynchronizationContext
27 |
28 | ///
29 | /// Gets the synchronization context used for UI-related operations. This is obtained as
30 | /// the current SynchronizationContext when the AsyncVirtualizingCollection is created.
31 | ///
32 | /// The synchronization context.
33 | protected SynchronizationContext? SynchronizationContext { get; }
34 |
35 | #endregion
36 |
37 | #region INotifyCollectionChanged
38 |
39 | ///
40 | /// Occurs when the collection changes.
41 | ///
42 | public event NotifyCollectionChangedEventHandler? CollectionChanged;
43 |
44 | ///
45 | /// Raises the event.
46 | ///
47 | /// The instance containing the event data.
48 | protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
49 | {
50 | CollectionChanged?.Invoke(this, e);
51 | }
52 |
53 | ///
54 | /// Fires the collection reset event.
55 | ///
56 | private void FireCollectionReset()
57 | {
58 | var e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
59 | OnCollectionChanged(e);
60 | }
61 |
62 | #endregion
63 |
64 | #region INotifyPropertyChanged
65 |
66 | ///
67 | /// Occurs when a property value changes.
68 | ///
69 | public event PropertyChangedEventHandler? PropertyChanged;
70 |
71 | ///
72 | /// Raises the event.
73 | ///
74 | /// The instance containing the event data.
75 | protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
76 | {
77 | PropertyChanged?.Invoke(this, e);
78 | }
79 |
80 | ///
81 | /// Fires the property changed event.
82 | ///
83 | /// Name of the property.
84 | private void FirePropertyChanged(string propertyName)
85 | {
86 | var e = new PropertyChangedEventArgs(propertyName);
87 | OnPropertyChanged(e);
88 | }
89 |
90 | #endregion
91 |
92 | #region IsLoading
93 |
94 | private bool _isLoading;
95 |
96 | ///
97 | /// Gets or sets a value indicating whether the collection is loading.
98 | ///
99 | ///
100 | /// true if this collection is loading; otherwise, false.
101 | ///
102 | public bool IsLoading
103 | {
104 | get
105 | {
106 | return _isLoading;
107 | }
108 | set
109 | {
110 | if (value != _isLoading)
111 | {
112 | _isLoading = value;
113 | FirePropertyChanged(nameof(IsLoading));
114 | }
115 | }
116 | }
117 |
118 | private bool _isInitializing;
119 |
120 | public bool IsInitializing
121 | {
122 | get
123 | {
124 | return _isInitializing;
125 | }
126 | set
127 | {
128 | if (value != _isInitializing)
129 | {
130 | _isInitializing = value;
131 | FirePropertyChanged(nameof(IsInitializing));
132 | }
133 | }
134 | }
135 | #endregion
136 |
137 | #region Load overrides
138 |
139 | ///
140 | /// Asynchronously loads the count of items.
141 | ///
142 | protected override void LoadCount()
143 | {
144 | if (Count == 0)
145 | {
146 | IsInitializing = true;
147 | }
148 | ThreadPool.QueueUserWorkItem(LoadCountWork);
149 | }
150 |
151 | ///
152 | /// Performed on background thread.
153 | ///
154 | /// None required.
155 | private void LoadCountWork(object? args)
156 | {
157 | var count = FetchCount();
158 | SynchronizationContext?.Send(LoadCountCompleted, count);
159 | }
160 |
161 | ///
162 | /// Performed on UI-thread after LoadCountWork.
163 | ///
164 | /// Number of items returned.
165 | protected virtual void LoadCountCompleted(object? args)
166 | {
167 | if (args is int newCount)
168 | {
169 | TakeNewCount(newCount);
170 | }
171 | IsInitializing = false;
172 | }
173 |
174 | private void TakeNewCount(int newCount)
175 | {
176 | if (newCount != Count)
177 | {
178 | Count = newCount;
179 | EmptyCache();
180 | FireCollectionReset();
181 | }
182 | }
183 |
184 | ///
185 | /// Asynchronously loads the page.
186 | ///
187 | /// The page index.
188 | /// The page length.
189 | protected override void LoadPage(int pageIndex, int pageLength)
190 | {
191 | IsLoading = true;
192 | ThreadPool.QueueUserWorkItem(LoadPageWork, new[] { pageIndex, pageLength });
193 | }
194 |
195 | ///
196 | /// Performed on background thread.
197 | ///
198 | /// Index of the page to load.
199 | private void LoadPageWork(object? state)
200 | {
201 | if (state is int[] args)
202 | {
203 | var pageIndex = args[0];
204 | var pageLength = args[1];
205 | var dataItems = FetchPage(pageIndex, pageLength, out var overallCount);
206 | SynchronizationContext?.Send(LoadPageCompleted, new object[] { pageIndex, dataItems, overallCount });
207 | }
208 | }
209 |
210 | ///
211 | /// Performed on UI-thread after LoadPageWork.
212 | ///
213 | /// object[] { int pageIndex, IList(T) page }
214 | private void LoadPageCompleted(object? state)
215 | {
216 | if (state is object[] args)
217 | {
218 | var pageIndex = (int)args[0];
219 | var dataItems = (IList)args[1];
220 | var newCount = (int)args[2];
221 | TakeNewCount(newCount);
222 |
223 | PopulatePage(pageIndex, dataItems);
224 | }
225 | IsLoading = false;
226 | }
227 |
228 | #endregion
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/src/DataBox.DataVirtualization/DataBox.DataVirtualization.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Library
4 | netstandard2.0;net461;net6.0;net8.0
5 | True
6 | enable
7 | Debug;Release
8 | AnyCPU;x64
9 | DataVirtualization
10 |
11 |
12 |
13 | DataBox.DataVirtualization
14 | Specialized list implementation that provides data virtualization.
15 | data;virtualization;scrolling
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/DataBox.DataVirtualization/DataPage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace DataVirtualization
6 | {
7 | public class DataPage where T : class
8 | {
9 | public DataPage(int firstIndex, int pageLength)
10 | {
11 | Items = new List>(pageLength);
12 | for (var i = 0; i < pageLength; i++)
13 | {
14 | Items.Add(new DataWrapper(firstIndex + i));
15 | }
16 | TouchTime = DateTime.Now;
17 | }
18 |
19 | public IList> Items { get; set; }
20 |
21 | public DateTime TouchTime { get; set; }
22 |
23 | public bool IsInUse
24 | {
25 | get { return Items.Any(wrapper => wrapper.IsInUse); }
26 | }
27 |
28 | public void Populate(IList newItems)
29 | {
30 | int i;
31 | var index = 0;
32 | for (i = 0; i < newItems.Count && i < Items.Count; i++)
33 | {
34 | Items[i].Data = newItems[i];
35 | index = Items[i].Index;
36 | }
37 |
38 | while (i < newItems.Count)
39 | {
40 | index++;
41 | Items.Add(new DataWrapper(index) { Data = newItems[i] });
42 | i++;
43 | }
44 |
45 | while (i < Items.Count)
46 | {
47 | Items.RemoveAt(Items.Count - 1);
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/DataBox.DataVirtualization/DataWrapper.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace DataVirtualization
4 | {
5 | public class DataWrapper : INotifyPropertyChanged where T : class
6 | {
7 | private readonly int _index;
8 | private T? _data;
9 |
10 | public event PropertyChangedEventHandler? PropertyChanged;
11 |
12 | public DataWrapper(int index)
13 | {
14 | _index = index;
15 | }
16 |
17 | public int Index
18 | {
19 | get { return _index; }
20 | }
21 |
22 | public int ItemNumber
23 | {
24 | get { return _index + 1; }
25 | }
26 |
27 | public bool IsLoading
28 | {
29 | get { return Data == null; }
30 | }
31 |
32 | public T? Data
33 | {
34 | get { return _data; }
35 | internal set
36 | {
37 | _data = value;
38 | OnPropertyChanged(nameof(Data));
39 | OnPropertyChanged(nameof(IsLoading));
40 | }
41 | }
42 |
43 | public bool IsInUse
44 | {
45 | get { return PropertyChanged != null; }
46 | }
47 |
48 | private void OnPropertyChanged(string propertyName)
49 | {
50 | System.Diagnostics.Debug.Assert(GetType().GetProperty(propertyName) != null);
51 | var handler = PropertyChanged;
52 | handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/DataBox.DataVirtualization/IItemsProvider.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace DataVirtualization
4 | {
5 | ///
6 | /// Represents a provider of collection details.
7 | ///
8 | /// The type of items in the collection.
9 | public interface IItemsProvider
10 | {
11 | ///
12 | /// Fetches the total number of items available.
13 | ///
14 | ///
15 | int FetchCount();
16 |
17 | ///
18 | /// Fetches a range of items.
19 | ///
20 | /// The start index.
21 | /// The number of items to fetch.
22 | /// The overall items count.
23 | ///
24 | IList FetchRange(int startIndex, int pageCount, out int overallCount);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/DataBox.DataVirtualization/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Beatriz Stollnitz
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/DataBox.DataVirtualization/README.txt:
--------------------------------------------------------------------------------
1 | https://github.com/bstollnitz/old-wpf-blog/tree/master/64-DataVirtualizationFilteringSorting
--------------------------------------------------------------------------------
/src/DataBox/Automation/Peers/DataBoxAutomationPeer.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Automation.Peers;
2 | using Avalonia.Automation.Provider;
3 | using Avalonia.Controls;
4 |
5 | namespace DataBox.Automation.Peers;
6 |
7 | public class DataBoxAutomationPeer : ControlAutomationPeer, IScrollProvider
8 | {
9 | private bool _searchedForScrollable;
10 | private IScrollProvider? _scroller;
11 |
12 | public DataBoxAutomationPeer(DataBox owner)
13 | : base(owner)
14 | {
15 | }
16 |
17 | public new DataBox Owner => (DataBox)base.Owner;
18 | public bool HorizontallyScrollable => _scroller?.HorizontallyScrollable ?? false;
19 | public double HorizontalScrollPercent => _scroller?.HorizontalScrollPercent ?? -1;
20 | public double HorizontalViewSize => _scroller?.HorizontalViewSize ?? 0;
21 | public bool VerticallyScrollable => _scroller?.VerticallyScrollable ?? false;
22 | public double VerticalScrollPercent => _scroller?.VerticalScrollPercent ?? -1;
23 | public double VerticalViewSize => _scroller?.VerticalViewSize ?? 0;
24 |
25 | protected virtual IScrollProvider? Scroller
26 | {
27 | get
28 | {
29 | if (!_searchedForScrollable)
30 | {
31 | if (Owner.RowsPresenter?.GetValue(ListBox.ScrollProperty) is Control scrollable)
32 | _scroller = GetOrCreate(scrollable).GetProvider();
33 | _searchedForScrollable = true;
34 | }
35 |
36 | return _scroller;
37 | }
38 | }
39 |
40 | protected override AutomationControlType GetAutomationControlTypeCore()
41 | {
42 | return AutomationControlType.DataGrid;
43 | }
44 |
45 | public void Scroll(ScrollAmount horizontalAmount, ScrollAmount verticalAmount)
46 | {
47 | _scroller?.Scroll(horizontalAmount, verticalAmount);
48 | }
49 |
50 | public void SetScrollPercent(double horizontalPercent, double verticalPercent)
51 | {
52 | _scroller?.SetScrollPercent(horizontalPercent, verticalPercent);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/DataBox/Automation/Peers/DataBoxCellAutomationPeer.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Automation.Peers;
2 |
3 | namespace DataBox.Automation.Peers;
4 |
5 | public class DataBoxCellAutomationPeer : ContentControlAutomationPeer
6 | {
7 | public DataBoxCellAutomationPeer(DataBoxCell owner)
8 | : base(owner)
9 | {
10 | }
11 |
12 | public new DataBoxCell Owner => (DataBoxCell)base.Owner;
13 |
14 | protected override AutomationControlType GetAutomationControlTypeCore()
15 | {
16 | return AutomationControlType.Custom;
17 | }
18 |
19 | protected override bool IsContentElementCore() => true;
20 |
21 | protected override bool IsControlElementCore() => true;
22 | }
23 |
--------------------------------------------------------------------------------
/src/DataBox/Automation/Peers/DataBoxColumnHeaderAutomationPeer.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Automation.Peers;
2 |
3 | namespace DataBox.Automation.Peers;
4 |
5 | public class DataBoxColumnHeaderAutomationPeer : ContentControlAutomationPeer
6 | {
7 | public DataBoxColumnHeaderAutomationPeer(DataBoxColumnHeader owner)
8 | : base(owner)
9 | {
10 | }
11 |
12 | public new DataBoxColumnHeader Owner => (DataBoxColumnHeader)base.Owner;
13 |
14 | protected override AutomationControlType GetAutomationControlTypeCore()
15 | {
16 | return AutomationControlType.HeaderItem;
17 | }
18 |
19 | protected override bool IsContentElementCore() => false;
20 |
21 | protected override bool IsControlElementCore() => true;
22 | }
23 |
--------------------------------------------------------------------------------
/src/DataBox/Automation/Peers/DataBoxColumnHeadersPresenterAutomationPeer.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Automation.Peers;
2 | using DataBox.Primitives;
3 |
4 | namespace DataBox.Automation.Peers;
5 |
6 | public class DataBoxColumnHeadersPresenterAutomationPeer : ControlAutomationPeer
7 | {
8 | public DataBoxColumnHeadersPresenterAutomationPeer(DataBoxColumnHeadersPresenter owner)
9 | : base(owner)
10 | {
11 | }
12 |
13 | public new DataBoxColumnHeadersPresenter Owner => (DataBoxColumnHeadersPresenter)base.Owner;
14 |
15 | protected override AutomationControlType GetAutomationControlTypeCore()
16 | {
17 | return AutomationControlType.Header;
18 | }
19 |
20 | protected override bool IsContentElementCore() => false;
21 |
22 | protected override bool IsControlElementCore() => true;
23 | }
24 |
--------------------------------------------------------------------------------
/src/DataBox/Automation/Peers/DataBoxRowAutomationPeer.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Automation.Peers;
2 | using Avalonia.Automation.Provider;
3 | using Avalonia.Controls;
4 |
5 | namespace DataBox.Automation.Peers;
6 |
7 | public class DataBoxRowAutomationPeer : ContentControlAutomationPeer,
8 | ISelectionItemProvider
9 | {
10 | public DataBoxRowAutomationPeer(ContentControl owner)
11 | : base(owner)
12 | {
13 | }
14 |
15 | public bool IsSelected => Owner.GetValue(ListBoxItem.IsSelectedProperty);
16 |
17 | public ISelectionProvider? SelectionContainer
18 | {
19 | get
20 | {
21 | if (Owner.Parent is DataBox parent)
22 | {
23 | var parentPeer = GetOrCreate(parent);
24 | return parentPeer.GetProvider();
25 | }
26 |
27 | return null;
28 | }
29 | }
30 |
31 | public void Select()
32 | {
33 | EnsureEnabled();
34 |
35 | if (Owner.Parent is DataBox parent && parent.RowsPresenter is not null)
36 | {
37 | var index = parent.RowsPresenter.IndexFromContainer(Owner);
38 |
39 | if (index != -1)
40 | parent.RowsPresenter.SelectedIndex = index;
41 | }
42 | }
43 |
44 | void ISelectionItemProvider.AddToSelection()
45 | {
46 | EnsureEnabled();
47 |
48 | if (Owner.Parent is DataBox parent
49 | && parent.RowsPresenter is not null
50 | && parent.RowsPresenter.GetValue(ListBox.SelectionProperty) is { } selectionModel)
51 | {
52 | var index = parent.RowsPresenter.IndexFromContainer(Owner);
53 |
54 | if (index != -1)
55 | selectionModel.Select(index);
56 | }
57 | }
58 |
59 | void ISelectionItemProvider.RemoveFromSelection()
60 | {
61 | EnsureEnabled();
62 |
63 | if (Owner.Parent is DataBox parent
64 | && parent.RowsPresenter is not null
65 | && parent.GetValue(ListBox.SelectionProperty) is { } selectionModel)
66 | {
67 | var index = parent.RowsPresenter.IndexFromContainer(Owner);
68 |
69 | if (index != -1)
70 | selectionModel.Deselect(index);
71 | }
72 | }
73 |
74 | protected override AutomationControlType GetAutomationControlTypeCore()
75 | {
76 | return AutomationControlType.DataItem;
77 | }
78 |
79 | protected override bool IsContentElementCore() => true;
80 | protected override bool IsControlElementCore() => true;
81 | }
82 |
--------------------------------------------------------------------------------
/src/DataBox/Columns/DataBoxAutoCompleteColumn.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Controls.Templates;
4 | using Avalonia.Data;
5 | using Avalonia.Layout;
6 |
7 | namespace DataBox.Columns;
8 |
9 | public class DataBoxAutoCompleteColumn : DataBoxBoundColumn
10 | {
11 | public static readonly StyledProperty ItemsProperty =
12 | AvaloniaProperty.Register(nameof(Items));
13 |
14 | public static readonly StyledProperty SelectedItemProperty =
15 | AvaloniaProperty.Register(nameof(SelectedItem));
16 |
17 | public static readonly StyledProperty TextProperty =
18 | AvaloniaProperty.Register(nameof(Text));
19 |
20 | [AssignBinding]
21 | public IBinding? SelectedItem
22 | {
23 | get => GetValue(SelectedItemProperty);
24 | set => SetValue(SelectedItemProperty, value);
25 | }
26 |
27 | [AssignBinding]
28 | public IBinding? Items
29 | {
30 | get => GetValue(ItemsProperty);
31 | set => SetValue(ItemsProperty, value);
32 | }
33 |
34 | [AssignBinding]
35 | public IBinding? Text
36 | {
37 | get => GetValue(TextProperty);
38 | set => SetValue(TextProperty, value);
39 | }
40 |
41 | public DataBoxAutoCompleteColumn()
42 | {
43 | CellTemplate = new FuncDataTemplate(
44 | _ => true,
45 | (_, _) =>
46 | {
47 | var autoCompleteBox = new AutoCompleteBox
48 | {
49 | VerticalAlignment = VerticalAlignment.Center
50 | };
51 |
52 | if (Items is { })
53 | {
54 | autoCompleteBox.Bind(AutoCompleteBox.ItemsSourceProperty, Items);
55 | }
56 |
57 | if (SelectedItem is { })
58 | {
59 | autoCompleteBox.Bind(AutoCompleteBox.SelectedItemProperty, SelectedItem);
60 | }
61 |
62 | if (Text is { })
63 | {
64 | autoCompleteBox.Bind(AutoCompleteBox.TextProperty, Text);
65 | }
66 |
67 | return autoCompleteBox;
68 | },
69 | supportsRecycling: true);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/DataBox/Columns/DataBoxBoundColumn.cs:
--------------------------------------------------------------------------------
1 | namespace DataBox.Columns;
2 |
3 | public abstract class DataBoxBoundColumn : DataBoxColumn
4 | {
5 | }
6 |
--------------------------------------------------------------------------------
/src/DataBox/Columns/DataBoxButtonColumn.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Controls.Templates;
4 | using Avalonia.Data;
5 | using Avalonia.Layout;
6 |
7 | namespace DataBox.Columns;
8 |
9 | public class DataBoxButtonColumn : DataBoxContentColumn
10 | {
11 | public static readonly StyledProperty CommandProperty =
12 | AvaloniaProperty.Register(nameof(Command));
13 |
14 | public static readonly StyledProperty CommandParameterProperty =
15 | AvaloniaProperty.Register(nameof(CommandParameter));
16 |
17 | [AssignBinding]
18 | public IBinding? Command
19 | {
20 | get => GetValue(CommandProperty);
21 | set => SetValue(CommandProperty, value);
22 | }
23 |
24 | [AssignBinding]
25 | public IBinding? CommandParameter
26 | {
27 | get => GetValue(CommandParameterProperty);
28 | set => SetValue(CommandParameterProperty, value);
29 | }
30 |
31 | public DataBoxButtonColumn()
32 | {
33 | CellTemplate = new FuncDataTemplate(
34 | _ => true,
35 | (_, _) =>
36 | {
37 | var button = new Button
38 | {
39 | HorizontalAlignment = HorizontalAlignment.Stretch,
40 | HorizontalContentAlignment = HorizontalAlignment.Center,
41 | VerticalAlignment = VerticalAlignment.Stretch,
42 | VerticalContentAlignment = VerticalAlignment.Center,
43 | };
44 |
45 | if (Content is { })
46 | {
47 | button.Bind(ContentControl.ContentProperty, Content);
48 | }
49 |
50 | if (Command is { })
51 | {
52 | button.Bind(Button.CommandProperty, Command);
53 | }
54 |
55 | if (CommandParameter is { })
56 | {
57 | button.Bind(Button.CommandParameterProperty, CommandParameter);
58 | }
59 |
60 | return button;
61 | },
62 | supportsRecycling: true);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/DataBox/Columns/DataBoxCheckBoxColumn.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Controls.Primitives;
4 | using Avalonia.Controls.Templates;
5 | using Avalonia.Layout;
6 |
7 | namespace DataBox.Columns;
8 |
9 | public class DataBoxCheckBoxColumn : DataBoxToggleColumn
10 | {
11 | public DataBoxCheckBoxColumn()
12 | {
13 | CellTemplate = new FuncDataTemplate(
14 | _ => true,
15 | (_, _) =>
16 | {
17 | var checkBox = new CheckBox
18 | {
19 | HorizontalAlignment = HorizontalAlignment.Stretch,
20 | HorizontalContentAlignment = HorizontalAlignment.Center,
21 | VerticalAlignment = VerticalAlignment.Center,
22 | VerticalContentAlignment = VerticalAlignment.Stretch,
23 | };
24 |
25 | if (Content is { })
26 | {
27 | checkBox.Bind(ContentControl.ContentProperty, Content);
28 | }
29 |
30 | if (Command is { })
31 | {
32 | checkBox.Bind(Button.CommandProperty, Command);
33 | }
34 |
35 | if (CommandParameter is { })
36 | {
37 | checkBox.Bind(Button.CommandParameterProperty, CommandParameter);
38 | }
39 |
40 | if (IsChecked is { })
41 | {
42 | checkBox.Bind(ToggleButton.IsCheckedProperty, IsChecked);
43 | }
44 |
45 | return checkBox;
46 | },
47 | supportsRecycling: true);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/DataBox/Columns/DataBoxContentColumn.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Controls.Templates;
4 | using Avalonia.Data;
5 | using Avalonia.Layout;
6 |
7 | namespace DataBox.Columns;
8 |
9 | public class DataBoxContentColumn : DataBoxBoundColumn
10 | {
11 | public static readonly StyledProperty ContentProperty =
12 | AvaloniaProperty.Register(nameof(Content));
13 |
14 | [AssignBinding]
15 | public IBinding? Content
16 | {
17 | get => GetValue(ContentProperty);
18 | set => SetValue(ContentProperty, value);
19 | }
20 |
21 | public DataBoxContentColumn()
22 | {
23 | CellTemplate = new FuncDataTemplate(
24 | _ => true,
25 | (_, _) =>
26 | {
27 | var button = new ContentControl
28 | {
29 | HorizontalAlignment = HorizontalAlignment.Center,
30 | };
31 |
32 | if (Content is { })
33 | {
34 | button.Bind(ContentControl.ContentProperty, Content);
35 | }
36 |
37 | return button;
38 | },
39 | supportsRecycling: true);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/DataBox/Columns/DataBoxDateColumn.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Controls.Templates;
4 | using Avalonia.Data;
5 | using Avalonia.Layout;
6 |
7 | namespace DataBox.Columns;
8 |
9 | public class DataBoxDateColumn : DataBoxBoundColumn
10 | {
11 | public static readonly StyledProperty SelectedDateProperty =
12 | AvaloniaProperty.Register(nameof(SelectedDate));
13 |
14 | [AssignBinding]
15 | public IBinding? SelectedDate
16 | {
17 | get => GetValue(SelectedDateProperty);
18 | set => SetValue(SelectedDateProperty, value);
19 | }
20 |
21 | public DataBoxDateColumn()
22 | {
23 | CellTemplate = new FuncDataTemplate(
24 | _ => true,
25 | (_, _) =>
26 | {
27 | var datePicker = new DatePicker
28 | {
29 | VerticalAlignment = VerticalAlignment.Center
30 | };
31 |
32 | if (SelectedDate is { })
33 | {
34 | datePicker.Bind(DatePicker.SelectedDateProperty, SelectedDate);
35 | }
36 |
37 | return datePicker;
38 | },
39 | supportsRecycling: true);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/DataBox/Columns/DataBoxEntryColumn.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Controls.Templates;
4 | using Avalonia.Data;
5 | using Avalonia.Layout;
6 |
7 | namespace DataBox.Columns;
8 |
9 | public class DataBoxEntryColumn : DataBoxBoundColumn
10 | {
11 | public static readonly StyledProperty TextProperty =
12 | AvaloniaProperty.Register(nameof(Text));
13 |
14 | [AssignBinding]
15 | public IBinding? Text
16 | {
17 | get => GetValue(TextProperty);
18 | set => SetValue(TextProperty, value);
19 | }
20 |
21 | public DataBoxEntryColumn()
22 | {
23 | CellTemplate = new FuncDataTemplate(
24 | _ => true,
25 | (_, _) =>
26 | {
27 | var textBox = new TextBox
28 | {
29 | VerticalAlignment = VerticalAlignment.Center
30 | };
31 |
32 | if (Text is { })
33 | {
34 | textBox.Bind(TextBox.TextProperty, Text);
35 | }
36 |
37 | return textBox;
38 | },
39 | supportsRecycling: true);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/DataBox/Columns/DataBoxItemsColumn.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Controls.Primitives;
4 | using Avalonia.Controls.Templates;
5 | using Avalonia.Data;
6 | using Avalonia.Layout;
7 |
8 | namespace DataBox.Columns;
9 |
10 | public class DataBoxItemsColumn : DataBoxBoundColumn
11 | {
12 | public static readonly StyledProperty ItemsProperty =
13 | AvaloniaProperty.Register(nameof(Items));
14 |
15 | public static readonly StyledProperty SelectedItemProperty =
16 | AvaloniaProperty.Register(nameof(SelectedItem));
17 |
18 | [AssignBinding]
19 | public IBinding? SelectedItem
20 | {
21 | get => GetValue(SelectedItemProperty);
22 | set => SetValue(SelectedItemProperty, value);
23 | }
24 |
25 | [AssignBinding]
26 | public IBinding? Items
27 | {
28 | get => GetValue(ItemsProperty);
29 | set => SetValue(ItemsProperty, value);
30 | }
31 |
32 | public DataBoxItemsColumn()
33 | {
34 | CellTemplate = new FuncDataTemplate(
35 | _ => true,
36 | (_, _) =>
37 | {
38 | var comboBox = new ComboBox
39 | {
40 | HorizontalAlignment = HorizontalAlignment.Center,
41 | VerticalAlignment = VerticalAlignment.Center,
42 | };
43 |
44 | if (Items is { })
45 | {
46 | comboBox.Bind(ItemsControl.ItemsSourceProperty, Items);
47 | }
48 |
49 | if (SelectedItem is { })
50 | {
51 | comboBox.Bind(SelectingItemsControl.SelectedItemProperty, SelectedItem);
52 | }
53 |
54 | return comboBox;
55 | },
56 | supportsRecycling: true);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/DataBox/Columns/DataBoxLabelColumn.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Controls.Templates;
4 | using Avalonia.Layout;
5 |
6 | namespace DataBox.Columns;
7 |
8 | public class DataBoxLabelColumn : DataBoxContentColumn
9 | {
10 | public DataBoxLabelColumn()
11 | {
12 | CellTemplate = new FuncDataTemplate(
13 | _ => true,
14 | (_, _) =>
15 | {
16 | var label = new Label
17 | {
18 | VerticalAlignment = VerticalAlignment.Center
19 | };
20 |
21 | if (Content is { })
22 | {
23 | label.Bind(ContentControl.ContentProperty, Content);
24 | }
25 |
26 | return label;
27 | },
28 | supportsRecycling: true);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/DataBox/Columns/DataBoxNumericColumn.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Controls.Templates;
4 | using Avalonia.Data;
5 | using Avalonia.Layout;
6 |
7 | namespace DataBox.Columns;
8 |
9 | public class DataBoxNumericColumn : DataBoxBoundColumn
10 | {
11 | public static readonly StyledProperty ValueProperty =
12 | AvaloniaProperty.Register(nameof(Value));
13 |
14 | public static readonly StyledProperty MinimumProperty =
15 | AvaloniaProperty.Register(nameof(Minimum));
16 |
17 | public static readonly StyledProperty MaximumProperty =
18 | AvaloniaProperty.Register(nameof(Maximum));
19 |
20 | public static readonly StyledProperty IncrementProperty =
21 | AvaloniaProperty.Register(nameof(Increment));
22 |
23 | [AssignBinding]
24 | public IBinding? Value
25 | {
26 | get => GetValue(ValueProperty);
27 | set => SetValue(ValueProperty, value);
28 | }
29 |
30 | [AssignBinding]
31 | public IBinding? Minimum
32 | {
33 | get => GetValue(MinimumProperty);
34 | set => SetValue(MinimumProperty, value);
35 | }
36 |
37 | [AssignBinding]
38 | public IBinding? Maximum
39 | {
40 | get => GetValue(MaximumProperty);
41 | set => SetValue(MaximumProperty, value);
42 | }
43 |
44 | [AssignBinding]
45 | public IBinding? Increment
46 | {
47 | get => GetValue(IncrementProperty);
48 | set => SetValue(IncrementProperty, value);
49 | }
50 |
51 | public DataBoxNumericColumn()
52 | {
53 | CellTemplate = new FuncDataTemplate(
54 | _ => true,
55 | (_, _) =>
56 | {
57 | var numericUpDown = new NumericUpDown
58 | {
59 | VerticalAlignment = VerticalAlignment.Center
60 | };
61 |
62 | if (Value is { })
63 | {
64 | numericUpDown.Bind(NumericUpDown.ValueProperty, Value);
65 | }
66 |
67 | if (Minimum is { })
68 | {
69 | numericUpDown.Bind(NumericUpDown.MinimumProperty, Minimum);
70 | }
71 |
72 | if (Maximum is { })
73 | {
74 | numericUpDown.Bind(NumericUpDown.MaximumProperty, Maximum);
75 | }
76 |
77 | if (Increment is { })
78 | {
79 | numericUpDown.Bind(NumericUpDown.IncrementProperty, Increment);
80 | }
81 |
82 | return numericUpDown;
83 | },
84 | supportsRecycling: true);
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/DataBox/Columns/DataBoxProgressColumn.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Controls.Primitives;
4 | using Avalonia.Controls.Templates;
5 | using Avalonia.Layout;
6 |
7 | namespace DataBox.Columns;
8 |
9 | public class DataBoxProgressColumn : DataBoxRangeColumn
10 | {
11 | public DataBoxProgressColumn()
12 | {
13 | CellTemplate = new FuncDataTemplate(
14 | _ => true,
15 | (_, _) =>
16 | {
17 | var progressbar = new ProgressBar
18 | {
19 | HorizontalAlignment = HorizontalAlignment.Stretch,
20 | VerticalAlignment = VerticalAlignment.Stretch,
21 | };
22 |
23 | if (Value is { })
24 | {
25 | progressbar.Bind(RangeBase.ValueProperty, Value);
26 | }
27 |
28 | if (Minimum is { })
29 | {
30 | progressbar.Bind(RangeBase.MinimumProperty, Minimum);
31 | }
32 |
33 | if (Maximum is { })
34 | {
35 | progressbar.Bind(RangeBase.MaximumProperty, Maximum);
36 | }
37 |
38 | return progressbar;
39 | },
40 | supportsRecycling: true);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/DataBox/Columns/DataBoxRangeColumn.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Data;
3 |
4 | namespace DataBox.Columns;
5 |
6 | public abstract class DataBoxRangeColumn : DataBoxBoundColumn
7 | {
8 | public static readonly StyledProperty ValueProperty =
9 | AvaloniaProperty.Register(nameof(Value));
10 |
11 | public static readonly StyledProperty MinimumProperty =
12 | AvaloniaProperty.Register(nameof(Minimum));
13 |
14 | public static readonly StyledProperty MaximumProperty =
15 | AvaloniaProperty.Register(nameof(Maximum));
16 |
17 | [AssignBinding]
18 | public IBinding? Value
19 | {
20 | get => GetValue(ValueProperty);
21 | set => SetValue(ValueProperty, value);
22 | }
23 |
24 | [AssignBinding]
25 | public IBinding? Minimum
26 | {
27 | get => GetValue(MinimumProperty);
28 | set => SetValue(MinimumProperty, value);
29 | }
30 |
31 | [AssignBinding]
32 | public IBinding? Maximum
33 | {
34 | get => GetValue(MaximumProperty);
35 | set => SetValue(MaximumProperty, value);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/DataBox/Columns/DataBoxSliderColumn.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Controls.Primitives;
4 | using Avalonia.Controls.Templates;
5 | using Avalonia.Layout;
6 |
7 | namespace DataBox.Columns;
8 |
9 | public class DataBoxSliderColumn : DataBoxRangeColumn
10 | {
11 | public DataBoxSliderColumn()
12 | {
13 | CellTemplate = new FuncDataTemplate(
14 | _ => true,
15 | (_, _) =>
16 | {
17 | var slider = new Slider
18 | {
19 | HorizontalAlignment = HorizontalAlignment.Stretch,
20 | VerticalAlignment = VerticalAlignment.Stretch,
21 | };
22 |
23 | if (Value is { })
24 | {
25 | slider.Bind(RangeBase.ValueProperty, Value);
26 | }
27 |
28 | if (Minimum is { })
29 | {
30 | slider.Bind(RangeBase.MinimumProperty, Minimum);
31 | }
32 |
33 | if (Maximum is { })
34 | {
35 | slider.Bind(RangeBase.MaximumProperty, Maximum);
36 | }
37 |
38 | return slider;
39 | },
40 | supportsRecycling: true);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/DataBox/Columns/DataBoxSwitchColumn.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Controls.Primitives;
4 | using Avalonia.Controls.Templates;
5 | using Avalonia.Data;
6 | using Avalonia.Layout;
7 |
8 | namespace DataBox.Columns;
9 |
10 | public class DataBoxSwitchColumn : DataBoxToggleColumn
11 | {
12 | public static readonly StyledProperty OffContentProperty =
13 | AvaloniaProperty.Register(nameof(OffContent));
14 |
15 | public static readonly StyledProperty OnContentProperty =
16 | AvaloniaProperty.Register(nameof(OnContent));
17 |
18 | [AssignBinding]
19 | public IBinding? OffContent
20 | {
21 | get => GetValue(OffContentProperty);
22 | set => SetValue(OffContentProperty, value);
23 | }
24 |
25 | [AssignBinding]
26 | public IBinding? OnContent
27 | {
28 | get => GetValue(OnContentProperty);
29 | set => SetValue(OnContentProperty, value);
30 | }
31 |
32 | public DataBoxSwitchColumn()
33 | {
34 | CellTemplate = new FuncDataTemplate(
35 | _ => true,
36 | (_, _) =>
37 | {
38 | var toggleSwitch = new ToggleSwitch
39 | {
40 | HorizontalAlignment = HorizontalAlignment.Stretch,
41 | HorizontalContentAlignment = HorizontalAlignment.Center,
42 | VerticalAlignment = VerticalAlignment.Stretch,
43 | VerticalContentAlignment = VerticalAlignment.Center,
44 | };
45 |
46 | if (OffContent is { })
47 | {
48 | toggleSwitch.Bind(ContentControl.ContentProperty, OffContent);
49 | }
50 |
51 | if (Command is { })
52 | {
53 | toggleSwitch.Bind(Button.CommandProperty, Command);
54 | }
55 |
56 | if (CommandParameter is { })
57 | {
58 | toggleSwitch.Bind(Button.CommandParameterProperty, CommandParameter);
59 | }
60 |
61 | if (IsChecked is { })
62 | {
63 | toggleSwitch.Bind(ToggleButton.IsCheckedProperty, IsChecked);
64 | }
65 |
66 | if (OffContent is { })
67 | {
68 | toggleSwitch.Bind(ToggleSwitch.OffContentProperty, OffContent);
69 | }
70 |
71 | if (OnContent is { })
72 | {
73 | toggleSwitch.Bind(ToggleSwitch.OnContentProperty, OnContent);
74 | }
75 |
76 | return toggleSwitch;
77 | },
78 | supportsRecycling: true);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/DataBox/Columns/DataBoxTemplateColumn.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Data;
3 |
4 | namespace DataBox.Columns;
5 |
6 | public class DataBoxTemplateColumn : DataBoxColumn
7 | {
8 | public static readonly StyledProperty BindingProperty =
9 | AvaloniaProperty.Register(nameof(Binding));
10 |
11 | [AssignBinding]
12 | public IBinding? Binding
13 | {
14 | get => GetValue(BindingProperty);
15 | set => SetValue(BindingProperty, value);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/DataBox/Columns/DataBoxTextColumn.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Controls.Templates;
4 | using Avalonia.Data;
5 | using Avalonia.Layout;
6 | using Avalonia.Markup.Xaml.MarkupExtensions;
7 |
8 | namespace DataBox.Columns;
9 |
10 | public class DataBoxTextColumn : DataBoxBoundColumn
11 | {
12 | public static readonly StyledProperty TextProperty =
13 | AvaloniaProperty.Register(nameof(Text));
14 |
15 | [AssignBinding]
16 | public IBinding? Text
17 | {
18 | get => GetValue(TextProperty);
19 | set => SetValue(TextProperty, value);
20 | }
21 |
22 | public DataBoxTextColumn()
23 | {
24 | CellTemplate = new FuncDataTemplate(
25 | _ => true,
26 | (_, _) =>
27 | {
28 | var textBlock = new TextBlock
29 | {
30 | [!Layoutable.MarginProperty] = new DynamicResourceExtension("DataGridTextColumnCellTextBlockMargin"),
31 | VerticalAlignment = VerticalAlignment.Center
32 | };
33 |
34 | if (Text is { })
35 | {
36 | textBlock.Bind(TextBlock.TextProperty, Text);
37 | }
38 |
39 | return textBlock;
40 | },
41 | supportsRecycling: true);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/DataBox/Columns/DataBoxTimeColumn.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Controls.Templates;
4 | using Avalonia.Data;
5 | using Avalonia.Layout;
6 |
7 | namespace DataBox.Columns;
8 |
9 | public class DataBoxTimeColumn : DataBoxBoundColumn
10 | {
11 | public static readonly StyledProperty SelectedTimeProperty =
12 | AvaloniaProperty.Register(nameof(SelectedTime));
13 |
14 | [AssignBinding]
15 | public IBinding? SelectedTime
16 | {
17 | get => GetValue(SelectedTimeProperty);
18 | set => SetValue(SelectedTimeProperty, value);
19 | }
20 |
21 | public DataBoxTimeColumn()
22 | {
23 | CellTemplate = new FuncDataTemplate(
24 | _ => true,
25 | (_, _) =>
26 | {
27 | var timePicker = new TimePicker
28 | {
29 | VerticalAlignment = VerticalAlignment.Center
30 | };
31 |
32 | if (SelectedTime is { })
33 | {
34 | timePicker.Bind(TimePicker.SelectedTimeProperty, SelectedTime);
35 | }
36 |
37 | return timePicker;
38 | },
39 | supportsRecycling: true);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/DataBox/Columns/DataBoxToggleColumn.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Controls.Primitives;
4 | using Avalonia.Controls.Templates;
5 | using Avalonia.Data;
6 | using Avalonia.Layout;
7 |
8 | namespace DataBox.Columns;
9 |
10 | public class DataBoxToggleColumn : DataBoxButtonColumn
11 | {
12 | public static readonly StyledProperty IsCheckedProperty =
13 | AvaloniaProperty.Register(nameof(IsChecked));
14 |
15 | [AssignBinding]
16 | public IBinding? IsChecked
17 | {
18 | get => GetValue(IsCheckedProperty);
19 | set => SetValue(IsCheckedProperty, value);
20 | }
21 |
22 | public DataBoxToggleColumn()
23 | {
24 | CellTemplate = new FuncDataTemplate(
25 | _ => true,
26 | (_, _) =>
27 | {
28 | var toggleButton = new ToggleButton
29 | {
30 | HorizontalAlignment = HorizontalAlignment.Stretch,
31 | HorizontalContentAlignment = HorizontalAlignment.Center,
32 | VerticalAlignment = VerticalAlignment.Stretch,
33 | VerticalContentAlignment = VerticalAlignment.Center,
34 | };
35 |
36 | if (Content is { })
37 | {
38 | toggleButton.Bind(ContentControl.ContentProperty, Content);
39 | }
40 |
41 | if (Command is { })
42 | {
43 | toggleButton.Bind(Button.CommandProperty, Command);
44 | }
45 |
46 | if (CommandParameter is { })
47 | {
48 | toggleButton.Bind(Button.CommandParameterProperty, CommandParameter);
49 | }
50 |
51 | if (IsChecked is { })
52 | {
53 | toggleButton.Bind(ToggleButton.IsCheckedProperty, IsChecked);
54 | }
55 |
56 | return toggleButton;
57 | },
58 | supportsRecycling: true);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/DataBox/Controls/DataBoxPanel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using Avalonia;
4 | using Avalonia.Controls;
5 | using Avalonia.LogicalTree;
6 | using DataBox.Primitives.Layout;
7 |
8 | namespace DataBox.Controls;
9 |
10 | public class DataBoxPanel : VirtualizingStackPanel
11 | {
12 | internal DataBox? DataBox { get; set; }
13 |
14 | protected override Type StyleKeyOverride => typeof(DataBoxPanel);
15 |
16 | public override void ApplyTemplate()
17 | {
18 | base.ApplyTemplate();
19 |
20 | DataBox = this.GetLogicalAncestors().FirstOrDefault(x => x is DataBox) as DataBox;
21 | }
22 |
23 | protected override Size MeasureOverride(Size availableSize)
24 | {
25 | if (DataBox is null)
26 | {
27 | return availableSize;
28 | }
29 |
30 | var children = GetRealizedContainers();
31 |
32 | if (children is null)
33 | {
34 | availableSize = base.MeasureOverride(availableSize);
35 | children = GetRealizedContainers();
36 | }
37 |
38 | return children is { }
39 | ? DataBoxRowsLayout.Measure(availableSize, DataBox, base.MeasureOverride, base.InvalidateMeasure, children)
40 | : availableSize;
41 | }
42 |
43 | protected override Size ArrangeOverride(Size finalSize)
44 | {
45 | // TODO:
46 | // finalSize = base.ArrangeOverride(finalSize);
47 |
48 | if (DataBox is null)
49 | {
50 | return finalSize;
51 | }
52 |
53 | var children = GetRealizedContainers();
54 | return children is { }
55 | ? DataBoxRowsLayout.Arrange(finalSize, DataBox, base.ArrangeOverride, children)
56 | : finalSize;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/DataBox/DataBox.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using Avalonia;
3 | using Avalonia.Automation.Peers;
4 | using Avalonia.Collections;
5 | using Avalonia.Controls;
6 | using Avalonia.Controls.Primitives;
7 | using Avalonia.Data;
8 | using Avalonia.Media;
9 | using Avalonia.Metadata;
10 | using DataBox.Automation.Peers;
11 | using DataBox.Primitives;
12 |
13 | namespace DataBox;
14 |
15 | public class DataBox : TemplatedControl
16 | {
17 | public static readonly DirectProperty ItemsSourceProperty =
18 | AvaloniaProperty.RegisterDirect(
19 | nameof(ItemsSource),
20 | o => o.ItemsSource,
21 | (o, v) => o.ItemsSource = v);
22 |
23 | public static readonly DirectProperty SelectedItemProperty =
24 | AvaloniaProperty.RegisterDirect(
25 | nameof(SelectedItem),
26 | o => o.SelectedItem,
27 | (o, v) => o.SelectedItem = v,
28 | defaultBindingMode: BindingMode.TwoWay);
29 |
30 | public static readonly DirectProperty> ColumnsProperty =
31 | AvaloniaProperty.RegisterDirect>(
32 | nameof(Columns),
33 | o => o.Columns);
34 |
35 | public static readonly StyledProperty CanUserSortColumnsProperty =
36 | AvaloniaProperty.Register(nameof(CanUserSortColumns), true);
37 |
38 | public static readonly StyledProperty CanUserResizeColumnsProperty =
39 | AvaloniaProperty.Register(nameof(CanUserResizeColumns));
40 |
41 | public static readonly StyledProperty GridLinesVisibilityProperty =
42 | AvaloniaProperty.Register(nameof(GridLinesVisibility));
43 |
44 | public static readonly StyledProperty IsReadOnlyProperty =
45 | AvaloniaProperty.Register(nameof(IsReadOnly));
46 |
47 | public static readonly StyledProperty HorizontalGridLinesBrushProperty =
48 | AvaloniaProperty.Register(nameof(HorizontalGridLinesBrush));
49 |
50 | public static readonly StyledProperty VerticalGridLinesBrushProperty =
51 | AvaloniaProperty.Register(nameof(VerticalGridLinesBrush));
52 |
53 | private IEnumerable? _itemsSource = new AvaloniaList