diff --git a/.ncrunch/BindingDemo.v3.ncrunchproject b/.ncrunch/BindingDemo.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/BindingDemo.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/RenderDemo.v3.ncrunchproject b/.ncrunch/RenderDemo.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/RenderDemo.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/VirtualizationDemo.v3.ncrunchproject b/.ncrunch/VirtualizationDemo.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/VirtualizationDemo.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/Avalonia.sln b/Avalonia.sln
index 810ba5c12f..38f8e5f720 100644
--- a/Avalonia.sln
+++ b/Avalonia.sln
@@ -204,16 +204,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Dialogs", "src\Ava
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.FreeDesktop", "src\Avalonia.FreeDesktop\Avalonia.FreeDesktop.csproj", "{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Controls.DataGrid.UnitTests", "tests\Avalonia.Controls.DataGrid.UnitTests\Avalonia.Controls.DataGrid.UnitTests.csproj", "{351337F5-D66F-461B-A957-4EF60BDB4BA6}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.DataGrid.UnitTests", "tests\Avalonia.Controls.DataGrid.UnitTests\Avalonia.Controls.DataGrid.UnitTests.csproj", "{351337F5-D66F-461B-A957-4EF60BDB4BA6}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
- src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 4
+ src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 5
src\Shared\PlatformSupport\PlatformSupport.projitems*{4488ad85-1495-4809-9aa4-ddfe0a48527e}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{7b92af71-6287-4693-9dcb-bd5b6e927e23}*SharedItemsImports = 4
- src\Shared\RenderHelpers\RenderHelpers.projitems*{7d2d3083-71dd-4cc9-8907-39a0d86fb322}*SharedItemsImports = 4
- tests\Avalonia.RenderTests\Avalonia.RenderTests.projitems*{dabfd304-d6a4-4752-8123-c2ccf7ac7831}*SharedItemsImports = 4
+ src\Shared\RenderHelpers\RenderHelpers.projitems*{7d2d3083-71dd-4cc9-8907-39a0d86fb322}*SharedItemsImports = 5
+ src\Shared\PlatformSupport\PlatformSupport.projitems*{88060192-33d5-4932-b0f9-8bd2763e857d}*SharedItemsImports = 5
src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index dc57a73f48..fde2931bf9 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -1,76 +1,130 @@
+
# Contributor Covenant Code of Conduct
## Our Pledge
-In the interest of fostering an open and welcoming environment, we as
-contributors and maintainers pledge to making participation in our project and
-our community a harassment-free experience for everyone, regardless of age, body
-size, disability, ethnicity, sex characteristics, gender identity and expression,
-level of experience, education, socio-economic status, nationality, personal
-appearance, race, religion, or sexual identity and orientation.
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, religion, or sexual identity
+and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
## Our Standards
-Examples of behavior that contributes to creating a positive environment
-include:
+Examples of behavior that contributes to a positive environment for our
+community include:
-* Using welcoming and inclusive language
-* Being respectful of differing viewpoints and experiences
-* Gracefully accepting constructive criticism
-* Focusing on what is best for the community
-* Showing empathy towards other community members
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the
+ overall community
-Examples of unacceptable behavior by participants include:
+Examples of unacceptable behavior include:
-* The use of sexualized language or imagery and unwelcome sexual attention or
- advances
-* Trolling, insulting/derogatory comments, and personal or political attacks
+* The use of sexualized language or imagery, and sexual attention or
+ advances of any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
-* Publishing others' private information, such as a physical or electronic
- address, without explicit permission
+* Publishing others' private information, such as a physical or email
+ address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
- professional setting
+ professional setting
-## Our Responsibilities
+## Enforcement Responsibilities
-Project maintainers are responsible for clarifying the standards of acceptable
-behavior and are expected to take appropriate and fair corrective action in
-response to any instances of unacceptable behavior.
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
-Project maintainers have the right and responsibility to remove, edit, or
-reject comments, commits, code, wiki edits, issues, and other contributions
-that are not aligned to this Code of Conduct, or to ban temporarily or
-permanently any contributor for other behaviors that they deem inappropriate,
-threatening, offensive, or harmful.
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
## Scope
-This Code of Conduct applies both within project spaces and in public spaces
-when an individual is representing the project or its community. Examples of
-representing a project or community include using an official project e-mail
-address, posting via an official social media account, or acting as an appointed
-representative at an online or offline event. Representation of a project may be
-further defined and clarified by project maintainers.
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
-reported by contacting the project team at steven@avaloniaui.net. All
-complaints will be reviewed and investigated and will result in a response that
-is deemed necessary and appropriate to the circumstances. The project team is
-obligated to maintain confidentiality with regard to the reporter of an incident.
-Further details of specific enforcement policies may be posted separately.
+reported to the community leaders responsible for enforcement at
+steven@avaloniaui.net.
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
-Project maintainers who do not follow or enforce the Code of Conduct in good
-faith may face temporary or permanent repercussions as determined by other
-members of the project's leadership.
+**Community Impact**: A violation through a single incident or series
+of actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or
+permanent ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within
+the community.
## Attribution
-This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
-available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.0, available at
+https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
+
+Community Impact Guidelines were inspired by [Mozilla's code of conduct
+enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
-For answers to common questions about this code of conduct, see
-https://www.contributor-covenant.org/faq
+For answers to common questions about this code of conduct, see the FAQ at
+https://www.contributor-covenant.org/faq. Translations are available at
+https://www.contributor-covenant.org/translations.
+
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000000..dcf95ce33c
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,69 @@
+# Contributing to Avalonia
+
+## Before You Start
+
+Drop into our [gitter chat room](https://gitter.im/AvaloniaUI/Avalonia) and let us know what you're thinking of doing. We might be able to give you guidance or let you know if someone else is already working on the feature.
+
+## Style
+
+The codebase uses [.net core](https://github.com/dotnet/runtime/blob/master/docs/coding-guidelines/coding-style.md) coding style.
+
+Try to keep lines of code around 100 characters in length or less, though this is not a hard limit.
+If you're a few characters over then don't worry too much.
+
+**DO NOT USE #REGIONS** full stop.
+
+## Pull requests
+
+A single pull request should be submitted for each change. If you're making more than one change,
+please submit separate pull requests for each change for easy review. Rebase your changes to make
+sense, so a history that looks like:
+
+* Add class A
+* Feature A didn't set Foo when Bar was set
+* Fix spacing
+* Add class B
+* Sort using statements
+
+Should be rebased to read:
+
+* Add class A
+* Add class B
+
+Again, this makes review much easier.
+
+Please try not to submit pull requests that don't add new features (e.g. moving stuff around)
+unless you see something that is obviously wrong or that could be written in a more terse or
+idiomatic style. It takes time to review each pull request - time that I'd prefer to spend writing
+new features!
+
+Prefer terseness to verbosity but don't try to be too clever.
+
+## Tests
+
+There are two types of tests currently in the codebase; unit tests and render tests.
+
+Unit tests should be contained in a class name that mirrors the class being tested with the suffix
+-Tests, e.g.
+
+ Avalonia.Controls.UnitTests.Presenters.TextPresenterTests
+
+Where Avalonia.Controls.UnitTests is the name of the project.
+
+Unit test methods should be named in a sentence style, separated by underscores, that describes in
+English what the test is testing, e.g.
+
+```csharp
+ void Calling_Foo_Should_Increment_Bar()
+```
+
+Render tests should describe what the produced image is:
+
+```csharp
+ void Rectangle_2px_Stroke_Filled()
+```
+
+## Code of Conduct
+
+This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community.
+For more information see the [Contributor Covenant Code of Conduct](https://dotnetfoundation.org/code-of-conduct)
diff --git a/Documentation/build.md b/Documentation/build.md
new file mode 100644
index 0000000000..56b028206d
--- /dev/null
+++ b/Documentation/build.md
@@ -0,0 +1,79 @@
+# Windows
+
+Avalonia requires at least Visual Studio 2019 and .NET Core SDK 3.1 to build on Windows.
+
+### Clone the Avalonia repository
+
+```
+git clone https://github.com/AvaloniaUI/Avalonia.git
+git submodule update --init
+```
+
+### Open in Visual Studio
+
+Open the `Avalonia.sln` solution in Visual Studio 2019 or newer. The free Visual Studio Community
+edition works fine. Run the `Samples\ControlCatalog.Desktop` project to see the sample application.
+
+# Linux/macOS
+
+It's *not* possible to build the *whole* project on Linux/macOS. You can only build the subset targeting .NET Standard and .NET Core (which is, however, sufficient to get UI working on Linux/macOS). If you want to something that involves changing platform-specific APIs you'll need a Windows machine.
+
+MonoDevelop, Xamarin Studio and Visual Studio for Mac aren't capable of properly opening our solution. You can use Rider (at least 2017.2 EAP) or VSCode instead. They will fail to load most of platform specific projects, but you don't need them to run on .NET Core.
+
+### Install the latest version of .NET Core
+
+Go to https://www.microsoft.com/net/core and follow instructions for your OS. You need SDK (not just "runtime") package.
+
+### Additional requirements for macOS
+
+The build process needs [Xcode](https://developer.apple.com/xcode/) to build the native library. Following the install instructions at the [Xcode](https://developer.apple.com/xcode/) website to properly install.
+
+Linux operating systems ship with their own respective package managers however we will use [Homebrew](https://brew.sh/) to manage packages on macOS. To install follow the instructions [here](https://docs.brew.sh/Installation).
+
+### Install CastXML
+
+Avalonia requires [CastXML](https://github.com/CastXML/CastXML) for XML processing during the build process. The easiest way to install this is via the operating system's package managers, such as below.
+
+On macOS:
+```
+brew install castxml
+```
+
+On Debian based Linux (Debian, Ubuntu, Mint, etc):
+```
+sudo apt install castxml
+```
+
+On Red Hat based Linux (Fedora, CentOS, RHEL, etc) using `yum` (`dnf` takes same arguments though):
+```
+sudo yum install castxml
+```
+
+
+### Clone the Avalonia repository
+
+```
+git clone https://github.com/AvaloniaUI/Avalonia.git
+cd Avalonia
+git submodule update --init --recursive
+```
+
+### Build native libraries (macOS only)
+
+On macOS it is necessary to build and manually install the respective native libraries using [Xcode](https://developer.apple.com/xcode/). The steps to get this working correctly are:
+- Navigate to the Avalonia/native/Avalonia.Native/src/OSX folder and open the `Avalonia.Native.OSX.xcodeproj` project
+- Build the library via the Product->Build menu. This will generate binaries in your local path under ~/Library/Developer/Xcode/DerivedData/Avalonia.Native.OSX-*guid* where "guid" is uniquely generated every time you build.
+- Manually install the native library by copying it from the build artifacts folder into the shared dynamic library path:
+
+```
+cd ~/Library/Developer/Xcode/DerivedData/Avalonia.Native.OSX-[guid]/Build/Products/Debug
+cp libAvalonia.Native.OSX.dylib /usr/local/lib/libAvaloniaNative.dylib
+```
+
+### Build and Run Avalonia
+
+```
+cd samples/ControlCatalog.NetCore
+dotnet restore
+dotnet run
+```
diff --git a/NOTICE.md b/NOTICE.md
new file mode 100644
index 0000000000..0e1d792e84
--- /dev/null
+++ b/NOTICE.md
@@ -0,0 +1,273 @@
+# WPF
+
+https://github.com/dotnet/wpf
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+# SharpDX
+
+https://github.com/sharpdx/SharpDX
+
+Copyright (c) 2010-2014 SharpDX - Alexandre Mutel
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+# Silverlight Toolkit
+
+https://github.com/microsoftarchive/SilverlightToolkit
+
+Microsoft Public License (MS-PL)
+
+This license governs use of the accompanying software. If you use the software, you
+accept this license. If you do not accept the license, do not use the software.
+
+1. Definitions
+The terms "reproduce," "reproduction," "derivative works," and "distribution" have the
+same meaning here as under U.S. copyright law.
+A "contribution" is the original software, or any additions or changes to the software.
+A "contributor" is any person that distributes its contribution under this license.
+"Licensed patents" are a contributor's patent claims that read directly on its contribution.
+
+2. Grant of Rights
+(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
+(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
+
+3. Conditions and Limitations
+(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
+(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
+(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
+(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
+(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
+
+# wayland-protocols
+
+https://github.com/wayland-project/wayland-protocols
+
+Copyright 2008-2013 Kristian Hgsberg
+Copyright 2010-2013 Intel Corporation
+Copyright 2013 Rafael Antognolli
+Copyright 2013 Jasper St. Pierre
+Copyright 2014 Jonas dahl
+Copyright 2014 Jason Ekstrand
+Copyright 2014-2015 Collabora, Ltd.
+Copyright 2015 Red Hat Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+# Metsys.Bson
+
+Copyright (c) 2010, Karl Seguin - http://www.openmymind.net/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# RichTextKit
+
+https://github.com/toptensoftware/RichTextKit
+
+Copyright 2019 Topten Software. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may
+not use this product except in compliance with the License. You may obtain
+a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations
+under the License.
+
+# Mono
+
+https://github.com/mono/mono
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+# Collections.Pooled
+
+https://github.com/jtmueller/Collections.Pooled
+
+The MIT License (MIT)
+
+Copyright (c) Joel Mueller
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+# EllipticalArc.java
+
+http://www.spaceroots.org/documents/ellipse/EllipticalArc.java
+http://www.spaceroots.org/documents/ellipse/elliptical-arc.pdf
+
+Copyright (c) 2003-2004, Luc Maisonobe
+All rights reserved.
+
+Redistribution and use in source and binary forms, with
+or without modification, are permitted provided that
+the following conditions are met:
+
+ Redistributions of source code must retain the
+ above copyright notice, this list of conditions and
+ the following disclaimer.
+ Redistributions in binary form must reproduce the
+ above copyright notice, this list of conditions and
+ the following disclaimer in the documentation
+ and/or other materials provided with the
+ distribution.
+ Neither the names of spaceroots.org, spaceroots.com
+ nor the names of their contributors may be used to
+ endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+# WinUI
+
+https://github.com/microsoft/microsoft-ui-xaml
+
+MIT License
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index accad63faa..54645e461e 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -14,7 +14,7 @@ jobs:
displayName: 'Install Nuke'
inputs:
script: |
- dotnet tool install --global Nuke.GlobalTool --version 0.12.3
+ dotnet tool install --global Nuke.GlobalTool --version 0.24.0
- task: CmdLine@2
displayName: 'Run Nuke'
inputs:
@@ -35,16 +35,16 @@ jobs:
vmImage: 'macOS-10.14'
steps:
- task: UseDotNet@2
- displayName: 'Use .NET Core SDK 3.0.x'
+ displayName: 'Use .NET Core SDK 3.1.101'
inputs:
packageType: sdk
- version: 3.0.x
+ version: 3.1.101
- task: UseDotNet@2
- displayName: 'Use .NET Core Runtime 2.1.x'
+ displayName: 'Use .NET Core Runtime 3.1.1'
inputs:
packageType: runtime
- version: 2.1.x
+ version: 3.1.1
- task: CmdLine@2
displayName: 'Install Mono 5.18'
@@ -68,13 +68,13 @@ jobs:
inputs:
script: |
brew update
- brew install castxml
+ brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/8a004a91a7fcd3f6620d5b01b6541ff0a640ffba/Formula/castxml.rb
- task: CmdLine@2
displayName: 'Install Nuke'
inputs:
script: |
- dotnet tool install --global Nuke.GlobalTool --version 0.12.3
+ dotnet tool install --global Nuke.GlobalTool --version 0.24.0
- task: CmdLine@2
displayName: 'Run Nuke'
@@ -116,7 +116,7 @@ jobs:
displayName: 'Install Nuke'
inputs:
script: |
- dotnet tool install --global Nuke.GlobalTool --version 0.12.3
+ dotnet tool install --global Nuke.GlobalTool --version 0.24.0
- task: CmdLine@2
displayName: 'Run Nuke'
diff --git a/build/Rx.props b/build/Rx.props
index edff0af160..8a15ccd6a9 100644
--- a/build/Rx.props
+++ b/build/Rx.props
@@ -1,5 +1,5 @@
-
+
diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props
index 08a9aa3ceb..4f69f39e02 100644
--- a/build/SkiaSharp.props
+++ b/build/SkiaSharp.props
@@ -1,6 +1,6 @@
-
-
+
+
diff --git a/global.json b/global.json
index 1e599211d4..a3fdca9bed 100644
--- a/global.json
+++ b/global.json
@@ -1,4 +1,7 @@
{
+ "sdk": {
+ "version": "3.1.101"
+ },
"msbuild-sdks": {
"Microsoft.Build.Traversal": "1.0.43",
"MSBuild.Sdk.Extras": "2.0.46",
diff --git a/licence.md b/licence.md
index d730e936db..d18aef99ad 100644
--- a/licence.md
+++ b/licence.md
@@ -1,6 +1,7 @@
The MIT License (MIT)
-Copyright (c) 2014 Steven Kirk
+Copyright (c) .NET Foundation and Contributors
+All Rights Reserved
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -18,4 +19,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
\ No newline at end of file
+SOFTWARE.
diff --git a/native/Avalonia.Native/inc/avalonia-native-guids.h b/native/Avalonia.Native/inc/avalonia-native-guids.h
index 439008fd4b..64fec729a2 100644
--- a/native/Avalonia.Native/inc/avalonia-native-guids.h
+++ b/native/Avalonia.Native/inc/avalonia-native-guids.h
@@ -1,5 +1,2 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
#define COM_GUIDS_MATERIALIZE
#include "avalonia-native.h"
diff --git a/native/Avalonia.Native/inc/avalonia-native.h b/native/Avalonia.Native/inc/avalonia-native.h
index 4a960d47a1..b10db08adc 100644
--- a/native/Avalonia.Native/inc/avalonia-native.h
+++ b/native/Avalonia.Native/inc/avalonia-native.h
@@ -1,8 +1,6 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
#include "com.h"
#include "key.h"
+#include "stddef.h"
#define AVNCOM(name, id) COMINTERFACE(name, 2e2cda0a, 9ae5, 4f1b, 8e, 20, 08, 1a, 04, 27, 9f, id)
@@ -22,8 +20,15 @@ struct IAvnGlContext;
struct IAvnGlDisplay;
struct IAvnGlSurfaceRenderTarget;
struct IAvnGlSurfaceRenderingSession;
-struct IAvnAppMenu;
-struct IAvnAppMenuItem;
+struct IAvnMenu;
+struct IAvnMenuItem;
+struct IAvnMenuEvents;
+
+enum SystemDecorations {
+ SystemDecorationsNone = 0,
+ SystemDecorationsBorderOnly = 1,
+ SystemDecorationsFull = 2,
+};
struct AvnSize
{
@@ -172,6 +177,13 @@ enum AvnWindowEdge
WindowEdgeSouthEast
};
+enum AvnMenuItemToggleType
+{
+ None,
+ CheckMark,
+ Radio
+};
+
AVNCOM(IAvaloniaNativeFactory, 01) : IUnknown
{
public:
@@ -185,11 +197,10 @@ public:
virtual HRESULT CreateClipboard(IAvnClipboard** ppv) = 0;
virtual HRESULT CreateCursorFactory(IAvnCursorFactory** ppv) = 0;
virtual HRESULT ObtainGlDisplay(IAvnGlDisplay** ppv) = 0;
- virtual HRESULT ObtainAppMenu(IAvnAppMenu** retOut) = 0;
- virtual HRESULT SetAppMenu(IAvnAppMenu* menu) = 0;
- virtual HRESULT CreateMenu (IAvnAppMenu** ppv) = 0;
- virtual HRESULT CreateMenuItem (IAvnAppMenuItem** ppv) = 0;
- virtual HRESULT CreateMenuItemSeperator (IAvnAppMenuItem** ppv) = 0;
+ virtual HRESULT SetAppMenu(IAvnMenu* menu) = 0;
+ virtual HRESULT CreateMenu (IAvnMenuEvents* cb, IAvnMenu** ppv) = 0;
+ virtual HRESULT CreateMenuItem (IAvnMenuItem** ppv) = 0;
+ virtual HRESULT CreateMenuItemSeperator (IAvnMenuItem** ppv) = 0;
};
AVNCOM(IAvnString, 17) : IUnknown
@@ -219,8 +230,7 @@ AVNCOM(IAvnWindowBase, 02) : IUnknown
virtual HRESULT SetTopMost (bool value) = 0;
virtual HRESULT SetCursor(IAvnCursor* cursor) = 0;
virtual HRESULT CreateGlRenderTarget(IAvnGlSurfaceRenderTarget** ret) = 0;
- virtual HRESULT SetMainMenu(IAvnAppMenu* menu) = 0;
- virtual HRESULT ObtainMainMenu(IAvnAppMenu** retOut) = 0;
+ virtual HRESULT SetMainMenu(IAvnMenu* menu) = 0;
virtual HRESULT ObtainNSWindowHandle(void** retOut) = 0;
virtual HRESULT ObtainNSWindowHandleRetained(void** retOut) = 0;
virtual HRESULT ObtainNSViewHandle(void** retOut) = 0;
@@ -236,7 +246,7 @@ AVNCOM(IAvnWindow, 04) : virtual IAvnWindowBase
{
virtual HRESULT ShowDialog (IAvnWindow* parent) = 0;
virtual HRESULT SetCanResize(bool value) = 0;
- virtual HRESULT SetHasDecorations(bool value) = 0;
+ virtual HRESULT SetHasDecorations(SystemDecorations value) = 0;
virtual HRESULT SetTitle (void* utf8Title) = 0;
virtual HRESULT SetTitleBarColor (AvnColor color) = 0;
virtual HRESULT SetWindowState(AvnWindowState state) = 0;
@@ -385,10 +395,10 @@ AVNCOM(IAvnGlSurfaceRenderingSession, 16) : IUnknown
virtual HRESULT GetScaling(double* ret) = 0;
};
-AVNCOM(IAvnAppMenu, 17) : IUnknown
+AVNCOM(IAvnMenu, 17) : IUnknown
{
- virtual HRESULT AddItem (IAvnAppMenuItem* item) = 0;
- virtual HRESULT RemoveItem (IAvnAppMenuItem* item) = 0;
+ virtual HRESULT InsertItem (int index, IAvnMenuItem* item) = 0;
+ virtual HRESULT RemoveItem (IAvnMenuItem* item) = 0;
virtual HRESULT SetTitle (void* utf8String) = 0;
virtual HRESULT Clear () = 0;
};
@@ -398,12 +408,23 @@ AVNCOM(IAvnPredicateCallback, 18) : IUnknown
virtual bool Evaluate() = 0;
};
-AVNCOM(IAvnAppMenuItem, 19) : IUnknown
+AVNCOM(IAvnMenuItem, 19) : IUnknown
{
- virtual HRESULT SetSubMenu (IAvnAppMenu* menu) = 0;
+ virtual HRESULT SetSubMenu (IAvnMenu* menu) = 0;
virtual HRESULT SetTitle (void* utf8String) = 0;
virtual HRESULT SetGesture (void* utf8String, AvnInputModifiers modifiers) = 0;
virtual HRESULT SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback) = 0;
+ virtual HRESULT SetIsChecked (bool isChecked) = 0;
+ virtual HRESULT SetToggleType (AvnMenuItemToggleType toggleType) = 0;
+ virtual HRESULT SetIcon (void* data, size_t length) = 0;
+};
+
+AVNCOM(IAvnMenuEvents, 1A) : IUnknown
+{
+ /**
+ * NeedsUpdate
+ */
+ virtual void NeedsUpdate () = 0;
};
extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative();
diff --git a/native/Avalonia.Native/inc/com.h b/native/Avalonia.Native/inc/com.h
index 22fb4a11a3..df251514ef 100644
--- a/native/Avalonia.Native/inc/com.h
+++ b/native/Avalonia.Native/inc/com.h
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
#pragma clang diagnostic push
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
#ifndef COM_H_INCLUDED
diff --git a/native/Avalonia.Native/inc/key.h b/native/Avalonia.Native/inc/key.h
index cdc9658e29..12d283cc17 100644
--- a/native/Avalonia.Native/inc/key.h
+++ b/native/Avalonia.Native/inc/key.h
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
#ifndef _KEY_H_
#define _KEY_H_
diff --git a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme
index 1a665d3ea5..5d20a135b9 100644
--- a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme
+++ b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme
@@ -29,8 +29,6 @@
shouldUseLaunchSchemeArgsEnv = "YES">
-
-
-
-
diff --git a/native/Avalonia.Native/src/OSX/SystemDialogs.mm b/native/Avalonia.Native/src/OSX/SystemDialogs.mm
index 567dd7f747..a47221056b 100644
--- a/native/Avalonia.Native/src/OSX/SystemDialogs.mm
+++ b/native/Avalonia.Native/src/OSX/SystemDialogs.mm
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
#include "common.h"
#include "window.h"
@@ -23,6 +20,7 @@ public:
if(title != nullptr)
{
+ panel.message = [NSString stringWithUTF8String:title];
panel.title = [NSString stringWithUTF8String:title];
}
@@ -97,6 +95,7 @@ public:
if(title != nullptr)
{
+ panel.message = [NSString stringWithUTF8String:title];
panel.title = [NSString stringWithUTF8String:title];
}
@@ -185,6 +184,7 @@ public:
if(title != nullptr)
{
+ panel.message = [NSString stringWithUTF8String:title];
panel.title = [NSString stringWithUTF8String:title];
}
diff --git a/native/Avalonia.Native/src/OSX/app.mm b/native/Avalonia.Native/src/OSX/app.mm
index 5c50aad4cc..1e74a70e66 100644
--- a/native/Avalonia.Native/src/OSX/app.mm
+++ b/native/Avalonia.Native/src/OSX/app.mm
@@ -2,7 +2,8 @@
@interface AvnAppDelegate : NSObject
@end
-extern NSApplicationActivationPolicy AvnDesiredActivationPolicy = NSApplicationActivationPolicyRegular;
+NSApplicationActivationPolicy AvnDesiredActivationPolicy = NSApplicationActivationPolicyRegular;
+
@implementation AvnAppDelegate
- (void)applicationWillFinishLaunching:(NSNotification *)notification
{
@@ -14,6 +15,10 @@ extern NSApplicationActivationPolicy AvnDesiredActivationPolicy = NSApplicationA
}
[[NSApplication sharedApplication] setActivationPolicy: AvnDesiredActivationPolicy];
+
+ [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSFullScreenMenuItemEverywhere"];
+
+ [[NSApplication sharedApplication] setHelpMenu: [[NSMenu new] initWithTitle:@""]];
}
}
diff --git a/native/Avalonia.Native/src/OSX/clipboard.mm b/native/Avalonia.Native/src/OSX/clipboard.mm
index 6e4d3ce668..c2cf1f1f61 100644
--- a/native/Avalonia.Native/src/OSX/clipboard.mm
+++ b/native/Avalonia.Native/src/OSX/clipboard.mm
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
#include "common.h"
#include "AvnString.h"
diff --git a/native/Avalonia.Native/src/OSX/common.h b/native/Avalonia.Native/src/OSX/common.h
index d7eda20f65..7a433bfd9f 100644
--- a/native/Avalonia.Native/src/OSX/common.h
+++ b/native/Avalonia.Native/src/OSX/common.h
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
#ifndef common_h
#define common_h
#include "comimpl.h"
@@ -18,11 +15,11 @@ extern IAvnScreens* CreateScreens();
extern IAvnClipboard* CreateClipboard();
extern IAvnCursorFactory* CreateCursorFactory();
extern IAvnGlDisplay* GetGlDisplay();
-extern IAvnAppMenu* CreateAppMenu();
-extern IAvnAppMenuItem* CreateAppMenuItem();
-extern IAvnAppMenuItem* CreateAppMenuItemSeperator();
-extern void SetAppMenu (NSString* appName, IAvnAppMenu* appMenu);
-extern IAvnAppMenu* GetAppMenu ();
+extern IAvnMenu* CreateAppMenu(IAvnMenuEvents* events);
+extern IAvnMenuItem* CreateAppMenuItem();
+extern IAvnMenuItem* CreateAppMenuItemSeperator();
+extern void SetAppMenu (NSString* appName, IAvnMenu* appMenu);
+extern IAvnMenu* GetAppMenu ();
extern NSMenuItem* GetAppMenuItem ();
extern void InitializeAvnApp();
diff --git a/native/Avalonia.Native/src/OSX/cursor.h b/native/Avalonia.Native/src/OSX/cursor.h
index cfe91955d8..75a9c3d2ad 100644
--- a/native/Avalonia.Native/src/OSX/cursor.h
+++ b/native/Avalonia.Native/src/OSX/cursor.h
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
#ifndef cursor_h
#define cursor_h
diff --git a/native/Avalonia.Native/src/OSX/cursor.mm b/native/Avalonia.Native/src/OSX/cursor.mm
index 799fa9e8e6..b6f9ed5071 100644
--- a/native/Avalonia.Native/src/OSX/cursor.mm
+++ b/native/Avalonia.Native/src/OSX/cursor.mm
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
#include "common.h"
#include "cursor.h"
#include
diff --git a/native/Avalonia.Native/src/OSX/main.mm b/native/Avalonia.Native/src/OSX/main.mm
index 2b6b24cfda..a63353bc0a 100644
--- a/native/Avalonia.Native/src/OSX/main.mm
+++ b/native/Avalonia.Native/src/OSX/main.mm
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
//This file will contain actual IID structures
#define COM_GUIDS_MATERIALIZE
#include "common.h"
@@ -95,12 +92,11 @@ void SetProcessName(NSString* appTitle) {
PrivateLSASN asn = ls_get_current_application_asn_func();
// Constant used by WebKit; what exactly it means is unknown.
const int magic_session_constant = -2;
- OSErr err =
+
ls_set_application_information_item_func(magic_session_constant, asn,
ls_display_name_key,
process_name,
NULL /* optional out param */);
- //LOG_IF(ERROR, err) << "Call to set process name failed, err " << err;
}
class MacOptions : public ComSingleObject
@@ -231,41 +227,29 @@ public:
return S_OK;
}
- virtual HRESULT CreateMenu (IAvnAppMenu** ppv) override
+ virtual HRESULT CreateMenu (IAvnMenuEvents* cb, IAvnMenu** ppv) override
{
- *ppv = ::CreateAppMenu();
+ *ppv = ::CreateAppMenu(cb);
return S_OK;
}
- virtual HRESULT CreateMenuItem (IAvnAppMenuItem** ppv) override
+ virtual HRESULT CreateMenuItem (IAvnMenuItem** ppv) override
{
*ppv = ::CreateAppMenuItem();
return S_OK;
}
- virtual HRESULT CreateMenuItemSeperator (IAvnAppMenuItem** ppv) override
+ virtual HRESULT CreateMenuItemSeperator (IAvnMenuItem** ppv) override
{
*ppv = ::CreateAppMenuItemSeperator();
return S_OK;
}
- virtual HRESULT SetAppMenu (IAvnAppMenu* appMenu) override
+ virtual HRESULT SetAppMenu (IAvnMenu* appMenu) override
{
::SetAppMenu(s_appTitle, appMenu);
return S_OK;
}
-
- virtual HRESULT ObtainAppMenu(IAvnAppMenu** retOut) override
- {
- if(retOut == nullptr)
- {
- return E_POINTER;
- }
-
- *retOut = ::GetAppMenu();
-
- return S_OK;
- }
};
extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative()
diff --git a/native/Avalonia.Native/src/OSX/menu.h b/native/Avalonia.Native/src/OSX/menu.h
index befbe6a7e0..bfbc6801f8 100644
--- a/native/Avalonia.Native/src/OSX/menu.h
+++ b/native/Avalonia.Native/src/OSX/menu.h
@@ -14,8 +14,10 @@
class AvnAppMenuItem;
class AvnAppMenu;
-@interface AvnMenu : NSMenu // for some reason it doesnt detect nsmenu here but compiler doesnt complain
-- (void)setMenu:(NSMenu*) menu;
+@interface AvnMenu : NSMenu
+- (id) initWithDelegate: (NSObject*) del;
+- (void) setHasGlobalMenuItem: (bool) value;
+- (bool) hasGlobalMenuItem;
@end
@interface AvnMenuItem : NSMenuItem
@@ -23,13 +25,14 @@ class AvnAppMenu;
- (void)didSelectItem:(id)sender;
@end
-class AvnAppMenuItem : public ComSingleObject
+class AvnAppMenuItem : public ComSingleObject
{
private:
NSMenuItem* _native; // here we hold a pointer to an AvnMenuItem
IAvnActionCallback* _callback;
IAvnPredicateCallback* _predicate;
bool _isSeperator;
+ bool _isCheckable;
public:
FORWARD_IUNKNOWN()
@@ -38,7 +41,7 @@ public:
NSMenuItem* GetNative();
- virtual HRESULT SetSubMenu (IAvnAppMenu* menu) override;
+ virtual HRESULT SetSubMenu (IAvnMenu* menu) override;
virtual HRESULT SetTitle (void* utf8String) override;
@@ -46,29 +49,36 @@ public:
virtual HRESULT SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback) override;
+ virtual HRESULT SetIsChecked (bool isChecked) override;
+
+ virtual HRESULT SetToggleType (AvnMenuItemToggleType toggleType) override;
+
+ virtual HRESULT SetIcon (void* data, size_t length) override;
+
bool EvaluateItemEnabled();
void RaiseOnClicked();
};
-class AvnAppMenu : public ComSingleObject
+class AvnAppMenu : public ComSingleObject
{
private:
AvnMenu* _native;
+ ComPtr _baseEvents;
public:
FORWARD_IUNKNOWN()
- AvnAppMenu();
-
- AvnAppMenu(AvnMenu* native);
-
+ AvnAppMenu(IAvnMenuEvents* events);
+
AvnMenu* GetNative();
- virtual HRESULT AddItem (IAvnAppMenuItem* item) override;
+ void RaiseNeedsUpdate ();
+
+ virtual HRESULT InsertItem (int index, IAvnMenuItem* item) override;
- virtual HRESULT RemoveItem (IAvnAppMenuItem* item) override;
+ virtual HRESULT RemoveItem (IAvnMenuItem* item) override;
virtual HRESULT SetTitle (void* utf8String) override;
@@ -76,5 +86,9 @@ public:
};
+@interface AvnMenuDelegate : NSObject
+- (id) initWithParent: (AvnAppMenu*) parent;
+@end
+
#endif
diff --git a/native/Avalonia.Native/src/OSX/menu.mm b/native/Avalonia.Native/src/OSX/menu.mm
index 1d2f075ccb..dc1245cd23 100644
--- a/native/Avalonia.Native/src/OSX/menu.mm
+++ b/native/Avalonia.Native/src/OSX/menu.mm
@@ -4,6 +4,30 @@
#include "window.h"
@implementation AvnMenu
+{
+ bool _isReparented;
+ NSObject* _wtf;
+}
+
+- (id) initWithDelegate: (NSObject*)del
+{
+ self = [super init];
+ self.delegate = del;
+ _wtf = del;
+ _isReparented = false;
+ return self;
+}
+
+- (bool)hasGlobalMenuItem
+{
+ return _isReparented;
+}
+
+- (void)setHasGlobalMenuItem:(bool)value
+{
+ _isReparented = value;
+}
+
@end
@implementation AvnMenuItem
@@ -46,6 +70,7 @@
AvnAppMenuItem::AvnAppMenuItem(bool isSeperator)
{
+ _isCheckable = false;
_isSeperator = isSeperator;
if(isSeperator)
@@ -65,49 +90,134 @@ NSMenuItem* AvnAppMenuItem::GetNative()
return _native;
}
-HRESULT AvnAppMenuItem::SetSubMenu (IAvnAppMenu* menu)
+HRESULT AvnAppMenuItem::SetSubMenu (IAvnMenu* menu)
{
- auto nsMenu = dynamic_cast(menu)->GetNative();
-
- [_native setSubmenu: nsMenu];
-
- return S_OK;
+ @autoreleasepool
+ {
+ if(menu != nullptr)
+ {
+ auto nsMenu = dynamic_cast(menu)->GetNative();
+
+ [_native setSubmenu: nsMenu];
+ }
+ else
+ {
+ [_native setSubmenu: nullptr];
+ }
+
+ return S_OK;
+ }
}
HRESULT AvnAppMenuItem::SetTitle (void* utf8String)
{
- if (utf8String != nullptr)
+ @autoreleasepool
{
- [_native setTitle:[NSString stringWithUTF8String:(const char*)utf8String]];
+ if (utf8String != nullptr)
+ {
+ [_native setTitle:[NSString stringWithUTF8String:(const char*)utf8String]];
+ }
+
+ return S_OK;
}
-
- return S_OK;
}
HRESULT AvnAppMenuItem::SetGesture (void* key, AvnInputModifiers modifiers)
{
- NSEventModifierFlags flags = 0;
-
- if (modifiers & Control)
- flags |= NSEventModifierFlagControl;
- if (modifiers & Shift)
- flags |= NSEventModifierFlagShift;
- if (modifiers & Alt)
- flags |= NSEventModifierFlagOption;
- if (modifiers & Windows)
- flags |= NSEventModifierFlagCommand;
-
- [_native setKeyEquivalent:[NSString stringWithUTF8String:(const char*)key]];
- [_native setKeyEquivalentModifierMask:flags];
-
- return S_OK;
+ @autoreleasepool
+ {
+ NSEventModifierFlags flags = 0;
+
+ if (modifiers & Control)
+ flags |= NSEventModifierFlagControl;
+ if (modifiers & Shift)
+ flags |= NSEventModifierFlagShift;
+ if (modifiers & Alt)
+ flags |= NSEventModifierFlagOption;
+ if (modifiers & Windows)
+ flags |= NSEventModifierFlagCommand;
+
+ [_native setKeyEquivalent:[NSString stringWithUTF8String:(const char*)key]];
+ [_native setKeyEquivalentModifierMask:flags];
+
+ return S_OK;
+ }
}
HRESULT AvnAppMenuItem::SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback)
{
- _predicate = predicate;
- _callback = callback;
- return S_OK;
+ @autoreleasepool
+ {
+ _predicate = predicate;
+ _callback = callback;
+ return S_OK;
+ }
+}
+
+HRESULT AvnAppMenuItem::SetIsChecked (bool isChecked)
+{
+ @autoreleasepool
+ {
+ [_native setState:(isChecked && _isCheckable ? NSOnState : NSOffState)];
+ return S_OK;
+ }
+}
+
+HRESULT AvnAppMenuItem::SetToggleType(AvnMenuItemToggleType toggleType)
+{
+ @autoreleasepool
+ {
+ switch(toggleType)
+ {
+ case AvnMenuItemToggleType::None:
+ [_native setOnStateImage: [NSImage imageNamed:@"NSMenuCheckmark"]];
+
+ _isCheckable = false;
+ break;
+
+ case AvnMenuItemToggleType::CheckMark:
+ [_native setOnStateImage: [NSImage imageNamed:@"NSMenuCheckmark"]];
+
+ _isCheckable = true;
+ break;
+
+ case AvnMenuItemToggleType::Radio:
+ [_native setOnStateImage: [NSImage imageNamed:@"NSMenuItemBullet"]];
+
+ _isCheckable = true;
+ break;
+ }
+
+ return S_OK;
+ }
+}
+
+HRESULT AvnAppMenuItem::SetIcon(void *data, size_t length)
+{
+ @autoreleasepool
+ {
+ if(data != nullptr)
+ {
+ NSData *imageData = [NSData dataWithBytes:data length:length];
+ NSImage *image = [[NSImage alloc] initWithData:imageData];
+
+ NSSize originalSize = [image size];
+
+ NSSize size;
+ size.height = [[NSFont menuFontOfSize:0] pointSize] * 1.333333;
+
+ auto scaleFactor = size.height / originalSize.height;
+ size.width = originalSize.width * scaleFactor;
+
+ [image setSize: size];
+ [_native setImage:image];
+ }
+ else
+ {
+ [_native setImage:nullptr];
+ }
+ return S_OK;
+ }
}
bool AvnAppMenuItem::EvaluateItemEnabled()
@@ -130,71 +240,123 @@ void AvnAppMenuItem::RaiseOnClicked()
}
}
-AvnAppMenu::AvnAppMenu()
+AvnAppMenu::AvnAppMenu(IAvnMenuEvents* events)
{
- _native = [AvnMenu new];
+ _baseEvents = events;
+ id del = [[AvnMenuDelegate alloc] initWithParent: this];
+ _native = [[AvnMenu alloc] initWithDelegate: del];
}
-AvnAppMenu::AvnAppMenu(AvnMenu* native)
-{
- _native = native;
-}
AvnMenu* AvnAppMenu::GetNative()
{
return _native;
}
-HRESULT AvnAppMenu::AddItem (IAvnAppMenuItem* item)
+void AvnAppMenu::RaiseNeedsUpdate()
{
- auto avnMenuItem = dynamic_cast(item);
-
- if(avnMenuItem != nullptr)
+ if(_baseEvents != nullptr)
{
- [_native addItem: avnMenuItem->GetNative()];
+ _baseEvents->NeedsUpdate();
}
-
- return S_OK;
}
-HRESULT AvnAppMenu::RemoveItem (IAvnAppMenuItem* item)
+HRESULT AvnAppMenu::InsertItem(int index, IAvnMenuItem *item)
{
- auto avnMenuItem = dynamic_cast(item);
-
- if(avnMenuItem != nullptr)
+ @autoreleasepool
{
- [_native removeItem:avnMenuItem->GetNative()];
+ if([_native hasGlobalMenuItem])
+ {
+ index++;
+ }
+
+ auto avnMenuItem = dynamic_cast(item);
+
+ if(avnMenuItem != nullptr)
+ {
+ [_native insertItem: avnMenuItem->GetNative() atIndex:index];
+ }
+
+ return S_OK;
+ }
+}
+
+HRESULT AvnAppMenu::RemoveItem (IAvnMenuItem* item)
+{
+ @autoreleasepool
+ {
+ auto avnMenuItem = dynamic_cast(item);
+
+ if(avnMenuItem != nullptr)
+ {
+ [_native removeItem:avnMenuItem->GetNative()];
+ }
+
+ return S_OK;
}
-
- return S_OK;
}
HRESULT AvnAppMenu::SetTitle (void* utf8String)
{
- if (utf8String != nullptr)
+ @autoreleasepool
{
- [_native setTitle:[NSString stringWithUTF8String:(const char*)utf8String]];
+ if (utf8String != nullptr)
+ {
+ [_native setTitle:[NSString stringWithUTF8String:(const char*)utf8String]];
+ }
+
+ return S_OK;
}
-
- return S_OK;
}
HRESULT AvnAppMenu::Clear()
{
- [_native removeAllItems];
- return S_OK;
+ @autoreleasepool
+ {
+ [_native removeAllItems];
+ return S_OK;
+ }
+}
+
+@implementation AvnMenuDelegate
+{
+ ComPtr _parent;
}
+- (id) initWithParent:(AvnAppMenu *)parent
+{
+ self = [super init];
+ _parent = parent;
+ return self;
+}
+- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel
+{
+ if(shouldCancel)
+ return NO;
+ return YES;
+}
+
+- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu
+{
+ return [menu numberOfItems];
+}
+
+- (void)menuNeedsUpdate:(NSMenu *)menu
+{
+ _parent->RaiseNeedsUpdate();
+}
+
+
+@end
-extern IAvnAppMenu* CreateAppMenu()
+extern IAvnMenu* CreateAppMenu(IAvnMenuEvents* cb)
{
@autoreleasepool
{
- id menuBar = [NSMenu new];
- return new AvnAppMenu(menuBar);
+ return new AvnAppMenu(cb);
}
}
-extern IAvnAppMenuItem* CreateAppMenuItem()
+extern IAvnMenuItem* CreateAppMenuItem()
{
@autoreleasepool
{
@@ -202,7 +364,7 @@ extern IAvnAppMenuItem* CreateAppMenuItem()
}
}
-extern IAvnAppMenuItem* CreateAppMenuItemSeperator()
+extern IAvnMenuItem* CreateAppMenuItemSeperator()
{
@autoreleasepool
{
@@ -210,10 +372,10 @@ extern IAvnAppMenuItem* CreateAppMenuItemSeperator()
}
}
-static IAvnAppMenu* s_appMenu = nullptr;
+static IAvnMenu* s_appMenu = nullptr;
static NSMenuItem* s_appMenuItem = nullptr;
-extern void SetAppMenu (NSString* appName, IAvnAppMenu* menu)
+extern void SetAppMenu (NSString* appName, IAvnMenu* menu)
{
s_appMenu = menu;
@@ -294,7 +456,7 @@ extern void SetAppMenu (NSString* appName, IAvnAppMenu* menu)
}
}
-extern IAvnAppMenu* GetAppMenu ()
+extern IAvnMenu* GetAppMenu ()
{
return s_appMenu;
}
diff --git a/native/Avalonia.Native/src/OSX/platformthreading.mm b/native/Avalonia.Native/src/OSX/platformthreading.mm
index ed00f8c5e1..f93436d157 100644
--- a/native/Avalonia.Native/src/OSX/platformthreading.mm
+++ b/native/Avalonia.Native/src/OSX/platformthreading.mm
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
#include "common.h"
class PlatformThreadingInterface;
@@ -57,9 +54,11 @@ private:
{
public:
FORWARD_IUNKNOWN()
+
bool Running = false;
bool Cancelled = false;
- virtual void Cancel()
+
+ virtual void Cancel() override
{
Cancelled = true;
if(Running)
diff --git a/native/Avalonia.Native/src/OSX/window.h b/native/Avalonia.Native/src/OSX/window.h
index 3e626675d2..8092db3663 100644
--- a/native/Avalonia.Native/src/OSX/window.h
+++ b/native/Avalonia.Native/src/OSX/window.h
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
#ifndef window_h
#define window_h
@@ -22,7 +19,11 @@ class WindowBaseImpl;
-(void) pollModalSession: (NSModalSession _Nonnull) session;
-(void) restoreParentWindow;
-(bool) shouldTryToHandleEvents;
--(void) applyMenu:(NSMenu *)menu;
+-(bool) isModal;
+-(void) setModal: (bool) isModal;
+-(void) showAppMenuOnly;
+-(void) showWindowMenuWithAppMenu;
+-(void) applyMenu:(NSMenu* _Nullable)menu;
-(double) getScaling;
@end
diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm
index b6ce172ffa..68899df9f0 100644
--- a/native/Avalonia.Native/src/OSX/window.mm
+++ b/native/Avalonia.Native/src/OSX/window.mm
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
#include "common.h"
#include "window.h"
#include "KeyTransform.h"
@@ -30,10 +27,12 @@ public:
NSObject* renderTarget;
AvnPoint lastPositionSet;
NSString* _lastTitle;
- IAvnAppMenu* _mainMenu;
+ IAvnMenu* _mainMenu;
+ bool _shown;
WindowBaseImpl(IAvnWindowBaseEvents* events, IAvnGlContext* gl)
{
+ _shown = false;
_mainMenu = nullptr;
BaseEvents = events;
_glContext = gl;
@@ -115,7 +114,8 @@ public:
[NSApp activateIgnoringOtherApps:YES];
[Window setTitle:_lastTitle];
- [Window setTitleVisibility:NSWindowTitleVisible];
+
+ _shown = true;
return S_OK;
}
@@ -234,7 +234,7 @@ public:
}
}
- virtual HRESULT SetMainMenu(IAvnAppMenu* menu) override
+ virtual HRESULT SetMainMenu(IAvnMenu* menu) override
{
_mainMenu = menu;
@@ -244,18 +244,11 @@ public:
[Window applyMenu:nsmenu];
- return S_OK;
- }
-
- virtual HRESULT ObtainMainMenu(IAvnAppMenu** ret) override
- {
- if(ret == nullptr)
+ if ([Window isKeyWindow])
{
- return E_POINTER;
+ [Window showWindowMenuWithAppMenu];
}
- *ret = _mainMenu;
-
return S_OK;
}
@@ -401,6 +394,7 @@ protected:
[Window setStyleMask:GetStyle()];
}
+public:
virtual void OnResized ()
{
@@ -411,7 +405,7 @@ class WindowImpl : public virtual WindowBaseImpl, public virtual IAvnWindow, pub
{
private:
bool _canResize = true;
- bool _hasDecorations = true;
+ SystemDecorations _hasDecorations = SystemDecorationsFull;
CGRect _lastUndecoratedFrame;
AvnWindowState _lastWindowState;
@@ -427,9 +421,11 @@ private:
ComPtr WindowEvents;
WindowImpl(IAvnWindowEvents* events, IAvnGlContext* gl) : WindowBaseImpl(events, gl)
{
+ _lastWindowState = Normal;
WindowEvents = events;
[Window setCanBecomeKeyAndMain];
[Window disableCursorRects];
+ [Window setTabbingMode:NSWindowTabbingModeDisallowed];
}
virtual HRESULT Show () override
@@ -438,9 +434,12 @@ private:
{
if([Window parentWindow] != nil)
[[Window parentWindow] removeChildWindow:Window];
+
+ [Window setModal:FALSE];
+
WindowBaseImpl::Show();
- return SetWindowState(Normal);
+ return SetWindowState(_lastWindowState);
}
}
@@ -455,6 +454,8 @@ private:
if(cparent == nullptr)
return E_INVALIDARG;
+ [Window setModal:TRUE];
+
[cparent->Window addChildWindow:Window ordered:NSWindowAbove];
WindowBaseImpl::Show();
@@ -476,23 +477,26 @@ private:
bool IsZoomed ()
{
- return _hasDecorations ? [Window isZoomed] : UndecoratedIsMaximized();
+ return _hasDecorations != SystemDecorationsNone ? [Window isZoomed] : UndecoratedIsMaximized();
}
void DoZoom()
{
- if (_hasDecorations)
+ switch (_hasDecorations)
{
- [Window performZoom:Window];
- }
- else
- {
- if (!UndecoratedIsMaximized())
- {
- _lastUndecoratedFrame = [Window frame];
- }
-
- [Window zoom:Window];
+ case SystemDecorationsNone:
+ if (!UndecoratedIsMaximized())
+ {
+ _lastUndecoratedFrame = [Window frame];
+ }
+
+ [Window zoom:Window];
+ break;
+
+ case SystemDecorationsBorderOnly:
+ case SystemDecorationsFull:
+ [Window performZoom:Window];
+ break;
}
}
@@ -506,13 +510,35 @@ private:
}
}
- virtual HRESULT SetHasDecorations(bool value) override
+ virtual HRESULT SetHasDecorations(SystemDecorations value) override
{
@autoreleasepool
{
_hasDecorations = value;
UpdateStyle();
-
+
+ switch (_hasDecorations)
+ {
+ case SystemDecorationsNone:
+ [Window setHasShadow:NO];
+ [Window setTitleVisibility:NSWindowTitleHidden];
+ [Window setTitlebarAppearsTransparent:YES];
+ break;
+
+ case SystemDecorationsBorderOnly:
+ [Window setHasShadow:YES];
+ [Window setTitleVisibility:NSWindowTitleHidden];
+ [Window setTitlebarAppearsTransparent:YES];
+ break;
+
+ case SystemDecorationsFull:
+ [Window setHasShadow:YES];
+ [Window setTitleVisibility:NSWindowTitleVisible];
+ [Window setTitlebarAppearsTransparent:NO];
+ [Window setTitle:_lastTitle];
+ break;
+ }
+
return S_OK;
}
}
@@ -523,7 +549,6 @@ private:
{
_lastTitle = [NSString stringWithUTF8String:(const char*)utf8title];
[Window setTitle:_lastTitle];
- [Window setTitleVisibility:NSWindowTitleVisible];
return S_OK;
}
@@ -591,64 +616,86 @@ private:
{
_lastWindowState = state;
- switch (state) {
- case Maximized:
- lastPositionSet.X = 0;
- lastPositionSet.Y = 0;
-
- if([Window isMiniaturized])
- {
- [Window deminiaturize:Window];
- }
-
- if(!IsZoomed())
- {
- DoZoom();
- }
- break;
-
- case Minimized:
- [Window miniaturize:Window];
- break;
-
- default:
- if([Window isMiniaturized])
- {
- [Window deminiaturize:Window];
- }
-
- if(IsZoomed())
- {
- DoZoom();
- }
- break;
+ if(_shown)
+ {
+ switch (state) {
+ case Maximized:
+ lastPositionSet.X = 0;
+ lastPositionSet.Y = 0;
+
+ if([Window isMiniaturized])
+ {
+ [Window deminiaturize:Window];
+ }
+
+ if(!IsZoomed())
+ {
+ DoZoom();
+ }
+ break;
+
+ case Minimized:
+ [Window miniaturize:Window];
+ break;
+
+ default:
+ if([Window isMiniaturized])
+ {
+ [Window deminiaturize:Window];
+ }
+
+ if(IsZoomed())
+ {
+ DoZoom();
+ }
+ break;
+ }
}
return S_OK;
}
}
-
-protected:
+
virtual void OnResized () override
{
- auto windowState = [Window isMiniaturized] ? Minimized
- : (IsZoomed() ? Maximized : Normal);
-
- if (windowState != _lastWindowState)
+ if(_shown)
{
- _lastWindowState = windowState;
+ auto windowState = [Window isMiniaturized] ? Minimized
+ : (IsZoomed() ? Maximized : Normal);
- WindowEvents->WindowStateChanged(windowState);
+ if (windowState != _lastWindowState)
+ {
+ _lastWindowState = windowState;
+
+ WindowEvents->WindowStateChanged(windowState);
+ }
}
}
+protected:
virtual NSWindowStyleMask GetStyle() override
{
unsigned long s = NSWindowStyleMaskBorderless;
- if(_hasDecorations)
- s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
- if(_canResize)
- s = s | NSWindowStyleMaskResizable;
+
+ switch (_hasDecorations)
+ {
+ case SystemDecorationsNone:
+ break;
+
+ case SystemDecorationsBorderOnly:
+ s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskFullSizeContentView;
+ break;
+
+ case SystemDecorationsFull:
+ s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskBorderless;
+ if(_canResize)
+ {
+ s = s | NSWindowStyleMaskResizable;
+ }
+
+ break;
+ }
+
return s;
}
};
@@ -1103,8 +1150,8 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
ComPtr _parent;
bool _canBecomeKeyAndMain;
bool _closed;
- NSMenu* _menu;
- bool _isAppMenuApplied;
+ bool _isModal;
+ AvnMenu* _menu;
double _lastScaling;
}
@@ -1141,32 +1188,64 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
}
}
--(void) applyMenu:(NSMenu *)menu
+-(void) showWindowMenuWithAppMenu
{
- if(menu == nullptr)
+ if(_menu != nullptr)
{
- menu = [NSMenu new];
+ auto appMenuItem = ::GetAppMenuItem();
+
+ if(appMenuItem != nullptr)
+ {
+ auto appMenu = [appMenuItem menu];
+
+ [appMenu removeItem:appMenuItem];
+
+ [_menu insertItem:appMenuItem atIndex:0];
+
+ [_menu setHasGlobalMenuItem:true];
+ }
+
+ [NSApp setMenu:_menu];
}
+}
+
+-(void) showAppMenuOnly
+{
+ auto appMenuItem = ::GetAppMenuItem();
- _menu = menu;
-
- if ([self isKeyWindow])
+ if(appMenuItem != nullptr)
{
- auto appMenu = ::GetAppMenuItem();
+ auto appMenu = ::GetAppMenu();
- if(appMenu != nullptr)
+ auto nativeAppMenu = dynamic_cast(appMenu);
+
+ [[appMenuItem menu] removeItem:appMenuItem];
+
+ if(_menu != nullptr)
{
- [[appMenu menu] removeItem:appMenu];
-
- [_menu insertItem:appMenu atIndex:0];
-
- _isAppMenuApplied = true;
+ [_menu setHasGlobalMenuItem:false];
}
- [NSApp setMenu:menu];
+ [nativeAppMenu->GetNative() addItem:appMenuItem];
+
+ [NSApp setMenu:nativeAppMenu->GetNative()];
+ }
+ else
+ {
+ [NSApp setMenu:nullptr];
}
}
+-(void) applyMenu:(AvnMenu *)menu
+{
+ if(menu == nullptr)
+ {
+ menu = [AvnMenu new];
+ }
+
+ _menu = menu;
+}
+
-(void) setCanBecomeKeyAndMain
{
_canBecomeKeyAndMain = true;
@@ -1250,11 +1329,25 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
auto ch = objc_cast(uch);
if(ch == nil)
continue;
+
+ if(![ch isModal])
+ continue;
+
return FALSE;
}
return TRUE;
}
+-(bool) isModal
+{
+ return _isModal;
+}
+
+-(void) setModal: (bool) isModal
+{
+ _isModal = isModal;
+}
+
-(void)makeKeyWindow
{
if([self activateAppropriateChild: true])
@@ -1267,23 +1360,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
{
if([self activateAppropriateChild: true])
{
- if(_menu == nullptr)
- {
- _menu = [NSMenu new];
- }
-
- auto appMenu = ::GetAppMenuItem();
-
- if(appMenu != nullptr)
- {
- [[appMenu menu] removeItem:appMenu];
-
- [_menu insertItem:appMenu atIndex:0];
-
- _isAppMenuApplied = true;
- }
-
- [NSApp setMenu:_menu];
+ [self showWindowMenuWithAppMenu];
_parent->BaseEvents->Activated();
[super becomeKeyWindow];
@@ -1320,6 +1397,11 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
}
}
+- (void)windowDidResize:(NSNotification *)notification
+{
+ _parent->OnResized();
+}
+
- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame
{
return true;
@@ -1330,26 +1412,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
if(_parent)
_parent->BaseEvents->Deactivated();
- auto appMenuItem = ::GetAppMenuItem();
-
- if(appMenuItem != nullptr)
- {
- auto appMenu = ::GetAppMenu();
-
- auto nativeAppMenu = dynamic_cast(appMenu);
-
- [[appMenuItem menu] removeItem:appMenuItem];
-
- [nativeAppMenu->GetNative() addItem:appMenuItem];
-
- [NSApp setMenu:nativeAppMenu->GetNative()];
- }
- else
- {
- [NSApp setMenu:nullptr];
- }
-
- // remove window menu items from appmenu?
+ [self showAppMenuOnly];
[super resignKeyWindow];
}
@@ -1390,6 +1453,7 @@ protected:
[Window setContentSize:NSSize{x, y}];
[Window setFrameTopLeftPoint:ToNSPoint(ConvertPointY(lastPositionSet))];
+
return S_OK;
}
}
diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs
index 7b3b8465ce..358846a14e 100644
--- a/nukebuild/Build.cs
+++ b/nukebuild/Build.cs
@@ -13,6 +13,7 @@ using Nuke.Common.Tooling;
using Nuke.Common.Tools.DotNet;
using Nuke.Common.Tools.MSBuild;
using Nuke.Common.Utilities;
+using Nuke.Common.Utilities.Collections;
using static Nuke.Common.EnvironmentInfo;
using static Nuke.Common.IO.FileSystemTasks;
using static Nuke.Common.IO.PathConstruction;
@@ -26,11 +27,13 @@ using static Nuke.Common.Tools.VSWhere.VSWhereTasks;
running and debugging a particular target (optionally without deps) would be way easier
ReSharper/Rider - https://plugins.jetbrains.com/plugin/10803-nuke-support
VSCode - https://marketplace.visualstudio.com/items?itemName=nuke.support
-
+
*/
partial class Build : NukeBuild
{
+ [Solution("Avalonia.sln")] readonly Solution Solution;
+
static Lazy MsBuildExe = new Lazy(() =>
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
@@ -54,7 +57,7 @@ partial class Build : NukeBuild
protected override void OnBuildInitialized()
{
Parameters = new BuildParameters(this);
- Information("Building version {0} of Avalonia ({1}) using version {2} of Nuke.",
+ Information("Building version {0} of Avalonia ({1}) using version {2} of Nuke.",
Parameters.Version,
Parameters.Configuration,
typeof(NukeBuild).Assembly.GetName().Version.ToString());
@@ -93,29 +96,24 @@ partial class Build : NukeBuild
string projectFile,
Configure configurator = null)
{
- return MSBuild(projectFile, c =>
- {
+ return MSBuild(c => c
+ .SetProjectFile(projectFile)
// This is required for VS2019 image on Azure Pipelines
- if (Parameters.IsRunningOnWindows && Parameters.IsRunningOnAzure)
- {
- var javaSdk = Environment.GetEnvironmentVariable("JAVA_HOME_8_X64");
- if (javaSdk != null)
- c = c.AddProperty("JavaSdkDirectory", javaSdk);
- }
-
- c = c.AddProperty("PackageVersion", Parameters.Version)
- .AddProperty("iOSRoslynPathHackRequired", "true")
- .SetToolPath(MsBuildExe.Value)
- .SetConfiguration(Parameters.Configuration)
- .SetVerbosity(MSBuildVerbosity.Minimal);
- c = configurator?.Invoke(c) ?? c;
- return c;
- });
+ .When(Parameters.IsRunningOnWindows &&
+ Parameters.IsRunningOnAzure, c => c
+ .AddProperty("JavaSdkDirectory", GetVariable("JAVA_HOME_8_X64")))
+ .AddProperty("PackageVersion", Parameters.Version)
+ .AddProperty("iOSRoslynPathHackRequired", true)
+ .SetToolPath(MsBuildExe.Value)
+ .SetConfiguration(Parameters.Configuration)
+ .SetVerbosity(MSBuildVerbosity.Minimal)
+ .Apply(configurator));
}
+
Target Clean => _ => _.Executes(() =>
{
- DeleteDirectories(Parameters.BuildDirs);
- EnsureCleanDirectories(Parameters.BuildDirs);
+ Parameters.BuildDirs.ForEach(DeleteDirectory);
+ Parameters.BuildDirs.ForEach(EnsureCleanDirectory);
EnsureCleanDirectory(Parameters.ArtifactsDir);
EnsureCleanDirectory(Parameters.NugetIntermediateRoot);
EnsureCleanDirectory(Parameters.NugetRoot);
@@ -134,97 +132,84 @@ partial class Build : NukeBuild
);
else
- DotNetBuild(Parameters.MSBuildSolution, c => c
+ DotNetBuild(c => c
+ .SetProjectFile(Parameters.MSBuildSolution)
.AddProperty("PackageVersion", Parameters.Version)
.SetConfiguration(Parameters.Configuration)
);
});
-
- void RunCoreTest(string project)
+
+ void RunCoreTest(string projectName)
{
- if(!project.EndsWith(".csproj"))
- project = System.IO.Path.Combine(project, System.IO.Path.GetFileName(project)+".csproj");
- Information("Running tests from " + project);
- XDocument xdoc;
- using (var s = File.OpenRead(project))
- xdoc = XDocument.Load(s);
-
- List frameworks = null;
- var targets = xdoc.Root.Descendants("TargetFrameworks").FirstOrDefault();
- if (targets != null)
- frameworks = targets.Value.Split(';').Where(f => !string.IsNullOrWhiteSpace(f)).ToList();
- else
- frameworks = new List {xdoc.Root.Descendants("TargetFramework").First().Value};
-
- foreach(var fw in frameworks)
+ Information($"Running tests from {projectName}");
+ var project = Solution.GetProject(projectName).NotNull("project != null");
+
+ foreach (var fw in project.GetTargetFrameworks())
{
if (fw.StartsWith("net4")
- && RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
+ && RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
&& Environment.GetEnvironmentVariable("FORCE_LINUX_TESTS") != "1")
{
- Information($"Skipping {fw} tests on Linux - https://github.com/mono/mono/issues/13969");
+ Information($"Skipping {projectName} ({fw}) tests on Linux - https://github.com/mono/mono/issues/13969");
continue;
}
- Information("Running for " + fw);
- DotNetTest(c =>
- {
- c = c
- .SetProjectFile(project)
- .SetConfiguration(Parameters.Configuration)
- .SetFramework(fw)
- .EnableNoBuild()
- .EnableNoRestore();
- // NOTE: I can see that we could maybe add another extension method "Switch" or "If" to make this more convenient
- if (Parameters.PublishTestResults)
- c = c.SetLogger("trx").SetResultsDirectory(Parameters.TestResultsRoot);
- return c;
- });
+ Information($"Running for {projectName} ({fw}) ...");
+
+ DotNetTest(c => c
+ .SetProjectFile(project)
+ .SetConfiguration(Parameters.Configuration)
+ .SetFramework(fw)
+ .EnableNoBuild()
+ .EnableNoRestore()
+ .When(Parameters.PublishTestResults, c => c
+ .SetLogger("trx")
+ .SetResultsDirectory(Parameters.TestResultsRoot)));
}
}
Target RunCoreLibsTests => _ => _
- .OnlyWhen(() => !Parameters.SkipTests)
+ .OnlyWhenStatic(() => !Parameters.SkipTests)
.DependsOn(Compile)
.Executes(() =>
{
- RunCoreTest("./tests/Avalonia.Animation.UnitTests");
- RunCoreTest("./tests/Avalonia.Base.UnitTests");
- RunCoreTest("./tests/Avalonia.Controls.UnitTests");
- RunCoreTest("./tests/Avalonia.Controls.DataGrid.UnitTests");
- RunCoreTest("./tests/Avalonia.Input.UnitTests");
- RunCoreTest("./tests/Avalonia.Interactivity.UnitTests");
- RunCoreTest("./tests/Avalonia.Layout.UnitTests");
- RunCoreTest("./tests/Avalonia.Markup.UnitTests");
- RunCoreTest("./tests/Avalonia.Markup.Xaml.UnitTests");
- RunCoreTest("./tests/Avalonia.Styling.UnitTests");
- RunCoreTest("./tests/Avalonia.Visuals.UnitTests");
- RunCoreTest("./tests/Avalonia.Skia.UnitTests");
- RunCoreTest("./tests/Avalonia.ReactiveUI.UnitTests");
+ RunCoreTest("Avalonia.Animation.UnitTests");
+ RunCoreTest("Avalonia.Base.UnitTests");
+ RunCoreTest("Avalonia.Controls.UnitTests");
+ RunCoreTest("Avalonia.Controls.DataGrid.UnitTests");
+ RunCoreTest("Avalonia.Input.UnitTests");
+ RunCoreTest("Avalonia.Interactivity.UnitTests");
+ RunCoreTest("Avalonia.Layout.UnitTests");
+ RunCoreTest("Avalonia.Markup.UnitTests");
+ RunCoreTest("Avalonia.Markup.Xaml.UnitTests");
+ RunCoreTest("Avalonia.Styling.UnitTests");
+ RunCoreTest("Avalonia.Visuals.UnitTests");
+ RunCoreTest("Avalonia.Skia.UnitTests");
+ RunCoreTest("Avalonia.ReactiveUI.UnitTests");
});
Target RunRenderTests => _ => _
- .OnlyWhen(() => !Parameters.SkipTests)
+ .OnlyWhenStatic(() => !Parameters.SkipTests)
.DependsOn(Compile)
.Executes(() =>
{
- RunCoreTest("./tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj");
+ RunCoreTest("Avalonia.Skia.RenderTests");
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- RunCoreTest("./tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj");
+ RunCoreTest("Avalonia.Direct2D1.RenderTests");
});
-
+
Target RunDesignerTests => _ => _
- .OnlyWhen(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows)
+ .OnlyWhenStatic(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows)
.DependsOn(Compile)
.Executes(() =>
{
- RunCoreTest("./tests/Avalonia.DesignerSupport.Tests");
+ RunCoreTest("Avalonia.DesignerSupport.Tests");
});
[PackageExecutable("JetBrains.dotMemoryUnit", "dotMemoryUnit.exe")] readonly Tool DotMemoryUnit;
Target RunLeakTests => _ => _
- .OnlyWhen(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows)
+ .OnlyWhenStatic(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows)
.DependsOn(Compile)
.Executes(() =>
{
@@ -235,7 +220,7 @@ partial class Build : NukeBuild
});
Target ZipFiles => _ => _
- .After(CreateNugetPackages, Compile, RunCoreLibsTests, Package)
+ .After(CreateNugetPackages, Compile, RunCoreLibsTests, Package)
.Executes(() =>
{
var data = Parameters;
@@ -259,9 +244,10 @@ partial class Build : NukeBuild
MsBuildCommon(Parameters.MSBuildSolution, c => c
.AddTargets("Pack"));
else
- DotNetPack(Parameters.MSBuildSolution, c =>
- c.SetConfiguration(Parameters.Configuration)
- .AddProperty("PackageVersion", Parameters.Version));
+ DotNetPack(c => c
+ .SetProject(Parameters.MSBuildSolution)
+ .SetConfiguration(Parameters.Configuration)
+ .AddProperty("PackageVersion", Parameters.Version));
});
Target CreateNugetPackages => _ => _
@@ -274,32 +260,40 @@ partial class Build : NukeBuild
new NumergeNukeLogger()))
throw new Exception("Package merge failed");
});
-
+
Target RunTests => _ => _
.DependsOn(RunCoreLibsTests)
.DependsOn(RunRenderTests)
.DependsOn(RunDesignerTests)
.DependsOn(RunLeakTests);
-
+
Target Package => _ => _
.DependsOn(RunTests)
.DependsOn(CreateNugetPackages);
-
+
Target CiAzureLinux => _ => _
.DependsOn(RunTests);
-
+
Target CiAzureOSX => _ => _
.DependsOn(Package)
.DependsOn(ZipFiles);
-
+
Target CiAzureWindows => _ => _
.DependsOn(Package)
.DependsOn(ZipFiles);
-
+
public static int Main() =>
RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? Execute(x => x.Package)
: Execute(x => x.RunTests);
}
+
+public static class ToolSettingsExtensions
+{
+ public static T Apply(this T settings, Configure configurator)
+ {
+ return configurator != null ? configurator(settings) : settings;
+ }
+}
diff --git a/nukebuild/BuildParameters.cs b/nukebuild/BuildParameters.cs
index 65ba5e9756..149716b416 100644
--- a/nukebuild/BuildParameters.cs
+++ b/nukebuild/BuildParameters.cs
@@ -4,24 +4,21 @@ using System.Linq;
using System.Runtime.InteropServices;
using System.Xml.Linq;
using Nuke.Common;
-using Nuke.Common.BuildServers;
-using Nuke.Common.Execution;
+using Nuke.Common.CI.AzurePipelines;
using Nuke.Common.IO;
-using static Nuke.Common.IO.FileSystemTasks;
using static Nuke.Common.IO.PathConstruction;
-using static Nuke.Common.Tools.MSBuild.MSBuildTasks;
public partial class Build
{
[Parameter("configuration")]
public string Configuration { get; set; }
-
+
[Parameter("skip-tests")]
public bool SkipTests { get; set; }
-
+
[Parameter("force-nuget-version")]
public string ForceNugetVersion { get; set; }
-
+
public class BuildParameters
{
public string Configuration { get; }
@@ -79,15 +76,15 @@ public partial class Build
IsRunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix ||
Environment.OSVersion.Platform == PlatformID.MacOSX;
IsRunningOnWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
- IsRunningOnAzure = Host == HostType.TeamServices ||
+ IsRunningOnAzure = Host == HostType.AzurePipelines ||
Environment.GetEnvironmentVariable("LOGNAME") == "vsts";
if (IsRunningOnAzure)
{
- RepositoryName = TeamServices.Instance.RepositoryUri;
- RepositoryBranch = TeamServices.Instance.SourceBranch;
- IsPullRequest = TeamServices.Instance.PullRequestId.HasValue;
- IsMainRepo = StringComparer.OrdinalIgnoreCase.Equals(MainRepo, TeamServices.Instance.RepositoryUri);
+ RepositoryName = AzurePipelines.Instance.RepositoryUri;
+ RepositoryBranch = AzurePipelines.Instance.SourceBranch;
+ IsPullRequest = AzurePipelines.Instance.PullRequestId.HasValue;
+ IsMainRepo = StringComparer.OrdinalIgnoreCase.Equals(MainRepo, AzurePipelines.Instance.RepositoryUri);
}
IsMainRepo =
StringComparer.OrdinalIgnoreCase.Equals(MainRepo,
diff --git a/nukebuild/Shims.cs b/nukebuild/Shims.cs
index 461d617643..1ac14bf622 100644
--- a/nukebuild/Shims.cs
+++ b/nukebuild/Shims.cs
@@ -19,9 +19,9 @@ public partial class Build
Logger.Info(info, args);
}
- private void Zip(PathConstruction.AbsolutePath target, params string[] paths) => Zip(target, paths.AsEnumerable());
+ private void Zip(AbsolutePath target, params string[] paths) => Zip(target, paths.AsEnumerable());
- private void Zip(PathConstruction.AbsolutePath target, IEnumerable paths)
+ private void Zip(AbsolutePath target, IEnumerable paths)
{
var targetPath = target.ToString();
bool finished = false, atLeastOneFileAdded = false;
@@ -38,7 +38,7 @@ public partial class Build
fileStream.CopyTo(entryStream);
atLeastOneFileAdded = true;
}
-
+
foreach (var path in paths)
{
if (Directory.Exists(path))
@@ -64,7 +64,7 @@ public partial class Build
finished = true;
}
- finally
+ finally
{
try
{
diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj
index 2a736e4653..584c36d033 100644
--- a/nukebuild/_build.csproj
+++ b/nukebuild/_build.csproj
@@ -2,7 +2,7 @@
Exe
- netcoreapp2.0
+ netcoreapp3.1
false
False
@@ -10,7 +10,7 @@
-
+
@@ -20,11 +20,11 @@
-
+
-
+
diff --git a/readme.md b/readme.md
index 42b1e52205..8ae3f1ad66 100644
--- a/readme.md
+++ b/readme.md
@@ -8,25 +8,21 @@
## About
-**Avalonia** is a WPF/UWP-inspired cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of Operating Systems such as Windows (.NET Framework, .NET Core), Linux (via Xorg), macOS and with experimental support for Android and iOS.
+**Avalonia** is a cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of Operating Systems such as Windows (.NET Framework, .NET Core), Linux (via Xorg), macOS.
-**Avalonia** is ready for **General-Purpose Desktop App Development**. However, there may be some bugs and [breaking changes](https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes) as we continue along into this project's development. To see the status of some of our features, please see our [Roadmap here](https://github.com/AvaloniaUI/Avalonia/issues/2239).
+**Avalonia** is ready for **General-Purpose Desktop App Development**. However, there may be some bugs and breaking changes as we continue along into this project's development.
-| Control catalog | Desktop platforms | Mobile platforms |
-|---|---|---|
-| | | |
+To see the status of some of our features, please see our [Roadmap here](https://github.com/AvaloniaUI/Avalonia/issues/2239).
-[Awesome Avalonia](https://github.com/AvaloniaCommunity/awesome-avalonia) is curated list of awesome Avalonia UI tools, libraries, projects and resources.
+You can also see what [breaking changes](https://github.com/AvaloniaUI/Avalonia/issues/3538) we have planned and what our [past breaking changes](https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes) have been.
-## Getting Started
-
-Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started. After installing it, open "New Project" dialog in Visual Studio, choose "Avalonia" in "Visual C#" section, select "Avalonia .NET Core Application" and press OK (screenshot ). Now you can write code and markup that will work on multiple platforms!
+[Awesome Avalonia](https://github.com/AvaloniaCommunity/awesome-avalonia) is community-curated list of awesome Avalonia UI tools, libraries, projects and resources. Go and see what people are building with Avalonia!
-For those without Visual Studio, a starter guide for .NET Core CLI can be found [here](http://avaloniaui.net/docs/quickstart/create-new-project#net-core).
+## Getting Started
-If you need to develop Avalonia app with JetBrains Rider, go and *vote* on [this issue](https://youtrack.jetbrains.com/issue/RIDER-39247) in their tracker. JetBrains won't do things without their users telling them that they want the feature, so only **YOU** can make it happen.
+The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starer guide see our [documentation](http://avaloniaui.net/docs/quickstart/create-new-project).
-Avalonia is delivered via NuGet package manager. You can find the packages here: [stable(ish)](https://www.nuget.org/packages/Avalonia/)
+Avalonia is delivered via NuGet package manager. You can find the packages here: https://www.nuget.org/packages/Avalonia/
Use these commands in the Package Manager console to install Avalonia manually:
```
@@ -34,40 +30,46 @@ Install-Package Avalonia
Install-Package Avalonia.Desktop
```
-## Bleeding Edge Builds
+## JetBrains Rider
-or use nightly build feeds as described here:
-https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed
+If you need to develop Avalonia app with JetBrains Rider, go and *vote* on [this issue](https://youtrack.jetbrains.com/issue/RIDER-39247) in their tracker. JetBrains won't do things without their users telling them that they want the feature, so only **YOU** can make it happen.
-## Documentation
+## Bleeding Edge Builds
-You can take a look at the [getting started page](http://avaloniaui.net/docs/quickstart/) for an overview of how to get started but probably the best thing to do for now is to already know a little bit about WPF/Silverlight/UWP/XAML and ask questions in our [Gitter room](https://gitter.im/AvaloniaUI/Avalonia).
+We also have a [nightly build](https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed) which tracks the current state of master. Although these packages are less stable than the release on NuGet.org, you'll get all the latest features and bugfixes right away and many of our users actually prefer this feed!
-There's also a high-level [architecture document](http://avaloniaui.net/architecture/project-structure) that is currently a little bit out of date, and I've also started writing blog posts on Avalonia at http://grokys.github.io/.
+## Documentation
-Contributions for our docs are always welcome!
+Documentation can be found on our website at http://avaloniaui.net/docs/. We also have a [tutorial](http://avaloniaui.net/docs/tutorial/) over there for newcomers.
## Building and Using
-See the [build instructions here](http://avaloniaui.net/contributing/build).
+See the [build instructions here](Documentation/build.md).
## Contributing
-Please read the [contribution guidelines](http://avaloniaui.net/contributing/contributing) before submitting a pull request.
+Please read the [contribution guidelines](CONTRIBUTING.md) before submitting a pull request.
+
+## Code of Conduct
-### Contributors
+This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community.
+For more information see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).
+
+## Licence
+
+Avalonia is licenced under the [MIT licence](licence.md).
+
+## Contributors
This project exists thanks to all the people who contribute. [[Contribute](http://avaloniaui.net/contributing/contributing)].
-
### Backers
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/Avalonia#backer)]
-
### Sponsors
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/Avalonia#sponsor)]
@@ -82,3 +84,7 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
+
+## .NET Foundation
+
+This project is supported by the [.NET Foundation](https://dotnetfoundation.org).
diff --git a/samples/BindingDemo/BindingDemo.csproj b/samples/BindingDemo/BindingDemo.csproj
index a3f16dc222..ce33f42143 100644
--- a/samples/BindingDemo/BindingDemo.csproj
+++ b/samples/BindingDemo/BindingDemo.csproj
@@ -1,7 +1,7 @@
Exe
- netcoreapp2.0;net461
+ netcoreapp3.1
diff --git a/samples/BindingDemo/ViewModels/DataAnnotationsErrorViewModel.cs b/samples/BindingDemo/ViewModels/DataAnnotationsErrorViewModel.cs
index e274f9180e..391d1791d3 100644
--- a/samples/BindingDemo/ViewModels/DataAnnotationsErrorViewModel.cs
+++ b/samples/BindingDemo/ViewModels/DataAnnotationsErrorViewModel.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations;
namespace BindingDemo.ViewModels
{
diff --git a/samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs b/samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs
index df80931367..0fe12a8ef7 100644
--- a/samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs
+++ b/samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using ReactiveUI;
+using ReactiveUI;
using System;
namespace BindingDemo.ViewModels
diff --git a/samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs b/samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs
index bb3b4d64e9..caf75c846c 100644
--- a/samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs
+++ b/samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using ReactiveUI;
+using ReactiveUI;
using System;
using System.ComponentModel;
using System.Collections;
diff --git a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
index 7919c3ac5a..772af9eacd 100644
--- a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
+++ b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
@@ -2,7 +2,7 @@
Exe
- netcoreapp2.0
+ netcoreapp3.1
true
diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index bbfa3be4ab..3a7a2a186f 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -60,10 +60,17 @@
-
+
+
+ No Decorations
+ Border Only
+ Full Decorations
+
+
Light
Dark
-
+
+
diff --git a/samples/ControlCatalog/MainView.xaml.cs b/samples/ControlCatalog/MainView.xaml.cs
index acb9bc5bc6..7c17b125d6 100644
--- a/samples/ControlCatalog/MainView.xaml.cs
+++ b/samples/ControlCatalog/MainView.xaml.cs
@@ -56,6 +56,21 @@ namespace ControlCatalog
}
};
Styles.Add(light);
+
+ var decorations = this.Find("Decorations");
+ decorations.SelectionChanged += (sender, e) =>
+ {
+ if (VisualRoot is Window window)
+ window.SystemDecorations = (SystemDecorations)decorations.SelectedIndex;
+ };
+ }
+
+ protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
+ {
+ base.OnAttachedToVisualTree(e);
+ var decorations = this.Find("Decorations");
+ if (VisualRoot is Window window)
+ decorations.SelectedIndex = (int)window.SystemDecorations;
}
}
}
diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml
index 248f94082d..bea751ad4c 100644
--- a/samples/ControlCatalog/MainWindow.xaml
+++ b/samples/ControlCatalog/MainWindow.xaml
@@ -14,15 +14,17 @@
-
+
-
+
-
+
@@ -34,6 +36,24 @@
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/MainWindow.xaml.cs b/samples/ControlCatalog/MainWindow.xaml.cs
index 38cbde9d92..d97325ef8d 100644
--- a/samples/ControlCatalog/MainWindow.xaml.cs
+++ b/samples/ControlCatalog/MainWindow.xaml.cs
@@ -1,13 +1,11 @@
+using System;
+using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Notifications;
-using Avalonia.Controls.Primitives;
+using Avalonia.Input;
using Avalonia.Markup.Xaml;
-using Avalonia.Threading;
using ControlCatalog.ViewModels;
-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
namespace ControlCatalog
{
@@ -31,10 +29,17 @@ namespace ControlCatalog
DataContext = new MainWindowViewModel(_notificationArea);
_recentMenu = ((NativeMenu.GetMenu(this).Items[0] as NativeMenuItem).Menu.Items[2] as NativeMenuItem).Menu;
+
var mainMenu = this.FindControl("MainMenu");
mainMenu.AttachedToVisualTree += MenuAttached;
}
+ public static string MenuQuitHeader => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "Quit Avalonia" : "E_xit";
+
+ public static KeyGesture MenuQuitGesture => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ?
+ new KeyGesture(Key.Q, KeyModifiers.Meta) :
+ new KeyGesture(Key.F4, KeyModifiers.Alt);
+
public void MenuAttached(object sender, VisualTreeAttachmentEventArgs e)
{
if (NativeMenu.GetIsNativeMenuExported(this) && sender is Menu mainMenu)
diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml b/samples/ControlCatalog/Pages/DialogsPage.xaml
index 60f8e3656e..1ed5c0cbfd 100644
--- a/samples/ControlCatalog/Pages/DialogsPage.xaml
+++ b/samples/ControlCatalog/Pages/DialogsPage.xaml
@@ -9,5 +9,6 @@
Decorated window
Decorated window (dialog)
Dialog
+ Dialog (No taskbar icon)
diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs
index d207689223..ba1921a185 100644
--- a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs
@@ -1,4 +1,7 @@
+using System;
using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
#pragma warning disable 4014
@@ -34,7 +37,9 @@ namespace ControlCatalog.Pages
new OpenFileDialog()
{
Title = "Open file",
- Filters = GetFilters()
+ Filters = GetFilters(),
+ // Almost guaranteed to exist
+ InitialFileName = Assembly.GetEntryAssembly()?.GetModules().FirstOrDefault()?.FullyQualifiedName
}.ShowAsync(GetWindow());
};
this.FindControl("SaveFile").Click += delegate
@@ -42,14 +47,15 @@ namespace ControlCatalog.Pages
new SaveFileDialog()
{
Title = "Save file",
- Filters = GetFilters()
+ Filters = GetFilters(),
+ InitialFileName = "test.txt"
}.ShowAsync(GetWindow());
};
this.FindControl("SelectFolder").Click += delegate
{
new OpenFolderDialog()
{
- Title = "Select folder"
+ Title = "Select folder",
}.ShowAsync(GetWindow());
};
this.FindControl("DecoratedWindow").Click += delegate
@@ -61,14 +67,29 @@ namespace ControlCatalog.Pages
new DecoratedWindow().ShowDialog(GetWindow());
};
this.FindControl("Dialog").Click += delegate
- {
- var window = new Window();
- window.Height = 200;
- window.Width = 200;
- window.Content = new TextBlock { Text = "Hello world!" };
- window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
- window.ShowDialog(GetWindow());
- };
+ {
+ var window = CreateSampleWindow();
+ window.Height = 200;
+ window.ShowDialog(GetWindow());
+ };
+ this.FindControl("DialogNoTaskbar").Click += delegate
+ {
+ var window = CreateSampleWindow();
+ window.Height = 200;
+ window.ShowInTaskbar = false;
+ window.ShowDialog(GetWindow());
+ };
+ }
+
+ private Window CreateSampleWindow()
+ {
+ var window = new Window();
+ window.Height = 200;
+ window.Width = 200;
+ window.Content = new TextBlock { Text = "Hello world!" };
+ window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
+
+ return window;
}
Window GetWindow() => (Window)this.VisualRoot;
diff --git a/samples/ControlCatalog/Pages/ImagePage.xaml b/samples/ControlCatalog/Pages/ImagePage.xaml
index 9b8f8af765..f61931ed72 100644
--- a/samples/ControlCatalog/Pages/ImagePage.xaml
+++ b/samples/ControlCatalog/Pages/ImagePage.xaml
@@ -7,7 +7,7 @@
Displays an image
-
+
Bitmap
@@ -22,6 +22,23 @@
+ Crop
+
+ None
+ Center
+ TopLeft
+ TopRight
+ BottomLeft
+ BottomRight
+
+
+
+
+
+
+
+
+
Drawing
None
diff --git a/samples/ControlCatalog/Pages/ImagePage.xaml.cs b/samples/ControlCatalog/Pages/ImagePage.xaml.cs
index bbe89d1dfd..d8f4d6d5a2 100644
--- a/samples/ControlCatalog/Pages/ImagePage.xaml.cs
+++ b/samples/ControlCatalog/Pages/ImagePage.xaml.cs
@@ -1,6 +1,10 @@
+using System;
+using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
+using Avalonia.Media.Imaging;
+using Avalonia.Platform;
namespace ControlCatalog.Pages
{
@@ -8,12 +12,14 @@ namespace ControlCatalog.Pages
{
private readonly Image _bitmapImage;
private readonly Image _drawingImage;
+ private readonly Image _croppedImage;
public ImagePage()
{
InitializeComponent();
_bitmapImage = this.FindControl("bitmapImage");
_drawingImage = this.FindControl("drawingImage");
+ _croppedImage = this.FindControl("croppedImage");
}
private void InitializeComponent()
@@ -38,5 +44,32 @@ namespace ControlCatalog.Pages
_drawingImage.Stretch = (Stretch)comboxBox.SelectedIndex;
}
}
+
+ public void BitmapCropChanged(object sender, SelectionChangedEventArgs e)
+ {
+ if (_croppedImage != null)
+ {
+ var comboxBox = (ComboBox)sender;
+ var croppedBitmap = _croppedImage.Source as CroppedBitmap;
+ croppedBitmap.SourceRect = GetCropRect(comboxBox.SelectedIndex);
+ }
+ }
+
+ private PixelRect GetCropRect(int index)
+ {
+ var bitmapWidth = 640;
+ var bitmapHeight = 426;
+ var cropSize = new PixelSize(320, 240);
+ return index switch
+ {
+ 1 => new PixelRect(new PixelPoint((bitmapWidth - cropSize.Width) / 2, (bitmapHeight - cropSize.Width) / 2), cropSize),
+ 2 => new PixelRect(new PixelPoint(0, 0), cropSize),
+ 3 => new PixelRect(new PixelPoint(bitmapWidth - cropSize.Width, 0), cropSize),
+ 4 => new PixelRect(new PixelPoint(0, bitmapHeight - cropSize.Height), cropSize),
+ 5 => new PixelRect(new PixelPoint(bitmapWidth - cropSize.Width, bitmapHeight - cropSize.Height), cropSize),
+ _ => PixelRect.Empty
+ };
+
+ }
}
}
diff --git a/samples/ControlCatalog/Pages/MenuPage.xaml b/samples/ControlCatalog/Pages/MenuPage.xaml
index 868f0df6ad..de9ea34e80 100644
--- a/samples/ControlCatalog/Pages/MenuPage.xaml
+++ b/samples/ControlCatalog/Pages/MenuPage.xaml
@@ -16,13 +16,13 @@
Defined in XAML
-
+
-
+
diff --git a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs
index 89e7653618..b6aa3e92cd 100644
--- a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs
+++ b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs
@@ -10,6 +10,8 @@ namespace ControlCatalog.ViewModels
{
private IManagedNotificationManager _notificationManager;
+ private bool _isMenuItemChecked = true;
+
public MainWindowViewModel(IManagedNotificationManager notificationManager)
{
_notificationManager = notificationManager;
@@ -42,6 +44,11 @@ namespace ControlCatalog.ViewModels
{
(App.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime).Shutdown();
});
+
+ ToggleMenuItemCheckedCommand = ReactiveCommand.Create(() =>
+ {
+ IsMenuItemChecked = !IsMenuItemChecked;
+ });
}
public IManagedNotificationManager NotificationManager
@@ -50,6 +57,12 @@ namespace ControlCatalog.ViewModels
set { this.RaiseAndSetIfChanged(ref _notificationManager, value); }
}
+ public bool IsMenuItemChecked
+ {
+ get { return _isMenuItemChecked; }
+ set { this.RaiseAndSetIfChanged(ref _isMenuItemChecked, value); }
+ }
+
public ReactiveCommand ShowCustomManagedNotificationCommand { get; }
public ReactiveCommand ShowManagedNotificationCommand { get; }
@@ -59,5 +72,7 @@ namespace ControlCatalog.ViewModels
public ReactiveCommand AboutCommand { get; }
public ReactiveCommand ExitCommand { get; }
+
+ public ReactiveCommand ToggleMenuItemCheckedCommand { get; }
}
}
diff --git a/samples/PlatformSanityChecks/PlatformSanityChecks.csproj b/samples/PlatformSanityChecks/PlatformSanityChecks.csproj
index 2adef5f64e..86d762a5bc 100644
--- a/samples/PlatformSanityChecks/PlatformSanityChecks.csproj
+++ b/samples/PlatformSanityChecks/PlatformSanityChecks.csproj
@@ -2,7 +2,7 @@
Exe
- netcoreapp2.0
+ netcoreapp3.1
diff --git a/samples/Previewer/Previewer.csproj b/samples/Previewer/Previewer.csproj
index 2cdde0c945..cd3daf61e1 100644
--- a/samples/Previewer/Previewer.csproj
+++ b/samples/Previewer/Previewer.csproj
@@ -1,7 +1,7 @@
Exe
- netcoreapp2.0
+ netcoreapp3.1
diff --git a/samples/RemoteDemo/RemoteDemo.csproj b/samples/RemoteDemo/RemoteDemo.csproj
index 2d7699561a..530cad805f 100644
--- a/samples/RemoteDemo/RemoteDemo.csproj
+++ b/samples/RemoteDemo/RemoteDemo.csproj
@@ -1,7 +1,7 @@
Exe
- netcoreapp2.0
+ netcoreapp3.1
diff --git a/samples/RenderDemo/App.xaml.cs b/samples/RenderDemo/App.xaml.cs
index d95018520a..923174d4c7 100644
--- a/samples/RenderDemo/App.xaml.cs
+++ b/samples/RenderDemo/App.xaml.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia;
using Avalonia.Logging.Serilog;
using Avalonia.Markup.Xaml;
diff --git a/samples/RenderDemo/MainWindow.xaml.cs b/samples/RenderDemo/MainWindow.xaml.cs
index f1f974f7a1..b45a605e04 100644
--- a/samples/RenderDemo/MainWindow.xaml.cs
+++ b/samples/RenderDemo/MainWindow.xaml.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia;
using Avalonia.Controls;
diff --git a/samples/RenderDemo/RenderDemo.csproj b/samples/RenderDemo/RenderDemo.csproj
index a3f16dc222..ce33f42143 100644
--- a/samples/RenderDemo/RenderDemo.csproj
+++ b/samples/RenderDemo/RenderDemo.csproj
@@ -1,7 +1,7 @@
Exe
- netcoreapp2.0;net461
+ netcoreapp3.1
diff --git a/samples/VirtualizationDemo/App.xaml.cs b/samples/VirtualizationDemo/App.xaml.cs
index b220807443..5990dd282c 100644
--- a/samples/VirtualizationDemo/App.xaml.cs
+++ b/samples/VirtualizationDemo/App.xaml.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia;
using Avalonia.Markup.Xaml;
diff --git a/samples/VirtualizationDemo/MainWindow.xaml.cs b/samples/VirtualizationDemo/MainWindow.xaml.cs
index 271519b10b..cea200dcec 100644
--- a/samples/VirtualizationDemo/MainWindow.xaml.cs
+++ b/samples/VirtualizationDemo/MainWindow.xaml.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
diff --git a/samples/VirtualizationDemo/Program.cs b/samples/VirtualizationDemo/Program.cs
index 9d8f7c1a3d..868a5e2640 100644
--- a/samples/VirtualizationDemo/Program.cs
+++ b/samples/VirtualizationDemo/Program.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Logging.Serilog;
diff --git a/samples/VirtualizationDemo/ViewModels/ItemViewModel.cs b/samples/VirtualizationDemo/ViewModels/ItemViewModel.cs
index 4401a2dfeb..cf34980b40 100644
--- a/samples/VirtualizationDemo/ViewModels/ItemViewModel.cs
+++ b/samples/VirtualizationDemo/ViewModels/ItemViewModel.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using ReactiveUI;
namespace VirtualizationDemo.ViewModels
diff --git a/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs b/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
index 649c64ab1d..95d90d52ff 100644
--- a/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
+++ b/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
diff --git a/samples/VirtualizationDemo/VirtualizationDemo.csproj b/samples/VirtualizationDemo/VirtualizationDemo.csproj
index a3f16dc222..ce33f42143 100644
--- a/samples/VirtualizationDemo/VirtualizationDemo.csproj
+++ b/samples/VirtualizationDemo/VirtualizationDemo.csproj
@@ -1,7 +1,7 @@
Exe
- netcoreapp2.0;net461
+ netcoreapp3.1
diff --git a/samples/interop/Direct3DInteropSample/MainWindow.cs b/samples/interop/Direct3DInteropSample/MainWindow.cs
index 1ac4b44a74..6cc3cb9116 100644
--- a/samples/interop/Direct3DInteropSample/MainWindow.cs
+++ b/samples/interop/Direct3DInteropSample/MainWindow.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using Avalonia;
using Avalonia.Controls;
diff --git a/scripts/ReplaceNugetCache.sh b/scripts/ReplaceNugetCache.sh
index e1c0487d60..7ac601571d 100755
--- a/scripts/ReplaceNugetCache.sh
+++ b/scripts/ReplaceNugetCache.sh
@@ -1,8 +1,8 @@
#!/usr/bin/env bash
- cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netcoreapp2.0/
- cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netstandard2.0/
- cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia.skia/$1/lib/netstandard2.0/
- cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia.native/$1/lib/netstandard2.0/
+ cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp3.1/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netcoreapp3.1/
+ cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp3.1/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netstandard2.0/
+ cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp3.1/Avalonia**.dll ~/.nuget/packages/avalonia.skia/$1/lib/netstandard2.0/
+ cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp3.1/Avalonia**.dll ~/.nuget/packages/avalonia.native/$1/lib/netstandard2.0/
diff --git a/src/Avalonia.Animation/Animatable.cs b/src/Avalonia.Animation/Animatable.cs
index cc1ac8ded6..fa1e955153 100644
--- a/src/Avalonia.Animation/Animatable.cs
+++ b/src/Avalonia.Animation/Animatable.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/Avalonia.Animation/Animation.cs b/src/Avalonia.Animation/Animation.cs
index ae6deb585c..ca1d97290e 100644
--- a/src/Avalonia.Animation/Animation.cs
+++ b/src/Avalonia.Animation/Animation.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Linq;
@@ -254,10 +251,10 @@ namespace Avalonia.Animation
if (keyframe.TimingMode == KeyFrameTimingMode.TimeSpan)
{
- cue = new Cue(keyframe.KeyTime.Ticks / Duration.Ticks);
+ cue = new Cue(keyframe.KeyTime.TotalSeconds / Duration.TotalSeconds);
}
- var newKF = new AnimatorKeyFrame(handler, cue);
+ var newKF = new AnimatorKeyFrame(handler, cue, keyframe.KeySpline);
subscriptions.Add(newKF.BindSetter(setter, control));
diff --git a/src/Avalonia.Animation/AnimatorKeyFrame.cs b/src/Avalonia.Animation/AnimatorKeyFrame.cs
index 36d15e518e..f6a0c12be4 100644
--- a/src/Avalonia.Animation/AnimatorKeyFrame.cs
+++ b/src/Avalonia.Animation/AnimatorKeyFrame.cs
@@ -24,11 +24,20 @@ namespace Avalonia.Animation
{
AnimatorType = animatorType;
Cue = cue;
+ KeySpline = null;
+ }
+
+ public AnimatorKeyFrame(Type animatorType, Cue cue, KeySpline keySpline)
+ {
+ AnimatorType = animatorType;
+ Cue = cue;
+ KeySpline = keySpline;
}
internal bool isNeutral;
public Type AnimatorType { get; }
public Cue Cue { get; }
+ public KeySpline KeySpline { get; }
public AvaloniaProperty Property { get; private set; }
private object _value;
diff --git a/src/Avalonia.Animation/Animators/Animator`1.cs b/src/Avalonia.Animation/Animators/Animator`1.cs
index e42489d6a6..0660440e30 100644
--- a/src/Avalonia.Animation/Animators/Animator`1.cs
+++ b/src/Avalonia.Animation/Animators/Animator`1.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
@@ -92,6 +89,9 @@ namespace Avalonia.Animation.Animators
else
newValue = (T)lastKeyframe.Value;
+ if (lastKeyframe.KeySpline != null)
+ progress = lastKeyframe.KeySpline.GetSplineProgress(progress);
+
return Interpolate(progress, oldValue, newValue);
}
diff --git a/src/Avalonia.Animation/Animators/BoolAnimator.cs b/src/Avalonia.Animation/Animators/BoolAnimator.cs
index 63ff4933d6..f02fd8dfaa 100644
--- a/src/Avalonia.Animation/Animators/BoolAnimator.cs
+++ b/src/Avalonia.Animation/Animators/BoolAnimator.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-namespace Avalonia.Animation.Animators
+namespace Avalonia.Animation.Animators
{
///
/// Animator that handles properties.
diff --git a/src/Avalonia.Animation/Animators/ByteAnimator.cs b/src/Avalonia.Animation/Animators/ByteAnimator.cs
index 0fb8f7fdc1..9fce07895c 100644
--- a/src/Avalonia.Animation/Animators/ByteAnimator.cs
+++ b/src/Avalonia.Animation/Animators/ByteAnimator.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Animation.Animators
{
diff --git a/src/Avalonia.Animation/Animators/DecimalAnimator.cs b/src/Avalonia.Animation/Animators/DecimalAnimator.cs
index b5fae7990c..5aed5e5f3d 100644
--- a/src/Avalonia.Animation/Animators/DecimalAnimator.cs
+++ b/src/Avalonia.Animation/Animators/DecimalAnimator.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-namespace Avalonia.Animation.Animators
+namespace Avalonia.Animation.Animators
{
///
/// Animator that handles properties.
diff --git a/src/Avalonia.Animation/Animators/DoubleAnimator.cs b/src/Avalonia.Animation/Animators/DoubleAnimator.cs
index 68975be9d0..1ca3fabc47 100644
--- a/src/Avalonia.Animation/Animators/DoubleAnimator.cs
+++ b/src/Avalonia.Animation/Animators/DoubleAnimator.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-namespace Avalonia.Animation.Animators
+namespace Avalonia.Animation.Animators
{
///
/// Animator that handles properties.
diff --git a/src/Avalonia.Animation/Animators/FloatAnimator.cs b/src/Avalonia.Animation/Animators/FloatAnimator.cs
index 0fd3bf8729..62f48a15a3 100644
--- a/src/Avalonia.Animation/Animators/FloatAnimator.cs
+++ b/src/Avalonia.Animation/Animators/FloatAnimator.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-namespace Avalonia.Animation.Animators
+namespace Avalonia.Animation.Animators
{
///
/// Animator that handles properties.
diff --git a/src/Avalonia.Animation/Animators/Int16Animator.cs b/src/Avalonia.Animation/Animators/Int16Animator.cs
index d7e7da5d38..5235082fc4 100644
--- a/src/Avalonia.Animation/Animators/Int16Animator.cs
+++ b/src/Avalonia.Animation/Animators/Int16Animator.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Animation.Animators
{
diff --git a/src/Avalonia.Animation/Animators/Int32Animator.cs b/src/Avalonia.Animation/Animators/Int32Animator.cs
index 792b810652..2596f13e84 100644
--- a/src/Avalonia.Animation/Animators/Int32Animator.cs
+++ b/src/Avalonia.Animation/Animators/Int32Animator.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Animation.Animators
{
diff --git a/src/Avalonia.Animation/Animators/Int64Animator.cs b/src/Avalonia.Animation/Animators/Int64Animator.cs
index ca5817924e..d05750d35c 100644
--- a/src/Avalonia.Animation/Animators/Int64Animator.cs
+++ b/src/Avalonia.Animation/Animators/Int64Animator.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Animation.Animators
{
diff --git a/src/Avalonia.Animation/Animators/UInt16Animator.cs b/src/Avalonia.Animation/Animators/UInt16Animator.cs
index 4b5463dade..6c9588a966 100644
--- a/src/Avalonia.Animation/Animators/UInt16Animator.cs
+++ b/src/Avalonia.Animation/Animators/UInt16Animator.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Animation.Animators
{
diff --git a/src/Avalonia.Animation/Animators/UInt32Animator.cs b/src/Avalonia.Animation/Animators/UInt32Animator.cs
index c1f09e3518..e2af533566 100644
--- a/src/Avalonia.Animation/Animators/UInt32Animator.cs
+++ b/src/Avalonia.Animation/Animators/UInt32Animator.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Animation.Animators
{
diff --git a/src/Avalonia.Animation/Animators/UInt64Animator.cs b/src/Avalonia.Animation/Animators/UInt64Animator.cs
index 0fd9fcb30a..a709a77100 100644
--- a/src/Avalonia.Animation/Animators/UInt64Animator.cs
+++ b/src/Avalonia.Animation/Animators/UInt64Animator.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Animation.Animators
{
diff --git a/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs b/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs
index 0c15524362..696f43d006 100644
--- a/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs
+++ b/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Animation.Animators;
diff --git a/src/Avalonia.Animation/Easing/BackEaseIn.cs b/src/Avalonia.Animation/Easing/BackEaseIn.cs
index a8d723d433..aab0b27294 100644
--- a/src/Avalonia.Animation/Easing/BackEaseIn.cs
+++ b/src/Avalonia.Animation/Easing/BackEaseIn.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Animation.Easings
diff --git a/src/Avalonia.Animation/Easing/BackEaseInOut.cs b/src/Avalonia.Animation/Easing/BackEaseInOut.cs
index 4844c2a0d1..aba0524209 100644
--- a/src/Avalonia.Animation/Easing/BackEaseInOut.cs
+++ b/src/Avalonia.Animation/Easing/BackEaseInOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Animation.Easings
diff --git a/src/Avalonia.Animation/Easing/BackEaseOut.cs b/src/Avalonia.Animation/Easing/BackEaseOut.cs
index 291c7c2541..c6a059cf66 100644
--- a/src/Avalonia.Animation/Easing/BackEaseOut.cs
+++ b/src/Avalonia.Animation/Easing/BackEaseOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Animation.Easings
diff --git a/src/Avalonia.Animation/Easing/BounceEaseIn.cs b/src/Avalonia.Animation/Easing/BounceEaseIn.cs
index 3fc879b3cf..343609a89a 100644
--- a/src/Avalonia.Animation/Easing/BounceEaseIn.cs
+++ b/src/Avalonia.Animation/Easing/BounceEaseIn.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Animation.Utils;
namespace Avalonia.Animation.Easings
diff --git a/src/Avalonia.Animation/Easing/BounceEaseInOut.cs b/src/Avalonia.Animation/Easing/BounceEaseInOut.cs
index b393a4e7c7..b0c0391177 100644
--- a/src/Avalonia.Animation/Easing/BounceEaseInOut.cs
+++ b/src/Avalonia.Animation/Easing/BounceEaseInOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Animation.Utils;
namespace Avalonia.Animation.Easings
diff --git a/src/Avalonia.Animation/Easing/BounceEaseOut.cs b/src/Avalonia.Animation/Easing/BounceEaseOut.cs
index 555c8d9c79..f2759c4568 100644
--- a/src/Avalonia.Animation/Easing/BounceEaseOut.cs
+++ b/src/Avalonia.Animation/Easing/BounceEaseOut.cs
@@ -1,5 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Avalonia.Animation.Utils;
namespace Avalonia.Animation.Easings
diff --git a/src/Avalonia.Animation/Easing/CircularEaseIn.cs b/src/Avalonia.Animation/Easing/CircularEaseIn.cs
index 1b22258099..cf6f0f84a8 100644
--- a/src/Avalonia.Animation/Easing/CircularEaseIn.cs
+++ b/src/Avalonia.Animation/Easing/CircularEaseIn.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Animation.Easings
diff --git a/src/Avalonia.Animation/Easing/CircularEaseInOut.cs b/src/Avalonia.Animation/Easing/CircularEaseInOut.cs
index 156b634d3e..d01c7ea76b 100644
--- a/src/Avalonia.Animation/Easing/CircularEaseInOut.cs
+++ b/src/Avalonia.Animation/Easing/CircularEaseInOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Animation.Easings
diff --git a/src/Avalonia.Animation/Easing/CircularEaseOut.cs b/src/Avalonia.Animation/Easing/CircularEaseOut.cs
index 2aa6161783..b5fcaa300c 100644
--- a/src/Avalonia.Animation/Easing/CircularEaseOut.cs
+++ b/src/Avalonia.Animation/Easing/CircularEaseOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Animation.Easings
diff --git a/src/Avalonia.Animation/Easing/CubicEaseIn.cs b/src/Avalonia.Animation/Easing/CubicEaseIn.cs
index 1997493fc0..294443c0b7 100644
--- a/src/Avalonia.Animation/Easing/CubicEaseIn.cs
+++ b/src/Avalonia.Animation/Easing/CubicEaseIn.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Animation.Easings
{
///
diff --git a/src/Avalonia.Animation/Easing/CubicEaseInOut.cs b/src/Avalonia.Animation/Easing/CubicEaseInOut.cs
index be4d46d180..5ff816e38d 100644
--- a/src/Avalonia.Animation/Easing/CubicEaseInOut.cs
+++ b/src/Avalonia.Animation/Easing/CubicEaseInOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Animation.Easings
{
///
diff --git a/src/Avalonia.Animation/Easing/CubicEaseOut.cs b/src/Avalonia.Animation/Easing/CubicEaseOut.cs
index cfa42afeb9..d51fb633a1 100644
--- a/src/Avalonia.Animation/Easing/CubicEaseOut.cs
+++ b/src/Avalonia.Animation/Easing/CubicEaseOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Animation.Easings
{
///
diff --git a/src/Avalonia.Animation/Easing/EasingTypeConverter.cs b/src/Avalonia.Animation/Easing/EasingTypeConverter.cs
index ee15761eff..6613f6d393 100644
--- a/src/Avalonia.Animation/Easing/EasingTypeConverter.cs
+++ b/src/Avalonia.Animation/Easing/EasingTypeConverter.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.ComponentModel;
using System.Globalization;
diff --git a/src/Avalonia.Animation/Easing/ElasticEaseIn.cs b/src/Avalonia.Animation/Easing/ElasticEaseIn.cs
index 654ac6991b..d678bebd0c 100644
--- a/src/Avalonia.Animation/Easing/ElasticEaseIn.cs
+++ b/src/Avalonia.Animation/Easing/ElasticEaseIn.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Animation.Utils;
diff --git a/src/Avalonia.Animation/Easing/ElasticEaseInOut.cs b/src/Avalonia.Animation/Easing/ElasticEaseInOut.cs
index b170cb2d6a..92331d49b6 100644
--- a/src/Avalonia.Animation/Easing/ElasticEaseInOut.cs
+++ b/src/Avalonia.Animation/Easing/ElasticEaseInOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Animation.Utils;
diff --git a/src/Avalonia.Animation/Easing/ElasticEaseOut.cs b/src/Avalonia.Animation/Easing/ElasticEaseOut.cs
index 1cc38a9dea..fdda568699 100644
--- a/src/Avalonia.Animation/Easing/ElasticEaseOut.cs
+++ b/src/Avalonia.Animation/Easing/ElasticEaseOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Animation.Utils;
diff --git a/src/Avalonia.Animation/Easing/ExponentialEaseIn.cs b/src/Avalonia.Animation/Easing/ExponentialEaseIn.cs
index 14977f6783..546e255348 100644
--- a/src/Avalonia.Animation/Easing/ExponentialEaseIn.cs
+++ b/src/Avalonia.Animation/Easing/ExponentialEaseIn.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Animation.Easings
diff --git a/src/Avalonia.Animation/Easing/ExponentialEaseInOut.cs b/src/Avalonia.Animation/Easing/ExponentialEaseInOut.cs
index 64eb51e116..de3cbf0202 100644
--- a/src/Avalonia.Animation/Easing/ExponentialEaseInOut.cs
+++ b/src/Avalonia.Animation/Easing/ExponentialEaseInOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Animation.Easings
diff --git a/src/Avalonia.Animation/Easing/ExponentialEaseOut.cs b/src/Avalonia.Animation/Easing/ExponentialEaseOut.cs
index b89f8e9fa2..7f91388e08 100644
--- a/src/Avalonia.Animation/Easing/ExponentialEaseOut.cs
+++ b/src/Avalonia.Animation/Easing/ExponentialEaseOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Animation.Easings
diff --git a/src/Avalonia.Animation/Easing/IEasing.cs b/src/Avalonia.Animation/Easing/IEasing.cs
index 3c954a8cab..9c9c7b3a99 100644
--- a/src/Avalonia.Animation/Easing/IEasing.cs
+++ b/src/Avalonia.Animation/Easing/IEasing.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Animation.Easings
{
///
diff --git a/src/Avalonia.Animation/Easing/LinearEasing.cs b/src/Avalonia.Animation/Easing/LinearEasing.cs
index f7a90c0eef..78a56005f6 100644
--- a/src/Avalonia.Animation/Easing/LinearEasing.cs
+++ b/src/Avalonia.Animation/Easing/LinearEasing.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Animation.Easings
{
///
diff --git a/src/Avalonia.Animation/Easing/QuadraticEaseIn.cs b/src/Avalonia.Animation/Easing/QuadraticEaseIn.cs
index 6c29b31516..49faec6187 100644
--- a/src/Avalonia.Animation/Easing/QuadraticEaseIn.cs
+++ b/src/Avalonia.Animation/Easing/QuadraticEaseIn.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Animation.Easings
{
///
diff --git a/src/Avalonia.Animation/Easing/QuadraticEaseInOut.cs b/src/Avalonia.Animation/Easing/QuadraticEaseInOut.cs
index 16ba02cc20..4d95bdc393 100644
--- a/src/Avalonia.Animation/Easing/QuadraticEaseInOut.cs
+++ b/src/Avalonia.Animation/Easing/QuadraticEaseInOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Animation.Easings
{
///
diff --git a/src/Avalonia.Animation/Easing/QuadraticEaseOut.cs b/src/Avalonia.Animation/Easing/QuadraticEaseOut.cs
index 5252b88cf3..8ec7265841 100644
--- a/src/Avalonia.Animation/Easing/QuadraticEaseOut.cs
+++ b/src/Avalonia.Animation/Easing/QuadraticEaseOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Animation.Easings
{
///
diff --git a/src/Avalonia.Animation/Easing/QuarticEaseIn.cs b/src/Avalonia.Animation/Easing/QuarticEaseIn.cs
index 988fd1f7fb..69785aec3c 100644
--- a/src/Avalonia.Animation/Easing/QuarticEaseIn.cs
+++ b/src/Avalonia.Animation/Easing/QuarticEaseIn.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Animation.Easings
{
///
diff --git a/src/Avalonia.Animation/Easing/QuarticEaseInOut.cs b/src/Avalonia.Animation/Easing/QuarticEaseInOut.cs
index 0ad908f6bb..5a7205087d 100644
--- a/src/Avalonia.Animation/Easing/QuarticEaseInOut.cs
+++ b/src/Avalonia.Animation/Easing/QuarticEaseInOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Animation.Easings
{
///
diff --git a/src/Avalonia.Animation/Easing/QuarticEaseOut.cs b/src/Avalonia.Animation/Easing/QuarticEaseOut.cs
index 8499575653..764a1a6ce6 100644
--- a/src/Avalonia.Animation/Easing/QuarticEaseOut.cs
+++ b/src/Avalonia.Animation/Easing/QuarticEaseOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Animation.Easings
{
///
diff --git a/src/Avalonia.Animation/Easing/QuinticEaseIn.cs b/src/Avalonia.Animation/Easing/QuinticEaseIn.cs
index 4b0c598c69..688f5b789d 100644
--- a/src/Avalonia.Animation/Easing/QuinticEaseIn.cs
+++ b/src/Avalonia.Animation/Easing/QuinticEaseIn.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Animation.Easings
{
///
diff --git a/src/Avalonia.Animation/Easing/QuinticEaseInOut.cs b/src/Avalonia.Animation/Easing/QuinticEaseInOut.cs
index 53c29f75dc..5b6c0c1162 100644
--- a/src/Avalonia.Animation/Easing/QuinticEaseInOut.cs
+++ b/src/Avalonia.Animation/Easing/QuinticEaseInOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Animation.Easings
{
///
diff --git a/src/Avalonia.Animation/Easing/QuinticEaseOut.cs b/src/Avalonia.Animation/Easing/QuinticEaseOut.cs
index 1ad31a9623..5cb5663dff 100644
--- a/src/Avalonia.Animation/Easing/QuinticEaseOut.cs
+++ b/src/Avalonia.Animation/Easing/QuinticEaseOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Animation.Easings
{
///
diff --git a/src/Avalonia.Animation/Easing/SineEaseIn.cs b/src/Avalonia.Animation/Easing/SineEaseIn.cs
index a4b496e4b6..01ae7bca04 100644
--- a/src/Avalonia.Animation/Easing/SineEaseIn.cs
+++ b/src/Avalonia.Animation/Easing/SineEaseIn.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Animation.Utils;
diff --git a/src/Avalonia.Animation/Easing/SineEaseInOut.cs b/src/Avalonia.Animation/Easing/SineEaseInOut.cs
index 51052575e2..6b8419f2a1 100644
--- a/src/Avalonia.Animation/Easing/SineEaseInOut.cs
+++ b/src/Avalonia.Animation/Easing/SineEaseInOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Animation.Easings
diff --git a/src/Avalonia.Animation/Easing/SineEaseOut.cs b/src/Avalonia.Animation/Easing/SineEaseOut.cs
index 267b4b3809..f7ead3feac 100644
--- a/src/Avalonia.Animation/Easing/SineEaseOut.cs
+++ b/src/Avalonia.Animation/Easing/SineEaseOut.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Animation.Utils;
diff --git a/src/Avalonia.Animation/FillMode.cs b/src/Avalonia.Animation/FillMode.cs
index 39beecf455..001e1cdeb4 100644
--- a/src/Avalonia.Animation/FillMode.cs
+++ b/src/Avalonia.Animation/FillMode.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-namespace Avalonia.Animation
+namespace Avalonia.Animation
{
public enum FillMode
{
diff --git a/src/Avalonia.Animation/IAnimation.cs b/src/Avalonia.Animation/IAnimation.cs
index 26cf4a6fd1..ff85535d8a 100644
--- a/src/Avalonia.Animation/IAnimation.cs
+++ b/src/Avalonia.Animation/IAnimation.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Threading.Tasks;
diff --git a/src/Avalonia.Animation/IAnimationSetter.cs b/src/Avalonia.Animation/IAnimationSetter.cs
index 9c8365ea37..2d22377286 100644
--- a/src/Avalonia.Animation/IAnimationSetter.cs
+++ b/src/Avalonia.Animation/IAnimationSetter.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Animation
{
public interface IAnimationSetter
diff --git a/src/Avalonia.Animation/IAnimator.cs b/src/Avalonia.Animation/IAnimator.cs
index d09f396d70..d0fb173c54 100644
--- a/src/Avalonia.Animation/IAnimator.cs
+++ b/src/Avalonia.Animation/IAnimator.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Collections.Generic;
namespace Avalonia.Animation
diff --git a/src/Avalonia.Animation/ITransition.cs b/src/Avalonia.Animation/ITransition.cs
index e5d8466f04..ade2ec8b9e 100644
--- a/src/Avalonia.Animation/ITransition.cs
+++ b/src/Avalonia.Animation/ITransition.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Animation
{
diff --git a/src/Avalonia.Animation/IterationCount.cs b/src/Avalonia.Animation/IterationCount.cs
index 9f57455639..9463718608 100644
--- a/src/Avalonia.Animation/IterationCount.cs
+++ b/src/Avalonia.Animation/IterationCount.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.ComponentModel;
using System.Globalization;
diff --git a/src/Avalonia.Animation/IterationCountTypeConverter.cs b/src/Avalonia.Animation/IterationCountTypeConverter.cs
index a2bb9a20f1..1c63f8cdf1 100644
--- a/src/Avalonia.Animation/IterationCountTypeConverter.cs
+++ b/src/Avalonia.Animation/IterationCountTypeConverter.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.ComponentModel;
using System.Globalization;
diff --git a/src/Avalonia.Animation/KeyFrame.cs b/src/Avalonia.Animation/KeyFrame.cs
index a6577505ee..c2cc1aa051 100644
--- a/src/Avalonia.Animation/KeyFrame.cs
+++ b/src/Avalonia.Animation/KeyFrame.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Collections.Generic;
using Avalonia.Collections;
using Avalonia.Metadata;
@@ -22,6 +19,7 @@ namespace Avalonia.Animation
{
private TimeSpan _ktimeSpan;
private Cue _kCue;
+ private KeySpline _kKeySpline;
public KeyFrame()
{
@@ -77,6 +75,25 @@ namespace Avalonia.Animation
}
}
+ ///
+ /// Gets or sets the KeySpline of this .
+ ///
+ /// The key spline.
+ public KeySpline KeySpline
+ {
+ get
+ {
+ return _kKeySpline;
+ }
+ set
+ {
+ _kKeySpline = value;
+ if (value != null && !value.IsValid())
+ {
+ throw new ArgumentException($"{nameof(KeySpline)} must have X coordinates >= 0.0 and <= 1.0.");
+ }
+ }
+ }
}
diff --git a/src/Avalonia.Animation/KeyFrames.cs b/src/Avalonia.Animation/KeyFrames.cs
index 9e3b1d9f51..2e9efa8691 100644
--- a/src/Avalonia.Animation/KeyFrames.cs
+++ b/src/Avalonia.Animation/KeyFrames.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Collections.Generic;
using Avalonia.Collections;
diff --git a/src/Avalonia.Animation/KeySpline.cs b/src/Avalonia.Animation/KeySpline.cs
new file mode 100644
index 0000000000..5a4f7a15a3
--- /dev/null
+++ b/src/Avalonia.Animation/KeySpline.cs
@@ -0,0 +1,349 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.Text;
+using Avalonia;
+using Avalonia.Utilities;
+
+// Ported from WPF open-source code.
+// https://github.com/dotnet/wpf/blob/ae1790531c3b993b56eba8b1f0dd395a3ed7de75/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/KeySpline.cs
+
+namespace Avalonia.Animation
+{
+ ///
+ /// Determines how an animation is used based on a cubic bezier curve.
+ /// X1 and X2 must be between 0.0 and 1.0, inclusive.
+ /// See https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.animation.keyspline
+ ///
+ [TypeConverter(typeof(KeySplineTypeConverter))]
+ public class KeySpline : AvaloniaObject
+ {
+ // Control points
+ private double _controlPointX1;
+ private double _controlPointY1;
+ private double _controlPointX2;
+ private double _controlPointY2;
+ private bool _isSpecified;
+ private bool _isDirty;
+
+ // The parameter that corresponds to the most recent time
+ private double _parameter;
+
+ // Cached coefficients
+ private double _Bx; // 3*points[0].X
+ private double _Cx; // 3*points[1].X
+ private double _Cx_Bx; // 2*(Cx - Bx)
+ private double _three_Cx; // 3 - Cx
+
+ private double _By; // 3*points[0].Y
+ private double _Cy; // 3*points[1].Y
+
+ // constants
+ private const double _accuracy = .001; // 1/3 the desired accuracy in X
+ private const double _fuzz = .000001; // computational zero
+
+ ///
+ /// Create a with X1 = Y1 = 0 and X2 = Y2 = 1.
+ ///
+ public KeySpline()
+ {
+ _controlPointX1 = 0.0;
+ _controlPointY1 = 0.0;
+ _controlPointX2 = 1.0;
+ _controlPointY2 = 1.0;
+ _isDirty = true;
+ }
+
+ ///
+ /// Create a with the given parameters
+ ///
+ /// X coordinate for the first control point
+ /// Y coordinate for the first control point
+ /// X coordinate for the second control point
+ /// Y coordinate for the second control point
+ public KeySpline(double x1, double y1, double x2, double y2)
+ {
+ _controlPointX1 = x1;
+ _controlPointY1 = y1;
+ _controlPointX2 = x2;
+ _controlPointY2 = y2;
+ _isDirty = true;
+ }
+
+ ///
+ /// Parse a from a string. The string
+ /// needs to contain 4 values in it for the 2 control points.
+ ///
+ /// string with 4 values in it
+ /// culture of the string
+ /// Thrown if the string does not have 4 values
+ /// A with the appropriate values set
+ public static KeySpline Parse(string value, CultureInfo culture)
+ {
+ using (var tokenizer = new StringTokenizer((string)value, CultureInfo.InvariantCulture, exceptionMessage: "Invalid KeySpline."))
+ {
+ return new KeySpline(tokenizer.ReadDouble(), tokenizer.ReadDouble(), tokenizer.ReadDouble(), tokenizer.ReadDouble());
+ }
+ }
+
+ ///
+ /// X coordinate of the first control point
+ ///
+ public double ControlPointX1
+ {
+ get => _controlPointX1;
+ set
+ {
+ if (IsValidXValue(value))
+ {
+ _controlPointX1 = value;
+ }
+ else
+ {
+ throw new ArgumentException("Invalid KeySpline X1 value. Must be >= 0.0 and <= 1.0.");
+ }
+ }
+ }
+
+ ///
+ /// Y coordinate of the first control point
+ ///
+ public double ControlPointY1
+ {
+ get => _controlPointY1;
+ set => _controlPointY1 = value;
+ }
+
+ ///
+ /// X coordinate of the second control point
+ ///
+ public double ControlPointX2
+ {
+ get => _controlPointX2;
+ set
+ {
+ if (IsValidXValue(value))
+ {
+ _controlPointX2 = value;
+ }
+ else
+ {
+ throw new ArgumentException("Invalid KeySpline X2 value. Must be >= 0.0 and <= 1.0.");
+ }
+ }
+ }
+
+ ///
+ /// Y coordinate of the second control point
+ ///
+ public double ControlPointY2
+ {
+ get => _controlPointY2;
+ set => _controlPointY2 = value;
+ }
+
+ ///
+ /// Calculates spline progress from a linear progress.
+ ///
+ /// the linear progress
+ /// the spline progress
+ public double GetSplineProgress(double linearProgress)
+ {
+ if (_isDirty)
+ {
+ Build();
+ }
+
+ if (!_isSpecified)
+ {
+ return linearProgress;
+ }
+ else
+ {
+ SetParameterFromX(linearProgress);
+
+ return GetBezierValue(_By, _Cy, _parameter);
+ }
+ }
+
+ ///
+ /// Check to see whether the is valid by looking
+ /// at its X values.
+ ///
+ /// true if the X values for this fall in
+ /// acceptable range; false otherwise.
+ public bool IsValid()
+ {
+ return IsValidXValue(_controlPointX1) && IsValidXValue(_controlPointX2);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ private bool IsValidXValue(double value)
+ {
+ return value >= 0.0 && value <= 1.0;
+ }
+
+ ///
+ /// Compute cached coefficients.
+ ///
+ private void Build()
+ {
+ if (_controlPointX1 == 0 && _controlPointY1 == 0 && _controlPointX2 == 1 && _controlPointY2 == 1)
+ {
+ // This KeySpline would have no effect on the progress.
+ _isSpecified = false;
+ }
+ else
+ {
+ _isSpecified = true;
+
+ _parameter = 0;
+
+ // X coefficients
+ _Bx = 3 * _controlPointX1;
+ _Cx = 3 * _controlPointX2;
+ _Cx_Bx = 2 * (_Cx - _Bx);
+ _three_Cx = 3 - _Cx;
+
+ // Y coefficients
+ _By = 3 * _controlPointY1;
+ _Cy = 3 * _controlPointY2;
+ }
+
+ _isDirty = false;
+ }
+
+ ///
+ /// Get an X or Y value with the Bezier formula.
+ ///
+ /// the second Bezier coefficient
+ /// the third Bezier coefficient
+ /// the parameter value to evaluate at
+ /// the value of the Bezier function at the given parameter
+ static private double GetBezierValue(double b, double c, double t)
+ {
+ double s = 1.0 - t;
+ double t2 = t * t;
+
+ return b * t * s * s + c * t2 * s + t2 * t;
+ }
+
+ ///
+ /// Get X and dX/dt at a given parameter
+ ///
+ /// the parameter value to evaluate at
+ /// the value of x there
+ /// the value of dx/dt there
+ private void GetXAndDx(double t, out double x, out double dx)
+ {
+ double s = 1.0 - t;
+ double t2 = t * t;
+ double s2 = s * s;
+
+ x = _Bx * t * s2 + _Cx * t2 * s + t2 * t;
+ dx = _Bx * s2 + _Cx_Bx * s * t + _three_Cx * t2;
+ }
+
+ ///
+ /// Compute the parameter value that corresponds to a given X value, using a modified
+ /// clamped Newton-Raphson algorithm to solve the equation X(t) - time = 0. We make
+ /// use of some known properties of this particular function:
+ /// * We are only interested in solutions in the interval [0,1]
+ /// * X(t) is increasing, so we can assume that if X(t) > time t > solution. We use
+ /// that to clamp down the search interval with every probe.
+ /// * The derivative of X and Y are between 0 and 3.
+ ///
+ /// the time, scaled to fit in [0,1]
+ private void SetParameterFromX(double time)
+ {
+ // Dynamic search interval to clamp with
+ double bottom = 0;
+ double top = 1;
+
+ if (time == 0)
+ {
+ _parameter = 0;
+ }
+ else if (time == 1)
+ {
+ _parameter = 1;
+ }
+ else
+ {
+ // Loop while improving the guess
+ while (top - bottom > _fuzz)
+ {
+ double x, dx, absdx;
+
+ // Get x and dx/dt at the current parameter
+ GetXAndDx(_parameter, out x, out dx);
+ absdx = Math.Abs(dx);
+
+ // Clamp down the search interval, relying on the monotonicity of X(t)
+ if (x > time)
+ {
+ top = _parameter; // because parameter > solution
+ }
+ else
+ {
+ bottom = _parameter; // because parameter < solution
+ }
+
+ // The desired accuracy is in ultimately in y, not in x, so the
+ // accuracy needs to be multiplied by dx/dy = (dx/dt) / (dy/dt).
+ // But dy/dt <=3, so we omit that
+ if (Math.Abs(x - time) < _accuracy * absdx)
+ {
+ break; // We're there
+ }
+
+ if (absdx > _fuzz)
+ {
+ // Nonzero derivative, use Newton-Raphson to obtain the next guess
+ double next = _parameter - (x - time) / dx;
+
+ // If next guess is out of the search interval then clamp it in
+ if (next >= top)
+ {
+ _parameter = (_parameter + top) / 2;
+ }
+ else if (next <= bottom)
+ {
+ _parameter = (_parameter + bottom) / 2;
+ }
+ else
+ {
+ // Next guess is inside the search interval, accept it
+ _parameter = next;
+ }
+ }
+ else // Zero derivative, halve the search interval
+ {
+ _parameter = (bottom + top) / 2;
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// Converts string values to values
+ ///
+ public class KeySplineTypeConverter : TypeConverter
+ {
+ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
+ {
+ return sourceType == typeof(string);
+ }
+
+ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+ {
+ return KeySpline.Parse((string)value, culture);
+ }
+ }
+}
diff --git a/src/Avalonia.Animation/PlayState.cs b/src/Avalonia.Animation/PlayState.cs
index 8d28f06eb1..313d33d586 100644
--- a/src/Avalonia.Animation/PlayState.cs
+++ b/src/Avalonia.Animation/PlayState.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-namespace Avalonia.Animation
+namespace Avalonia.Animation
{
///
/// Determines the playback state of an animation.
diff --git a/src/Avalonia.Animation/PlaybackDirection.cs b/src/Avalonia.Animation/PlaybackDirection.cs
index a44dd388ae..bbce6106e1 100644
--- a/src/Avalonia.Animation/PlaybackDirection.cs
+++ b/src/Avalonia.Animation/PlaybackDirection.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-namespace Avalonia.Animation
+namespace Avalonia.Animation
{
///
/// Determines the playback direction of an animation.
diff --git a/src/Avalonia.Animation/Properties/AssemblyInfo.cs b/src/Avalonia.Animation/Properties/AssemblyInfo.cs
index 8523b9537d..d34fd06272 100644
--- a/src/Avalonia.Animation/Properties/AssemblyInfo.cs
+++ b/src/Avalonia.Animation/Properties/AssemblyInfo.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Metadata;
using System.Reflection;
using System.Runtime.CompilerServices;
diff --git a/src/Avalonia.Animation/TransitionInstance.cs b/src/Avalonia.Animation/TransitionInstance.cs
index a69ad50a4b..efbbed51b5 100644
--- a/src/Avalonia.Animation/TransitionInstance.cs
+++ b/src/Avalonia.Animation/TransitionInstance.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Metadata;
using System;
using System.Reactive.Linq;
diff --git a/src/Avalonia.Animation/Transition`1.cs b/src/Avalonia.Animation/Transition`1.cs
index cd0d5d9ce9..138131acb9 100644
--- a/src/Avalonia.Animation/Transition`1.cs
+++ b/src/Avalonia.Animation/Transition`1.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Reactive.Linq;
using Avalonia.Animation.Easings;
diff --git a/src/Avalonia.Animation/Transitions.cs b/src/Avalonia.Animation/Transitions.cs
index 7e742fc0b4..2741039ebc 100644
--- a/src/Avalonia.Animation/Transitions.cs
+++ b/src/Avalonia.Animation/Transitions.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Collections;
namespace Avalonia.Animation
diff --git a/src/Avalonia.Animation/Transitions/DoubleTransition.cs b/src/Avalonia.Animation/Transitions/DoubleTransition.cs
index d7dd93c743..8cae1e1f81 100644
--- a/src/Avalonia.Animation/Transitions/DoubleTransition.cs
+++ b/src/Avalonia.Animation/Transitions/DoubleTransition.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Reactive.Linq;
diff --git a/src/Avalonia.Animation/Transitions/FloatTransition.cs b/src/Avalonia.Animation/Transitions/FloatTransition.cs
index 825a3f958f..427563e559 100644
--- a/src/Avalonia.Animation/Transitions/FloatTransition.cs
+++ b/src/Avalonia.Animation/Transitions/FloatTransition.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Reactive.Linq;
diff --git a/src/Avalonia.Animation/Transitions/IntegerTransition.cs b/src/Avalonia.Animation/Transitions/IntegerTransition.cs
index e3dca5b26d..7a85bd75dc 100644
--- a/src/Avalonia.Animation/Transitions/IntegerTransition.cs
+++ b/src/Avalonia.Animation/Transitions/IntegerTransition.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Reactive.Linq;
diff --git a/src/Avalonia.Animation/Utils/BounceEaseUtils.cs b/src/Avalonia.Animation/Utils/BounceEaseUtils.cs
index 71b4ec4d94..0fc9f923f6 100644
--- a/src/Avalonia.Animation/Utils/BounceEaseUtils.cs
+++ b/src/Avalonia.Animation/Utils/BounceEaseUtils.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Animation.Utils
{
///
diff --git a/src/Avalonia.Animation/Utils/EasingUtils.cs b/src/Avalonia.Animation/Utils/EasingUtils.cs
index 1a7688cace..1179ff6919 100644
--- a/src/Avalonia.Animation/Utils/EasingUtils.cs
+++ b/src/Avalonia.Animation/Utils/EasingUtils.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Animation.Utils
{
diff --git a/src/Avalonia.Base/AttachedProperty.cs b/src/Avalonia.Base/AttachedProperty.cs
index d1df5fa5e3..b8ab4d6bf5 100644
--- a/src/Avalonia.Base/AttachedProperty.cs
+++ b/src/Avalonia.Base/AttachedProperty.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia
diff --git a/src/Avalonia.Base/AvaloniaInternalException.cs b/src/Avalonia.Base/AvaloniaInternalException.cs
index 205dc29a97..a536073174 100644
--- a/src/Avalonia.Base/AvaloniaInternalException.cs
+++ b/src/Avalonia.Base/AvaloniaInternalException.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia
diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs
index b0ff591682..ed36e6da43 100644
--- a/src/Avalonia.Base/AvaloniaObject.cs
+++ b/src/Avalonia.Base/AvaloniaObject.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.ComponentModel;
@@ -80,8 +77,12 @@ namespace Avalonia
_inheritanceParent?.RemoveInheritanceChild(this);
_inheritanceParent = value;
- foreach (var property in AvaloniaPropertyRegistry.Instance.GetRegisteredInherited(GetType()))
+ var properties = AvaloniaPropertyRegistry.Instance.GetRegisteredInherited(GetType());
+ var propertiesCount = properties.Count;
+
+ for (var i = 0; i < propertiesCount; i++)
{
+ var property = properties[i];
if (valuestore?.IsSet(property) == true)
{
// If local value set there can be no change.
@@ -311,7 +312,10 @@ namespace Avalonia
/// The property.
/// The value.
/// The priority of the value.
- public void SetValue(
+ ///
+ /// An if setting the property can be undone, otherwise null.
+ ///
+ public IDisposable SetValue(
StyledPropertyBase property,
T value,
BindingPriority priority = BindingPriority.LocalValue)
@@ -335,8 +339,10 @@ namespace Avalonia
}
else if (!(value is DoNothingType))
{
- Values.SetValue(property, value, priority);
+ return Values.SetValue(property, value, priority);
}
+
+ return null;
}
///
diff --git a/src/Avalonia.Base/AvaloniaObjectExtensions.cs b/src/Avalonia.Base/AvaloniaObjectExtensions.cs
index a4c7fa95a5..4fc65a3ed4 100644
--- a/src/Avalonia.Base/AvaloniaObjectExtensions.cs
+++ b/src/Avalonia.Base/AvaloniaObjectExtensions.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Reactive;
using System.Reactive.Disposables;
@@ -458,7 +455,10 @@ namespace Avalonia
/// The property.
/// The value.
/// The priority of the value.
- public static void SetValue(
+ ///
+ /// An if setting the property can be undone, otherwise null.
+ ///
+ public static IDisposable SetValue(
this IAvaloniaObject target,
AvaloniaProperty property,
object value,
@@ -467,7 +467,7 @@ namespace Avalonia
target = target ?? throw new ArgumentNullException(nameof(target));
property = property ?? throw new ArgumentNullException(nameof(property));
- property.RouteSetValue(target, value, priority);
+ return property.RouteSetValue(target, value, priority);
}
///
@@ -478,7 +478,10 @@ namespace Avalonia
/// The property.
/// The value.
/// The priority of the value.
- public static void SetValue(
+ ///
+ /// An if setting the property can be undone, otherwise null.
+ ///
+ public static IDisposable SetValue(
this IAvaloniaObject target,
AvaloniaProperty property,
T value,
@@ -490,11 +493,10 @@ namespace Avalonia
switch (property)
{
case StyledPropertyBase styled:
- target.SetValue(styled, value, priority);
- break;
+ return target.SetValue(styled, value, priority);
case DirectPropertyBase direct:
target.SetValue(direct, value);
- break;
+ return null;
default:
throw new NotSupportedException("Unsupported AvaloniaProperty type.");
}
diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs
index aa7a675764..74d7039751 100644
--- a/src/Avalonia.Base/AvaloniaProperty.cs
+++ b/src/Avalonia.Base/AvaloniaProperty.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Reactive.Subjects;
@@ -469,6 +466,15 @@ namespace Avalonia
return Name;
}
+ ///
+ /// Uses the visitor pattern to resolve an untyped property to a typed property.
+ ///
+ /// The type of user data passed.
+ /// The visitor which will accept the typed property.
+ /// The user data to pass.
+ public abstract void Accept(IAvaloniaPropertyVisitor vistor, ref TData data)
+ where TData : struct;
+
///
/// Notifies the observable.
///
@@ -496,7 +502,10 @@ namespace Avalonia
/// The object instance.
/// The value.
/// The priority.
- internal abstract void RouteSetValue(
+ ///
+ /// An if setting the property can be undone, otherwise null.
+ ///
+ internal abstract IDisposable? RouteSetValue(
IAvaloniaObject o,
object value,
BindingPriority priority);
diff --git a/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs b/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs
index 479d730e48..0f09747865 100644
--- a/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs
+++ b/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Data;
diff --git a/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs`1.cs b/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs`1.cs
index d8ac3752b3..fca32b4ffc 100644
--- a/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs`1.cs
+++ b/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs`1.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Data;
diff --git a/src/Avalonia.Base/AvaloniaPropertyRegistry.cs b/src/Avalonia.Base/AvaloniaPropertyRegistry.cs
index 29ab10278b..4a3b104f2a 100644
--- a/src/Avalonia.Base/AvaloniaPropertyRegistry.cs
+++ b/src/Avalonia.Base/AvaloniaPropertyRegistry.cs
@@ -1,11 +1,6 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Runtime.CompilerServices;
-using Avalonia.Data;
namespace Avalonia
{
@@ -28,8 +23,6 @@ namespace Avalonia
new Dictionary>();
private readonly Dictionary> _directCache =
new Dictionary>();
- private readonly Dictionary> _initializedCache =
- new Dictionary>();
private readonly Dictionary> _inheritedCache =
new Dictionary>();
@@ -49,7 +42,7 @@ namespace Avalonia
///
/// The type.
/// A collection of definitions.
- public IEnumerable GetRegistered(Type type)
+ public IReadOnlyList GetRegistered(Type type)
{
Contract.Requires(type != null);
@@ -83,7 +76,7 @@ namespace Avalonia
///
/// The type.
/// A collection of definitions.
- public IEnumerable GetRegisteredAttached(Type type)
+ public IReadOnlyList GetRegisteredAttached(Type type)
{
Contract.Requires(type != null);
@@ -114,7 +107,7 @@ namespace Avalonia
///
/// The type.
/// A collection of definitions.
- public IEnumerable GetRegisteredDirect(Type type)
+ public IReadOnlyList GetRegisteredDirect(Type type)
{
Contract.Requires(type != null);
@@ -145,7 +138,7 @@ namespace Avalonia
///
/// The type.
/// A collection of definitions.
- public IEnumerable GetRegisteredInherited(Type type)
+ public IReadOnlyList GetRegisteredInherited(Type type)
{
Contract.Requires(type != null);
@@ -157,16 +150,27 @@ namespace Avalonia
result = new List();
var visited = new HashSet();
- foreach (var property in GetRegistered(type))
+ var registered = GetRegistered(type);
+ var registeredCount = registered.Count;
+
+ for (var i = 0; i < registeredCount; i++)
{
+ var property = registered[i];
+
if (property.Inherits)
{
result.Add(property);
visited.Add(property);
}
}
- foreach (var property in GetRegisteredAttached(type))
+
+ var registeredAttached = GetRegisteredAttached(type);
+ var registeredAttachedCount = registeredAttached.Count;
+
+ for (var i = 0; i < registeredAttachedCount; i++)
{
+ var property = registeredAttached[i];
+
if (property.Inherits)
{
if (!visited.Contains(property))
@@ -185,7 +189,7 @@ namespace Avalonia
///
/// The object.
/// A collection of definitions.
- public IEnumerable GetRegistered(IAvaloniaObject o)
+ public IReadOnlyList GetRegistered(IAvaloniaObject o)
{
Contract.Requires(o != null);
@@ -229,8 +233,13 @@ namespace Avalonia
throw new InvalidOperationException("Attached properties not supported.");
}
- foreach (AvaloniaProperty x in GetRegistered(type))
+ var registered = GetRegistered(type);
+ var registeredCount = registered.Count;
+
+ for (var i = 0; i < registeredCount; i++)
{
+ AvaloniaProperty x = registered[i];
+
if (x.Name == name)
{
return x;
@@ -276,8 +285,13 @@ namespace Avalonia
return property;
}
- foreach (var p in GetRegisteredDirect(o.GetType()))
+ var registeredDirect = GetRegisteredDirect(o.GetType());
+ var registeredDirectCount = registeredDirect.Count;
+
+ for (var i = 0; i < registeredDirectCount; i++)
{
+ var p = registeredDirect[i];
+
if (p == property)
{
return (DirectPropertyBase)p;
@@ -308,8 +322,23 @@ namespace Avalonia
Contract.Requires(type != null);
Contract.Requires(property != null);
- return Instance.GetRegistered(type).Any(x => x == property) ||
- Instance.GetRegisteredAttached(type).Any(x => x == property);
+ static bool ContainsProperty(IReadOnlyList properties, AvaloniaProperty property)
+ {
+ var propertiesCount = properties.Count;
+
+ for (var i = 0; i < propertiesCount; i++)
+ {
+ if (properties[i] == property)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ return ContainsProperty(Instance.GetRegistered(type), property) ||
+ ContainsProperty(Instance.GetRegisteredAttached(type), property);
}
///
@@ -374,7 +403,6 @@ namespace Avalonia
}
_registeredCache.Clear();
- _initializedCache.Clear();
_inheritedCache.Clear();
}
@@ -411,32 +439,7 @@ namespace Avalonia
}
_attachedCache.Clear();
- _initializedCache.Clear();
_inheritedCache.Clear();
}
-
- private readonly struct PropertyInitializationData
- {
- public AvaloniaProperty Property { get; }
- public object Value { get; }
- public bool IsDirect { get; }
- public IDirectPropertyAccessor DirectAccessor { get; }
-
- public PropertyInitializationData(AvaloniaProperty property, IDirectPropertyAccessor directAccessor)
- {
- Property = property;
- Value = null;
- IsDirect = true;
- DirectAccessor = directAccessor;
- }
-
- public PropertyInitializationData(AvaloniaProperty property, IStyledPropertyAccessor styledAccessor, Type type)
- {
- Property = property;
- Value = styledAccessor.GetDefaultValue(type);
- IsDirect = false;
- DirectAccessor = null;
- }
- }
}
}
diff --git a/src/Avalonia.Base/AvaloniaProperty`1.cs b/src/Avalonia.Base/AvaloniaProperty`1.cs
index be58ff796d..2f26d855f2 100644
--- a/src/Avalonia.Base/AvaloniaProperty`1.cs
+++ b/src/Avalonia.Base/AvaloniaProperty`1.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Data;
using Avalonia.Utilities;
diff --git a/src/Avalonia.Base/Collections/AvaloniaDictionary.cs b/src/Avalonia.Base/Collections/AvaloniaDictionary.cs
index 4de4c540a0..a3c51dc965 100644
--- a/src/Avalonia.Base/Collections/AvaloniaDictionary.cs
+++ b/src/Avalonia.Base/Collections/AvaloniaDictionary.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections;
using System.Collections.Generic;
diff --git a/src/Avalonia.Base/Collections/AvaloniaList.cs b/src/Avalonia.Base/Collections/AvaloniaList.cs
index ca51822eed..f201cfab1f 100644
--- a/src/Avalonia.Base/Collections/AvaloniaList.cs
+++ b/src/Avalonia.Base/Collections/AvaloniaList.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections;
using System.Collections.Generic;
diff --git a/src/Avalonia.Base/Collections/AvaloniaListConverter.cs b/src/Avalonia.Base/Collections/AvaloniaListConverter.cs
index 63c2e07ecf..f3e22bfe69 100644
--- a/src/Avalonia.Base/Collections/AvaloniaListConverter.cs
+++ b/src/Avalonia.Base/Collections/AvaloniaListConverter.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.ComponentModel;
using System.Globalization;
diff --git a/src/Avalonia.Base/Collections/AvaloniaListExtensions.cs b/src/Avalonia.Base/Collections/AvaloniaListExtensions.cs
index 58f3413780..d915887e4c 100644
--- a/src/Avalonia.Base/Collections/AvaloniaListExtensions.cs
+++ b/src/Avalonia.Base/Collections/AvaloniaListExtensions.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections;
using System.Collections.Generic;
diff --git a/src/Avalonia.Base/Collections/IAvaloniaList.cs b/src/Avalonia.Base/Collections/IAvaloniaList.cs
index b7ed9b1ad6..250d4faeb9 100644
--- a/src/Avalonia.Base/Collections/IAvaloniaList.cs
+++ b/src/Avalonia.Base/Collections/IAvaloniaList.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Collections.Generic;
namespace Avalonia.Collections
diff --git a/src/Avalonia.Base/Collections/IAvaloniaReadOnlyList.cs b/src/Avalonia.Base/Collections/IAvaloniaReadOnlyList.cs
index 755efa3eaf..a6a5953827 100644
--- a/src/Avalonia.Base/Collections/IAvaloniaReadOnlyList.cs
+++ b/src/Avalonia.Base/Collections/IAvaloniaReadOnlyList.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
diff --git a/src/Avalonia.Base/Collections/NotifyCollectionChangedExtensions.cs b/src/Avalonia.Base/Collections/NotifyCollectionChangedExtensions.cs
index ba84c37e4a..fe9ef667b0 100644
--- a/src/Avalonia.Base/Collections/NotifyCollectionChangedExtensions.cs
+++ b/src/Avalonia.Base/Collections/NotifyCollectionChangedExtensions.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Collections.Specialized;
using System.Reactive.Linq;
using Avalonia.Reactive;
diff --git a/src/Avalonia.Base/Contract.cs b/src/Avalonia.Base/Contract.cs
index 0b67601db5..27427700ac 100644
--- a/src/Avalonia.Base/Contract.cs
+++ b/src/Avalonia.Base/Contract.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Runtime.CompilerServices;
using JetBrains.Annotations;
diff --git a/src/Avalonia.Base/Data/AssignBindingAttribute.cs b/src/Avalonia.Base/Data/AssignBindingAttribute.cs
index 0d050449cd..15bd32c7c2 100644
--- a/src/Avalonia.Base/Data/AssignBindingAttribute.cs
+++ b/src/Avalonia.Base/Data/AssignBindingAttribute.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Data
diff --git a/src/Avalonia.Base/Data/BindingChainException.cs b/src/Avalonia.Base/Data/BindingChainException.cs
index a609ace4ec..86112ce12d 100644
--- a/src/Avalonia.Base/Data/BindingChainException.cs
+++ b/src/Avalonia.Base/Data/BindingChainException.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Data
{
diff --git a/src/Avalonia.Base/Data/BindingMode.cs b/src/Avalonia.Base/Data/BindingMode.cs
index 1e0e80f496..0d04c2eb10 100644
--- a/src/Avalonia.Base/Data/BindingMode.cs
+++ b/src/Avalonia.Base/Data/BindingMode.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Data
{
///
diff --git a/src/Avalonia.Base/Data/BindingNotification.cs b/src/Avalonia.Base/Data/BindingNotification.cs
index 9a2cc1bfde..516c26d1d3 100644
--- a/src/Avalonia.Base/Data/BindingNotification.cs
+++ b/src/Avalonia.Base/Data/BindingNotification.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Data
{
diff --git a/src/Avalonia.Base/Data/BindingOperations.cs b/src/Avalonia.Base/Data/BindingOperations.cs
index 1b47cc7490..dc8421fb35 100644
--- a/src/Avalonia.Base/Data/BindingOperations.cs
+++ b/src/Avalonia.Base/Data/BindingOperations.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Reactive.Disposables;
using System.Reactive.Linq;
diff --git a/src/Avalonia.Base/Data/BindingPriority.cs b/src/Avalonia.Base/Data/BindingPriority.cs
index 55246cabf5..68b2912ffe 100644
--- a/src/Avalonia.Base/Data/BindingPriority.cs
+++ b/src/Avalonia.Base/Data/BindingPriority.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Data
{
///
diff --git a/src/Avalonia.Base/Data/Converters/BoolConverters.cs b/src/Avalonia.Base/Data/Converters/BoolConverters.cs
index 6b429e1087..817d1cea9a 100644
--- a/src/Avalonia.Base/Data/Converters/BoolConverters.cs
+++ b/src/Avalonia.Base/Data/Converters/BoolConverters.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Linq;
namespace Avalonia.Data.Converters
diff --git a/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs b/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs
index 0ffd6a9539..5e80a15059 100644
--- a/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs
+++ b/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Globalization;
using System.Windows.Input;
diff --git a/src/Avalonia.Base/Data/Converters/FuncMultiValueConverter.cs b/src/Avalonia.Base/Data/Converters/FuncMultiValueConverter.cs
index 6e1c4cb0e3..988cc123f9 100644
--- a/src/Avalonia.Base/Data/Converters/FuncMultiValueConverter.cs
+++ b/src/Avalonia.Base/Data/Converters/FuncMultiValueConverter.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -30,7 +27,23 @@ namespace Avalonia.Data.Converters
///
public object Convert(IList values, Type targetType, object parameter, CultureInfo culture)
{
- var converted = values.OfType().ToList();
+ //standard OfType skip null values, even they are valid for the Type
+ static IEnumerable OfTypeWithDefaultSupport(IList list)
+ {
+ foreach (object obj in list)
+ {
+ if (obj is TIn result)
+ {
+ yield return result;
+ }
+ else if (Equals(obj, default(TIn)))
+ {
+ yield return default(TIn);
+ }
+ }
+ }
+
+ var converted = OfTypeWithDefaultSupport(values).ToList();
if (converted.Count == values.Count)
{
diff --git a/src/Avalonia.Base/Data/Converters/FuncValueConverter.cs b/src/Avalonia.Base/Data/Converters/FuncValueConverter.cs
index b747587b4a..9ec600d2bc 100644
--- a/src/Avalonia.Base/Data/Converters/FuncValueConverter.cs
+++ b/src/Avalonia.Base/Data/Converters/FuncValueConverter.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Globalization;
using Avalonia.Utilities;
diff --git a/src/Avalonia.Base/Data/Converters/IMultiValueConverter.cs b/src/Avalonia.Base/Data/Converters/IMultiValueConverter.cs
index 3f84fcb3e7..0468835c41 100644
--- a/src/Avalonia.Base/Data/Converters/IMultiValueConverter.cs
+++ b/src/Avalonia.Base/Data/Converters/IMultiValueConverter.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Globalization;
diff --git a/src/Avalonia.Base/Data/Converters/IValueConverter.cs b/src/Avalonia.Base/Data/Converters/IValueConverter.cs
index 754aa7975d..f31f4d522e 100644
--- a/src/Avalonia.Base/Data/Converters/IValueConverter.cs
+++ b/src/Avalonia.Base/Data/Converters/IValueConverter.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Globalization;
diff --git a/src/Avalonia.Base/Data/Converters/ObjectConverters.cs b/src/Avalonia.Base/Data/Converters/ObjectConverters.cs
index 3cadfd5b47..755d826dda 100644
--- a/src/Avalonia.Base/Data/Converters/ObjectConverters.cs
+++ b/src/Avalonia.Base/Data/Converters/ObjectConverters.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Data.Converters
{
diff --git a/src/Avalonia.Base/Data/Converters/StringConverters.cs b/src/Avalonia.Base/Data/Converters/StringConverters.cs
index 42eb8e1d81..4b0a845770 100644
--- a/src/Avalonia.Base/Data/Converters/StringConverters.cs
+++ b/src/Avalonia.Base/Data/Converters/StringConverters.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Data.Converters
{
diff --git a/src/Avalonia.Base/Data/Core/BindingExpression.cs b/src/Avalonia.Base/Data/Core/BindingExpression.cs
index 9eec5d6b2b..9721369e47 100644
--- a/src/Avalonia.Base/Data/Core/BindingExpression.cs
+++ b/src/Avalonia.Base/Data/Core/BindingExpression.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Globalization;
using System.Reactive.Linq;
diff --git a/src/Avalonia.Base/Data/Core/CommonPropertyNames.cs b/src/Avalonia.Base/Data/Core/CommonPropertyNames.cs
index 6760c3f259..da6f407d81 100644
--- a/src/Avalonia.Base/Data/Core/CommonPropertyNames.cs
+++ b/src/Avalonia.Base/Data/Core/CommonPropertyNames.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Data.Core
{
public static class CommonPropertyNames
diff --git a/src/Avalonia.Base/Data/Core/EmptyExpressionNode.cs b/src/Avalonia.Base/Data/Core/EmptyExpressionNode.cs
index d5658b124b..4e142fbee9 100644
--- a/src/Avalonia.Base/Data/Core/EmptyExpressionNode.cs
+++ b/src/Avalonia.Base/Data/Core/EmptyExpressionNode.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-namespace Avalonia.Data.Core
+namespace Avalonia.Data.Core
{
public class EmptyExpressionNode : ExpressionNode
{
diff --git a/src/Avalonia.Base/Data/Core/ExpressionNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNode.cs
index c2e5c8e4f3..84cbe32318 100644
--- a/src/Avalonia.Base/Data/Core/ExpressionNode.cs
+++ b/src/Avalonia.Base/Data/Core/ExpressionNode.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Data.Core
diff --git a/src/Avalonia.Base/Data/Core/ExpressionObserver.cs b/src/Avalonia.Base/Data/Core/ExpressionObserver.cs
index 91a27be634..3bacd38a20 100644
--- a/src/Avalonia.Base/Data/Core/ExpressionObserver.cs
+++ b/src/Avalonia.Base/Data/Core/ExpressionObserver.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
diff --git a/src/Avalonia.Base/Data/Core/ExpressionParseException.cs b/src/Avalonia.Base/Data/Core/ExpressionParseException.cs
index 2432410203..b0d5c21dab 100644
--- a/src/Avalonia.Base/Data/Core/ExpressionParseException.cs
+++ b/src/Avalonia.Base/Data/Core/ExpressionParseException.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Data.Core
diff --git a/src/Avalonia.Base/Data/Core/LogicalNotNode.cs b/src/Avalonia.Base/Data/Core/LogicalNotNode.cs
index 6d58b18a9f..7c402f42f6 100644
--- a/src/Avalonia.Base/Data/Core/LogicalNotNode.cs
+++ b/src/Avalonia.Base/Data/Core/LogicalNotNode.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Globalization;
diff --git a/src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs
index fa72235a89..c1e8eb115d 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Runtime.ExceptionServices;
diff --git a/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs
index f5b545d2ff..3b61f6d898 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
diff --git a/src/Avalonia.Base/Data/Core/Plugins/DataValidationBase.cs b/src/Avalonia.Base/Data/Core/Plugins/DataValidationBase.cs
index 2e0d1aa805..63e2c3a97b 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/DataValidationBase.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/DataValidationBase.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Data.Core.Plugins
{
diff --git a/src/Avalonia.Base/Data/Core/Plugins/ExceptionValidationPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/ExceptionValidationPlugin.cs
index f305912fe1..f7ab48943a 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/ExceptionValidationPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/ExceptionValidationPlugin.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Reflection;
namespace Avalonia.Data.Core.Plugins
diff --git a/src/Avalonia.Base/Data/Core/Plugins/IDataValidationPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/IDataValidationPlugin.cs
index 5b1af22f14..324279e9f0 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/IDataValidationPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/IDataValidationPlugin.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Data.Core.Plugins
{
diff --git a/src/Avalonia.Base/Data/Core/Plugins/IPropertyAccessor.cs b/src/Avalonia.Base/Data/Core/Plugins/IPropertyAccessor.cs
index 33ea5bba08..688fb8cdc2 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/IPropertyAccessor.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/IPropertyAccessor.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Data.Core.Plugins
diff --git a/src/Avalonia.Base/Data/Core/Plugins/IPropertyAccessorPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/IPropertyAccessorPlugin.cs
index a0021fa4d4..b176225fba 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/IPropertyAccessorPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/IPropertyAccessorPlugin.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Data.Core.Plugins
diff --git a/src/Avalonia.Base/Data/Core/Plugins/IStreamPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/IStreamPlugin.cs
index 3df578d25b..514e6f430a 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/IStreamPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/IStreamPlugin.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Data.Core.Plugins
{
diff --git a/src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs
index b353d03bcd..7be2a6db86 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
diff --git a/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs
index cbceb58204..f2ed86d2aa 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.ComponentModel;
using System.Linq;
diff --git a/src/Avalonia.Base/Data/Core/Plugins/ObservableStreamPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/ObservableStreamPlugin.cs
index ef5ce05821..33a1d02211 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/ObservableStreamPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/ObservableStreamPlugin.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Linq;
using System.Reactive.Linq;
using System.Reflection;
diff --git a/src/Avalonia.Base/Data/Core/Plugins/PropertyAccessorBase.cs b/src/Avalonia.Base/Data/Core/Plugins/PropertyAccessorBase.cs
index e840b2c5c9..59e8e01a44 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/PropertyAccessorBase.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/PropertyAccessorBase.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Data.Core.Plugins
{
diff --git a/src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs
index a3d2714747..dad0832e12 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Reflection;
diff --git a/src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs b/src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs
index 45b7207413..e20685b1dd 100644
--- a/src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs
+++ b/src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Data.Core.Plugins;
diff --git a/src/Avalonia.Base/Data/Core/StreamNode.cs b/src/Avalonia.Base/Data/Core/StreamNode.cs
index 183e0662aa..e501c0a03d 100644
--- a/src/Avalonia.Base/Data/Core/StreamNode.cs
+++ b/src/Avalonia.Base/Data/Core/StreamNode.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Reactive.Linq;
diff --git a/src/Avalonia.Base/Data/IBinding.cs b/src/Avalonia.Base/Data/IBinding.cs
index 95239cae06..bc91cf8960 100644
--- a/src/Avalonia.Base/Data/IBinding.cs
+++ b/src/Avalonia.Base/Data/IBinding.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Data
{
///
diff --git a/src/Avalonia.Base/Data/IndexerBinding.cs b/src/Avalonia.Base/Data/IndexerBinding.cs
index 6b5a84989a..cc3baa4530 100644
--- a/src/Avalonia.Base/Data/IndexerBinding.cs
+++ b/src/Avalonia.Base/Data/IndexerBinding.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Data
{
diff --git a/src/Avalonia.Base/Data/IndexerDescriptor.cs b/src/Avalonia.Base/Data/IndexerDescriptor.cs
index fef21a55c4..3cf6767b89 100644
--- a/src/Avalonia.Base/Data/IndexerDescriptor.cs
+++ b/src/Avalonia.Base/Data/IndexerDescriptor.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Reactive;
diff --git a/src/Avalonia.Base/Data/InstancedBinding.cs b/src/Avalonia.Base/Data/InstancedBinding.cs
index dc35fe076b..0d20f25fe2 100644
--- a/src/Avalonia.Base/Data/InstancedBinding.cs
+++ b/src/Avalonia.Base/Data/InstancedBinding.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Reactive.Subjects;
diff --git a/src/Avalonia.Base/Diagnostics/AvaloniaObjectExtensions.cs b/src/Avalonia.Base/Diagnostics/AvaloniaObjectExtensions.cs
index d062856a73..d7b1f2e053 100644
--- a/src/Avalonia.Base/Diagnostics/AvaloniaObjectExtensions.cs
+++ b/src/Avalonia.Base/Diagnostics/AvaloniaObjectExtensions.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Data;
diff --git a/src/Avalonia.Base/Diagnostics/AvaloniaPropertyValue.cs b/src/Avalonia.Base/Diagnostics/AvaloniaPropertyValue.cs
index af15f66bb0..c881c389c1 100644
--- a/src/Avalonia.Base/Diagnostics/AvaloniaPropertyValue.cs
+++ b/src/Avalonia.Base/Diagnostics/AvaloniaPropertyValue.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Data;
namespace Avalonia.Diagnostics
diff --git a/src/Avalonia.Base/Diagnostics/IAvaloniaObjectDebug.cs b/src/Avalonia.Base/Diagnostics/IAvaloniaObjectDebug.cs
index f1d31cc1e7..7f09425905 100644
--- a/src/Avalonia.Base/Diagnostics/IAvaloniaObjectDebug.cs
+++ b/src/Avalonia.Base/Diagnostics/IAvaloniaObjectDebug.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Diagnostics
diff --git a/src/Avalonia.Base/Diagnostics/INotifyCollectionChangedDebug.cs b/src/Avalonia.Base/Diagnostics/INotifyCollectionChangedDebug.cs
index 557d5bdc42..36152e6430 100644
--- a/src/Avalonia.Base/Diagnostics/INotifyCollectionChangedDebug.cs
+++ b/src/Avalonia.Base/Diagnostics/INotifyCollectionChangedDebug.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Specialized;
using Avalonia.Collections;
diff --git a/src/Avalonia.Base/DirectProperty.cs b/src/Avalonia.Base/DirectProperty.cs
index 2a8c731614..d21969502a 100644
--- a/src/Avalonia.Base/DirectProperty.cs
+++ b/src/Avalonia.Base/DirectProperty.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Data;
diff --git a/src/Avalonia.Base/DirectPropertyBase.cs b/src/Avalonia.Base/DirectPropertyBase.cs
index 39ed3b084f..d3b5277c53 100644
--- a/src/Avalonia.Base/DirectPropertyBase.cs
+++ b/src/Avalonia.Base/DirectPropertyBase.cs
@@ -1,6 +1,7 @@
using System;
using Avalonia.Data;
using Avalonia.Reactive;
+using Avalonia.Utilities;
#nullable enable
@@ -101,6 +102,12 @@ namespace Avalonia
return (DirectPropertyMetadata)base.GetMetadata(type);
}
+ ///
+ public override void Accept(IAvaloniaPropertyVisitor vistor, ref TData data)
+ {
+ vistor.Visit(this, ref data);
+ }
+
///
internal override void RouteClearValue(IAvaloniaObject o)
{
@@ -114,7 +121,7 @@ namespace Avalonia
}
///
- internal override void RouteSetValue(
+ internal override IDisposable? RouteSetValue(
IAvaloniaObject o,
object value,
BindingPriority priority)
@@ -133,6 +140,8 @@ namespace Avalonia
{
throw v.Error!;
}
+
+ return null;
}
///
diff --git a/src/Avalonia.Base/DirectPropertyMetadata`1.cs b/src/Avalonia.Base/DirectPropertyMetadata`1.cs
index 26de578a45..59a60507dc 100644
--- a/src/Avalonia.Base/DirectPropertyMetadata`1.cs
+++ b/src/Avalonia.Base/DirectPropertyMetadata`1.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Data;
namespace Avalonia
diff --git a/src/Avalonia.Base/EnumExtensions.cs b/src/Avalonia.Base/EnumExtensions.cs
index a8306c2d69..1e4864283f 100644
--- a/src/Avalonia.Base/EnumExtensions.cs
+++ b/src/Avalonia.Base/EnumExtensions.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Runtime.CompilerServices;
diff --git a/src/Avalonia.Base/IAvaloniaObject.cs b/src/Avalonia.Base/IAvaloniaObject.cs
index fb85ae222c..867249bf0e 100644
--- a/src/Avalonia.Base/IAvaloniaObject.cs
+++ b/src/Avalonia.Base/IAvaloniaObject.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Data;
@@ -65,7 +62,7 @@ namespace Avalonia
/// The property.
/// The value.
/// The priority of the value.
- void SetValue(
+ IDisposable SetValue(
StyledPropertyBase property,
T value,
BindingPriority priority = BindingPriority.LocalValue);
diff --git a/src/Avalonia.Base/IDescription.cs b/src/Avalonia.Base/IDescription.cs
index db43f7a140..b3d9f16bb7 100644
--- a/src/Avalonia.Base/IDescription.cs
+++ b/src/Avalonia.Base/IDescription.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia
{
///
diff --git a/src/Avalonia.Base/IDirectPropertyAccessor.cs b/src/Avalonia.Base/IDirectPropertyAccessor.cs
index 4f46652693..6ae71bc2c6 100644
--- a/src/Avalonia.Base/IDirectPropertyAccessor.cs
+++ b/src/Avalonia.Base/IDirectPropertyAccessor.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia
diff --git a/src/Avalonia.Base/IDirectPropertyMetadata.cs b/src/Avalonia.Base/IDirectPropertyMetadata.cs
index c283855e5f..992fa4ffc9 100644
--- a/src/Avalonia.Base/IDirectPropertyMetadata.cs
+++ b/src/Avalonia.Base/IDirectPropertyMetadata.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia
{
///
diff --git a/src/Avalonia.Base/IStyledPropertyAccessor.cs b/src/Avalonia.Base/IStyledPropertyAccessor.cs
index dfa0208c38..45d106164f 100644
--- a/src/Avalonia.Base/IStyledPropertyAccessor.cs
+++ b/src/Avalonia.Base/IStyledPropertyAccessor.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia
diff --git a/src/Avalonia.Base/IStyledPropertyMetadata.cs b/src/Avalonia.Base/IStyledPropertyMetadata.cs
index cc92e21261..f567cd930c 100644
--- a/src/Avalonia.Base/IStyledPropertyMetadata.cs
+++ b/src/Avalonia.Base/IStyledPropertyMetadata.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia
diff --git a/src/Avalonia.Base/Logging/ILogSink.cs b/src/Avalonia.Base/Logging/ILogSink.cs
index 8b5751b0af..1649679b95 100644
--- a/src/Avalonia.Base/Logging/ILogSink.cs
+++ b/src/Avalonia.Base/Logging/ILogSink.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Logging
{
///
diff --git a/src/Avalonia.Base/Logging/LogArea.cs b/src/Avalonia.Base/Logging/LogArea.cs
index 6bc1609cbc..3c19b47a05 100644
--- a/src/Avalonia.Base/Logging/LogArea.cs
+++ b/src/Avalonia.Base/Logging/LogArea.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Logging
{
///
diff --git a/src/Avalonia.Base/Logging/LogEventLevel.cs b/src/Avalonia.Base/Logging/LogEventLevel.cs
index fbb3b14d59..68406667ff 100644
--- a/src/Avalonia.Base/Logging/LogEventLevel.cs
+++ b/src/Avalonia.Base/Logging/LogEventLevel.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Logging
{
///
diff --git a/src/Avalonia.Base/Logging/Logger.cs b/src/Avalonia.Base/Logging/Logger.cs
index c895c70094..136f56a620 100644
--- a/src/Avalonia.Base/Logging/Logger.cs
+++ b/src/Avalonia.Base/Logging/Logger.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Logging
{
///
diff --git a/src/Avalonia.Base/Logging/ParametrizedLogger.cs b/src/Avalonia.Base/Logging/ParametrizedLogger.cs
index 1550cc1b40..3dfb3c1ecf 100644
--- a/src/Avalonia.Base/Logging/ParametrizedLogger.cs
+++ b/src/Avalonia.Base/Logging/ParametrizedLogger.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Runtime.CompilerServices;
namespace Avalonia.Logging
diff --git a/src/Avalonia.Base/Metadata/AmbientAttribute.cs b/src/Avalonia.Base/Metadata/AmbientAttribute.cs
index db36953300..85ca6c4ec9 100644
--- a/src/Avalonia.Base/Metadata/AmbientAttribute.cs
+++ b/src/Avalonia.Base/Metadata/AmbientAttribute.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Metadata
diff --git a/src/Avalonia.Base/Metadata/ContentAttribute.cs b/src/Avalonia.Base/Metadata/ContentAttribute.cs
index 803769561d..a0b2fa0e1d 100644
--- a/src/Avalonia.Base/Metadata/ContentAttribute.cs
+++ b/src/Avalonia.Base/Metadata/ContentAttribute.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Metadata
diff --git a/src/Avalonia.Base/Metadata/DependsOnAttribute.cs b/src/Avalonia.Base/Metadata/DependsOnAttribute.cs
index a719d33d59..92c6a58170 100644
--- a/src/Avalonia.Base/Metadata/DependsOnAttribute.cs
+++ b/src/Avalonia.Base/Metadata/DependsOnAttribute.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Metadata
diff --git a/src/Avalonia.Base/Metadata/TemplateContent.cs b/src/Avalonia.Base/Metadata/TemplateContent.cs
index ecc16b04a2..fcd7d69e7b 100644
--- a/src/Avalonia.Base/Metadata/TemplateContent.cs
+++ b/src/Avalonia.Base/Metadata/TemplateContent.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Metadata
diff --git a/src/Avalonia.Base/Metadata/XmlnsDefinitionAttribute.cs b/src/Avalonia.Base/Metadata/XmlnsDefinitionAttribute.cs
index d6ff2d8b84..d43fa55f5c 100644
--- a/src/Avalonia.Base/Metadata/XmlnsDefinitionAttribute.cs
+++ b/src/Avalonia.Base/Metadata/XmlnsDefinitionAttribute.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Metadata
diff --git a/src/Avalonia.Base/Platform/IAssetLoader.cs b/src/Avalonia.Base/Platform/IAssetLoader.cs
index 4356fac4c0..c2e422cabb 100644
--- a/src/Avalonia.Base/Platform/IAssetLoader.cs
+++ b/src/Avalonia.Base/Platform/IAssetLoader.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.IO;
diff --git a/src/Avalonia.Base/Platform/IMacOSTopLevelPlatformHandle.cs b/src/Avalonia.Base/Platform/IMacOSTopLevelPlatformHandle.cs
index 837ea1abcd..e399976bbe 100644
--- a/src/Avalonia.Base/Platform/IMacOSTopLevelPlatformHandle.cs
+++ b/src/Avalonia.Base/Platform/IMacOSTopLevelPlatformHandle.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Platform
{
diff --git a/src/Avalonia.Base/Platform/IPlatformHandle.cs b/src/Avalonia.Base/Platform/IPlatformHandle.cs
index 39c34e97fd..a3b9d8f07c 100644
--- a/src/Avalonia.Base/Platform/IPlatformHandle.cs
+++ b/src/Avalonia.Base/Platform/IPlatformHandle.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Platform
diff --git a/src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs b/src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs
index 9f5417ca95..2137f965cc 100644
--- a/src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs
+++ b/src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Threading;
using Avalonia.Threading;
diff --git a/src/Avalonia.Base/Platform/PlatformHandle.cs b/src/Avalonia.Base/Platform/PlatformHandle.cs
index 24cc8f2651..bed25a3b5b 100644
--- a/src/Avalonia.Base/Platform/PlatformHandle.cs
+++ b/src/Avalonia.Base/Platform/PlatformHandle.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Platform
diff --git a/src/Avalonia.Base/PropertyMetadata.cs b/src/Avalonia.Base/PropertyMetadata.cs
index bec562354d..806051e1d1 100644
--- a/src/Avalonia.Base/PropertyMetadata.cs
+++ b/src/Avalonia.Base/PropertyMetadata.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Data;
namespace Avalonia
diff --git a/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs b/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs
index f15f56e32b..aa054c46ff 100644
--- a/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs
+++ b/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs
@@ -10,16 +10,20 @@ namespace Avalonia.PropertyStore
/// .
///
/// The property type.
- internal class ConstantValueEntry : IPriorityValueEntry
+ internal class ConstantValueEntry : IPriorityValueEntry, IDisposable
{
+ private IValueSink _sink;
+
public ConstantValueEntry(
StyledPropertyBase property,
T value,
- BindingPriority priority)
+ BindingPriority priority,
+ IValueSink sink)
{
Property = property;
Value = value;
Priority = priority;
+ _sink = sink;
}
public StyledPropertyBase Property { get; }
@@ -28,6 +32,7 @@ namespace Avalonia.PropertyStore
Optional IValue.Value => Value.ToObject();
BindingPriority IValue.ValuePriority => Priority;
- public void Reparent(IValueSink sink) { }
+ public void Dispose() => _sink.Completed(Property, this, Value);
+ public void Reparent(IValueSink sink) => _sink = sink;
}
}
diff --git a/src/Avalonia.Base/PropertyStore/PriorityValue.cs b/src/Avalonia.Base/PropertyStore/PriorityValue.cs
index 4ef8f650fa..affb20f334 100644
--- a/src/Avalonia.Base/PropertyStore/PriorityValue.cs
+++ b/src/Avalonia.Base/PropertyStore/PriorityValue.cs
@@ -78,8 +78,10 @@ namespace Avalonia.PropertyStore
public void ClearLocalValue() => UpdateEffectiveValue();
- public void SetValue(T value, BindingPriority priority)
+ public IDisposable? SetValue(T value, BindingPriority priority)
{
+ IDisposable? result = null;
+
if (priority == BindingPriority.LocalValue)
{
_localValue = value;
@@ -87,10 +89,13 @@ namespace Avalonia.PropertyStore
else
{
var insert = FindInsertPoint(priority);
- _entries.Insert(insert, new ConstantValueEntry(Property, value, priority));
+ var entry = new ConstantValueEntry(Property, value, priority, this);
+ _entries.Insert(insert, entry);
+ result = entry;
}
UpdateEffectiveValue();
+ return result;
}
public BindingEntry AddBinding(IObservable> source, BindingPriority priority)
diff --git a/src/Avalonia.Base/Reactive/ObservableEx.cs b/src/Avalonia.Base/Reactive/ObservableEx.cs
index a1ec8f9a8a..8e963fb9d5 100644
--- a/src/Avalonia.Base/Reactive/ObservableEx.cs
+++ b/src/Avalonia.Base/Reactive/ObservableEx.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Reactive.Disposables;
diff --git a/src/Avalonia.Base/Reactive/SingleSubscriberObservableBase.cs b/src/Avalonia.Base/Reactive/SingleSubscriberObservableBase.cs
index cd8ce2cd80..d3ac3dac8a 100644
--- a/src/Avalonia.Base/Reactive/SingleSubscriberObservableBase.cs
+++ b/src/Avalonia.Base/Reactive/SingleSubscriberObservableBase.cs
@@ -36,7 +36,7 @@ namespace Avalonia.Reactive
return this;
}
- void IDisposable.Dispose()
+ public virtual void Dispose()
{
Unsubscribed();
_observer = null;
diff --git a/src/Avalonia.Base/StyledProperty.cs b/src/Avalonia.Base/StyledProperty.cs
index 62443b424c..75275858cd 100644
--- a/src/Avalonia.Base/StyledProperty.cs
+++ b/src/Avalonia.Base/StyledProperty.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia
diff --git a/src/Avalonia.Base/StyledPropertyBase.cs b/src/Avalonia.Base/StyledPropertyBase.cs
index d1f961a567..1f88bfb2aa 100644
--- a/src/Avalonia.Base/StyledPropertyBase.cs
+++ b/src/Avalonia.Base/StyledPropertyBase.cs
@@ -1,10 +1,8 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Diagnostics;
using Avalonia.Data;
using Avalonia.Reactive;
+using Avalonia.Utilities;
namespace Avalonia
{
@@ -169,6 +167,12 @@ namespace Avalonia
base.OverrideMetadata(type, metadata);
}
+ ///
+ public override void Accept(IAvaloniaPropertyVisitor vistor, ref TData data)
+ {
+ vistor.Visit(this, ref data);
+ }
+
///
/// Gets the string representation of the property.
///
@@ -194,7 +198,7 @@ namespace Avalonia
}
///
- internal override void RouteSetValue(
+ internal override IDisposable RouteSetValue(
IAvaloniaObject o,
object value,
BindingPriority priority)
@@ -203,7 +207,7 @@ namespace Avalonia
if (v.HasValue)
{
- o.SetValue(this, (TValue)v.Value, priority);
+ return o.SetValue(this, (TValue)v.Value, priority);
}
else if (v.Type == BindingValueType.UnsetValue)
{
@@ -213,6 +217,8 @@ namespace Avalonia
{
throw v.Error;
}
+
+ return null;
}
///
diff --git a/src/Avalonia.Base/StyledPropertyMetadata`1.cs b/src/Avalonia.Base/StyledPropertyMetadata`1.cs
index f96298a298..300548db0a 100644
--- a/src/Avalonia.Base/StyledPropertyMetadata`1.cs
+++ b/src/Avalonia.Base/StyledPropertyMetadata`1.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Diagnostics;
using Avalonia.Data;
diff --git a/src/Avalonia.Base/Threading/AvaloniaScheduler.cs b/src/Avalonia.Base/Threading/AvaloniaScheduler.cs
index 46529f0a5a..0bfc713ba0 100644
--- a/src/Avalonia.Base/Threading/AvaloniaScheduler.cs
+++ b/src/Avalonia.Base/Threading/AvaloniaScheduler.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
diff --git a/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs b/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs
index 278efbcd0d..38a23f918f 100644
--- a/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs
+++ b/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Threading;
namespace Avalonia.Threading
diff --git a/src/Avalonia.Base/Threading/Dispatcher.cs b/src/Avalonia.Base/Threading/Dispatcher.cs
index 55a9b6984a..fe2cec11f0 100644
--- a/src/Avalonia.Base/Threading/Dispatcher.cs
+++ b/src/Avalonia.Base/Threading/Dispatcher.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Threading;
using System.Threading.Tasks;
diff --git a/src/Avalonia.Base/Threading/DispatcherPriority.cs b/src/Avalonia.Base/Threading/DispatcherPriority.cs
index 1faa2da7f8..a2b4b86bac 100644
--- a/src/Avalonia.Base/Threading/DispatcherPriority.cs
+++ b/src/Avalonia.Base/Threading/DispatcherPriority.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Threading
{
///
@@ -20,7 +17,7 @@ namespace Avalonia.Threading
SystemIdle = 1,
///
- /// The job will be processed when the application sis idle.
+ /// The job will be processed when the application is idle.
///
ApplicationIdle = 2,
diff --git a/src/Avalonia.Base/Threading/DispatcherTimer.cs b/src/Avalonia.Base/Threading/DispatcherTimer.cs
index 4a8a9d673f..ebafc8b946 100644
--- a/src/Avalonia.Base/Threading/DispatcherTimer.cs
+++ b/src/Avalonia.Base/Threading/DispatcherTimer.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Reactive.Disposables;
using Avalonia.Platform;
diff --git a/src/Avalonia.Base/Threading/JobRunner.cs b/src/Avalonia.Base/Threading/JobRunner.cs
index b922370e84..58f623fb3f 100644
--- a/src/Avalonia.Base/Threading/JobRunner.cs
+++ b/src/Avalonia.Base/Threading/JobRunner.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/Avalonia.Base/Utilities/AvaloniaPropertyValueStore.cs b/src/Avalonia.Base/Utilities/AvaloniaPropertyValueStore.cs
index a4e7a23454..0238446892 100644
--- a/src/Avalonia.Base/Utilities/AvaloniaPropertyValueStore.cs
+++ b/src/Avalonia.Base/Utilities/AvaloniaPropertyValueStore.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Collections.Generic;
namespace Avalonia.Utilities
diff --git a/src/Avalonia.Base/Utilities/CharacterReader.cs b/src/Avalonia.Base/Utilities/CharacterReader.cs
index 9be2d230d4..0a05915802 100644
--- a/src/Avalonia.Base/Utilities/CharacterReader.cs
+++ b/src/Avalonia.Base/Utilities/CharacterReader.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Utilities
diff --git a/src/Avalonia.Base/Utilities/IAvaloniaPropertyVisitor.cs b/src/Avalonia.Base/Utilities/IAvaloniaPropertyVisitor.cs
new file mode 100644
index 0000000000..4b889eb129
--- /dev/null
+++ b/src/Avalonia.Base/Utilities/IAvaloniaPropertyVisitor.cs
@@ -0,0 +1,34 @@
+#nullable enable
+
+namespace Avalonia.Utilities
+{
+ ///
+ /// A visitor to resolve an untyped to a typed property.
+ ///
+ /// The type of user data passed.
+ ///
+ /// Pass an instance that implements this interface to
+ ///
+ /// in order to resolve un untyped to a typed
+ /// or .
+ ///
+ public interface IAvaloniaPropertyVisitor
+ where TData : struct
+ {
+ ///
+ /// Called when the property is a styled property.
+ ///
+ /// The property value type.
+ /// The property.
+ /// The user data.
+ void Visit(StyledPropertyBase property, ref TData data);
+
+ ///
+ /// Called when the property is a direct property.
+ ///
+ /// The property value type.
+ /// The property.
+ /// The user data.
+ void Visit(DirectPropertyBase property, ref TData data);
+ }
+}
diff --git a/src/Avalonia.Base/Utilities/IWeakSubscriber.cs b/src/Avalonia.Base/Utilities/IWeakSubscriber.cs
index 5518d41168..a2907eea2e 100644
--- a/src/Avalonia.Base/Utilities/IWeakSubscriber.cs
+++ b/src/Avalonia.Base/Utilities/IWeakSubscriber.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Utilities
diff --git a/src/Avalonia.Base/Utilities/IdentifierParser.cs b/src/Avalonia.Base/Utilities/IdentifierParser.cs
index 973b0aa641..b105d0746b 100644
--- a/src/Avalonia.Base/Utilities/IdentifierParser.cs
+++ b/src/Avalonia.Base/Utilities/IdentifierParser.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Globalization;
namespace Avalonia.Utilities
diff --git a/src/Avalonia.Base/Utilities/MathUtilities.cs b/src/Avalonia.Base/Utilities/MathUtilities.cs
index 027028480c..a1a2d6c3d0 100644
--- a/src/Avalonia.Base/Utilities/MathUtilities.cs
+++ b/src/Avalonia.Base/Utilities/MathUtilities.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Runtime.InteropServices;
diff --git a/src/Avalonia.Base/Utilities/TypeUtilities.cs b/src/Avalonia.Base/Utilities/TypeUtilities.cs
index 8a25d29c3f..66b4676b45 100644
--- a/src/Avalonia.Base/Utilities/TypeUtilities.cs
+++ b/src/Avalonia.Base/Utilities/TypeUtilities.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.ComponentModel;
using System.Globalization;
diff --git a/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs b/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs
index aca08f5259..28c9dcc262 100644
--- a/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs
+++ b/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/Avalonia.Base/Utilities/WeakObservable.cs b/src/Avalonia.Base/Utilities/WeakObservable.cs
index b1fe78c206..20e01c751f 100644
--- a/src/Avalonia.Base/Utilities/WeakObservable.cs
+++ b/src/Avalonia.Base/Utilities/WeakObservable.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Reactive;
using System.Reactive.Linq;
diff --git a/src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs b/src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs
index f1e8fa6f9b..65128e7932 100644
--- a/src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs
+++ b/src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/Avalonia.Base/ValueStore.cs b/src/Avalonia.Base/ValueStore.cs
index e310be0f0a..104c06de0f 100644
--- a/src/Avalonia.Base/ValueStore.cs
+++ b/src/Avalonia.Base/ValueStore.cs
@@ -70,23 +70,25 @@ namespace Avalonia
return false;
}
- public void SetValue(StyledPropertyBase property, T value, BindingPriority priority)
+ public IDisposable? SetValue(StyledPropertyBase property, T value, BindingPriority priority)
{
if (property.ValidateValue?.Invoke(value) == false)
{
throw new ArgumentException($"{value} is not a valid value for '{property.Name}.");
}
+ IDisposable? result = null;
+
if (_values.TryGetValue(property, out var slot))
{
- SetExisting(slot, property, value, priority);
+ result = SetExisting(slot, property, value, priority);
}
else if (property.HasCoercion)
{
// If the property has any coercion callbacks then always create a PriorityValue.
var entry = new PriorityValue(_owner, property, this);
_values.AddValue(property, entry);
- entry.SetValue(value, priority);
+ result = entry.SetValue(value, priority);
}
else if (priority == BindingPriority.LocalValue)
{
@@ -95,10 +97,13 @@ namespace Avalonia
}
else
{
- var entry = new ConstantValueEntry(property, value, priority);
+ var entry = new ConstantValueEntry(property, value, priority, this);
_values.AddValue(property, entry);
_sink.ValueChanged(property, priority, default, value);
+ result = entry;
}
+
+ return result;
}
public IDisposable AddBinding(
@@ -205,21 +210,23 @@ namespace Avalonia
}
}
- private void SetExisting(
+ private IDisposable? SetExisting(
object slot,
StyledPropertyBase property,
T value,
BindingPriority priority)
{
+ IDisposable? result = null;
+
if (slot is IPriorityValueEntry e)
{
var priorityValue = new PriorityValue(_owner, property, this, e);
_values.SetValue(property, priorityValue);
- priorityValue.SetValue(value, priority);
+ result = priorityValue.SetValue(value, priority);
}
else if (slot is PriorityValue p)
{
- p.SetValue(value, priority);
+ result = p.SetValue(value, priority);
}
else if (slot is LocalValueEntry l)
{
@@ -232,7 +239,7 @@ namespace Avalonia
else
{
var priorityValue = new PriorityValue(_owner, property, this, l);
- priorityValue.SetValue(value, priority);
+ result = priorityValue.SetValue(value, priority);
_values.SetValue(property, priorityValue);
}
}
@@ -240,6 +247,8 @@ namespace Avalonia
{
throw new NotSupportedException("Unrecognised value store slot type.");
}
+
+ return result;
}
private IDisposable BindExisting(
diff --git a/src/Avalonia.Controls.DataGrid/Collections/DataGridSortDescription.cs b/src/Avalonia.Controls.DataGrid/Collections/DataGridSortDescription.cs
index bea6f01243..f741d40571 100644
--- a/src/Avalonia.Controls.DataGrid/Collections/DataGridSortDescription.cs
+++ b/src/Avalonia.Controls.DataGrid/Collections/DataGridSortDescription.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
diff --git a/src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs
index 09c3d07a41..8e82bf1a38 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs
@@ -55,7 +55,7 @@ namespace Avalonia.Controls
binding.Mode = BindingMode.TwoWay;
}
- if (binding.Converter == null)
+ if (binding.Converter == null && string.IsNullOrEmpty(binding.StringFormat))
{
binding.Converter = DataGridValueConverter.Instance;
}
diff --git a/src/Avalonia.Controls.DataGrid/Primitives/DataGridCellsPresenter.cs b/src/Avalonia.Controls.DataGrid/Primitives/DataGridCellsPresenter.cs
index b014c699bb..0f513e7f42 100644
--- a/src/Avalonia.Controls.DataGrid/Primitives/DataGridCellsPresenter.cs
+++ b/src/Avalonia.Controls.DataGrid/Primitives/DataGridCellsPresenter.cs
@@ -269,6 +269,9 @@ namespace Avalonia.Controls.Primitives
// Since we didn't know the final widths of the columns until we resized,
// we waited until now to measure each cell
double leftEdge = 0;
+ if (autoSizeHeight)
+ DesiredHeight = 0;
+
foreach (DataGridColumn column in OwningGrid.ColumnsInternal.GetVisibleColumns())
{
DataGridCell cell = OwningRow.Cells[column.Index];
diff --git a/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs b/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs
index 489bfc31d0..82b01e99bb 100644
--- a/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs
+++ b/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Reflection;
using System.Runtime.CompilerServices;
using Avalonia.Metadata;
diff --git a/src/Avalonia.Controls/AppBuilderBase.cs b/src/Avalonia.Controls/AppBuilderBase.cs
index 3b644191c2..d69052ad3d 100644
--- a/src/Avalonia.Controls/AppBuilderBase.cs
+++ b/src/Avalonia.Controls/AppBuilderBase.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
diff --git a/src/Avalonia.Controls/Application.cs b/src/Avalonia.Controls/Application.cs
index d7b1aec0b7..5cae798dc8 100644
--- a/src/Avalonia.Controls/Application.cs
+++ b/src/Avalonia.Controls/Application.cs
@@ -1,7 +1,5 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
+using System.Collections.Generic;
using System.Reactive.Concurrency;
using System.Threading;
using Avalonia.Animation;
@@ -45,6 +43,8 @@ namespace Avalonia
private Styles _styles;
private IResourceDictionary _resources;
private bool _notifyingResourcesChanged;
+ private Action> _stylesAdded;
+ private Action> _stylesRemoved;
///
/// Defines the property.
@@ -201,6 +201,18 @@ namespace Avalonia
///
public IApplicationLifetime ApplicationLifetime { get; set; }
+ event Action> IGlobalStyles.GlobalStylesAdded
+ {
+ add => _stylesAdded += value;
+ remove => _stylesAdded -= value;
+ }
+
+ event Action> IGlobalStyles.GlobalStylesRemoved
+ {
+ add => _stylesRemoved += value;
+ remove => _stylesRemoved -= value;
+ }
+
///
/// Initializes the application by loading XAML etc.
///
@@ -214,6 +226,16 @@ namespace Avalonia
Styles.TryGetResource(key, out value);
}
+ void IStyleHost.StylesAdded(IReadOnlyList styles)
+ {
+ _stylesAdded?.Invoke(styles);
+ }
+
+ void IStyleHost.StylesRemoved(IReadOnlyList styles)
+ {
+ _stylesRemoved?.Invoke(styles);
+ }
+
///
/// Register's the services needed by Avalonia.
///
@@ -286,6 +308,5 @@ namespace Avalonia
get => _name;
set => SetAndRaise(NameProperty, ref _name, value);
}
-
}
}
diff --git a/src/Avalonia.Controls/ApplicationLifetimes/ControlledApplicationLifetimeExitEventArgs.cs b/src/Avalonia.Controls/ApplicationLifetimes/ControlledApplicationLifetimeExitEventArgs.cs
index 2963c019cc..e2ff7784d6 100644
--- a/src/Avalonia.Controls/ApplicationLifetimes/ControlledApplicationLifetimeExitEventArgs.cs
+++ b/src/Avalonia.Controls/ApplicationLifetimes/ControlledApplicationLifetimeExitEventArgs.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Controls.ApplicationLifetimes
{
diff --git a/src/Avalonia.Controls/ApplicationLifetimes/StartupEventArgs.cs b/src/Avalonia.Controls/ApplicationLifetimes/StartupEventArgs.cs
index 423832793e..203be248bb 100644
--- a/src/Avalonia.Controls/ApplicationLifetimes/StartupEventArgs.cs
+++ b/src/Avalonia.Controls/ApplicationLifetimes/StartupEventArgs.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/Avalonia.Controls/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox.cs
index bf177d64cd..9bc7ba9e2f 100644
--- a/src/Avalonia.Controls/AutoCompleteBox.cs
+++ b/src/Avalonia.Controls/AutoCompleteBox.cs
@@ -1630,7 +1630,7 @@ namespace Avalonia.Controls
///
/// The source object.
/// The event data.
- private void DropDownPopup_Closed(object sender, EventArgs e)
+ private void DropDownPopup_Closed(object sender, PopupClosedEventArgs e)
{
// Force the drop down dependency property to be false.
if (IsDropDownOpen)
@@ -1638,6 +1638,11 @@ namespace Avalonia.Controls
IsDropDownOpen = false;
}
+ if (e.CloseEvent is PointerEventArgs pointerEvent)
+ {
+ pointerEvent.Handled = true;
+ }
+
// Fire the DropDownClosed event
if (_popupHasOpened)
{
diff --git a/src/Avalonia.Controls/Border.cs b/src/Avalonia.Controls/Border.cs
index 0edb272015..993528a12a 100644
--- a/src/Avalonia.Controls/Border.cs
+++ b/src/Avalonia.Controls/Border.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.Utils;
using Avalonia.Layout;
using Avalonia.Media;
diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs
index 0bc6394b19..8143bb1cf9 100644
--- a/src/Avalonia.Controls/Button.cs
+++ b/src/Avalonia.Controls/Button.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Linq;
using System.Windows.Input;
diff --git a/src/Avalonia.Controls/Calendar/DatePicker.cs b/src/Avalonia.Controls/Calendar/DatePicker.cs
index ea06bdb394..b4e4ad1452 100644
--- a/src/Avalonia.Controls/Calendar/DatePicker.cs
+++ b/src/Avalonia.Controls/Calendar/DatePicker.cs
@@ -476,7 +476,7 @@ namespace Avalonia.Controls
{
_dropDownButton.Click += DropDownButton_Click;
_buttonPointerPressedSubscription =
- _dropDownButton.AddHandler(PointerPressedEvent, DropDownButton_PointerPressed, handledEventsToo: true);
+ _dropDownButton.AddDisposableHandler(PointerPressedEvent, DropDownButton_PointerPressed, handledEventsToo: true);
}
if (_textBox != null)
@@ -895,12 +895,17 @@ namespace Avalonia.Controls
_ignoreButtonClick = false;
}
}
- private void PopUp_Closed(object sender, EventArgs e)
+ private void PopUp_Closed(object sender, PopupClosedEventArgs e)
{
IsDropDownOpen = false;
if(!_isPopupClosing)
{
+ if (e.CloseEvent is PointerEventArgs pointerEvent)
+ {
+ pointerEvent.Handled = true;
+ }
+
_isPopupClosing = true;
Threading.Dispatcher.UIThread.InvokeAsync(() => _isPopupClosing = false);
}
diff --git a/src/Avalonia.Controls/Canvas.cs b/src/Avalonia.Controls/Canvas.cs
index e16a0b074b..5cc823a6af 100644
--- a/src/Avalonia.Controls/Canvas.cs
+++ b/src/Avalonia.Controls/Canvas.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Input;
using Avalonia.Layout;
diff --git a/src/Avalonia.Controls/Carousel.cs b/src/Avalonia.Controls/Carousel.cs
index ebc8890721..4cacf51fa1 100644
--- a/src/Avalonia.Controls/Carousel.cs
+++ b/src/Avalonia.Controls/Carousel.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Animation;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
diff --git a/src/Avalonia.Controls/CheckBox.cs b/src/Avalonia.Controls/CheckBox.cs
index 13903ec378..05d49a44b1 100644
--- a/src/Avalonia.Controls/CheckBox.cs
+++ b/src/Avalonia.Controls/CheckBox.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.Primitives;
namespace Avalonia.Controls
diff --git a/src/Avalonia.Controls/ColumnDefinition.cs b/src/Avalonia.Controls/ColumnDefinition.cs
index 293b6326d6..2eb3ae3010 100644
--- a/src/Avalonia.Controls/ColumnDefinition.cs
+++ b/src/Avalonia.Controls/ColumnDefinition.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Controls
{
///
diff --git a/src/Avalonia.Controls/ColumnDefinitions.cs b/src/Avalonia.Controls/ColumnDefinitions.cs
index d4fc2ee0a1..ed4f9dbe99 100644
--- a/src/Avalonia.Controls/ColumnDefinitions.cs
+++ b/src/Avalonia.Controls/ColumnDefinitions.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Specialized;
using System.Linq;
diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs
index 9d471a0fc0..67ef6cd1e9 100644
--- a/src/Avalonia.Controls/ComboBox.cs
+++ b/src/Avalonia.Controls/ComboBox.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Linq;
using Avalonia.Controls.Generators;
@@ -9,6 +6,7 @@ using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates;
using Avalonia.Input;
+using Avalonia.Interactivity;
using Avalonia.LogicalTree;
using Avalonia.Media;
using Avalonia.VisualTree;
@@ -236,6 +234,23 @@ namespace Avalonia.Controls
base.OnTemplateApplied(e);
}
+ ///
+ /// Called when the ComboBox popup is closed, with the
+ /// that caused the popup to close.
+ ///
+ /// The event args.
+ ///
+ /// This method can be overridden to control whether the event that caused the popup to close
+ /// is swallowed or passed through.
+ ///
+ protected virtual void PopupClosedOverride(PopupClosedEventArgs e)
+ {
+ if (e.CloseEvent is PointerEventArgs pointerEvent)
+ {
+ pointerEvent.Handled = true;
+ }
+ }
+
internal void ItemFocused(ComboBoxItem dropDownItem)
{
if (IsDropDownOpen && dropDownItem.IsFocused && dropDownItem.IsArrangeValid)
@@ -244,11 +259,13 @@ namespace Avalonia.Controls
}
}
- private void PopupClosed(object sender, EventArgs e)
+ private void PopupClosed(object sender, PopupClosedEventArgs e)
{
_subscriptionsOnOpen?.Dispose();
_subscriptionsOnOpen = null;
+ PopupClosedOverride(e);
+
if (CanFocus(this))
{
Focus();
@@ -265,7 +282,7 @@ namespace Avalonia.Controls
var toplevel = this.GetVisualRoot() as TopLevel;
if (toplevel != null)
{
- _subscriptionsOnOpen = toplevel.AddHandler(PointerWheelChangedEvent, (s, ev) =>
+ _subscriptionsOnOpen = toplevel.AddDisposableHandler(PointerWheelChangedEvent, (s, ev) =>
{
//eat wheel scroll event outside dropdown popup while it's open
if (IsDropDownOpen && (ev.Source as IVisual).GetVisualRoot() == toplevel)
diff --git a/src/Avalonia.Controls/ComboBoxItem.cs b/src/Avalonia.Controls/ComboBoxItem.cs
index 988ca9e274..a0a1f2a4aa 100644
--- a/src/Avalonia.Controls/ComboBoxItem.cs
+++ b/src/Avalonia.Controls/ComboBoxItem.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Reactive.Linq;
diff --git a/src/Avalonia.Controls/ContentControl.cs b/src/Avalonia.Controls/ContentControl.cs
index bb3cc4585b..1329bd91c7 100644
--- a/src/Avalonia.Controls/ContentControl.cs
+++ b/src/Avalonia.Controls/ContentControl.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Collections;
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Presenters;
diff --git a/src/Avalonia.Controls/ContextMenu.cs b/src/Avalonia.Controls/ContextMenu.cs
index fc56e26add..1735599988 100644
--- a/src/Avalonia.Controls/ContextMenu.cs
+++ b/src/Avalonia.Controls/ContextMenu.cs
@@ -20,6 +20,8 @@ namespace Avalonia.Controls
private static readonly ITemplate DefaultPanel =
new FuncTemplate(() => new StackPanel { Orientation = Orientation.Vertical });
private Popup _popup;
+ private Control _attachedControl;
+ private IInputElement _previousFocus;
///
/// Initializes a new instance of the class.
@@ -69,13 +71,16 @@ namespace Avalonia.Controls
{
var control = (Control)e.Sender;
- if (e.OldValue != null)
+ if (e.OldValue is ContextMenu oldMenu)
{
control.PointerReleased -= ControlPointerReleased;
+ oldMenu._attachedControl = null;
+ ((ISetLogicalParent)oldMenu._popup)?.SetParent(null);
}
- if (e.NewValue != null)
+ if (e.NewValue is ContextMenu newMenu)
{
+ newMenu._attachedControl = control;
control.PointerReleased += ControlPointerReleased;
}
}
@@ -91,8 +96,18 @@ namespace Avalonia.Controls
/// The control.
public void Open(Control control)
{
- if (control == null)
+ if (control is null && _attachedControl is null)
+ {
throw new ArgumentNullException(nameof(control));
+ }
+
+ if (control is object && _attachedControl is object && control != _attachedControl)
+ {
+ throw new ArgumentException(
+ "Cannot show ContentMenu on a different control to the one it is attached to.",
+ nameof(control));
+ }
+
if (IsOpen)
{
return;
@@ -145,36 +160,38 @@ namespace Avalonia.Controls
return new MenuItemContainerGenerator(this);
}
- private void CloseCore()
- {
- SelectedIndex = -1;
- IsOpen = false;
-
- RaiseEvent(new RoutedEventArgs
- {
- RoutedEvent = MenuClosedEvent,
- Source = this,
- });
- }
-
private void PopupOpened(object sender, EventArgs e)
{
+ _previousFocus = FocusManager.Instance?.Current;
Focus();
}
private void PopupClosed(object sender, EventArgs e)
{
- var contextMenu = (sender as Popup)?.Child as ContextMenu;
-
- if (contextMenu != null)
+ foreach (var i in LogicalChildren)
{
- foreach (var i in contextMenu.GetLogicalChildren().OfType())
+ if (i is MenuItem menuItem)
{
- i.IsSubMenuOpen = false;
+ menuItem.IsSubMenuOpen = false;
}
+ }
- contextMenu.CloseCore();
+ SelectedIndex = -1;
+ IsOpen = false;
+
+ if (_attachedControl is null)
+ {
+ ((ISetLogicalParent)_popup).SetParent(null);
}
+
+ // HACK: Reset the focus when the popup is closed. We need to fix this so it's automatic.
+ FocusManager.Instance?.Focus(_previousFocus);
+
+ RaiseEvent(new RoutedEventArgs
+ {
+ RoutedEvent = MenuClosedEvent,
+ Source = this,
+ });
}
private static void ControlPointerReleased(object sender, PointerReleasedEventArgs e)
diff --git a/src/Avalonia.Controls/Control.cs b/src/Avalonia.Controls/Control.cs
index ca5edae4a9..41370d8464 100644
--- a/src/Avalonia.Controls/Control.cs
+++ b/src/Avalonia.Controls/Control.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.ComponentModel;
using Avalonia.Controls.Primitives;
diff --git a/src/Avalonia.Controls/ControlExtensions.cs b/src/Avalonia.Controls/ControlExtensions.cs
index 859fd59548..c3cab0a729 100644
--- a/src/Avalonia.Controls/ControlExtensions.cs
+++ b/src/Avalonia.Controls/ControlExtensions.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Linq;
using Avalonia.Data;
diff --git a/src/Avalonia.Controls/Controls.cs b/src/Avalonia.Controls/Controls.cs
index 02b745ddf6..a504b39196 100644
--- a/src/Avalonia.Controls/Controls.cs
+++ b/src/Avalonia.Controls/Controls.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Collections.Generic;
using Avalonia.Collections;
diff --git a/src/Avalonia.Controls/Converters/PlatformKeyGestureConverter.cs b/src/Avalonia.Controls/Converters/PlatformKeyGestureConverter.cs
new file mode 100644
index 0000000000..603a470a93
--- /dev/null
+++ b/src/Avalonia.Controls/Converters/PlatformKeyGestureConverter.cs
@@ -0,0 +1,195 @@
+using System;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using System.Text;
+using Avalonia.Data.Converters;
+using Avalonia.Input;
+
+namespace Avalonia.Controls.Converters
+{
+ ///
+ /// Converts a to a string, formatting it according to the current
+ /// platform's style guidelines.
+ ///
+ public class PlatformKeyGestureConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (value is null)
+ {
+ return null;
+ }
+ else if (value is KeyGesture gesture && targetType == typeof(string))
+ {
+ return ToPlatformString(gesture);
+ }
+ else
+ {
+ throw new NotSupportedException();
+ }
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ /// Converts a to a string, formatting it according to the current
+ /// platform's style guidelines.
+ ///
+ /// The gesture.
+ /// The gesture formatted according to the current platform.
+ public static string ToPlatformString(KeyGesture gesture)
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return ToString(gesture, "Win");
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ return ToString(gesture, "Super");
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ return ToOSXString(gesture);
+ }
+ else
+ {
+ return gesture.ToString();
+ }
+ }
+
+ private static string ToString(KeyGesture gesture, string meta)
+ {
+ var s = new StringBuilder();
+
+ static void Plus(StringBuilder s)
+ {
+ if (s.Length > 0)
+ {
+ s.Append("+");
+ }
+ }
+
+ if (gesture.KeyModifiers.HasFlagCustom(KeyModifiers.Control))
+ {
+ s.Append("Ctrl");
+ }
+
+ if (gesture.KeyModifiers.HasFlagCustom(KeyModifiers.Shift))
+ {
+ Plus(s);
+ s.Append("Shift");
+ }
+
+ if (gesture.KeyModifiers.HasFlagCustom(KeyModifiers.Alt))
+ {
+ Plus(s);
+ s.Append("Alt");
+ }
+
+ if (gesture.KeyModifiers.HasFlagCustom(KeyModifiers.Meta))
+ {
+ Plus(s);
+ s.Append(meta);
+ }
+
+ Plus(s);
+ s.Append(ToString(gesture.Key));
+
+ return s.ToString();
+ }
+
+ private static string ToOSXString(KeyGesture gesture)
+ {
+ var s = new StringBuilder();
+
+ if (gesture.KeyModifiers.HasFlagCustom(KeyModifiers.Control))
+ {
+ s.Append('⌃');
+ }
+
+ if (gesture.KeyModifiers.HasFlagCustom(KeyModifiers.Alt))
+ {
+ s.Append('⌥');
+ }
+
+ if (gesture.KeyModifiers.HasFlagCustom(KeyModifiers.Shift))
+ {
+ s.Append('⇧');
+ }
+
+ if (gesture.KeyModifiers.HasFlagCustom(KeyModifiers.Meta))
+ {
+ s.Append('⌘');
+ }
+
+ s.Append(ToOSXString(gesture.Key));
+
+ return s.ToString();
+ }
+
+ private static string ToString(Key key)
+ {
+ return key switch
+ {
+ Key.Add => "+",
+ Key.Back => "Backspace",
+ Key.D0 => "0",
+ Key.D1 => "1",
+ Key.D2 => "2",
+ Key.D3 => "3",
+ Key.D4 => "4",
+ Key.D5 => "5",
+ Key.D6 => "6",
+ Key.D7 => "7",
+ Key.D8 => "8",
+ Key.D9 => "9",
+ Key.Decimal => ".",
+ Key.Divide => "/",
+ Key.Down => "Down Arrow",
+ Key.Left => "Left Arrow",
+ Key.Multiply => "*",
+ Key.OemBackslash => "\\",
+ Key.OemCloseBrackets => "]",
+ Key.OemComma => ",",
+ Key.OemMinus => "-",
+ Key.OemOpenBrackets => "[",
+ Key.OemPeriod=> ".",
+ Key.OemPipe => "|",
+ Key.OemPlus => "+",
+ Key.OemQuestion => "/",
+ Key.OemQuotes => "\"",
+ Key.OemSemicolon => ";",
+ Key.OemTilde => "`",
+ Key.Right => "Right Arrow",
+ Key.Separator => "/",
+ Key.Subtract => "-",
+ Key.Up => "Up Arrow",
+ _ => key.ToString(),
+ };
+ }
+
+ private static string ToOSXString(Key key)
+ {
+ return key switch
+ {
+ Key.Back => "⌫",
+ Key.Down => "↓",
+ Key.End => "↘",
+ Key.Escape => "⎋",
+ Key.Home => "↖",
+ Key.Left => "←",
+ Key.Return => "↩",
+ Key.PageDown => "⇞",
+ Key.PageUp => "⇟",
+ Key.Right => "→",
+ Key.Space => "␣",
+ Key.Tab => "⇥",
+ Key.Up => "↑",
+ _ => ToString(key),
+ };
+ }
+ }
+}
diff --git a/src/Avalonia.Controls/DataValidationErrors.cs b/src/Avalonia.Controls/DataValidationErrors.cs
index 2588b7cc11..dfe9a16532 100644
--- a/src/Avalonia.Controls/DataValidationErrors.cs
+++ b/src/Avalonia.Controls/DataValidationErrors.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
diff --git a/src/Avalonia.Controls/Decorator.cs b/src/Avalonia.Controls/Decorator.cs
index 6f16870b9f..8959f0e306 100644
--- a/src/Avalonia.Controls/Decorator.cs
+++ b/src/Avalonia.Controls/Decorator.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Layout;
using Avalonia.Metadata;
diff --git a/src/Avalonia.Controls/DefinitionList.cs b/src/Avalonia.Controls/DefinitionList.cs
index 97d92bdcb7..bb815171c0 100644
--- a/src/Avalonia.Controls/DefinitionList.cs
+++ b/src/Avalonia.Controls/DefinitionList.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Specialized;
using System.Linq;
diff --git a/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs
index 2d6757219d..6220a20a82 100644
--- a/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs
+++ b/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using Avalonia.Controls.Templates;
diff --git a/src/Avalonia.Controls/Generators/ITreeItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/ITreeItemContainerGenerator.cs
index 5c931bc771..335e0df5f7 100644
--- a/src/Avalonia.Controls/Generators/ITreeItemContainerGenerator.cs
+++ b/src/Avalonia.Controls/Generators/ITreeItemContainerGenerator.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Controls.Generators
{
///
diff --git a/src/Avalonia.Controls/Generators/ItemContainerEventArgs.cs b/src/Avalonia.Controls/Generators/ItemContainerEventArgs.cs
index d361abfbfc..f65018531e 100644
--- a/src/Avalonia.Controls/Generators/ItemContainerEventArgs.cs
+++ b/src/Avalonia.Controls/Generators/ItemContainerEventArgs.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
diff --git a/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
index 8d1d69db1c..f16834f6e1 100644
--- a/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
+++ b/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs b/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs
index d1d1c2b172..3a098593dc 100644
--- a/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs
+++ b/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Controls.Templates;
using Avalonia.Data;
diff --git a/src/Avalonia.Controls/Generators/ItemContainerInfo.cs b/src/Avalonia.Controls/Generators/ItemContainerInfo.cs
index b9387f1022..023b108061 100644
--- a/src/Avalonia.Controls/Generators/ItemContainerInfo.cs
+++ b/src/Avalonia.Controls/Generators/ItemContainerInfo.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Controls.Generators
{
///
diff --git a/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs
index c216037aba..d2e05ee136 100644
--- a/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs
+++ b/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.Primitives;
namespace Avalonia.Controls.Generators
diff --git a/src/Avalonia.Controls/Generators/TreeContainerIndex.cs b/src/Avalonia.Controls/Generators/TreeContainerIndex.cs
index 0da84008f6..1660d6b1ad 100644
--- a/src/Avalonia.Controls/Generators/TreeContainerIndex.cs
+++ b/src/Avalonia.Controls/Generators/TreeContainerIndex.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
index 22e06a40b1..cd1ce3deae 100644
--- a/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
+++ b/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/Avalonia.Controls/GridLength.cs b/src/Avalonia.Controls/GridLength.cs
index 02be95b647..57f308d59f 100644
--- a/src/Avalonia.Controls/GridLength.cs
+++ b/src/Avalonia.Controls/GridLength.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Globalization;
diff --git a/src/Avalonia.Controls/IContentControl.cs b/src/Avalonia.Controls/IContentControl.cs
index 863c132778..889771b355 100644
--- a/src/Avalonia.Controls/IContentControl.cs
+++ b/src/Avalonia.Controls/IContentControl.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.Templates;
using Avalonia.Layout;
diff --git a/src/Avalonia.Controls/IControl.cs b/src/Avalonia.Controls/IControl.cs
index 87b66d5f81..6298531a16 100644
--- a/src/Avalonia.Controls/IControl.cs
+++ b/src/Avalonia.Controls/IControl.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.Templates;
using Avalonia.Input;
using Avalonia.Layout;
diff --git a/src/Avalonia.Controls/IGlobalDataTemplates.cs b/src/Avalonia.Controls/IGlobalDataTemplates.cs
index 248615de0d..92dcd2c189 100644
--- a/src/Avalonia.Controls/IGlobalDataTemplates.cs
+++ b/src/Avalonia.Controls/IGlobalDataTemplates.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.Templates;
namespace Avalonia.Controls
diff --git a/src/Avalonia.Controls/IHeadered.cs b/src/Avalonia.Controls/IHeadered.cs
index 99537b6a14..c208e21c97 100644
--- a/src/Avalonia.Controls/IHeadered.cs
+++ b/src/Avalonia.Controls/IHeadered.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Controls
{
///
diff --git a/src/Avalonia.Controls/INativeMenuExporterEventsImplBridge.cs b/src/Avalonia.Controls/INativeMenuExporterEventsImplBridge.cs
new file mode 100644
index 0000000000..672d5c1a13
--- /dev/null
+++ b/src/Avalonia.Controls/INativeMenuExporterEventsImplBridge.cs
@@ -0,0 +1,7 @@
+namespace Avalonia.Controls
+{
+ public interface INativeMenuExporterEventsImplBridge
+ {
+ void RaiseNeedsUpdate ();
+ }
+}
diff --git a/src/Avalonia.Controls/INativeMenuItemExporterEventsImplBridge.cs b/src/Avalonia.Controls/INativeMenuItemExporterEventsImplBridge.cs
new file mode 100644
index 0000000000..6cb68d8ddd
--- /dev/null
+++ b/src/Avalonia.Controls/INativeMenuItemExporterEventsImplBridge.cs
@@ -0,0 +1,7 @@
+namespace Avalonia.Controls
+{
+ public interface INativeMenuItemExporterEventsImplBridge
+ {
+ void RaiseClicked ();
+ }
+}
diff --git a/src/Avalonia.Controls/IPanel.cs b/src/Avalonia.Controls/IPanel.cs
index ce2c63ffc8..7b9e2c2074 100644
--- a/src/Avalonia.Controls/IPanel.cs
+++ b/src/Avalonia.Controls/IPanel.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Controls
{
///
diff --git a/src/Avalonia.Controls/IScrollable.cs b/src/Avalonia.Controls/IScrollable.cs
index 204e918d7b..2a98b3910a 100644
--- a/src/Avalonia.Controls/IScrollable.cs
+++ b/src/Avalonia.Controls/IScrollable.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Controls.Primitives
{
diff --git a/src/Avalonia.Controls/ISelectable.cs b/src/Avalonia.Controls/ISelectable.cs
index e6716c84ca..144adaa2f5 100644
--- a/src/Avalonia.Controls/ISelectable.cs
+++ b/src/Avalonia.Controls/ISelectable.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.Primitives;
namespace Avalonia.Controls
diff --git a/src/Avalonia.Controls/IVirtualizingController.cs b/src/Avalonia.Controls/IVirtualizingController.cs
index 0b997f4948..7c87f8abbc 100644
--- a/src/Avalonia.Controls/IVirtualizingController.cs
+++ b/src/Avalonia.Controls/IVirtualizingController.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-namespace Avalonia.Controls
+namespace Avalonia.Controls
{
///
/// Interface implemented by controls that act as controllers for an
diff --git a/src/Avalonia.Controls/IVirtualizingPanel.cs b/src/Avalonia.Controls/IVirtualizingPanel.cs
index cba196dfa8..8c4dc80934 100644
--- a/src/Avalonia.Controls/IVirtualizingPanel.cs
+++ b/src/Avalonia.Controls/IVirtualizingPanel.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using Avalonia.Layout;
+using Avalonia.Layout;
namespace Avalonia.Controls
{
diff --git a/src/Avalonia.Controls/Image.cs b/src/Avalonia.Controls/Image.cs
index 41b6e5449a..8d249fe790 100644
--- a/src/Avalonia.Controls/Image.cs
+++ b/src/Avalonia.Controls/Image.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Media;
using Avalonia.Media.Imaging;
diff --git a/src/Avalonia.Controls/ItemVirtualizationMode.cs b/src/Avalonia.Controls/ItemVirtualizationMode.cs
index f17e8c07ad..1950bb7f20 100644
--- a/src/Avalonia.Controls/ItemVirtualizationMode.cs
+++ b/src/Avalonia.Controls/ItemVirtualizationMode.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-namespace Avalonia.Controls
+namespace Avalonia.Controls
{
///
/// Describes the item virtualization method to use for a list.
diff --git a/src/Avalonia.Controls/ItemsControl.cs b/src/Avalonia.Controls/ItemsControl.cs
index ca3c290d7b..6e0ad66699 100644
--- a/src/Avalonia.Controls/ItemsControl.cs
+++ b/src/Avalonia.Controls/ItemsControl.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections;
using System.Collections.Generic;
diff --git a/src/Avalonia.Controls/LayoutTransformControl.cs b/src/Avalonia.Controls/LayoutTransformControl.cs
index a3bb654629..8d48f6646d 100644
--- a/src/Avalonia.Controls/LayoutTransformControl.cs
+++ b/src/Avalonia.Controls/LayoutTransformControl.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-//
// Idea got from and adapted to work in avalonia
// http://silverlight.codeplex.com/SourceControl/changeset/view/74775#Release/Silverlight4/Source/Controls.Layout.Toolkit/LayoutTransformer/LayoutTransformer.cs
//
diff --git a/src/Avalonia.Controls/ListBox.cs b/src/Avalonia.Controls/ListBox.cs
index 1761eeb3cf..a9349dadd9 100644
--- a/src/Avalonia.Controls/ListBox.cs
+++ b/src/Avalonia.Controls/ListBox.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Collections;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Presenters;
diff --git a/src/Avalonia.Controls/ListBoxItem.cs b/src/Avalonia.Controls/ListBoxItem.cs
index 0c55010f43..199c9e0ff8 100644
--- a/src/Avalonia.Controls/ListBoxItem.cs
+++ b/src/Avalonia.Controls/ListBoxItem.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.Mixins;
namespace Avalonia.Controls
diff --git a/src/Avalonia.Controls/Menu.cs b/src/Avalonia.Controls/Menu.cs
index 6ec97aa04e..7205af0e75 100644
--- a/src/Avalonia.Controls/Menu.cs
+++ b/src/Avalonia.Controls/Menu.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.Platform;
using Avalonia.Controls.Templates;
using Avalonia.Input;
diff --git a/src/Avalonia.Controls/MenuBase.cs b/src/Avalonia.Controls/MenuBase.cs
index be677b5479..4554cb2bcf 100644
--- a/src/Avalonia.Controls/MenuBase.cs
+++ b/src/Avalonia.Controls/MenuBase.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/Avalonia.Controls/MenuItem.cs b/src/Avalonia.Controls/MenuItem.cs
index e0baa5e679..91ee0cf534 100644
--- a/src/Avalonia.Controls/MenuItem.cs
+++ b/src/Avalonia.Controls/MenuItem.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Linq;
@@ -13,6 +10,7 @@ using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.LogicalTree;
+using Avalonia.VisualTree;
namespace Avalonia.Controls
{
@@ -48,6 +46,12 @@ namespace Avalonia.Controls
public static readonly StyledProperty IconProperty =
AvaloniaProperty.Register(nameof(Icon));
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty InputGestureProperty =
+ AvaloniaProperty.Register(nameof(InputGesture));
+
///
/// Defines the property.
///
@@ -93,6 +97,7 @@ namespace Avalonia.Controls
private ICommand _command;
private bool _commandCanExecute = true;
private Popup _popup;
+ private IDisposable _gridHack;
///
/// Initializes static members of the class.
@@ -194,6 +199,19 @@ namespace Avalonia.Controls
set { SetValue(IconProperty, value); }
}
+ ///
+ /// Gets or sets the input gesture that will be displayed in the menu item.
+ ///
+ ///
+ /// Setting this property does not cause the input gesture to be handled by the menu item,
+ /// it simply displays the gesture text in the menu.
+ ///
+ public KeyGesture InputGesture
+ {
+ get { return GetValue(InputGestureProperty); }
+ set { SetValue(InputGestureProperty, value); }
+ }
+
///
/// Gets or sets a value indicating whether the is currently selected.
///
@@ -304,6 +322,32 @@ namespace Avalonia.Controls
{
Command.CanExecuteChanged -= CanExecuteChanged;
}
+
+ _gridHack?.Dispose();
+ _gridHack = null;
+ }
+
+ protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
+ {
+ base.OnAttachedToVisualTree(e);
+
+ if (this.GetVisualParent() is IControl parent)
+ {
+ // HACK: This nasty but it's all WPF's fault. Grid uses an inherited attached
+ // property to store SharedSizeGroup state, except property inheritance is done
+ // down the logical tree. In this case, the control which is setting
+ // Grid.IsSharedSizeScope="True" is not in the logical tree. Instead of fixing
+ // the way Grid stores shared size state, the developers of WPF just created a
+ // binding of the internal state of the visual parent to the menu item. We don't
+ // have much choice but to do the same for now unless we want to refactor Grid,
+ // which I honestly am not brave enough to do right now. Here's the same hack in
+ // the WPF codebase:
+ //
+ // https://github.com/dotnet/wpf/blob/89537909bdf36bc918e88b37751add46a8980bb0/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/MenuItem.cs#L2126-L2141
+ _gridHack = Bind(
+ DefinitionBase.PrivateSharedSizeScopeProperty,
+ parent.GetBindingObservable(DefinitionBase.PrivateSharedSizeScopeProperty));
+ }
}
///
diff --git a/src/Avalonia.Controls/MenuItemAccessKeyHandler.cs b/src/Avalonia.Controls/MenuItemAccessKeyHandler.cs
index 002946bb79..2c3dac8482 100644
--- a/src/Avalonia.Controls/MenuItemAccessKeyHandler.cs
+++ b/src/Avalonia.Controls/MenuItemAccessKeyHandler.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/Avalonia.Controls/Mixins/SelectableMixin.cs b/src/Avalonia.Controls/Mixins/SelectableMixin.cs
index 2369e9f530..d2586ab6e8 100644
--- a/src/Avalonia.Controls/Mixins/SelectableMixin.cs
+++ b/src/Avalonia.Controls/Mixins/SelectableMixin.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Interactivity;
using Avalonia.Controls.Primitives;
diff --git a/src/Avalonia.Controls/NativeMenu.cs b/src/Avalonia.Controls/NativeMenu.cs
index 54aa2b5e3d..38a9f03d29 100644
--- a/src/Avalonia.Controls/NativeMenu.cs
+++ b/src/Avalonia.Controls/NativeMenu.cs
@@ -3,13 +3,11 @@ using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using Avalonia.Collections;
-using Avalonia.Data;
-using Avalonia.LogicalTree;
using Avalonia.Metadata;
namespace Avalonia.Controls
{
- public partial class NativeMenu : AvaloniaObject, IEnumerable
+ public partial class NativeMenu : AvaloniaObject, IEnumerable, INativeMenuExporterEventsImplBridge
{
private readonly AvaloniaList _items =
new AvaloniaList { ResetBehavior = ResetBehavior.Remove };
@@ -17,12 +15,22 @@ namespace Avalonia.Controls
[Content]
public IList Items => _items;
+ ///
+ /// Raised when the user clicks the menu and before its opened. Use this event to update the menu dynamically.
+ ///
+ public event EventHandler Opening;
+
public NativeMenu()
{
_items.Validate = Validator;
_items.CollectionChanged += ItemsChanged;
}
+ void INativeMenuExporterEventsImplBridge.RaiseNeedsUpdate()
+ {
+ Opening?.Invoke(this, EventArgs.Empty);
+ }
+
private void Validator(NativeMenuItemBase obj)
{
if (obj.Parent != null)
@@ -31,10 +39,10 @@ namespace Avalonia.Controls
private void ItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
- if(e.OldItems!=null)
+ if (e.OldItems != null)
foreach (NativeMenuItemBase i in e.OldItems)
i.Parent = null;
- if(e.NewItems!=null)
+ if (e.NewItems != null)
foreach (NativeMenuItemBase i in e.NewItems)
i.Parent = this;
}
@@ -49,7 +57,7 @@ namespace Avalonia.Controls
}
public void Add(NativeMenuItemBase item) => _items.Add(item);
-
+
public IEnumerator GetEnumerator() => _items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
diff --git a/src/Avalonia.Controls/NativeMenuBar.cs b/src/Avalonia.Controls/NativeMenuBar.cs
index 9b96ab9c8c..63bb39108f 100644
--- a/src/Avalonia.Controls/NativeMenuBar.cs
+++ b/src/Avalonia.Controls/NativeMenuBar.cs
@@ -30,7 +30,7 @@ namespace Avalonia.Controls
private static void OnMenuItemClick(object sender, RoutedEventArgs e)
{
- (((MenuItem)sender).DataContext as NativeMenuItem)?.RaiseClick();
+ (((MenuItem)sender).DataContext as INativeMenuItemExporterEventsImplBridge)?.RaiseClicked();
}
}
}
diff --git a/src/Avalonia.Controls/NativeMenuItem.cs b/src/Avalonia.Controls/NativeMenuItem.cs
index c1144d45b2..4c94d82eb4 100644
--- a/src/Avalonia.Controls/NativeMenuItem.cs
+++ b/src/Avalonia.Controls/NativeMenuItem.cs
@@ -1,15 +1,20 @@
using System;
using System.Windows.Input;
using Avalonia.Input;
+using Avalonia.Media.Imaging;
using Avalonia.Utilities;
namespace Avalonia.Controls
{
- public class NativeMenuItem : NativeMenuItemBase
+ public class NativeMenuItem : NativeMenuItemBase, INativeMenuItemExporterEventsImplBridge
{
private string _header;
private KeyGesture _gesture;
- private bool _enabled = true;
+ private bool _isEnabled = true;
+ private ICommand _command;
+ private bool _isChecked = false;
+ private NativeMenuItemToggleType _toggleType;
+ private IBitmap _icon;
private NativeMenu _menu;
@@ -55,13 +60,7 @@ namespace Avalonia.Controls
}
public static readonly DirectProperty MenuProperty =
- AvaloniaProperty.RegisterDirect(nameof(Menu), o => o._menu,
- (o, v) =>
- {
- if (v.Parent != null && v.Parent != o)
- throw new InvalidOperationException("NativeMenu already has a parent");
- o._menu = v;
- });
+ AvaloniaProperty.RegisterDirect(nameof(Menu), o => o.Menu, (o, v) => o.Menu = v);
public NativeMenu Menu
{
@@ -74,39 +73,63 @@ namespace Avalonia.Controls
}
}
+ public static readonly DirectProperty IconProperty =
+ AvaloniaProperty.RegisterDirect(nameof(Icon), o => o.Icon, (o, v) => o.Icon = v);
+
+
+ public IBitmap Icon
+ {
+ get => _icon;
+ set => SetAndRaise(IconProperty, ref _icon, value);
+ }
+
public static readonly DirectProperty HeaderProperty =
- AvaloniaProperty.RegisterDirect(nameof(Header), o => o._header, (o, v) => o._header = v);
+ AvaloniaProperty.RegisterDirect(nameof(Header), o => o.Header, (o, v) => o.Header = v);
public string Header
{
- get => GetValue(HeaderProperty);
- set => SetValue(HeaderProperty, value);
+ get => _header;
+ set => SetAndRaise(HeaderProperty, ref _header, value);
}
public static readonly DirectProperty GestureProperty =
- AvaloniaProperty.RegisterDirect(nameof(Gesture), o => o._gesture, (o, v) => o._gesture = v);
+ AvaloniaProperty.RegisterDirect(nameof(Gesture), o => o.Gesture, (o, v) => o.Gesture = v);
public KeyGesture Gesture
{
- get => GetValue(GestureProperty);
- set => SetValue(GestureProperty, value);
+ get => _gesture;
+ set => SetAndRaise(GestureProperty, ref _gesture, value);
}
- private ICommand _command;
+ public static readonly DirectProperty IsCheckedProperty =
+ AvaloniaProperty.RegisterDirect(
+ nameof(IsChecked),
+ o => o.IsChecked,
+ (o, v) => o.IsChecked = v);
+
+ public bool IsChecked
+ {
+ get => _isChecked;
+ set => SetAndRaise(IsCheckedProperty, ref _isChecked, value);
+ }
+
+ public static readonly DirectProperty ToggleTypeProperty =
+ AvaloniaProperty.RegisterDirect(
+ nameof(ToggleType),
+ o => o.ToggleType,
+ (o, v) => o.ToggleType = v);
+
+ public NativeMenuItemToggleType ToggleType
+ {
+ get => _toggleType;
+ set => SetAndRaise(ToggleTypeProperty, ref _toggleType, value);
+ }
public static readonly DirectProperty CommandProperty =
- AvaloniaProperty.RegisterDirect(nameof(Command),
- o => o._command, (o, v) =>
- {
- if (o._command != null)
- WeakSubscriptionManager.Unsubscribe(o._command,
- nameof(ICommand.CanExecuteChanged), o._canExecuteChangedSubscriber);
- o._command = v;
- if (o._command != null)
- WeakSubscriptionManager.Subscribe(o._command,
- nameof(ICommand.CanExecuteChanged), o._canExecuteChangedSubscriber);
- o.CanExecuteChanged();
- });
+ Button.CommandProperty.AddOwner(
+ menuItem => menuItem.Command,
+ (menuItem, command) => menuItem.Command = command,
+ enableDataValidation: true);
///
/// Defines the property.
@@ -114,27 +137,39 @@ namespace Avalonia.Controls
public static readonly StyledProperty CommandParameterProperty =
Button.CommandParameterProperty.AddOwner();
- public static readonly DirectProperty EnabledProperty =
- AvaloniaProperty.RegisterDirect(nameof(Enabled), o => o._enabled,
- (o, v) => o._enabled = v, true);
+ public static readonly DirectProperty IsEnabledProperty =
+ AvaloniaProperty.RegisterDirect(nameof(IsEnabled), o => o.IsEnabled, (o, v) => o.IsEnabled = v, true);
- public bool Enabled
+ public bool IsEnabled
{
- get => GetValue(EnabledProperty);
- set => SetValue(EnabledProperty, value);
+ get => _isEnabled;
+ set => SetAndRaise(IsEnabledProperty, ref _isEnabled, value);
}
void CanExecuteChanged()
{
- Enabled = _command?.CanExecute(null) ?? true;
+ IsEnabled = _command?.CanExecute(null) ?? true;
}
public bool HasClickHandlers => Clicked != null;
public ICommand Command
{
- get => GetValue(CommandProperty);
- set => SetValue(CommandProperty, value);
+ get => _command;
+ set
+ {
+ if (_command != null)
+ WeakSubscriptionManager.Unsubscribe(_command,
+ nameof(ICommand.CanExecuteChanged), _canExecuteChangedSubscriber);
+
+ SetAndRaise(CommandProperty, ref _command, value);
+
+ if (_command != null)
+ WeakSubscriptionManager.Subscribe(_command,
+ nameof(ICommand.CanExecuteChanged), _canExecuteChangedSubscriber);
+
+ CanExecuteChanged();
+ }
}
///
@@ -149,7 +184,7 @@ namespace Avalonia.Controls
public event EventHandler Clicked;
- public void RaiseClick()
+ void INativeMenuItemExporterEventsImplBridge.RaiseClicked()
{
Clicked?.Invoke(this, new EventArgs());
@@ -159,4 +194,11 @@ namespace Avalonia.Controls
}
}
}
+
+ public enum NativeMenuItemToggleType
+ {
+ None,
+ CheckBox,
+ Radio
+ }
}
diff --git a/src/Avalonia.Controls/Notifications/IManagedNotificationManager.cs b/src/Avalonia.Controls/Notifications/IManagedNotificationManager.cs
index 03c2fe85b8..977544674d 100644
--- a/src/Avalonia.Controls/Notifications/IManagedNotificationManager.cs
+++ b/src/Avalonia.Controls/Notifications/IManagedNotificationManager.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-namespace Avalonia.Controls.Notifications
+namespace Avalonia.Controls.Notifications
{
///
/// Represents a notification manager that can show arbitrary content.
diff --git a/src/Avalonia.Controls/Notifications/INotification.cs b/src/Avalonia.Controls/Notifications/INotification.cs
index 2c6cb90133..dc69a12887 100644
--- a/src/Avalonia.Controls/Notifications/INotification.cs
+++ b/src/Avalonia.Controls/Notifications/INotification.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Controls.Notifications
{
diff --git a/src/Avalonia.Controls/Notifications/INotificationManager.cs b/src/Avalonia.Controls/Notifications/INotificationManager.cs
index 21430c900d..72fb8e6c08 100644
--- a/src/Avalonia.Controls/Notifications/INotificationManager.cs
+++ b/src/Avalonia.Controls/Notifications/INotificationManager.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-namespace Avalonia.Controls.Notifications
+namespace Avalonia.Controls.Notifications
{
///
/// Represents a notification manager that can be used to show notifications in a window or using
diff --git a/src/Avalonia.Controls/Notifications/Notification.cs b/src/Avalonia.Controls/Notifications/Notification.cs
index 4204ad0aee..9bb514971b 100644
--- a/src/Avalonia.Controls/Notifications/Notification.cs
+++ b/src/Avalonia.Controls/Notifications/Notification.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
namespace Avalonia.Controls.Notifications
{
diff --git a/src/Avalonia.Controls/Notifications/NotificationCard.cs b/src/Avalonia.Controls/Notifications/NotificationCard.cs
index 9e9eeec7c5..f90746bf06 100644
--- a/src/Avalonia.Controls/Notifications/NotificationCard.cs
+++ b/src/Avalonia.Controls/Notifications/NotificationCard.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Linq;
using System.Reactive.Linq;
using Avalonia.Interactivity;
diff --git a/src/Avalonia.Controls/Notifications/NotificationPosition.cs b/src/Avalonia.Controls/Notifications/NotificationPosition.cs
index ef1d5e53d6..79f22f7972 100644
--- a/src/Avalonia.Controls/Notifications/NotificationPosition.cs
+++ b/src/Avalonia.Controls/Notifications/NotificationPosition.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-namespace Avalonia.Controls.Notifications
+namespace Avalonia.Controls.Notifications
{
///
/// Describes the possible positions for s that are displayed by a
diff --git a/src/Avalonia.Controls/Notifications/NotificationType.cs b/src/Avalonia.Controls/Notifications/NotificationType.cs
index fdcf5eec0a..f4ab46e973 100644
--- a/src/Avalonia.Controls/Notifications/NotificationType.cs
+++ b/src/Avalonia.Controls/Notifications/NotificationType.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-namespace Avalonia.Controls.Notifications
+namespace Avalonia.Controls.Notifications
{
///
/// Enumeration of types for .
diff --git a/src/Avalonia.Controls/Notifications/ReversibleStackPanel.cs b/src/Avalonia.Controls/Notifications/ReversibleStackPanel.cs
index 9edf9848fd..b64d94ff9b 100644
--- a/src/Avalonia.Controls/Notifications/ReversibleStackPanel.cs
+++ b/src/Avalonia.Controls/Notifications/ReversibleStackPanel.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Linq;
using Avalonia.Layout;
diff --git a/src/Avalonia.Controls/Notifications/WindowNotificationManager.cs b/src/Avalonia.Controls/Notifications/WindowNotificationManager.cs
index 56044ea522..f1d8fe6763 100644
--- a/src/Avalonia.Controls/Notifications/WindowNotificationManager.cs
+++ b/src/Avalonia.Controls/Notifications/WindowNotificationManager.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections;
using System.Linq;
diff --git a/src/Avalonia.Controls/Panel.cs b/src/Avalonia.Controls/Panel.cs
index a4c674a03b..ccb92dc497 100644
--- a/src/Avalonia.Controls/Panel.cs
+++ b/src/Avalonia.Controls/Panel.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
diff --git a/src/Avalonia.Controls/PixelPointEventArgs.cs b/src/Avalonia.Controls/PixelPointEventArgs.cs
index 2456d0aea4..57940b361b 100644
--- a/src/Avalonia.Controls/PixelPointEventArgs.cs
+++ b/src/Avalonia.Controls/PixelPointEventArgs.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Controls
diff --git a/src/Avalonia.Controls/PlacementMode.cs b/src/Avalonia.Controls/PlacementMode.cs
index 99958c4c9e..68a4b9eecb 100644
--- a/src/Avalonia.Controls/PlacementMode.cs
+++ b/src/Avalonia.Controls/PlacementMode.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.Primitives;
namespace Avalonia.Controls
diff --git a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
index bf811ad008..3715bc52a4 100644
--- a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
+++ b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
@@ -96,7 +96,7 @@ namespace Avalonia.Controls.Platform
root.Deactivated -= WindowDeactivated;
}
- _inputManagerSubscription!.Dispose();
+ _inputManagerSubscription?.Dispose();
Menu = null;
_root = null;
diff --git a/src/Avalonia.Controls/Platform/IEmbeddableWindowImpl.cs b/src/Avalonia.Controls/Platform/IEmbeddableWindowImpl.cs
index 3f974f3748..e2d174d9b6 100644
--- a/src/Avalonia.Controls/Platform/IEmbeddableWindowImpl.cs
+++ b/src/Avalonia.Controls/Platform/IEmbeddableWindowImpl.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Platform
diff --git a/src/Avalonia.Controls/Platform/IMountedVolumeInfoProvider.cs b/src/Avalonia.Controls/Platform/IMountedVolumeInfoProvider.cs
index 1420fce3c2..6e10163175 100644
--- a/src/Avalonia.Controls/Platform/IMountedVolumeInfoProvider.cs
+++ b/src/Avalonia.Controls/Platform/IMountedVolumeInfoProvider.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
diff --git a/src/Avalonia.Controls/Platform/IPopupImpl.cs b/src/Avalonia.Controls/Platform/IPopupImpl.cs
index 2978016519..3944695f04 100644
--- a/src/Avalonia.Controls/Platform/IPopupImpl.cs
+++ b/src/Avalonia.Controls/Platform/IPopupImpl.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.Primitives.PopupPositioning;
namespace Avalonia.Platform
diff --git a/src/Avalonia.Controls/Platform/ISystemDialogImpl.cs b/src/Avalonia.Controls/Platform/ISystemDialogImpl.cs
index c1e97320a1..affec6301b 100644
--- a/src/Avalonia.Controls/Platform/ISystemDialogImpl.cs
+++ b/src/Avalonia.Controls/Platform/ISystemDialogImpl.cs
@@ -1,8 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Threading.Tasks;
-using Avalonia.Platform;
namespace Avalonia.Controls.Platform
{
@@ -17,8 +13,8 @@ namespace Avalonia.Controls.Platform
/// The details of the file dialog to show.
/// The parent window.
/// A task returning the selected filenames.
- Task ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent);
+ Task ShowFileDialogAsync(FileDialog dialog, Window parent);
- Task ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent);
+ Task ShowFolderDialogAsync(OpenFolderDialog dialog, Window parent);
}
}
diff --git a/src/Avalonia.Controls/Platform/ITopLevelImpl.cs b/src/Avalonia.Controls/Platform/ITopLevelImpl.cs
index cfbc0b1c4b..98ee17ee1f 100644
--- a/src/Avalonia.Controls/Platform/ITopLevelImpl.cs
+++ b/src/Avalonia.Controls/Platform/ITopLevelImpl.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using Avalonia.Input;
diff --git a/src/Avalonia.Controls/Platform/IWindowIconImpl.cs b/src/Avalonia.Controls/Platform/IWindowIconImpl.cs
index d106e2a616..7086b7651c 100644
--- a/src/Avalonia.Controls/Platform/IWindowIconImpl.cs
+++ b/src/Avalonia.Controls/Platform/IWindowIconImpl.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System.IO;
+using System.IO;
namespace Avalonia.Platform
{
diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs
index 91b895f38a..5fa0ec57b5 100644
--- a/src/Avalonia.Controls/Platform/IWindowImpl.cs
+++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Controls;
using Avalonia.Input;
@@ -36,7 +33,7 @@ namespace Avalonia.Platform
///
/// Enables or disables system window decorations (title bar, buttons, etc)
///
- void SetSystemDecorations(bool enabled);
+ void SetSystemDecorations(SystemDecorations enabled);
///
/// Sets the icon of this window.
diff --git a/src/Avalonia.Controls/Platform/MountedDriveInfo.cs b/src/Avalonia.Controls/Platform/MountedDriveInfo.cs
index b534d11d40..9448f16c38 100644
--- a/src/Avalonia.Controls/Platform/MountedDriveInfo.cs
+++ b/src/Avalonia.Controls/Platform/MountedDriveInfo.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Controls.Platform
diff --git a/src/Avalonia.Controls/Presenters/CarouselPresenter.cs b/src/Avalonia.Controls/Presenters/CarouselPresenter.cs
index 89de24a81a..70a7583daf 100644
--- a/src/Avalonia.Controls/Presenters/CarouselPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/CarouselPresenter.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Collections.Specialized;
using System.Linq;
using System.Reactive.Linq;
diff --git a/src/Avalonia.Controls/Presenters/ContentPresenter.cs b/src/Avalonia.Controls/Presenters/ContentPresenter.cs
index 9b1215c9ae..55ed91893c 100644
--- a/src/Avalonia.Controls/Presenters/ContentPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/ContentPresenter.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
diff --git a/src/Avalonia.Controls/Presenters/IContentPresenter.cs b/src/Avalonia.Controls/Presenters/IContentPresenter.cs
index 31ab3a21a6..b1e64c2f25 100644
--- a/src/Avalonia.Controls/Presenters/IContentPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/IContentPresenter.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.Primitives;
namespace Avalonia.Controls.Presenters
diff --git a/src/Avalonia.Controls/Presenters/IContentPresenterHost.cs b/src/Avalonia.Controls/Presenters/IContentPresenterHost.cs
index 4acfba2c71..78c4affe44 100644
--- a/src/Avalonia.Controls/Presenters/IContentPresenterHost.cs
+++ b/src/Avalonia.Controls/Presenters/IContentPresenterHost.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Collections;
using Avalonia.LogicalTree;
using Avalonia.Styling;
diff --git a/src/Avalonia.Controls/Presenters/IItemsPresenter.cs b/src/Avalonia.Controls/Presenters/IItemsPresenter.cs
index c4acf1ebef..d8cf7a35de 100644
--- a/src/Avalonia.Controls/Presenters/IItemsPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/IItemsPresenter.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Collections;
using System.Collections.Specialized;
diff --git a/src/Avalonia.Controls/Presenters/IItemsPresenterHost.cs b/src/Avalonia.Controls/Presenters/IItemsPresenterHost.cs
index 0bb1d03d1e..ba9ee0fe31 100644
--- a/src/Avalonia.Controls/Presenters/IItemsPresenterHost.cs
+++ b/src/Avalonia.Controls/Presenters/IItemsPresenterHost.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Styling;
namespace Avalonia.Controls.Presenters
diff --git a/src/Avalonia.Controls/Presenters/IPresenter.cs b/src/Avalonia.Controls/Presenters/IPresenter.cs
index f78ba4c19d..5318ea2757 100644
--- a/src/Avalonia.Controls/Presenters/IPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/IPresenter.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.Primitives;
namespace Avalonia.Controls.Presenters
diff --git a/src/Avalonia.Controls/Presenters/ItemVirtualizer.cs b/src/Avalonia.Controls/Presenters/ItemVirtualizer.cs
index ae52e733b7..5ba6b6b9a3 100644
--- a/src/Avalonia.Controls/Presenters/ItemVirtualizer.cs
+++ b/src/Avalonia.Controls/Presenters/ItemVirtualizer.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Collections;
using System.Collections.Specialized;
using System.Reactive.Linq;
@@ -9,6 +6,7 @@ using Avalonia.Controls.Primitives;
using Avalonia.Controls.Utils;
using Avalonia.Input;
using Avalonia.Layout;
+using Avalonia.VisualTree;
namespace Avalonia.Controls.Presenters
{
@@ -102,9 +100,14 @@ namespace Avalonia.Controls.Presenters
{
get
{
- return Vertical ?
- new Size(Owner.Panel.DesiredSize.Width, ExtentValue) :
- new Size(ExtentValue, Owner.Panel.DesiredSize.Height);
+ if (IsLogicalScrollEnabled)
+ {
+ return Vertical ?
+ new Size(Owner.Panel.DesiredSize.Width, ExtentValue) :
+ new Size(ExtentValue, Owner.Panel.DesiredSize.Height);
+ }
+
+ return default;
}
}
@@ -115,9 +118,14 @@ namespace Avalonia.Controls.Presenters
{
get
{
- return Vertical ?
- new Size(Owner.Panel.Bounds.Width, ViewportValue) :
- new Size(ViewportValue, Owner.Panel.Bounds.Height);
+ if (IsLogicalScrollEnabled)
+ {
+ return Vertical ?
+ new Size(Owner.Panel.Bounds.Width, ViewportValue) :
+ new Size(ViewportValue, Owner.Panel.Bounds.Height);
+ }
+
+ return default;
}
}
@@ -128,11 +136,21 @@ namespace Avalonia.Controls.Presenters
{
get
{
- return Vertical ? new Vector(_crossAxisOffset, OffsetValue) : new Vector(OffsetValue, _crossAxisOffset);
+ if (IsLogicalScrollEnabled)
+ {
+ return Vertical ? new Vector(_crossAxisOffset, OffsetValue) : new Vector(OffsetValue, _crossAxisOffset);
+ }
+
+ return default;
}
set
{
+ if (!IsLogicalScrollEnabled)
+ {
+ throw new NotSupportedException("Logical scrolling disabled.");
+ }
+
var oldCrossAxisOffset = _crossAxisOffset;
if (Vertical)
@@ -167,10 +185,10 @@ namespace Avalonia.Controls.Presenters
}
var virtualizingPanel = owner.Panel as IVirtualizingPanel;
- var scrollable = (ILogicalScrollable)owner;
+ var scrollContentPresenter = owner.Parent as IScrollable;
ItemVirtualizer result = null;
- if (virtualizingPanel != null && scrollable.InvalidateScroll != null)
+ if (virtualizingPanel != null && scrollContentPresenter is object)
{
switch (owner.VirtualizationMode)
{
@@ -280,6 +298,6 @@ namespace Avalonia.Controls.Presenters
///
/// Invalidates the current scroll.
///
- protected void InvalidateScroll() => ((ILogicalScrollable)Owner).InvalidateScroll?.Invoke();
+ protected void InvalidateScroll() => ((ILogicalScrollable)Owner).RaiseScrollInvalidated(EventArgs.Empty);
}
}
diff --git a/src/Avalonia.Controls/Presenters/ItemVirtualizerNone.cs b/src/Avalonia.Controls/Presenters/ItemVirtualizerNone.cs
index 56f64779f6..3acb78edb8 100644
--- a/src/Avalonia.Controls/Presenters/ItemVirtualizerNone.cs
+++ b/src/Avalonia.Controls/Presenters/ItemVirtualizerNone.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
diff --git a/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs b/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs
index d27de7a80d..b8d338741a 100644
--- a/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs
+++ b/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Collections;
using System.Collections.Specialized;
using System.Linq;
diff --git a/src/Avalonia.Controls/Presenters/ItemsPresenter.cs b/src/Avalonia.Controls/Presenters/ItemsPresenter.cs
index ab40fbd53b..26be85beb3 100644
--- a/src/Avalonia.Controls/Presenters/ItemsPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/ItemsPresenter.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Specialized;
using Avalonia.Controls.Primitives;
@@ -24,6 +21,7 @@ namespace Avalonia.Controls.Presenters
private bool _canHorizontallyScroll;
private bool _canVerticallyScroll;
+ private EventHandler _scrollInvalidated;
///
/// Initializes static members of the class.
@@ -98,13 +96,17 @@ namespace Avalonia.Controls.Presenters
Size IScrollable.Viewport => Virtualizer?.Viewport ?? Bounds.Size;
///
- Action ILogicalScrollable.InvalidateScroll { get; set; }
+ event EventHandler ILogicalScrollable.ScrollInvalidated
+ {
+ add => _scrollInvalidated += value;
+ remove => _scrollInvalidated -= value;
+ }
///
- Size ILogicalScrollable.ScrollSize => new Size(1, 1);
+ Size ILogicalScrollable.ScrollSize => new Size(ScrollViewer.DefaultSmallChange, 1);
///
- Size ILogicalScrollable.PageScrollSize => new Size(0, 1);
+ Size ILogicalScrollable.PageScrollSize => Virtualizer?.Viewport ?? new Size(16, 16);
internal ItemVirtualizer Virtualizer { get; private set; }
@@ -120,6 +122,12 @@ namespace Avalonia.Controls.Presenters
return Virtualizer?.GetControlInDirection(direction, from);
}
+ ///
+ void ILogicalScrollable.RaiseScrollInvalidated(EventArgs e)
+ {
+ _scrollInvalidated?.Invoke(this, e);
+ }
+
public override void ScrollIntoView(object item)
{
Virtualizer?.ScrollIntoView(item);
@@ -141,7 +149,7 @@ namespace Avalonia.Controls.Presenters
{
Virtualizer?.Dispose();
Virtualizer = ItemVirtualizer.Create(this);
- ((ILogicalScrollable)this).InvalidateScroll?.Invoke();
+ _scrollInvalidated?.Invoke(this, EventArgs.Empty);
KeyboardNavigation.SetTabNavigation(
(InputElement)Panel,
@@ -165,7 +173,7 @@ namespace Avalonia.Controls.Presenters
{
Virtualizer?.Dispose();
Virtualizer = ItemVirtualizer.Create(this);
- ((ILogicalScrollable)this).InvalidateScroll?.Invoke();
+ _scrollInvalidated?.Invoke(this, EventArgs.Empty);
}
}
}
diff --git a/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs b/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs
index ef1f277162..3a0e6b67c9 100644
--- a/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs
+++ b/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections;
using System.Collections.Specialized;
diff --git a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs
index 48d0aff551..98a5b10023 100644
--- a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs
@@ -1,13 +1,12 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
+using System.Runtime.InteropServices.ComTypes;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
+using Avalonia.LogicalTree;
using Avalonia.VisualTree;
namespace Avalonia.Controls.Presenters
@@ -352,7 +351,7 @@ namespace Avalonia.Controls.Presenters
if (scrollable != null)
{
- scrollable.InvalidateScroll = () => UpdateFromScrollable(scrollable);
+ scrollable.ScrollInvalidated += ScrollInvalidated;
if (scrollable.IsLogicalScrollEnabled)
{
@@ -363,12 +362,17 @@ namespace Avalonia.Controls.Presenters
.Subscribe(x => scrollable.CanVerticallyScroll = x),
this.GetObservable(OffsetProperty)
.Skip(1).Subscribe(x => scrollable.Offset = x),
- Disposable.Create(() => scrollable.InvalidateScroll = null));
+ Disposable.Create(() => scrollable.ScrollInvalidated -= ScrollInvalidated));
UpdateFromScrollable(scrollable);
}
}
}
+ private void ScrollInvalidated(object sender, EventArgs e)
+ {
+ UpdateFromScrollable((ILogicalScrollable)sender);
+ }
+
private void UpdateFromScrollable(ILogicalScrollable scrollable)
{
var logicalScroll = _logicalScrollSubscription != null;
diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs
index ca893f3171..905a14cfee 100644
--- a/src/Avalonia.Controls/Presenters/TextPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Reactive.Linq;
using Avalonia.Media;
@@ -82,6 +79,7 @@ namespace Avalonia.Controls.Presenters
SelectionStartProperty, SelectionEndProperty);
Observable.Merge(
+ TextProperty.Changed,
SelectionStartProperty.Changed,
SelectionEndProperty.Changed,
PasswordCharProperty.Changed
@@ -291,6 +289,8 @@ namespace Avalonia.Controls.Presenters
_constraint = _formattedText.Constraint;
_formattedText = null;
}
+
+ InvalidateVisual();
}
///
diff --git a/src/Avalonia.Controls/Primitives/AccessText.cs b/src/Avalonia.Controls/Primitives/AccessText.cs
index 7e5c434caf..4208a2f2f7 100644
--- a/src/Avalonia.Controls/Primitives/AccessText.cs
+++ b/src/Avalonia.Controls/Primitives/AccessText.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Input;
using Avalonia.Media;
@@ -160,17 +157,6 @@ namespace Avalonia.Controls.Primitives
return base.CreateTextLayout(constraint, StripAccessKey(text));
}
- ///
- /// Measures the control.
- ///
- /// The available size for the control.
- /// The desired size.
- protected override Size MeasureOverride(Size availableSize)
- {
- var result = base.MeasureOverride(availableSize);
- return result.WithHeight(result.Height + 1);
- }
-
///
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
diff --git a/src/Avalonia.Controls/Primitives/AdornerLayer.cs b/src/Avalonia.Controls/Primitives/AdornerLayer.cs
index 9a2f0310d7..87ab6cf450 100644
--- a/src/Avalonia.Controls/Primitives/AdornerLayer.cs
+++ b/src/Avalonia.Controls/Primitives/AdornerLayer.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Specialized;
using System.Linq;
diff --git a/src/Avalonia.Controls/Primitives/HeaderedContentControl.cs b/src/Avalonia.Controls/Primitives/HeaderedContentControl.cs
index d431420a8f..7a43d38d8a 100644
--- a/src/Avalonia.Controls/Primitives/HeaderedContentControl.cs
+++ b/src/Avalonia.Controls/Primitives/HeaderedContentControl.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Templates;
diff --git a/src/Avalonia.Controls/Primitives/HeaderedItemsControl.cs b/src/Avalonia.Controls/Primitives/HeaderedItemsControl.cs
index f4af694f28..be3c100ecf 100644
--- a/src/Avalonia.Controls/Primitives/HeaderedItemsControl.cs
+++ b/src/Avalonia.Controls/Primitives/HeaderedItemsControl.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Collections;
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Presenters;
diff --git a/src/Avalonia.Controls/Primitives/HeaderedSelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/HeaderedSelectingItemsControl.cs
index 5e053ed9b4..78b5771b80 100644
--- a/src/Avalonia.Controls/Primitives/HeaderedSelectingItemsControl.cs
+++ b/src/Avalonia.Controls/Primitives/HeaderedSelectingItemsControl.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Collections;
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Presenters;
diff --git a/src/Avalonia.Controls/Primitives/ILogicalScrollable.cs b/src/Avalonia.Controls/Primitives/ILogicalScrollable.cs
index 490beb12b3..5c29945735 100644
--- a/src/Avalonia.Controls/Primitives/ILogicalScrollable.cs
+++ b/src/Avalonia.Controls/Primitives/ILogicalScrollable.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Input;
@@ -34,22 +31,6 @@ namespace Avalonia.Controls.Primitives
///
bool IsLogicalScrollEnabled { get; }
- ///
- /// Gets or sets the scroll invalidation method.
- ///
- ///
- ///
- /// This method notifies the attached of a change in
- /// the , or
- /// properties.
- ///
- ///
- /// This property is set by the parent when the
- /// is placed inside it.
- ///
- ///
- Action InvalidateScroll { get; set; }
-
///
/// Gets the size to scroll by, in logical units.
///
@@ -60,6 +41,15 @@ namespace Avalonia.Controls.Primitives
///
Size PageScrollSize { get; }
+ ///
+ /// Raised when the scroll is invalidated.
+ ///
+ ///
+ /// This event notifies an attached of a change in
+ /// one of the scroll properties.
+ ///
+ event EventHandler ScrollInvalidated;
+
///
/// Attempts to bring a portion of the target visual into view by scrolling the content.
///
@@ -75,5 +65,11 @@ namespace Avalonia.Controls.Primitives
/// The control from which movement begins.
/// The control.
IControl GetControlInDirection(NavigationDirection direction, IControl from);
+
+ ///
+ /// Raises the event.
+ ///
+ /// The event args.
+ void RaiseScrollInvalidated(EventArgs e);
}
}
diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs
index 9dd481cf40..66f2153b6c 100644
--- a/src/Avalonia.Controls/Primitives/Popup.cs
+++ b/src/Avalonia.Controls/Primitives/Popup.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Diagnostics;
using System.Linq;
@@ -98,7 +95,7 @@ namespace Avalonia.Controls.Primitives
///
/// Raised when the popup closes.
///
- public event EventHandler? Closed;
+ public event EventHandler? Closed;
///
/// Raised when the popup opens.
@@ -273,13 +270,13 @@ namespace Avalonia.Controls.Primitives
if (parentPopupRoot?.Parent is Popup popup)
{
- DeferCleanup(SubscribeToEventHandler(popup, ParentClosed,
+ DeferCleanup(SubscribeToEventHandler>(popup, ParentClosed,
(x, handler) => x.Closed += handler,
(x, handler) => x.Closed -= handler));
}
}
- DeferCleanup(topLevel.AddHandler(PointerPressedEvent, PointerPressedOutside, RoutingStrategies.Tunnel));
+ DeferCleanup(topLevel.AddDisposableHandler(PointerPressedEvent, PointerPressedOutside, RoutingStrategies.Tunnel));
DeferCleanup(InputManager.Instance?.Process.Subscribe(ListenForNonClientClick));
@@ -309,28 +306,7 @@ namespace Avalonia.Controls.Primitives
///
/// Closes the popup.
///
- public void Close()
- {
- if (_openState is null)
- {
- using (BeginIgnoringIsOpen())
- {
- IsOpen = false;
- }
-
- return;
- }
-
- _openState.Dispose();
- _openState = null;
-
- using (BeginIgnoringIsOpen())
- {
- IsOpen = false;
- }
-
- Closed?.Invoke(this, EventArgs.Empty);
- }
+ public void Close() => CloseCore(null);
///
/// Measures the control.
@@ -392,22 +368,44 @@ namespace Avalonia.Controls.Primitives
}
}
+ private void CloseCore(EventArgs? closeEvent)
+ {
+ if (_openState is null)
+ {
+ using (BeginIgnoringIsOpen())
+ {
+ IsOpen = false;
+ }
+
+ return;
+ }
+
+ _openState.Dispose();
+ _openState = null;
+
+ using (BeginIgnoringIsOpen())
+ {
+ IsOpen = false;
+ }
+
+ Closed?.Invoke(this, new PopupClosedEventArgs(closeEvent));
+ }
+
private void ListenForNonClientClick(RawInputEventArgs e)
{
var mouse = e as RawPointerEventArgs;
if (!StaysOpen && mouse?.Type == RawPointerEventType.NonClientLeftButtonDown)
{
- Close();
+ CloseCore(e);
}
}
private void PointerPressedOutside(object sender, PointerPressedEventArgs e)
{
- if (!StaysOpen && !IsChildOrThis((IVisual)e.Source))
+ if (!StaysOpen && e.Source is IVisual v && !IsChildOrThis(v))
{
- Close();
- e.Handled = true;
+ CloseCore(e);
}
}
diff --git a/src/Avalonia.Controls/Primitives/PopupClosedEventArgs.cs b/src/Avalonia.Controls/Primitives/PopupClosedEventArgs.cs
new file mode 100644
index 0000000000..c51543438c
--- /dev/null
+++ b/src/Avalonia.Controls/Primitives/PopupClosedEventArgs.cs
@@ -0,0 +1,33 @@
+using System;
+using Avalonia.Interactivity;
+
+#nullable enable
+
+namespace Avalonia.Controls.Primitives
+{
+ ///
+ /// Holds data for the event.
+ ///
+ public class PopupClosedEventArgs : EventArgs
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ public PopupClosedEventArgs(EventArgs? closeEvent)
+ {
+ CloseEvent = closeEvent;
+ }
+
+ ///
+ /// Gets the event that closed the popup, if any.
+ ///
+ ///
+ /// If is false, then this property will hold details of the
+ /// interaction that caused the popup to close if the close was caused by e.g. a pointer press
+ /// outside the popup. It can be used to mark the event as handled if the event should not
+ /// be propagated.
+ ///
+ public EventArgs? CloseEvent { get; }
+ }
+}
diff --git a/src/Avalonia.Controls/Primitives/PopupRoot.cs b/src/Avalonia.Controls/Primitives/PopupRoot.cs
index caaf58b25b..788fe03162 100644
--- a/src/Avalonia.Controls/Primitives/PopupRoot.cs
+++ b/src/Avalonia.Controls/Primitives/PopupRoot.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Reactive.Disposables;
@@ -120,20 +117,41 @@ namespace Avalonia.Controls.Primitives
});
}
- ///
- /// Carries out the arrange pass of the window.
- ///
- /// The final window size.
- /// The parameter unchanged.
- protected override Size ArrangeOverride(Size finalSize)
+ protected override Size MeasureOverride(Size availableSize)
+ {
+ var measured = base.MeasureOverride(availableSize);
+ var width = measured.Width;
+ var height = measured.Height;
+ var widthCache = Width;
+ var heightCache = Height;
+
+ if (!double.IsNaN(widthCache))
+ {
+ width = widthCache;
+ }
+
+ width = Math.Min(width, MaxWidth);
+ width = Math.Max(width, MinWidth);
+
+ if (!double.IsNaN(heightCache))
+ {
+ height = heightCache;
+ }
+
+ height = Math.Min(height, MaxHeight);
+ height = Math.Max(height, MinHeight);
+
+ return new Size(width, height);
+ }
+
+ protected override sealed Size ArrangeSetBounds(Size size)
{
using (BeginAutoSizing())
{
- _positionerParameters.Size = finalSize;
+ _positionerParameters.Size = size;
UpdatePosition();
+ return ClientSize;
}
-
- return base.ArrangeOverride(PlatformImpl?.ClientSize ?? default(Size));
}
}
}
diff --git a/src/Avalonia.Controls/Primitives/RangeBase.cs b/src/Avalonia.Controls/Primitives/RangeBase.cs
index baa51f92ec..0b716ec1ca 100644
--- a/src/Avalonia.Controls/Primitives/RangeBase.cs
+++ b/src/Avalonia.Controls/Primitives/RangeBase.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Data;
using Avalonia.Utilities;
diff --git a/src/Avalonia.Controls/Primitives/ScrollBar.cs b/src/Avalonia.Controls/Primitives/ScrollBar.cs
index 4d3ae3c5b8..d48a9316e8 100644
--- a/src/Avalonia.Controls/Primitives/ScrollBar.cs
+++ b/src/Avalonia.Controls/Primitives/ScrollBar.cs
@@ -1,9 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
-using System.Reactive;
-using System.Reactive.Linq;
using Avalonia.Data;
using Avalonia.Interactivity;
using Avalonia.Input;
@@ -64,13 +59,6 @@ namespace Avalonia.Controls.Primitives
///
public ScrollBar()
{
- var isVisible = Observable.Merge(
- this.GetObservable(MinimumProperty).Select(_ => Unit.Default),
- this.GetObservable(MaximumProperty).Select(_ => Unit.Default),
- this.GetObservable(ViewportSizeProperty).Select(_ => Unit.Default),
- this.GetObservable(VisibilityProperty).Select(_ => Unit.Default))
- .Select(_ => CalculateIsVisible());
- this.Bind(IsVisibleProperty, isVisible, BindingPriority.Style);
UpdatePseudoClasses(Orientation);
}
@@ -105,26 +93,20 @@ namespace Avalonia.Controls.Primitives
public event EventHandler Scroll;
///
- /// Calculates whether the scrollbar should be visible.
+ /// Calculates and updates whether the scrollbar should be visible.
///
- /// The scrollbar's visibility.
- private bool CalculateIsVisible()
+ private void UpdateIsVisible()
{
- switch (Visibility)
+ var isVisible = Visibility switch
{
- case ScrollBarVisibility.Visible:
- return true;
-
- case ScrollBarVisibility.Disabled:
- case ScrollBarVisibility.Hidden:
- return false;
-
- case ScrollBarVisibility.Auto:
- return double.IsNaN(ViewportSize) || Maximum > 0;
-
- default:
- throw new InvalidOperationException("Invalid value for ScrollBar.Visibility.");
- }
+ ScrollBarVisibility.Visible => true,
+ ScrollBarVisibility.Disabled => false,
+ ScrollBarVisibility.Hidden => false,
+ ScrollBarVisibility.Auto => (double.IsNaN(ViewportSize) || Maximum > 0),
+ _ => throw new InvalidOperationException("Invalid value for ScrollBar.Visibility.")
+ };
+
+ SetValue(IsVisibleProperty, isVisible, BindingPriority.Style);
}
protected override void OnKeyDown(KeyEventArgs e)
@@ -153,6 +135,16 @@ namespace Avalonia.Controls.Primitives
{
UpdatePseudoClasses(newValue.GetValueOrDefault());
}
+ else
+ {
+ if (property == MinimumProperty ||
+ property == MaximumProperty ||
+ property == ViewportSizeProperty ||
+ property == VisibilityProperty)
+ {
+ UpdateIsVisible();
+ }
+ }
}
protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
diff --git a/src/Avalonia.Controls/Primitives/ScrollBarVisibility.cs b/src/Avalonia.Controls/Primitives/ScrollBarVisibility.cs
index f1cca8f909..90727a3505 100644
--- a/src/Avalonia.Controls/Primitives/ScrollBarVisibility.cs
+++ b/src/Avalonia.Controls/Primitives/ScrollBarVisibility.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Controls.Primitives
{
public enum ScrollBarVisibility
diff --git a/src/Avalonia.Controls/Primitives/ScrollEventType.cs b/src/Avalonia.Controls/Primitives/ScrollEventType.cs
index ea639d82e0..4b5c24e6ee 100644
--- a/src/Avalonia.Controls/Primitives/ScrollEventType.cs
+++ b/src/Avalonia.Controls/Primitives/ScrollEventType.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-namespace Avalonia.Controls.Primitives
+namespace Avalonia.Controls.Primitives
{
///
/// Specifies the type of Avalonia.Controls.Primitives.ScrollBar.Scroll event
diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
index 6bc4e71508..e39cbdc016 100644
--- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
+++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections;
using System.Collections.Generic;
diff --git a/src/Avalonia.Controls/Primitives/TabStrip.cs b/src/Avalonia.Controls/Primitives/TabStrip.cs
index e1a6cf79bb..f8f7674da8 100644
--- a/src/Avalonia.Controls/Primitives/TabStrip.cs
+++ b/src/Avalonia.Controls/Primitives/TabStrip.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.Generators;
using Avalonia.Controls.Templates;
using Avalonia.Input;
diff --git a/src/Avalonia.Controls/Primitives/TabStripItem.cs b/src/Avalonia.Controls/Primitives/TabStripItem.cs
index f7b73304e8..fb2016b485 100644
--- a/src/Avalonia.Controls/Primitives/TabStripItem.cs
+++ b/src/Avalonia.Controls/Primitives/TabStripItem.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Controls.Primitives
{
///
diff --git a/src/Avalonia.Controls/Primitives/TemplateAppliedEventArgs.cs b/src/Avalonia.Controls/Primitives/TemplateAppliedEventArgs.cs
index 1b2c243071..a689a63e27 100644
--- a/src/Avalonia.Controls/Primitives/TemplateAppliedEventArgs.cs
+++ b/src/Avalonia.Controls/Primitives/TemplateAppliedEventArgs.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Interactivity;
namespace Avalonia.Controls.Primitives
diff --git a/src/Avalonia.Controls/Primitives/TemplatedControl.cs b/src/Avalonia.Controls/Primitives/TemplatedControl.cs
index 0ace387185..3837ef4699 100644
--- a/src/Avalonia.Controls/Primitives/TemplatedControl.cs
+++ b/src/Avalonia.Controls/Primitives/TemplatedControl.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Controls.Templates;
using Avalonia.Interactivity;
diff --git a/src/Avalonia.Controls/Primitives/Thumb.cs b/src/Avalonia.Controls/Primitives/Thumb.cs
index d88018cf32..96810ed01b 100644
--- a/src/Avalonia.Controls/Primitives/Thumb.cs
+++ b/src/Avalonia.Controls/Primitives/Thumb.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Input;
using Avalonia.Interactivity;
diff --git a/src/Avalonia.Controls/Primitives/ToggleButton.cs b/src/Avalonia.Controls/Primitives/ToggleButton.cs
index 83a2d6d9e4..13031ddad8 100644
--- a/src/Avalonia.Controls/Primitives/ToggleButton.cs
+++ b/src/Avalonia.Controls/Primitives/ToggleButton.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Data;
using Avalonia.Interactivity;
diff --git a/src/Avalonia.Controls/ProgressBar.cs b/src/Avalonia.Controls/ProgressBar.cs
index 786f0092a2..361a82e49c 100644
--- a/src/Avalonia.Controls/ProgressBar.cs
+++ b/src/Avalonia.Controls/ProgressBar.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Controls.Primitives;
diff --git a/src/Avalonia.Controls/Properties/AssemblyInfo.cs b/src/Avalonia.Controls/Properties/AssemblyInfo.cs
index c04c66a77f..060db46212 100644
--- a/src/Avalonia.Controls/Properties/AssemblyInfo.cs
+++ b/src/Avalonia.Controls/Properties/AssemblyInfo.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Reflection;
using System.Runtime.CompilerServices;
using Avalonia.Metadata;
diff --git a/src/Avalonia.Controls/RadioButton.cs b/src/Avalonia.Controls/RadioButton.cs
index 54afde7da2..4bda241497 100644
--- a/src/Avalonia.Controls/RadioButton.cs
+++ b/src/Avalonia.Controls/RadioButton.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/Avalonia.Controls/Remote/RemoteWidget.cs b/src/Avalonia.Controls/Remote/RemoteWidget.cs
index c7a1a24c25..fabb38f87d 100644
--- a/src/Avalonia.Controls/Remote/RemoteWidget.cs
+++ b/src/Avalonia.Controls/Remote/RemoteWidget.cs
@@ -75,7 +75,11 @@ namespace Avalonia.Controls.Remote
var fmt = (PixelFormat) _lastFrame.Format;
if (_bitmap == null || _bitmap.PixelSize.Width != _lastFrame.Width ||
_bitmap.PixelSize.Height != _lastFrame.Height)
- _bitmap = new WriteableBitmap(new PixelSize(_lastFrame.Width, _lastFrame.Height), new Vector(96, 96), fmt);
+ {
+ _bitmap?.Dispose();
+ _bitmap = new WriteableBitmap(new PixelSize(_lastFrame.Width, _lastFrame.Height),
+ new Vector(96, 96), fmt);
+ }
using (var l = _bitmap.Lock())
{
var lineLen = (fmt == PixelFormat.Rgb565 ? 2 : 4) * _lastFrame.Width;
diff --git a/src/Avalonia.Controls/RequestBringIntoViewEventArgs.cs b/src/Avalonia.Controls/RequestBringIntoViewEventArgs.cs
index 21b658632e..dd55de85d4 100644
--- a/src/Avalonia.Controls/RequestBringIntoViewEventArgs.cs
+++ b/src/Avalonia.Controls/RequestBringIntoViewEventArgs.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Interactivity;
using Avalonia.VisualTree;
diff --git a/src/Avalonia.Controls/RowDefinition.cs b/src/Avalonia.Controls/RowDefinition.cs
index 85e7ed6519..fac795035b 100644
--- a/src/Avalonia.Controls/RowDefinition.cs
+++ b/src/Avalonia.Controls/RowDefinition.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Controls
{
///
diff --git a/src/Avalonia.Controls/RowDefinitions.cs b/src/Avalonia.Controls/RowDefinitions.cs
index cf72cc8ba3..02ab12b5af 100644
--- a/src/Avalonia.Controls/RowDefinitions.cs
+++ b/src/Avalonia.Controls/RowDefinitions.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Linq;
using Avalonia.Collections;
diff --git a/src/Avalonia.Controls/ScrollChangedEventArgs.cs b/src/Avalonia.Controls/ScrollChangedEventArgs.cs
new file mode 100644
index 0000000000..fed23964f5
--- /dev/null
+++ b/src/Avalonia.Controls/ScrollChangedEventArgs.cs
@@ -0,0 +1,45 @@
+using Avalonia.Interactivity;
+
+namespace Avalonia.Controls
+{
+ ///
+ /// Describes a change in scrolling state.
+ ///
+ public class ScrollChangedEventArgs : RoutedEventArgs
+ {
+ public ScrollChangedEventArgs(
+ Vector extentDelta,
+ Vector offsetDelta,
+ Vector viewportDelta)
+ : this(ScrollViewer.ScrollChangedEvent, extentDelta, offsetDelta, viewportDelta)
+ {
+ }
+
+ public ScrollChangedEventArgs(
+ RoutedEvent routedEvent,
+ Vector extentDelta,
+ Vector offsetDelta,
+ Vector viewportDelta)
+ : base(routedEvent)
+ {
+ ExtentDelta = extentDelta;
+ OffsetDelta = offsetDelta;
+ ViewportDelta = viewportDelta;
+ }
+
+ ///
+ /// Gets the change to the value of .
+ ///
+ public Vector ExtentDelta { get; }
+
+ ///
+ /// Gets the change to the value of .
+ ///
+ public Vector OffsetDelta { get; }
+
+ ///
+ /// Gets the change to the value of .
+ ///
+ public Vector ViewportDelta { get; }
+ }
+}
diff --git a/src/Avalonia.Controls/ScrollViewer.cs b/src/Avalonia.Controls/ScrollViewer.cs
index 3d508d8b68..c3f0dc0056 100644
--- a/src/Avalonia.Controls/ScrollViewer.cs
+++ b/src/Avalonia.Controls/ScrollViewer.cs
@@ -1,10 +1,8 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
+using Avalonia.Interactivity;
namespace Avalonia.Controls
{
@@ -62,6 +60,22 @@ namespace Avalonia.Controls
o => o.Viewport,
(o, v) => o.Viewport = v);
+ ///
+ /// Defines the property.
+ ///
+ public static readonly DirectProperty LargeChangeProperty =
+ AvaloniaProperty.RegisterDirect(
+ nameof(LargeChange),
+ o => o.LargeChange);
+
+ ///
+ /// Defines the property.
+ ///
+ public static readonly DirectProperty SmallChangeProperty =
+ AvaloniaProperty.RegisterDirect(
+ nameof(SmallChange),
+ o => o.SmallChange);
+
///
/// Defines the HorizontalScrollBarMaximum property.
///
@@ -152,9 +166,23 @@ namespace Avalonia.Controls
nameof(VerticalScrollBarVisibility),
ScrollBarVisibility.Auto);
+ ///
+ /// Defines the event.
+ ///
+ public static readonly RoutedEvent ScrollChangedEvent =
+ RoutedEvent.Register(
+ nameof(ScrollChanged),
+ RoutingStrategies.Bubble);
+
+ internal const double DefaultSmallChange = 16;
+
+ private IDisposable _childSubscription;
+ private ILogicalScrollable _logicalScrollable;
private Size _extent;
private Vector _offset;
private Size _viewport;
+ private Size _largeChange;
+ private Size _smallChange = new Size(DefaultSmallChange, DefaultSmallChange);
///
/// Initializes static members of the class.
@@ -172,6 +200,15 @@ namespace Avalonia.Controls
{
}
+ ///
+ /// Occurs when changes are detected to the scroll position, extent, or viewport size.
+ ///
+ public event EventHandler ScrollChanged
+ {
+ add => AddHandler(ScrollChangedEvent, value);
+ remove => RemoveHandler(ScrollChangedEvent, value);
+ }
+
///
/// Gets the extent of the scrollable content.
///
@@ -184,9 +221,11 @@ namespace Avalonia.Controls
private set
{
+ var old = _extent;
+
if (SetAndRaise(ExtentProperty, ref _extent, value))
{
- CalculatedPropertiesChanged();
+ CalculatedPropertiesChanged(extentDelta: value - old);
}
}
}
@@ -203,11 +242,13 @@ namespace Avalonia.Controls
set
{
+ var old = _offset;
+
value = ValidateOffset(this, value);
if (SetAndRaise(OffsetProperty, ref _offset, value))
{
- CalculatedPropertiesChanged();
+ CalculatedPropertiesChanged(offsetDelta: value - old);
}
}
}
@@ -224,13 +265,25 @@ namespace Avalonia.Controls
private set
{
+ var old = _viewport;
+
if (SetAndRaise(ViewportProperty, ref _viewport, value))
{
- CalculatedPropertiesChanged();
+ CalculatedPropertiesChanged(viewportDelta: value - old);
}
}
}
+ ///
+ /// Gets the large (page) change value for the scroll viewer.
+ ///
+ public Size LargeChange => _largeChange;
+
+ ///
+ /// Gets the small (line) change value for the scroll viewer.
+ ///
+ public Size SmallChange => _smallChange;
+
///
/// Gets or sets the horizontal scrollbar visibility.
///
@@ -249,22 +302,6 @@ namespace Avalonia.Controls
set { SetValue(VerticalScrollBarVisibilityProperty, value); }
}
- ///
- /// Scrolls to the top-left corner of the content.
- ///
- public void ScrollToHome()
- {
- Offset = new Vector(double.NegativeInfinity, double.NegativeInfinity);
- }
-
- ///
- /// Scrolls to the bottom-left corner of the content.
- ///
- public void ScrollToEnd()
- {
- Offset = new Vector(double.NegativeInfinity, double.PositiveInfinity);
- }
-
///
/// Gets a value indicating whether the viewer can scroll horizontally.
///
@@ -350,6 +387,22 @@ namespace Avalonia.Controls
///
IControl IScrollAnchorProvider.CurrentAnchor => null; // TODO: Implement
+ ///
+ /// Scrolls to the top-left corner of the content.
+ ///
+ public void ScrollToHome()
+ {
+ Offset = new Vector(double.NegativeInfinity, double.NegativeInfinity);
+ }
+
+ ///
+ /// Scrolls to the bottom-left corner of the content.
+ ///
+ public void ScrollToEnd()
+ {
+ Offset = new Vector(double.NegativeInfinity, double.PositiveInfinity);
+ }
+
///
/// Gets the value of the HorizontalScrollBarVisibility attached property.
///
@@ -400,6 +453,22 @@ namespace Avalonia.Controls
// TODO: Implement
}
+ protected override bool RegisterContentPresenter(IContentPresenter presenter)
+ {
+ _childSubscription?.Dispose();
+ _childSubscription = null;
+
+ if (base.RegisterContentPresenter(presenter))
+ {
+ _childSubscription = Presenter?
+ .GetObservable(ContentPresenter.ChildProperty)
+ .Subscribe(ChildChanged);
+ return true;
+ }
+
+ return false;
+ }
+
internal static Vector CoerceOffset(Size extent, Size viewport, Vector offset)
{
var maxX = Math.Max(extent.Width - viewport.Width, 0);
@@ -434,6 +503,28 @@ namespace Avalonia.Controls
}
}
+ private void ChildChanged(IControl child)
+ {
+ if (_logicalScrollable is object)
+ {
+ _logicalScrollable.ScrollInvalidated -= LogicalScrollInvalidated;
+ _logicalScrollable = null;
+ }
+
+ if (child is ILogicalScrollable logical)
+ {
+ _logicalScrollable = logical;
+ logical.ScrollInvalidated += LogicalScrollInvalidated;
+ }
+
+ CalculatedPropertiesChanged();
+ }
+
+ private void LogicalScrollInvalidated(object sender, EventArgs e)
+ {
+ CalculatedPropertiesChanged();
+ }
+
private void ScrollBarVisibilityChanged(AvaloniaPropertyChangedEventArgs e)
{
var wasEnabled = !ScrollBarVisibility.Disabled.Equals(e.OldValue);
@@ -458,7 +549,10 @@ namespace Avalonia.Controls
}
}
- private void CalculatedPropertiesChanged()
+ private void CalculatedPropertiesChanged(
+ Size extentDelta = default,
+ Vector offsetDelta = default,
+ Size viewportDelta = default)
{
// Pass old values of 0 here because we don't have the old values at this point,
// and it shouldn't matter as only the template uses these properies.
@@ -468,6 +562,31 @@ namespace Avalonia.Controls
RaisePropertyChanged(VerticalScrollBarMaximumProperty, 0, VerticalScrollBarMaximum);
RaisePropertyChanged(VerticalScrollBarValueProperty, 0, VerticalScrollBarValue);
RaisePropertyChanged(VerticalScrollBarViewportSizeProperty, 0, VerticalScrollBarViewportSize);
+
+ if (_logicalScrollable?.IsLogicalScrollEnabled == true)
+ {
+ SetAndRaise(SmallChangeProperty, ref _smallChange, _logicalScrollable.ScrollSize);
+ SetAndRaise(LargeChangeProperty, ref _largeChange, _logicalScrollable.PageScrollSize);
+ }
+ else
+ {
+ SetAndRaise(SmallChangeProperty, ref _smallChange, new Size(DefaultSmallChange, DefaultSmallChange));
+ SetAndRaise(LargeChangeProperty, ref _largeChange, Viewport);
+ }
+
+ if (extentDelta != default || offsetDelta != default || viewportDelta != default)
+ {
+ using var route = BuildEventRoute(ScrollChangedEvent);
+
+ if (route.HasHandlers)
+ {
+ var e = new ScrollChangedEventArgs(
+ new Vector(extentDelta.Width, extentDelta.Height),
+ offsetDelta,
+ new Vector(viewportDelta.Width, viewportDelta.Height));
+ route.RaiseEvent(this, e);
+ }
+ }
}
protected override void OnKeyDown(KeyEventArgs e)
diff --git a/src/Avalonia.Controls/SelectionChangedEventArgs.cs b/src/Avalonia.Controls/SelectionChangedEventArgs.cs
index fb412a64a8..c19d868d57 100644
--- a/src/Avalonia.Controls/SelectionChangedEventArgs.cs
+++ b/src/Avalonia.Controls/SelectionChangedEventArgs.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Collections;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
diff --git a/src/Avalonia.Controls/SelectionMode.cs b/src/Avalonia.Controls/SelectionMode.cs
index 6ba30b968c..07cb01ff0b 100644
--- a/src/Avalonia.Controls/SelectionMode.cs
+++ b/src/Avalonia.Controls/SelectionMode.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Controls
diff --git a/src/Avalonia.Controls/Separator.cs b/src/Avalonia.Controls/Separator.cs
index 84b2a33d7b..537af5186e 100644
--- a/src/Avalonia.Controls/Separator.cs
+++ b/src/Avalonia.Controls/Separator.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.Primitives;
namespace Avalonia.Controls
diff --git a/src/Avalonia.Controls/Shapes/Ellipse.cs b/src/Avalonia.Controls/Shapes/Ellipse.cs
index f80bf5d967..4d2fd238ee 100644
--- a/src/Avalonia.Controls/Shapes/Ellipse.cs
+++ b/src/Avalonia.Controls/Shapes/Ellipse.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Media;
namespace Avalonia.Controls.Shapes
diff --git a/src/Avalonia.Controls/Shapes/Line.cs b/src/Avalonia.Controls/Shapes/Line.cs
index b06fe40710..e37630cbdf 100644
--- a/src/Avalonia.Controls/Shapes/Line.cs
+++ b/src/Avalonia.Controls/Shapes/Line.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Media;
namespace Avalonia.Controls.Shapes
diff --git a/src/Avalonia.Controls/Shapes/Path.cs b/src/Avalonia.Controls/Shapes/Path.cs
index e0952d3e9b..3fd84c0c7b 100644
--- a/src/Avalonia.Controls/Shapes/Path.cs
+++ b/src/Avalonia.Controls/Shapes/Path.cs
@@ -1,6 +1,5 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
+using System;
+using Avalonia.Data;
using Avalonia.Media;
namespace Avalonia.Controls.Shapes
@@ -13,6 +12,7 @@ namespace Avalonia.Controls.Shapes
static Path()
{
AffectsGeometry(DataProperty);
+ DataProperty.Changed.AddClassHandler((o, e) => o.DataChanged(e));
}
public Geometry Data
@@ -22,5 +22,26 @@ namespace Avalonia.Controls.Shapes
}
protected override Geometry CreateDefiningGeometry() => Data;
+
+ private void DataChanged(AvaloniaPropertyChangedEventArgs e)
+ {
+ var oldGeometry = (Geometry)e.OldValue;
+ var newGeometry = (Geometry)e.NewValue;
+
+ if (oldGeometry is object)
+ {
+ oldGeometry.Changed -= GeometryChanged;
+ }
+
+ if (newGeometry is object)
+ {
+ newGeometry.Changed += GeometryChanged;
+ }
+ }
+
+ private void GeometryChanged(object sender, EventArgs e)
+ {
+ InvalidateGeometry();
+ }
}
}
diff --git a/src/Avalonia.Controls/Shapes/Polygon.cs b/src/Avalonia.Controls/Shapes/Polygon.cs
index 5b9baa94fe..70a45f3516 100644
--- a/src/Avalonia.Controls/Shapes/Polygon.cs
+++ b/src/Avalonia.Controls/Shapes/Polygon.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Collections.Generic;
using Avalonia.Media;
diff --git a/src/Avalonia.Controls/Shapes/Polyline.cs b/src/Avalonia.Controls/Shapes/Polyline.cs
index c56336212c..4b4bb3ffd0 100644
--- a/src/Avalonia.Controls/Shapes/Polyline.cs
+++ b/src/Avalonia.Controls/Shapes/Polyline.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Collections.Generic;
using Avalonia.Media;
diff --git a/src/Avalonia.Controls/Shapes/Rectangle.cs b/src/Avalonia.Controls/Shapes/Rectangle.cs
index b803bde588..f3db2644a9 100644
--- a/src/Avalonia.Controls/Shapes/Rectangle.cs
+++ b/src/Avalonia.Controls/Shapes/Rectangle.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Media;
namespace Avalonia.Controls.Shapes
diff --git a/src/Avalonia.Controls/Shapes/Shape.cs b/src/Avalonia.Controls/Shapes/Shape.cs
index 7728302aad..371b5d92f7 100644
--- a/src/Avalonia.Controls/Shapes/Shape.cs
+++ b/src/Avalonia.Controls/Shapes/Shape.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Collections;
using Avalonia.Media;
diff --git a/src/Avalonia.Controls/ShutdownMode.cs b/src/Avalonia.Controls/ShutdownMode.cs
index ee593c28a8..c94567d690 100644
--- a/src/Avalonia.Controls/ShutdownMode.cs
+++ b/src/Avalonia.Controls/ShutdownMode.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.ApplicationLifetimes;
namespace Avalonia.Controls
diff --git a/src/Avalonia.Controls/Slider.cs b/src/Avalonia.Controls/Slider.cs
index e88a8bfb1b..b883a76d1b 100644
--- a/src/Avalonia.Controls/Slider.cs
+++ b/src/Avalonia.Controls/Slider.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
diff --git a/src/Avalonia.Controls/SystemDialog.cs b/src/Avalonia.Controls/SystemDialog.cs
index 6ccaa3c742..e74b950f23 100644
--- a/src/Avalonia.Controls/SystemDialog.cs
+++ b/src/Avalonia.Controls/SystemDialog.cs
@@ -32,7 +32,7 @@ namespace Avalonia.Controls
if(parent == null)
throw new ArgumentNullException(nameof(parent));
return ((await AvaloniaLocator.Current.GetService()
- .ShowFileDialogAsync(this, parent?.PlatformImpl)) ??
+ .ShowFileDialogAsync(this, parent)) ??
Array.Empty()).FirstOrDefault();
}
}
@@ -45,7 +45,7 @@ namespace Avalonia.Controls
{
if(parent == null)
throw new ArgumentNullException(nameof(parent));
- return AvaloniaLocator.Current.GetService().ShowFileDialogAsync(this, parent?.PlatformImpl);
+ return AvaloniaLocator.Current.GetService().ShowFileDialogAsync(this, parent);
}
}
@@ -61,7 +61,7 @@ namespace Avalonia.Controls
{
if(parent == null)
throw new ArgumentNullException(nameof(parent));
- return AvaloniaLocator.Current.GetService().ShowFolderDialogAsync(this, parent?.PlatformImpl);
+ return AvaloniaLocator.Current.GetService().ShowFolderDialogAsync(this, parent);
}
}
diff --git a/src/Avalonia.Controls/TabControl.cs b/src/Avalonia.Controls/TabControl.cs
index 8b1cd48379..f556865fda 100644
--- a/src/Avalonia.Controls/TabControl.cs
+++ b/src/Avalonia.Controls/TabControl.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Linq;
using Avalonia.Collections;
using Avalonia.Controls.Generators;
diff --git a/src/Avalonia.Controls/TabItem.cs b/src/Avalonia.Controls/TabItem.cs
index e27977bf3d..038ea225ce 100644
--- a/src/Avalonia.Controls/TabItem.cs
+++ b/src/Avalonia.Controls/TabItem.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Primitives;
diff --git a/src/Avalonia.Controls/Templates/DataTemplateExtensions.cs b/src/Avalonia.Controls/Templates/DataTemplateExtensions.cs
index 559cb9b776..f6e28483fd 100644
--- a/src/Avalonia.Controls/Templates/DataTemplateExtensions.cs
+++ b/src/Avalonia.Controls/Templates/DataTemplateExtensions.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Linq;
using Avalonia.LogicalTree;
diff --git a/src/Avalonia.Controls/Templates/DataTemplates.cs b/src/Avalonia.Controls/Templates/DataTemplates.cs
index 4011e32a07..f203539536 100644
--- a/src/Avalonia.Controls/Templates/DataTemplates.cs
+++ b/src/Avalonia.Controls/Templates/DataTemplates.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Collections;
namespace Avalonia.Controls.Templates
diff --git a/src/Avalonia.Controls/Templates/FuncControlTemplate.cs b/src/Avalonia.Controls/Templates/FuncControlTemplate.cs
index 19458cc6b8..3ed7abdfef 100644
--- a/src/Avalonia.Controls/Templates/FuncControlTemplate.cs
+++ b/src/Avalonia.Controls/Templates/FuncControlTemplate.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Controls.Primitives;
using Avalonia.Styling;
diff --git a/src/Avalonia.Controls/Templates/FuncControlTemplate`2.cs b/src/Avalonia.Controls/Templates/FuncControlTemplate`2.cs
index eec7a6030f..aad80af652 100644
--- a/src/Avalonia.Controls/Templates/FuncControlTemplate`2.cs
+++ b/src/Avalonia.Controls/Templates/FuncControlTemplate`2.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Controls.Primitives;
using Avalonia.Styling;
diff --git a/src/Avalonia.Controls/Templates/FuncDataTemplate.cs b/src/Avalonia.Controls/Templates/FuncDataTemplate.cs
index 76813af8e5..d454a29021 100644
--- a/src/Avalonia.Controls/Templates/FuncDataTemplate.cs
+++ b/src/Avalonia.Controls/Templates/FuncDataTemplate.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Reactive.Linq;
diff --git a/src/Avalonia.Controls/Templates/FuncDataTemplate`1.cs b/src/Avalonia.Controls/Templates/FuncDataTemplate`1.cs
index 68b737928d..4a6a1c6cfb 100644
--- a/src/Avalonia.Controls/Templates/FuncDataTemplate`1.cs
+++ b/src/Avalonia.Controls/Templates/FuncDataTemplate`1.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Controls.Templates
diff --git a/src/Avalonia.Controls/Templates/FuncTemplate`1.cs b/src/Avalonia.Controls/Templates/FuncTemplate`1.cs
index 88321ee1a3..e1818b07d5 100644
--- a/src/Avalonia.Controls/Templates/FuncTemplate`1.cs
+++ b/src/Avalonia.Controls/Templates/FuncTemplate`1.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Styling;
diff --git a/src/Avalonia.Controls/Templates/FuncTemplate`2.cs b/src/Avalonia.Controls/Templates/FuncTemplate`2.cs
index e0608d0471..d08616b968 100644
--- a/src/Avalonia.Controls/Templates/FuncTemplate`2.cs
+++ b/src/Avalonia.Controls/Templates/FuncTemplate`2.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
namespace Avalonia.Controls.Templates
diff --git a/src/Avalonia.Controls/Templates/FuncTreeDataTemplate.cs b/src/Avalonia.Controls/Templates/FuncTreeDataTemplate.cs
index eba503e815..4e40d87d47 100644
--- a/src/Avalonia.Controls/Templates/FuncTreeDataTemplate.cs
+++ b/src/Avalonia.Controls/Templates/FuncTreeDataTemplate.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections;
using Avalonia.Data;
diff --git a/src/Avalonia.Controls/Templates/FuncTreeDataTemplate`1.cs b/src/Avalonia.Controls/Templates/FuncTreeDataTemplate`1.cs
index 41f870ab42..c366107be4 100644
--- a/src/Avalonia.Controls/Templates/FuncTreeDataTemplate`1.cs
+++ b/src/Avalonia.Controls/Templates/FuncTreeDataTemplate`1.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections;
diff --git a/src/Avalonia.Controls/Templates/IControlTemplate.cs b/src/Avalonia.Controls/Templates/IControlTemplate.cs
index a3ef0fa954..7414f438a1 100644
--- a/src/Avalonia.Controls/Templates/IControlTemplate.cs
+++ b/src/Avalonia.Controls/Templates/IControlTemplate.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Controls.Primitives;
using Avalonia.Styling;
diff --git a/src/Avalonia.Controls/Templates/IDataTemplate.cs b/src/Avalonia.Controls/Templates/IDataTemplate.cs
index f9c97e55f3..cfde029eb8 100644
--- a/src/Avalonia.Controls/Templates/IDataTemplate.cs
+++ b/src/Avalonia.Controls/Templates/IDataTemplate.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Controls.Templates
{
///
diff --git a/src/Avalonia.Controls/Templates/IDataTemplateHost.cs b/src/Avalonia.Controls/Templates/IDataTemplateHost.cs
index 267938b3bd..61986a0661 100644
--- a/src/Avalonia.Controls/Templates/IDataTemplateHost.cs
+++ b/src/Avalonia.Controls/Templates/IDataTemplateHost.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-
+
namespace Avalonia.Controls.Templates
{
///
diff --git a/src/Avalonia.Controls/Templates/ITemplate`1.cs b/src/Avalonia.Controls/Templates/ITemplate`1.cs
index 2bf4b5a285..a241a9a6e8 100644
--- a/src/Avalonia.Controls/Templates/ITemplate`1.cs
+++ b/src/Avalonia.Controls/Templates/ITemplate`1.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Styling;
namespace Avalonia.Controls
diff --git a/src/Avalonia.Controls/Templates/ITemplate`2.cs b/src/Avalonia.Controls/Templates/ITemplate`2.cs
index a0c0e88eca..0e0263b785 100644
--- a/src/Avalonia.Controls/Templates/ITemplate`2.cs
+++ b/src/Avalonia.Controls/Templates/ITemplate`2.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
namespace Avalonia.Controls.Templates
{
///
diff --git a/src/Avalonia.Controls/Templates/ITreeDataTemplate.cs b/src/Avalonia.Controls/Templates/ITreeDataTemplate.cs
index 9ed8987681..60da65304f 100644
--- a/src/Avalonia.Controls/Templates/ITreeDataTemplate.cs
+++ b/src/Avalonia.Controls/Templates/ITreeDataTemplate.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Data;
namespace Avalonia.Controls.Templates
diff --git a/src/Avalonia.Controls/Templates/TemplateExtensions.cs b/src/Avalonia.Controls/Templates/TemplateExtensions.cs
index 18c8bfdeda..7656ccd9bb 100644
--- a/src/Avalonia.Controls/Templates/TemplateExtensions.cs
+++ b/src/Avalonia.Controls/Templates/TemplateExtensions.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs
index 1655e22331..e9867e4503 100644
--- a/src/Avalonia.Controls/TextBlock.cs
+++ b/src/Avalonia.Controls/TextBlock.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Reactive.Linq;
using Avalonia.LogicalTree;
using Avalonia.Media;
@@ -20,6 +17,12 @@ namespace Avalonia.Controls
public static readonly StyledProperty BackgroundProperty =
Border.BackgroundProperty.AddOwner();
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty PaddingProperty =
+ Decorator.PaddingProperty.AddOwner();
+
// TODO: Define these attached properties elsewhere (e.g. on a Text class) and AddOwner
// them into TextBlock.
@@ -29,7 +32,7 @@ namespace Avalonia.Controls
public static readonly AttachedProperty FontFamilyProperty =
AvaloniaProperty.RegisterAttached(
nameof(FontFamily),
- defaultValue: FontFamily.Default,
+ defaultValue: FontFamily.Default,
inherits: true);
///
@@ -110,20 +113,21 @@ namespace Avalonia.Controls
static TextBlock()
{
ClipToBoundsProperty.OverrideDefaultValue(true);
- AffectsRender(
- BackgroundProperty,
- ForegroundProperty,
- FontWeightProperty,
- FontSizeProperty,
- FontStyleProperty);
-
- Observable.Merge(
- TextProperty.Changed,
- TextAlignmentProperty.Changed,
- FontSizeProperty.Changed,
- FontStyleProperty.Changed,
- FontWeightProperty.Changed
- ).AddClassHandler((x, _) => x.OnTextPropertiesChanged());
+
+ AffectsRender(BackgroundProperty, ForegroundProperty,
+ TextAlignmentProperty, TextDecorationsProperty);
+
+ AffectsMeasure(FontSizeProperty, FontWeightProperty,
+ FontStyleProperty, TextWrappingProperty, FontFamilyProperty,
+ TextTrimmingProperty, TextProperty, PaddingProperty);
+
+ Observable.Merge(TextProperty.Changed, ForegroundProperty.Changed,
+ TextAlignmentProperty.Changed, TextWrappingProperty.Changed,
+ TextTrimmingProperty.Changed, FontSizeProperty.Changed,
+ FontStyleProperty.Changed, FontWeightProperty.Changed,
+ FontFamilyProperty.Changed, TextDecorationsProperty.Changed,
+ PaddingProperty.Changed
+ ).AddClassHandler((x, _) => x.InvalidateTextLayout());
}
///
@@ -145,6 +149,15 @@ namespace Avalonia.Controls
}
}
+ ///
+ /// Gets or sets the padding to place around the .
+ ///
+ public Thickness Padding
+ {
+ get { return GetValue(PaddingProperty); }
+ set { SetValue(PaddingProperty, value); }
+ }
+
///
/// Gets or sets a brush used to paint the control's background.
///
@@ -363,7 +376,9 @@ namespace Avalonia.Controls
context.FillRectangle(background, new Rect(Bounds.Size));
}
- TextLayout?.Draw(context.PlatformImpl, new Point());
+ var padding = Padding;
+
+ TextLayout?.Draw(context.PlatformImpl, new Point(padding.Left, padding.Top));
}
///
@@ -412,6 +427,10 @@ namespace Avalonia.Controls
return new Size();
}
+ var padding = Padding;
+
+ availableSize = availableSize.Deflate(padding);
+
if (_constraint != availableSize)
{
InvalidateTextLayout();
@@ -419,19 +438,17 @@ namespace Avalonia.Controls
_constraint = availableSize;
- return TextLayout?.Bounds.Size ?? Size.Empty;
+ var measuredSize = TextLayout?.Bounds.Size ?? Size.Empty;
+
+ return measuredSize.Inflate(padding);
}
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
base.OnAttachedToLogicalTree(e);
- InvalidateTextLayout();
- InvalidateMeasure();
- }
- private void OnTextPropertiesChanged()
- {
InvalidateTextLayout();
+
InvalidateMeasure();
}
}
diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs
index a438d7380b..06624c555f 100644
--- a/src/Avalonia.Controls/TextBox.cs
+++ b/src/Avalonia.Controls/TextBox.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using Avalonia.Input.Platform;
using System;
using System.Collections.Generic;
@@ -275,6 +272,24 @@ namespace Avalonia.Controls
}
}
+ public string SelectedText
+ {
+ get { return GetSelection(); }
+ set
+ {
+ _undoRedoHelper.Snapshot();
+ if (string.IsNullOrEmpty(value))
+ {
+ DeleteSelection();
+ }
+ else
+ {
+ HandleTextInput(value);
+ }
+ _undoRedoHelper.Snapshot();
+ }
+ }
+
///
/// Gets or sets the horizontal alignment of the content within the control.
///
@@ -458,8 +473,10 @@ namespace Avalonia.Controls
{
if (!IsPasswordBox)
{
+ _undoRedoHelper.Snapshot();
Copy();
DeleteSelection();
+ _undoRedoHelper.Snapshot();
}
handled = true;
@@ -585,6 +602,7 @@ namespace Avalonia.Controls
break;
case Key.Back:
+ _undoRedoHelper.Snapshot();
if (hasWholeWordModifiers && SelectionStart == SelectionEnd)
{
SetSelectionForControlBackspace();
@@ -608,11 +626,13 @@ namespace Avalonia.Controls
CaretIndex -= removedCharacters;
SelectionStart = SelectionEnd = CaretIndex;
}
+ _undoRedoHelper.Snapshot();
handled = true;
break;
case Key.Delete:
+ _undoRedoHelper.Snapshot();
if (hasWholeWordModifiers && SelectionStart == SelectionEnd)
{
SetSelectionForControlDelete();
@@ -634,6 +654,7 @@ namespace Avalonia.Controls
SetTextInternal(text.Substring(0, caretIndex) +
text.Substring(caretIndex + removedCharacters));
}
+ _undoRedoHelper.Snapshot();
handled = true;
break;
@@ -641,7 +662,9 @@ namespace Avalonia.Controls
case Key.Enter:
if (AcceptsReturn)
{
+ _undoRedoHelper.Snapshot();
HandleTextInput(NewLine);
+ _undoRedoHelper.Snapshot();
handled = true;
}
@@ -650,7 +673,9 @@ namespace Avalonia.Controls
case Key.Tab:
if (AcceptsTab)
{
+ _undoRedoHelper.Snapshot();
HandleTextInput("\t");
+ _undoRedoHelper.Snapshot();
handled = true;
}
else
@@ -683,12 +708,13 @@ namespace Avalonia.Controls
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
- var point = e.GetPosition(_presenter);
- var index = CaretIndex = _presenter.GetCaretIndex(point);
var text = Text;
- if (text != null && e.MouseButton == MouseButton.Left)
+ var clickInfo = e.GetCurrentPoint(this);
+ if (text != null && clickInfo.Properties.IsLeftButtonPressed && !(clickInfo.Pointer?.Captured is Border))
{
+ var point = e.GetPosition(_presenter);
+ var index = CaretIndex = _presenter.GetCaretIndex(point);
switch (e.ClickCount)
{
case 1:
@@ -714,7 +740,8 @@ namespace Avalonia.Controls
protected override void OnPointerMoved(PointerEventArgs e)
{
- if (_presenter != null && e.Pointer.Captured == _presenter)
+ // selection should not change during pointer move if the user right clicks
+ if (_presenter != null && e.Pointer.Captured == _presenter && e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
{
var point = e.GetPosition(_presenter);
@@ -727,6 +754,22 @@ namespace Avalonia.Controls
{
if (_presenter != null && e.Pointer.Captured == _presenter)
{
+ if (e.InitialPressMouseButton == MouseButton.Right)
+ {
+ var point = e.GetPosition(_presenter);
+ var caretIndex = _presenter.GetCaretIndex(point);
+
+ // see if mouse clicked inside current selection
+ // if it did not, we change the selection to where the user clicked
+ var firstSelection = Math.Min(SelectionStart, SelectionEnd);
+ var lastSelection = Math.Max(SelectionStart, SelectionEnd);
+ var didClickInSelection = SelectionStart != SelectionEnd &&
+ caretIndex >= firstSelection && caretIndex <= lastSelection;
+ if (!didClickInSelection)
+ {
+ CaretIndex = SelectionEnd = SelectionStart = caretIndex;
+ }
+ }
e.Pointer.Capture(null);
}
}
diff --git a/src/Avalonia.Controls/ToolTip.cs b/src/Avalonia.Controls/ToolTip.cs
index 5fe1e3804b..3e57ba529f 100644
--- a/src/Avalonia.Controls/ToolTip.cs
+++ b/src/Avalonia.Controls/ToolTip.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Reactive.Linq;
using Avalonia.Controls.Primitives;
diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs
index cabadac7d6..d17f3b0423 100644
--- a/src/Avalonia.Controls/TopLevel.cs
+++ b/src/Avalonia.Controls/TopLevel.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Reactive.Linq;
using Avalonia.Controls.Primitives;
@@ -50,6 +47,7 @@ namespace Avalonia.Controls
private readonly IAccessKeyHandler _accessKeyHandler;
private readonly IKeyboardNavigationHandler _keyboardNavigationHandler;
private readonly IPlatformRenderInterface _renderInterface;
+ private readonly IGlobalStyles _globalStyles;
private Size _clientSize;
private ILayoutManager _layoutManager;
@@ -94,6 +92,7 @@ namespace Avalonia.Controls
_inputManager = TryGetService(dependencyResolver);
_keyboardNavigationHandler = TryGetService(dependencyResolver);
_renderInterface = TryGetService(dependencyResolver);
+ _globalStyles = TryGetService(dependencyResolver);
Renderer = impl.CreateRenderer(this);
@@ -112,6 +111,13 @@ namespace Avalonia.Controls
_keyboardNavigationHandler?.SetOwner(this);
_accessKeyHandler?.SetOwner(this);
+
+ if (_globalStyles is object)
+ {
+ _globalStyles.GlobalStylesAdded += ((IStyleHost)this).StylesAdded;
+ _globalStyles.GlobalStylesRemoved += ((IStyleHost)this).StylesRemoved;
+ }
+
styler?.ApplyStyles(this);
ClientSize = impl.ClientSize;
@@ -215,10 +221,7 @@ namespace Avalonia.Controls
///
double IRenderRoot.RenderScaling => PlatformImpl?.Scaling ?? 1;
- IStyleHost IStyleHost.StylingParent
- {
- get { return AvaloniaLocator.Current.GetService(); }
- }
+ IStyleHost IStyleHost.StylingParent => _globalStyles;
IRenderTarget IRenderRoot.CreateRenderTarget() => CreateRenderTarget();
@@ -267,6 +270,12 @@ namespace Avalonia.Controls
///
protected virtual void HandleClosed()
{
+ if (_globalStyles is object)
+ {
+ _globalStyles.GlobalStylesAdded -= ((IStyleHost)this).StylesAdded;
+ _globalStyles.GlobalStylesRemoved -= ((IStyleHost)this).StylesRemoved;
+ }
+
var logicalArgs = new LogicalTreeAttachmentEventArgs(this, this, null);
((ILogical)this).NotifyDetachedFromLogicalTree(logicalArgs);
diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs
index 99e9ac2ecf..89d72566e2 100644
--- a/src/Avalonia.Controls/TreeView.cs
+++ b/src/Avalonia.Controls/TreeView.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections;
using System.Collections.Generic;
diff --git a/src/Avalonia.Controls/TreeViewItem.cs b/src/Avalonia.Controls/TreeViewItem.cs
index 4d24337c3a..d3bd45d13c 100644
--- a/src/Avalonia.Controls/TreeViewItem.cs
+++ b/src/Avalonia.Controls/TreeViewItem.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Linq;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Mixins;
@@ -54,6 +51,7 @@ namespace Avalonia.Controls
SelectableMixin.Attach(IsSelectedProperty);
FocusableProperty.OverrideDefaultValue(true);
ItemsPanelProperty.OverrideDefaultValue(DefaultPanel);
+ ParentProperty.Changed.AddClassHandler((o, e) => o.OnParentChanged(e));
RequestBringIntoViewEvent.AddClassHandler((x, e) => x.OnRequestBringIntoView(e));
}
@@ -182,5 +180,16 @@ namespace Avalonia.Controls
return logical != null ? result : @default;
}
+
+ private void OnParentChanged(AvaloniaPropertyChangedEventArgs e)
+ {
+ if (!((ILogical)this).IsAttachedToLogicalTree && e.NewValue is null)
+ {
+ // If we're not attached to the logical tree, then OnDetachedFromLogicalTree isn't going to be
+ // called when the item is removed. This results in the item not being removed from the index,
+ // causing #3551. In this case, update the index when Parent is changed to null.
+ ItemContainerGenerator.UpdateIndex();
+ }
+ }
}
}
diff --git a/src/Avalonia.Controls/UserControl.cs b/src/Avalonia.Controls/UserControl.cs
index 4f15839821..7b9cc2da1c 100644
--- a/src/Avalonia.Controls/UserControl.cs
+++ b/src/Avalonia.Controls/UserControl.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using Avalonia.Styling;
diff --git a/src/Avalonia.Controls/Utils/BorderRenderHelper.cs b/src/Avalonia.Controls/Utils/BorderRenderHelper.cs
index d6cf3df536..126f3e35ca 100644
--- a/src/Avalonia.Controls/Utils/BorderRenderHelper.cs
+++ b/src/Avalonia.Controls/Utils/BorderRenderHelper.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using Avalonia.Media;
namespace Avalonia.Controls.Utils
diff --git a/src/Avalonia.Controls/Utils/IEnumerableUtils.cs b/src/Avalonia.Controls/Utils/IEnumerableUtils.cs
index 40ebd406c3..9b6444fc66 100644
--- a/src/Avalonia.Controls/Utils/IEnumerableUtils.cs
+++ b/src/Avalonia.Controls/Utils/IEnumerableUtils.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
using System.Collections;
using System.Linq;
diff --git a/src/Avalonia.Controls/Utils/StringUtils.cs b/src/Avalonia.Controls/Utils/StringUtils.cs
index 2304866a85..8cf2e836bb 100644
--- a/src/Avalonia.Controls/Utils/StringUtils.cs
+++ b/src/Avalonia.Controls/Utils/StringUtils.cs
@@ -1,6 +1,3 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System.Globalization;
namespace Avalonia.Controls.Utils
diff --git a/src/Avalonia.Controls/VirtualizingStackPanel.cs b/src/Avalonia.Controls/VirtualizingStackPanel.cs
index 5f7b63c57a..da8bbe4fcf 100644
--- a/src/Avalonia.Controls/VirtualizingStackPanel.cs
+++ b/src/Avalonia.Controls/VirtualizingStackPanel.cs
@@ -1,7 +1,4 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
+using System;
using System.Collections.Specialized;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs
index 6554237b3a..75f32c862e 100644
--- a/src/Avalonia.Controls/Window.cs
+++ b/src/Avalonia.Controls/Window.cs
@@ -1,20 +1,17 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
using System;
+using System.ComponentModel;
+using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
using Avalonia.Controls.Platform;
+using Avalonia.Data;
using Avalonia.Input;
+using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Styling;
-using System.Collections.Generic;
-using System.Linq;
using JetBrains.Annotations;
-using System.ComponentModel;
-using Avalonia.Interactivity;
namespace Avalonia.Controls
{
@@ -45,6 +42,27 @@ namespace Avalonia.Controls
WidthAndHeight = 3,
}
+ ///
+ /// Determines system decorations (title bar, border, etc) for a
+ ///
+ public enum SystemDecorations
+ {
+ ///
+ /// No decorations
+ ///
+ None = 0,
+
+ ///
+ /// Window border without titlebar
+ ///
+ BorderOnly = 1,
+
+ ///
+ /// Fully decorated (default)
+ ///
+ Full = 2
+ }
+
///
/// A top-level window.
///
@@ -59,8 +77,18 @@ namespace Avalonia.Controls
///
/// Enables or disables system window decorations (title bar, buttons, etc)
///
- public static readonly StyledProperty HasSystemDecorationsProperty =
- AvaloniaProperty.Register(nameof(HasSystemDecorations), true);
+ [Obsolete("Use SystemDecorationsProperty instead")]
+ public static readonly DirectProperty HasSystemDecorationsProperty =
+ AvaloniaProperty.RegisterDirect(
+ nameof(HasSystemDecorations),
+ o => o.HasSystemDecorations,
+ (o, v) => o.HasSystemDecorations = v);
+
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty SystemDecorationsProperty =
+ AvaloniaProperty.Register(nameof(SystemDecorations), SystemDecorations.Full);
///
/// Enables or disables the taskbar icon
@@ -124,9 +152,6 @@ namespace Avalonia.Controls
{
BackgroundProperty.OverrideDefaultValue(typeof(Window), Brushes.White);
TitleProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl?.SetTitle((string)e.NewValue));
- HasSystemDecorationsProperty.Changed.AddClassHandler(
- (s, e) => s.PlatformImpl?.SetSystemDecorations((bool)e.NewValue));
-
ShowInTaskbarProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.ShowTaskbarIcon((bool)e.NewValue));
IconProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue)?.PlatformImpl));
@@ -135,12 +160,11 @@ namespace Avalonia.Controls
WindowStateProperty.Changed.AddClassHandler(
(w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.WindowState = (WindowState)e.NewValue; });
-
+
MinWidthProperty.Changed.AddClassHandler