diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 6b910fc615..4e34d4b132 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -4,7 +4,6 @@ about: Create a report to help us improve Avalonia
title: ''
labels: bug
assignees: ''
-
---
**Describe the bug**
@@ -12,6 +11,7 @@ A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
+
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
@@ -24,8 +24,9 @@ A clear and concise description of what you expected to happen.
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- - OS: [e.g. Windows, Mac, Linux (State distribution)]
- - Version [e.g. 0.10.0-rc1 or 0.9.12]
+
+- OS: [e.g. Windows, Mac, Linux (State distribution)]
+- Version [e.g. 0.10.0-rc1 or 0.9.12]
**Additional context**
Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000000..687355d825
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,8 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Questions, Discussions, Ideas
+ url: https://github.com/AvaloniaUI/Avalonia/discussions/new
+ about: Please ask and answer questions here.
+ - name: Avalonia Community Support on Gitter
+ url: https://gitter.im/AvaloniaUI/Avalonia
+ about: Please ask and answer questions here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index 11fc491ef1..5f0a04cee3 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -4,7 +4,6 @@ about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
-
---
**Is your feature request related to a problem? Please describe.**
diff --git a/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj b/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj
index 89e2c096ee..7b9cd0212e 100644
--- a/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj
+++ b/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj
@@ -2,6 +2,8 @@
netstandard2.0
Avalonia
+ Enable
+ CS8600;CS8602;CS8603
diff --git a/src/Markup/Avalonia.Markup/Data/Binding.cs b/src/Markup/Avalonia.Markup/Data/Binding.cs
index bf43730481..50be598d7f 100644
--- a/src/Markup/Avalonia.Markup/Data/Binding.cs
+++ b/src/Markup/Avalonia.Markup/Data/Binding.cs
@@ -39,17 +39,17 @@ namespace Avalonia.Data
///
/// Gets or sets the name of the element to use as the binding source.
///
- public string ElementName { get; set; }
+ public string? ElementName { get; set; }
///
/// Gets or sets the relative source for the binding.
///
- public RelativeSource RelativeSource { get; set; }
+ public RelativeSource? RelativeSource { get; set; }
///
/// Gets or sets the source for the binding.
///
- public object Source { get; set; }
+ public object? Source { get; set; }
///
/// Gets or sets the binding path.
@@ -59,24 +59,36 @@ namespace Avalonia.Data
///
/// Gets or sets a function used to resolve types from names in the binding path.
///
- public Func TypeResolver { get; set; }
+ public Func? TypeResolver { get; set; }
- protected override ExpressionObserver CreateExpressionObserver(IAvaloniaObject target, AvaloniaProperty targetProperty, object anchor, bool enableDataValidation)
+ protected override ExpressionObserver CreateExpressionObserver(IAvaloniaObject target, AvaloniaProperty targetProperty, object? anchor, bool enableDataValidation)
{
- Contract.Requires(target != null);
- anchor = anchor ?? DefaultAnchor?.Target;
-
+ _ = target ?? throw new ArgumentNullException(nameof(target));
+
+ anchor ??= DefaultAnchor?.Target;
enableDataValidation = enableDataValidation && Priority == BindingPriority.LocalValue;
- INameScope nameScope = null;
+ INameScope? nameScope = null;
NameScope?.TryGetTarget(out nameScope);
var (node, mode) = ExpressionObserverBuilder.Parse(Path, enableDataValidation, TypeResolver, nameScope);
+ if (node is null)
+ {
+ throw new InvalidOperationException("Could not parse binding expression.");
+ }
+
+ IStyledElement GetSource()
+ {
+ return target as IStyledElement ??
+ anchor as IStyledElement ??
+ throw new ArgumentException("Could not find binding source: either target or anchor must be an IStyledElement.");
+ }
+
if (ElementName != null)
{
return CreateElementObserver(
- (target as IStyledElement) ?? (anchor as IStyledElement),
+ GetSource(),
ElementName,
node);
}
@@ -96,9 +108,7 @@ namespace Avalonia.Data
}
else
{
- return CreateSourceObserver(
- (target as IStyledElement) ?? (anchor as IStyledElement),
- node);
+ return CreateSourceObserver(GetSource(), node);
}
}
else if (RelativeSource.Mode == RelativeSourceMode.DataContext)
@@ -111,15 +121,11 @@ namespace Avalonia.Data
}
else if (RelativeSource.Mode == RelativeSourceMode.Self)
{
- return CreateSourceObserver(
- (target as IStyledElement) ?? (anchor as IStyledElement),
- node);
+ return CreateSourceObserver(GetSource(), node);
}
else if (RelativeSource.Mode == RelativeSourceMode.TemplatedParent)
{
- return CreateTemplatedParentObserver(
- (target as IStyledElement) ?? (anchor as IStyledElement),
- node);
+ return CreateTemplatedParentObserver(GetSource(), node);
}
else if (RelativeSource.Mode == RelativeSourceMode.FindAncestor)
{
@@ -128,10 +134,7 @@ namespace Avalonia.Data
throw new InvalidOperationException("AncestorType must be set for RelativeSourceMode.FindAncestor when searching the visual tree.");
}
- return CreateFindAncestorObserver(
- (target as IStyledElement) ?? (anchor as IStyledElement),
- RelativeSource,
- node);
+ return CreateFindAncestorObserver(GetSource(), RelativeSource, node);
}
else
{
diff --git a/src/Markup/Avalonia.Markup/Data/BindingBase.cs b/src/Markup/Avalonia.Markup/Data/BindingBase.cs
index 3dbc83a7df..c25ef49167 100644
--- a/src/Markup/Avalonia.Markup/Data/BindingBase.cs
+++ b/src/Markup/Avalonia.Markup/Data/BindingBase.cs
@@ -38,22 +38,22 @@ namespace Avalonia.Data
///
/// Gets or sets the to use.
///
- public IValueConverter Converter { get; set; }
+ public IValueConverter? Converter { get; set; }
///
/// Gets or sets a parameter to pass to .
///
- public object ConverterParameter { get; set; }
+ public object? ConverterParameter { get; set; }
///
/// Gets or sets the value to use when the binding is unable to produce a value.
///
- public object FallbackValue { get; set; }
+ public object? FallbackValue { get; set; }
///
/// Gets or sets the value to use when the binding result is null.
///
- public object TargetNullValue { get; set; }
+ public object? TargetNullValue { get; set; }
///
/// Gets or sets the binding mode.
@@ -68,26 +68,27 @@ namespace Avalonia.Data
///
/// Gets or sets the string format.
///
- public string StringFormat { get; set; }
+ public string? StringFormat { get; set; }
- public WeakReference DefaultAnchor { get; set; }
+ public WeakReference? DefaultAnchor { get; set; }
- public WeakReference NameScope { get; set; }
+ public WeakReference? NameScope { get; set; }
protected abstract ExpressionObserver CreateExpressionObserver(
IAvaloniaObject target,
AvaloniaProperty targetProperty,
- object anchor,
+ object? anchor,
bool enableDataValidation);
///
public InstancedBinding Initiate(
IAvaloniaObject target,
AvaloniaProperty targetProperty,
- object anchor = null,
+ object? anchor = null,
bool enableDataValidation = false)
{
- Contract.Requires(target != null);
+ _ = target ?? throw new ArgumentNullException(nameof(target));
+
anchor = anchor ?? DefaultAnchor?.Target;
enableDataValidation = enableDataValidation && Priority == BindingPriority.LocalValue;
@@ -133,18 +134,13 @@ namespace Avalonia.Data
IAvaloniaObject target,
ExpressionNode node,
bool targetIsDataContext,
- object anchor)
+ object? anchor)
{
- Contract.Requires(target != null);
+ _ = target ?? throw new ArgumentNullException(nameof(target));
if (!(target is IDataContextProvider))
{
- target = anchor as IDataContextProvider;
-
- if (target == null)
- {
- throw new InvalidOperationException("Cannot find a DataContext to bind to.");
- }
+ target = anchor as IDataContextProvider ?? throw new InvalidOperationException("Cannot find a DataContext to bind to.");
}
if (!targetIsDataContext)
@@ -171,10 +167,9 @@ namespace Avalonia.Data
string elementName,
ExpressionNode node)
{
- Contract.Requires(target != null);
+ _ = target ?? throw new ArgumentNullException(nameof(target));
- NameScope.TryGetTarget(out var scope);
- if (scope == null)
+ if (NameScope is null || !NameScope.TryGetTarget(out var scope) || scope is null)
throw new InvalidOperationException("Name scope is null or was already collected");
var result = new ExpressionObserver(
NameScopeLocator.Track(scope, elementName),
@@ -188,9 +183,9 @@ namespace Avalonia.Data
RelativeSource relativeSource,
ExpressionNode node)
{
- Contract.Requires(target != null);
+ _ = target ?? throw new ArgumentNullException(nameof(target));
- IObservable