diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 0bf4a912c..b9e1e2ce1 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -1,6 +1,6 @@
{
"name": "WPF UI Docs Dev Container",
- "image": "mcr.microsoft.com/dotnet/sdk:8.0",
+ "image": "mcr.microsoft.com/dotnet/sdk:9.0",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
diff --git a/.github/workflows/top-issues-dashboard.yml b/.github/workflows/top-issues-dashboard.yml
new file mode 100644
index 000000000..f1c3ffbf6
--- /dev/null
+++ b/.github/workflows/top-issues-dashboard.yml
@@ -0,0 +1,24 @@
+name: wpf-ui-top-issues-dashboard
+on:
+ schedule:
+ - cron: '0 0 */1 * *'
+
+jobs:
+ ShowAndLabelTopIssues:
+ name: Display and label top issues.
+ runs-on: ubuntu-latest
+ steps:
+ - name: Top Issues action
+ uses: rickstaa/top-issues-action@v1.3.101
+ env:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ top_list_size: 10
+ label: true
+ dashboard: true
+ dashboard_show_total_reactions: true
+ top_issues: true
+ top_bugs: true
+ top_features: true
+ feature_label: feature
+ top_pull_requests: true
diff --git a/.github/workflows/wpf-ui-cd-docs.yaml b/.github/workflows/wpf-ui-cd-docs.yaml
index f6b39b482..1464f4dc6 100644
--- a/.github/workflows/wpf-ui-cd-docs.yaml
+++ b/.github/workflows/wpf-ui-cd-docs.yaml
@@ -33,10 +33,10 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: 18.x
- - name: Setup .NET Core SDK 8.x
+ - name: Setup .NET Core SDK 9.x
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 8.x
+ dotnet-version: 9.x
- name: Install docfx
run: dotnet tool update -g docfx
diff --git a/.github/workflows/wpf-ui-cd-extension.yaml b/.github/workflows/wpf-ui-cd-extension.yaml
index 6bd56b3c9..2635972b5 100644
--- a/.github/workflows/wpf-ui-cd-extension.yaml
+++ b/.github/workflows/wpf-ui-cd-extension.yaml
@@ -4,7 +4,7 @@ on:
push:
branches: [main]
paths:
- - 'src/Wpf.Ui.Extension**`
+ - 'src/Wpf.Ui.Extension**'
workflow_dispatch:
diff --git a/.github/workflows/wpf-ui-cd-nuget.yaml b/.github/workflows/wpf-ui-cd-nuget.yaml
index a49cb274e..de485012d 100644
--- a/.github/workflows/wpf-ui-cd-nuget.yaml
+++ b/.github/workflows/wpf-ui-cd-nuget.yaml
@@ -2,7 +2,11 @@ name: wpf-ui-cd-nuget
on:
push:
- branches: [main]
+ branches:
+ - main
+ - release/*
+ paths:
+ - 'src/**'
workflow_dispatch:
@@ -17,10 +21,10 @@ jobs:
- uses: nuget/setup-nuget@v2
with:
nuget-api-key: ${{ secrets.NUGET_API_KEY }}
- - name: Setup .NET Core SDK 8.x
+ - name: Setup .NET Core SDK 9.x
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 8.x
+ dotnet-version: 9.x
- name: Fetch the certificate
run: |
diff --git a/.github/workflows/wpf-ui-pr-validator.yaml b/.github/workflows/wpf-ui-pr-validator.yaml
index c2e4fa698..7a641dcac 100644
--- a/.github/workflows/wpf-ui-pr-validator.yaml
+++ b/.github/workflows/wpf-ui-pr-validator.yaml
@@ -17,10 +17,10 @@ jobs:
- uses: nuget/setup-nuget@v2
with:
nuget-api-key: ${{ secrets.NUGET_API_KEY }}
- - name: Setup .NET Core SDK 8.x
+ - name: Setup .NET Core SDK 9.x
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 8.x
+ dotnet-version: 9.x
- name: Install dependencies
run: dotnet restore
diff --git a/Directory.Build.props b/Directory.Build.props
index f3160f4fa..cf67c770c 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -6,7 +6,7 @@
- 4.0.0-rc.2
+ 4.0.0-rc.3
4.0.0
@@ -41,7 +41,7 @@
true
- 12.0
+ 13.0
enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Wpf.Ui/Controls/CardAction/CardAction.cs b/src/Wpf.Ui/Controls/CardAction/CardAction.cs
index dc73e9189..9614b8388 100644
--- a/src/Wpf.Ui/Controls/CardAction/CardAction.cs
+++ b/src/Wpf.Ui/Controls/CardAction/CardAction.cs
@@ -4,6 +4,8 @@
// All Rights Reserved.
// ReSharper disable once CheckNamespace
+using System.Windows.Automation.Peers;
+
namespace Wpf.Ui.Controls;
///
@@ -48,4 +50,9 @@ public IconElement? Icon
get => (IconElement?)GetValue(IconProperty);
set => SetValue(IconProperty, value);
}
-}
+
+ protected override AutomationPeer OnCreateAutomationPeer()
+ {
+ return new CardActionAutomationPeer(this);
+ }
+}
\ No newline at end of file
diff --git a/src/Wpf.Ui/Controls/CardAction/CardActionAutomationPeer.cs b/src/Wpf.Ui/Controls/CardAction/CardActionAutomationPeer.cs
new file mode 100644
index 000000000..ffba11b5f
--- /dev/null
+++ b/src/Wpf.Ui/Controls/CardAction/CardActionAutomationPeer.cs
@@ -0,0 +1,77 @@
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
+// Copyright (C) Leszek Pomianowski and WPF UI Contributors.
+// All Rights Reserved.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Automation;
+using System.Windows.Automation.Peers;
+
+namespace Wpf.Ui.Controls;
+
+internal class CardActionAutomationPeer : FrameworkElementAutomationPeer
+{
+ private readonly CardAction _owner;
+
+ public CardActionAutomationPeer(CardAction owner)
+ : base(owner)
+ {
+ _owner = owner;
+ }
+
+ protected override string GetClassNameCore()
+ {
+ return "Button";
+ }
+
+ protected override AutomationControlType GetAutomationControlTypeCore()
+ {
+ return AutomationControlType.Button;
+ }
+
+ public override object GetPattern(PatternInterface patternInterface)
+ {
+ if (patternInterface == PatternInterface.ItemContainer)
+ {
+ return this;
+ }
+
+ return base.GetPattern(patternInterface);
+ }
+
+ protected override AutomationPeer GetLabeledByCore()
+ {
+ if (_owner.Content is UIElement element)
+ {
+ return CreatePeerForElement(element);
+ }
+
+ return base.GetLabeledByCore();
+ }
+
+ protected override string GetNameCore()
+ {
+ var result = base.GetNameCore() ?? string.Empty;
+
+ if (result == string.Empty)
+ {
+ result = AutomationProperties.GetName(_owner);
+ }
+
+ if (result == string.Empty && _owner.Content is DependencyObject d)
+ {
+ result = AutomationProperties.GetName(d);
+ }
+
+ if (result == string.Empty && _owner.Content is string s)
+ {
+ result = s;
+ }
+
+ return result;
+ }
+}
diff --git a/src/Wpf.Ui/Controls/CardControl/CardControl.xaml b/src/Wpf.Ui/Controls/CardControl/CardControl.xaml
index 1c33c7e63..6d7693529 100644
--- a/src/Wpf.Ui/Controls/CardControl/CardControl.xaml
+++ b/src/Wpf.Ui/Controls/CardControl/CardControl.xaml
@@ -86,24 +86,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Wpf.Ui/Controls/CheckBox/CheckBox.xaml b/src/Wpf.Ui/Controls/CheckBox/CheckBox.xaml
index 501634304..c54d6c90c 100644
--- a/src/Wpf.Ui/Controls/CheckBox/CheckBox.xaml
+++ b/src/Wpf.Ui/Controls/CheckBox/CheckBox.xaml
@@ -60,6 +60,7 @@
diff --git a/src/Wpf.Ui/Controls/DataGrid/DataGrid.cs b/src/Wpf.Ui/Controls/DataGrid/DataGrid.cs
index dfbd4196f..77d0e7e73 100644
--- a/src/Wpf.Ui/Controls/DataGrid/DataGrid.cs
+++ b/src/Wpf.Ui/Controls/DataGrid/DataGrid.cs
@@ -16,6 +16,10 @@ namespace Wpf.Ui.Controls;
///
[StyleTypedProperty(Property = nameof(CheckBoxColumnElementStyle), StyleTargetType = typeof(CheckBox))]
[StyleTypedProperty(Property = nameof(CheckBoxColumnEditingElementStyle), StyleTargetType = typeof(CheckBox))]
+[StyleTypedProperty(Property = nameof(ComboBoxColumnElementStyle), StyleTargetType = typeof(ComboBox))]
+[StyleTypedProperty(Property = nameof(ComboBoxColumnEditingElementStyle), StyleTargetType = typeof(ComboBox))]
+[StyleTypedProperty(Property = nameof(TextColumnElementStyle), StyleTargetType = typeof(TextBlock))]
+[StyleTypedProperty(Property = nameof(TextColumnEditingElementStyle), StyleTargetType = typeof(TextBox))]
public class DataGrid : System.Windows.Controls.DataGrid
{
/// Identifies the dependency property.
@@ -36,6 +40,42 @@ public class DataGrid : System.Windows.Controls.DataGrid
new FrameworkPropertyMetadata(null)
);
+ /// Identifies the dependency property.
+ public static readonly DependencyProperty ComboBoxColumnElementStyleProperty =
+ DependencyProperty.Register(
+ nameof(ComboBoxColumnElementStyle),
+ typeof(Style),
+ typeof(DataGrid),
+ new FrameworkPropertyMetadata(null)
+ );
+
+ /// Identifies the dependency property.
+ public static readonly DependencyProperty ComboBoxColumnEditingElementStyleProperty =
+ DependencyProperty.Register(
+ nameof(ComboBoxColumnEditingElementStyle),
+ typeof(Style),
+ typeof(DataGrid),
+ new FrameworkPropertyMetadata(null)
+ );
+
+ /// Identifies the dependency property.
+ public static readonly DependencyProperty TextColumnElementStyleProperty =
+ DependencyProperty.Register(
+ nameof(TextColumnElementStyle),
+ typeof(Style),
+ typeof(DataGrid),
+ new FrameworkPropertyMetadata(null)
+ );
+
+ /// Identifies the dependency property.
+ public static readonly DependencyProperty TextColumnEditingElementStyleProperty =
+ DependencyProperty.Register(
+ nameof(TextColumnEditingElementStyle),
+ typeof(Style),
+ typeof(DataGrid),
+ new FrameworkPropertyMetadata(null)
+ );
+
///
/// Gets or sets the style which is applied to all checkbox column in the DataGrid
///
@@ -54,6 +94,42 @@ public Style? CheckBoxColumnEditingElementStyle
set => SetValue(CheckBoxColumnEditingElementStyleProperty, value);
}
+ ///
+ /// Gets or sets the style which is applied to all combobox column in the DataGrid
+ ///
+ public Style? ComboBoxColumnElementStyle
+ {
+ get => (Style?)GetValue(ComboBoxColumnElementStyleProperty);
+ set => SetValue(ComboBoxColumnElementStyleProperty, value);
+ }
+
+ ///
+ /// Gets or sets the style for all the column comboboxes in the DataGrid
+ ///
+ public Style? ComboBoxColumnEditingElementStyle
+ {
+ get => (Style?)GetValue(ComboBoxColumnEditingElementStyleProperty);
+ set => SetValue(ComboBoxColumnEditingElementStyleProperty, value);
+ }
+
+ ///
+ /// Gets or sets the style which is applied to all textbox column in the DataGrid
+ ///
+ public Style? TextColumnElementStyle
+ {
+ get => (Style?)GetValue(TextColumnElementStyleProperty);
+ set => SetValue(TextColumnElementStyleProperty, value);
+ }
+
+ ///
+ /// Gets or sets the style for all the column textboxes in the DataGrid
+ ///
+ public Style? TextColumnEditingElementStyle
+ {
+ get => (Style?)GetValue(TextColumnEditingElementStyleProperty);
+ set => SetValue(TextColumnEditingElementStyleProperty, value);
+ }
+
protected override void OnInitialized(EventArgs e)
{
Columns.CollectionChanged += ColumnsOnCollectionChanged;
@@ -78,35 +154,109 @@ private void UpdateColumnElementStyles()
private void UpdateSingleColumn(DataGridColumn dataGridColumn)
{
- if (dataGridColumn is DataGridCheckBoxColumn checkBoxColumn)
+ switch (dataGridColumn)
{
- if (
- checkBoxColumn.ReadLocalValue(DataGridCheckBoxColumn.ElementStyleProperty)
- == DependencyProperty.UnsetValue
- )
- {
- _ = BindingOperations.SetBinding(
- checkBoxColumn,
- DataGridCheckBoxColumn.ElementStyleProperty,
- new Binding { Path = new PropertyPath(CheckBoxColumnElementStyleProperty), Source = this }
- );
- }
-
- if (
- checkBoxColumn.ReadLocalValue(DataGridCheckBoxColumn.EditingElementStyleProperty)
- == DependencyProperty.UnsetValue
- )
- {
- _ = BindingOperations.SetBinding(
- checkBoxColumn,
- DataGridCheckBoxColumn.EditingElementStyleProperty,
- new Binding
- {
- Path = new PropertyPath(CheckBoxColumnEditingElementStyleProperty),
- Source = this
- }
- );
- }
+ case DataGridCheckBoxColumn checkBoxColumn:
+ if (
+ checkBoxColumn.ReadLocalValue(DataGridBoundColumn.ElementStyleProperty)
+ == DependencyProperty.UnsetValue
+ )
+ {
+ _ = BindingOperations.SetBinding(
+ checkBoxColumn,
+ DataGridBoundColumn.ElementStyleProperty,
+ new Binding { Path = new PropertyPath(CheckBoxColumnElementStyleProperty), Source = this }
+ );
+ }
+
+ if (
+ checkBoxColumn.ReadLocalValue(DataGridBoundColumn.EditingElementStyleProperty)
+ == DependencyProperty.UnsetValue
+ )
+ {
+ _ = BindingOperations.SetBinding(
+ checkBoxColumn,
+ DataGridBoundColumn.EditingElementStyleProperty,
+ new Binding
+ {
+ Path = new PropertyPath(CheckBoxColumnEditingElementStyleProperty), Source = this
+ }
+ );
+ }
+
+ break;
+
+ case DataGridComboBoxColumn comboBoxColumn:
+ if (
+ comboBoxColumn.ReadLocalValue(DataGridBoundColumn.ElementStyleProperty)
+ == DependencyProperty.UnsetValue
+ )
+ {
+ _ = BindingOperations.SetBinding(
+ comboBoxColumn,
+ DataGridBoundColumn.ElementStyleProperty,
+ new Binding { Path = new PropertyPath(ComboBoxColumnElementStyleProperty), Source = this }
+ );
+ }
+
+ if (
+ comboBoxColumn.ReadLocalValue(DataGridBoundColumn.EditingElementStyleProperty)
+ == DependencyProperty.UnsetValue
+ )
+ {
+ _ = BindingOperations.SetBinding(
+ comboBoxColumn,
+ DataGridBoundColumn.EditingElementStyleProperty,
+ new Binding
+ {
+ Path = new PropertyPath(ComboBoxColumnEditingElementStyleProperty), Source = this
+ }
+ );
+ }
+
+ if (
+ comboBoxColumn.ReadLocalValue(DataGridBoundColumn.EditingElementStyleProperty)
+ == DependencyProperty.UnsetValue
+ )
+ {
+ _ = BindingOperations.SetBinding(
+ comboBoxColumn,
+ DataGridBoundColumn.EditingElementStyleProperty,
+ new Binding
+ {
+ Path = new PropertyPath(ComboBoxColumnEditingElementStyleProperty), Source = this
+ }
+ );
+ }
+
+ break;
+
+ case DataGridTextColumn textBoxColumn:
+ if (
+ textBoxColumn.ReadLocalValue(DataGridBoundColumn.ElementStyleProperty)
+ == DependencyProperty.UnsetValue
+ )
+ {
+ _ = BindingOperations.SetBinding(
+ textBoxColumn,
+ DataGridBoundColumn.ElementStyleProperty,
+ new Binding { Path = new PropertyPath(TextColumnElementStyleProperty), Source = this }
+ );
+ }
+
+ if (
+ textBoxColumn.ReadLocalValue(DataGridBoundColumn.EditingElementStyleProperty)
+ == DependencyProperty.UnsetValue
+ )
+ {
+ _ = BindingOperations.SetBinding(
+ textBoxColumn,
+ DataGridBoundColumn.EditingElementStyleProperty,
+ new Binding { Path = new PropertyPath(TextColumnEditingElementStyleProperty), Source = this }
+ );
+ }
+
+ break;
}
}
}
diff --git a/src/Wpf.Ui/Controls/DataGrid/DataGrid.xaml b/src/Wpf.Ui/Controls/DataGrid/DataGrid.xaml
index 46a301bbc..c122ada05 100644
--- a/src/Wpf.Ui/Controls/DataGrid/DataGrid.xaml
+++ b/src/Wpf.Ui/Controls/DataGrid/DataGrid.xaml
@@ -19,9 +19,16 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Wpf.Ui.Controls"
- xmlns:converters="clr-namespace:Wpf.Ui.Converters"
xmlns:system="clr-namespace:System;assembly=System.Runtime">
+
+
+
+
+
+
+
+
@@ -30,95 +37,69 @@
14
- #FFE8EDF9
- #FFC5CBF9
- #FF888888
-
- White
- #FF7381F9
- #FF211AA9
-
- #FF3843C4
- #FF211AA9
- #FF444444
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
- #FFFF0000
+
- 11,5,11,6
- 1
- 8,0,0,0
- 14
- 22
- 22
+
-
+
+
+
+
+
+
+
+
diff --git a/src/Wpf.Ui/Controls/EventIdentifier.cs b/src/Wpf.Ui/Controls/EventIdentifier.cs
index bd74a74a9..acd93a182 100644
--- a/src/Wpf.Ui/Controls/EventIdentifier.cs
+++ b/src/Wpf.Ui/Controls/EventIdentifier.cs
@@ -3,8 +3,6 @@
// Copyright (C) Leszek Pomianowski and WPF UI Contributors.
// All Rights Reserved.
-using Wpf.Ui.Extensions;
-
namespace Wpf.Ui.Controls;
///
diff --git a/src/Wpf.Ui/Controls/GridView/GridViewRowPresenter.cs b/src/Wpf.Ui/Controls/GridView/GridViewRowPresenter.cs
index f6be31290..a416b647b 100644
--- a/src/Wpf.Ui/Controls/GridView/GridViewRowPresenter.cs
+++ b/src/Wpf.Ui/Controls/GridView/GridViewRowPresenter.cs
@@ -3,9 +3,7 @@
// Copyright (C) Leszek Pomianowski and WPF UI Contributors.
// All Rights Reserved.
-using System.Reflection;
-using System.Windows.Controls;
-
+// ReSharper disable once CheckNamespace
namespace Wpf.Ui.Controls;
///
diff --git a/src/Wpf.Ui/Controls/IconElement/FontIcon.cs b/src/Wpf.Ui/Controls/IconElement/FontIcon.cs
index 34678aafa..d71fddd43 100644
--- a/src/Wpf.Ui/Controls/IconElement/FontIcon.cs
+++ b/src/Wpf.Ui/Controls/IconElement/FontIcon.cs
@@ -112,14 +112,15 @@ public string Glyph
protected override UIElement InitializeChildren()
{
- if (VisualParent is not null)
- {
- SetCurrentValue(FontSizeProperty, TextElement.GetFontSize(VisualParent));
- }
-
if (FontSize.Equals(SystemFonts.MessageFontSize))
{
SetResourceReference(FontSizeProperty, "DefaultIconFontSize");
+
+ // If the FontSize is the default, set it to the parent's FontSize.
+ if (VisualParent is not null && TextElement.GetFontSize(VisualParent) != SystemFonts.MessageFontSize)
+ {
+ SetCurrentValue(FontSizeProperty, TextElement.GetFontSize(VisualParent));
+ }
}
TextBlock = new TextBlock
diff --git a/src/Wpf.Ui/Controls/IconElement/IconElementConverter.cs b/src/Wpf.Ui/Controls/IconElement/IconElementConverter.cs
index 119bd3a2a..ab04650c9 100644
--- a/src/Wpf.Ui/Controls/IconElement/IconElementConverter.cs
+++ b/src/Wpf.Ui/Controls/IconElement/IconElementConverter.cs
@@ -3,8 +3,6 @@
// Copyright (C) Leszek Pomianowski and WPF UI Contributors.
// All Rights Reserved.
-using Wpf.Ui.Extensions;
-
// ReSharper disable once CheckNamespace
namespace Wpf.Ui.Controls;
diff --git a/src/Wpf.Ui/Controls/IconElement/IconSourceElement.cs b/src/Wpf.Ui/Controls/IconElement/IconSourceElement.cs
index 90241627c..19c349db4 100644
--- a/src/Wpf.Ui/Controls/IconElement/IconSourceElement.cs
+++ b/src/Wpf.Ui/Controls/IconElement/IconSourceElement.cs
@@ -4,7 +4,6 @@
// All Rights Reserved.
using System.Windows.Markup;
-using Wpf.Ui.Converters;
// ReSharper disable once CheckNamespace
namespace Wpf.Ui.Controls;
diff --git a/src/Wpf.Ui/Controls/IconElement/SymbolIcon.cs b/src/Wpf.Ui/Controls/IconElement/SymbolIcon.cs
index 43f173f6e..7cd3189b8 100644
--- a/src/Wpf.Ui/Controls/IconElement/SymbolIcon.cs
+++ b/src/Wpf.Ui/Controls/IconElement/SymbolIcon.cs
@@ -3,8 +3,6 @@
// Copyright (C) Leszek Pomianowski and WPF UI Contributors.
// All Rights Reserved.
-using Wpf.Ui.Extensions;
-
// ReSharper disable once CheckNamespace
namespace Wpf.Ui.Controls;
diff --git a/src/Wpf.Ui/Controls/InfoBar/InfoBar.xaml b/src/Wpf.Ui/Controls/InfoBar/InfoBar.xaml
index 44da6f3f1..0f38eeb10 100644
--- a/src/Wpf.Ui/Controls/InfoBar/InfoBar.xaml
+++ b/src/Wpf.Ui/Controls/InfoBar/InfoBar.xaml
@@ -40,7 +40,7 @@
+
+
+
+
diff --git a/src/Wpf.Ui/Controls/ListView/ListView.cs b/src/Wpf.Ui/Controls/ListView/ListView.cs
index ef2b44a30..32e8862d3 100644
--- a/src/Wpf.Ui/Controls/ListView/ListView.cs
+++ b/src/Wpf.Ui/Controls/ListView/ListView.cs
@@ -26,6 +26,8 @@ namespace Wpf.Ui.Controls;
///
public class ListView : System.Windows.Controls.ListView
{
+ private DependencyPropertyDescriptor? _descriptor;
+
/// Identifies the dependency property.
public static readonly DependencyProperty ViewStateProperty = DependencyProperty.Register(
nameof(ViewState),
@@ -62,6 +64,7 @@ protected virtual void OnViewStateChanged(DependencyPropertyChangedEventArgs e)
public ListView()
{
Loaded += OnLoaded;
+ Unloaded += OnUnloaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
@@ -69,14 +72,21 @@ private void OnLoaded(object sender, RoutedEventArgs e)
Loaded -= OnLoaded; // prevent memory leaks
// Setup initial ViewState and hook into View property changes
- var descriptor = DependencyPropertyDescriptor.FromProperty(
+ _descriptor = DependencyPropertyDescriptor.FromProperty(
System.Windows.Controls.ListView.ViewProperty,
typeof(System.Windows.Controls.ListView)
);
- descriptor?.AddValueChanged(this, OnViewPropertyChanged);
+ _descriptor?.AddValueChanged(this, OnViewPropertyChanged);
UpdateViewState(); // set the initial state
}
+ private void OnUnloaded(object sender, RoutedEventArgs e)
+ {
+ Unloaded -= OnUnloaded;
+
+ _descriptor?.RemoveValueChanged(this, OnViewPropertyChanged);
+ }
+
private void OnViewPropertyChanged(object? sender, EventArgs e)
{
UpdateViewState();
diff --git a/src/Wpf.Ui/Controls/Menu/MenuItem.xaml b/src/Wpf.Ui/Controls/Menu/MenuItem.xaml
index 61a176453..da8cb5f73 100644
--- a/src/Wpf.Ui/Controls/Menu/MenuItem.xaml
+++ b/src/Wpf.Ui/Controls/Menu/MenuItem.xaml
@@ -74,6 +74,16 @@
ContentSource="Header"
RecognizesAccessKey="True"
TextElement.Foreground="{TemplateBinding Foreground}" />
+
+
+
+
@@ -264,6 +284,17 @@
FontSize="11"
Foreground="{DynamicResource TextFillColorDisabledBrush}"
Text="{TemplateBinding InputGestureText}" />
+
+
+
@@ -334,6 +365,17 @@
FontSize="{TemplateBinding FontSize}"
Symbol="ChevronRight20" />
+
+
+
diff --git a/src/Wpf.Ui/Controls/NavigationView/NavigationView.Base.cs b/src/Wpf.Ui/Controls/NavigationView/NavigationView.Base.cs
index 0beabb6ba..3b6939051 100644
--- a/src/Wpf.Ui/Controls/NavigationView/NavigationView.Base.cs
+++ b/src/Wpf.Ui/Controls/NavigationView/NavigationView.Base.cs
@@ -67,7 +67,7 @@ public NavigationView()
private readonly ObservableCollection _breadcrumbBarItems = [];
private static readonly Thickness TitleBarPaneOpenMarginDefault = new(35, 0, 0, 0);
- private static readonly Thickness TitleBarPaneCompactMarginDefault = new(55, 0, 0, 0);
+ private static readonly Thickness TitleBarPaneCompactMarginDefault = new(35, 0, 0, 0);
private static readonly Thickness AutoSuggestBoxMarginDefault = new(8, 8, 8, 16);
private static readonly Thickness FrameMarginDefault = new(0, 50, 0, 0);
diff --git a/src/Wpf.Ui/Controls/NavigationView/NavigationViewContentPresenter.cs b/src/Wpf.Ui/Controls/NavigationView/NavigationViewContentPresenter.cs
index 66817641e..3d4b2a1ac 100644
--- a/src/Wpf.Ui/Controls/NavigationView/NavigationViewContentPresenter.cs
+++ b/src/Wpf.Ui/Controls/NavigationView/NavigationViewContentPresenter.cs
@@ -140,11 +140,23 @@ protected override void OnMouseDown(MouseButtonEventArgs e)
if (e.ChangedButton is MouseButton.XButton1 or MouseButton.XButton2)
{
e.Handled = true;
+ return;
}
base.OnMouseDown(e);
}
+ protected override void OnPreviewKeyDown(KeyEventArgs e)
+ {
+ if (e.Key == Key.F5)
+ {
+ e.Handled = true;
+ return;
+ }
+
+ base.OnPreviewKeyDown(e);
+ }
+
protected virtual void OnNavigating(System.Windows.Navigation.NavigatingCancelEventArgs eventArgs)
{
NotifyContentAboutNavigatingTo(eventArgs.Content);
@@ -199,27 +211,32 @@ private static void NotifyContentAboutNavigatingFrom(object content)
)]
private static void NotifyContentAboutNavigating(object content, Func function)
{
+ async void PerformNotify(INavigationAware navigationAware)
+ {
+ await function(navigationAware).ConfigureAwait(false);
+ }
+
switch (content)
{
// The order in which the OnNavigatedToAsync/OnNavigatedFromAsync methods of View and ViewModel are called
// is not guaranteed
case INavigationAware navigationAwareNavigationContent:
- _ = Task.Run(() => function(navigationAwareNavigationContent)).ConfigureAwait(false);
+ PerformNotify(navigationAwareNavigationContent);
if (
navigationAwareNavigationContent
is FrameworkElement { DataContext: INavigationAware viewModel }
&& !ReferenceEquals(viewModel, navigationAwareNavigationContent)
)
{
- _ = Task.Run(() => function(viewModel)).ConfigureAwait(false);
+ PerformNotify(viewModel);
}
break;
case INavigableView
+ ///
+ /// Property for .
+ ///
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
nameof(Header),
typeof(object),
typeof(TitleBar),
new PropertyMetadata(null)
);
+
+ ///
+ /// Property for .
+ ///
+ public static readonly DependencyProperty TrailingContentProperty = DependencyProperty.Register(
+ nameof(TrailingContent),
+ typeof(object),
+ typeof(TitleBar),
+ new PropertyMetadata(null)
+ );
/// Identifies the dependency property.
public static readonly DependencyProperty ButtonsForegroundProperty = DependencyProperty.Register(
@@ -210,13 +222,22 @@ public string? Title
}
///
- /// Gets or sets the content displayed in the .
+ /// Gets or sets the content displayed in the left side of the .
///
- public object? Header
+ public object Header
{
get => GetValue(HeaderProperty);
set => SetValue(HeaderProperty, value);
}
+
+ ///
+ /// Gets or sets the content displayed in right side of the .
+ ///
+ public object TrailingContent
+ {
+ get => GetValue(TrailingContentProperty);
+ set => SetValue(TrailingContentProperty, value);
+ }
///
/// Gets or sets the foreground of the navigation buttons.
@@ -377,6 +398,7 @@ public event TypedEventHandler HelpClicked
/*private System.Windows.Controls.Grid _mainGrid = null!;*/
private System.Windows.Controls.ContentPresenter _icon = null!;
+ private readonly TextBlock _titleBlock;
///
/// Initializes a new instance of the class and sets the default event.
@@ -387,6 +409,12 @@ public TitleBar()
dpiScale ??= VisualTreeHelper.GetDpi(this);
+ _titleBlock = new TextBlock();
+ _titleBlock.VerticalAlignment = VerticalAlignment.Center;
+ _titleBlock.SetBinding(System.Windows.Controls.TextBlock.TextProperty, new Binding(nameof(Title)) { Source = this });
+ _titleBlock.SetBinding(System.Windows.Controls.TextBlock.FontSizeProperty, new Binding(nameof(FontSize)) { Source = this });
+ Header = _titleBlock;
+
Loaded += OnLoaded;
Unloaded += OnUnloaded;
}
@@ -618,9 +646,19 @@ or User32.WM.NCLBUTTONUP
bool isMouseOverHeaderContent = false;
- if (message == User32.WM.NCHITTEST && Header is UIElement headerUiElement)
+ if (message == User32.WM.NCHITTEST && (TrailingContent is UIElement || Header is UIElement))
{
- isMouseOverHeaderContent = headerUiElement.IsMouseOverElement(lParam);
+ UIElement? headerLeftUIElement = Header as UIElement;
+ UIElement? headerRightUiElement = TrailingContent as UIElement;
+
+ if (headerLeftUIElement is not null && headerLeftUIElement != _titleBlock)
+ {
+ isMouseOverHeaderContent = headerLeftUIElement.IsMouseOverElement(lParam) || (headerRightUiElement?.IsMouseOverElement(lParam) ?? false);
+ }
+ else
+ {
+ isMouseOverHeaderContent = headerRightUiElement?.IsMouseOverElement(lParam) ?? false;
+ }
}
switch (message)
diff --git a/src/Wpf.Ui/Controls/TitleBar/TitleBar.xaml b/src/Wpf.Ui/Controls/TitleBar/TitleBar.xaml
index 82097c1e9..9dddd9b1c 100644
--- a/src/Wpf.Ui/Controls/TitleBar/TitleBar.xaml
+++ b/src/Wpf.Ui/Controls/TitleBar/TitleBar.xaml
@@ -118,7 +118,6 @@
VerticalAlignment="Center">
-
@@ -126,34 +125,34 @@
x:Name="PART_Icon"
Grid.Column="0"
Height="16"
- Margin="0,0,12,0"
VerticalAlignment="Center"
Content="{TemplateBinding Icon}"
Focusable="False"
RenderOptions.BitmapScalingMode="HighQuality" />
-
-
-
+
+
-
+
+
+
+
diff --git a/src/Wpf.Ui/Controls/TitleBar/TitleBarButton.cs b/src/Wpf.Ui/Controls/TitleBar/TitleBarButton.cs
index e87f3352f..235da5852 100644
--- a/src/Wpf.Ui/Controls/TitleBar/TitleBarButton.cs
+++ b/src/Wpf.Ui/Controls/TitleBar/TitleBarButton.cs
@@ -5,7 +5,6 @@
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;
-using Wpf.Ui.Extensions;
using Wpf.Ui.Interop;
// ReSharper disable once CheckNamespace
diff --git a/src/Wpf.Ui/Controls/ToggleButton/ToggleButton.xaml b/src/Wpf.Ui/Controls/ToggleButton/ToggleButton.xaml
index 04af06574..3b3f232b5 100644
--- a/src/Wpf.Ui/Controls/ToggleButton/ToggleButton.xaml
+++ b/src/Wpf.Ui/Controls/ToggleButton/ToggleButton.xaml
@@ -10,7 +10,7 @@
- 11,5,11,6
+ 11,5,11,5
1
0,0,8,0
@@ -41,20 +41,23 @@
Height="{TemplateBinding Height}"
MinWidth="{TemplateBinding MinWidth}"
MinHeight="{TemplateBinding MinHeight}"
- Padding="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Background="{TemplateBinding Background}"
- BorderBrush="{TemplateBinding BorderBrush}"
- BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding Border.CornerRadius}">
-
+
+
+
diff --git a/src/Wpf.Ui/Extensions/StringExtensions.cs b/src/Wpf.Ui/Extensions/StringExtensions.cs
new file mode 100644
index 000000000..89258c798
--- /dev/null
+++ b/src/Wpf.Ui/Extensions/StringExtensions.cs
@@ -0,0 +1,26 @@
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
+// Copyright (C) Leszek Pomianowski and WPF UI Contributors.
+// All Rights Reserved.
+
+#if NETFRAMEWORK
+using System.Diagnostics.Contracts;
+
+namespace Wpf.Ui.Extensions;
+
+internal static class StringExtensions
+{
+ ///
+ /// Returns a value indicating whether a specified string occurs within this string, using the specified comparison rules.
+ ///
+ /// Source string.
+ /// The string to seek.
+ /// One of the enumeration values that specifies the rules to use in the comparison.
+ /// true if the value parameter occurs within this string, or if value is the empty string (""); otherwise, false.
+ [Pure]
+ public static bool Contains(this string source, string value, StringComparison comparison)
+ {
+ return source.IndexOf(value, comparison) >= 0;
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/Wpf.Ui/GlobalUsings.cs b/src/Wpf.Ui/GlobalUsings.cs
index d8d8592ff..2ce035a12 100644
--- a/src/Wpf.Ui/GlobalUsings.cs
+++ b/src/Wpf.Ui/GlobalUsings.cs
@@ -13,3 +13,4 @@
global using System.Windows;
global using System.Windows.Interop;
global using System.Windows.Media;
+global using Wpf.Ui.Extensions;
\ No newline at end of file
diff --git a/src/Wpf.Ui/Resources/Theme/Dark.xaml b/src/Wpf.Ui/Resources/Theme/Dark.xaml
index 77c105868..e71689765 100644
--- a/src/Wpf.Ui/Resources/Theme/Dark.xaml
+++ b/src/Wpf.Ui/Resources/Theme/Dark.xaml
@@ -243,7 +243,7 @@
-
+
@@ -260,7 +260,7 @@
-
+
@@ -270,10 +270,13 @@
-
+
+
-
-
+
+
@@ -597,7 +600,7 @@
-
+
diff --git a/src/Wpf.Ui/Resources/Theme/Light.xaml b/src/Wpf.Ui/Resources/Theme/Light.xaml
index 61fd61064..d25f0189f 100644
--- a/src/Wpf.Ui/Resources/Theme/Light.xaml
+++ b/src/Wpf.Ui/Resources/Theme/Light.xaml
@@ -244,7 +244,7 @@
-
+
@@ -261,7 +261,7 @@
-
+
@@ -271,10 +271,13 @@
-
+
+
+
+
-
-
+
+
@@ -598,7 +601,7 @@
-
+
diff --git a/src/Wpf.Ui/UiApplication.cs b/src/Wpf.Ui/UiApplication.cs
index b12c0b7a9..25aa4b4b5 100644
--- a/src/Wpf.Ui/UiApplication.cs
+++ b/src/Wpf.Ui/UiApplication.cs
@@ -132,7 +132,7 @@ private static bool ApplicationHasResources(Application application)
return application
.Resources.MergedDictionaries.Where(e => e.Source is not null)
.Any(e =>
- e.Source.ToString().ToLower().Contains(Appearance.ApplicationThemeManager.LibraryNamespace)
+ e.Source.ToString().Contains(Appearance.ApplicationThemeManager.LibraryNamespace, StringComparison.OrdinalIgnoreCase)
);
}
}
diff --git a/src/Wpf.Ui/Wpf.Ui.csproj b/src/Wpf.Ui/Wpf.Ui.csproj
index 5e7b139d2..ad0903130 100644
--- a/src/Wpf.Ui/Wpf.Ui.csproj
+++ b/src/Wpf.Ui/Wpf.Ui.csproj
@@ -2,7 +2,7 @@
WPF-UI
- net462;net472;net481;net6.0-windows;net8.0-windows
+ net462;net472;net481;net6.0-windows;net8.0-windows;net9.0-windows
true
WPF UI provides the Fluent experience in your known and loved WPF framework. Intuitive design, themes, navigation and new immersive controls. All natively and effortlessly.
true
diff --git a/tests/Wpf.Ui.Gallery.UnitTests/Wpf.Ui.Gallery.UnitTests.csproj b/tests/Wpf.Ui.Gallery.UnitTests/Wpf.Ui.Gallery.UnitTests.csproj
index 91abfb142..d0047db9f 100644
--- a/tests/Wpf.Ui.Gallery.UnitTests/Wpf.Ui.Gallery.UnitTests.csproj
+++ b/tests/Wpf.Ui.Gallery.UnitTests/Wpf.Ui.Gallery.UnitTests.csproj
@@ -1,7 +1,7 @@
- net8.0-windows10.0.22621.0
+ net9.0-windows10.0.22621.0
false
diff --git a/tests/Wpf.Ui.UnitTests/Wpf.Ui.UnitTests.csproj b/tests/Wpf.Ui.UnitTests/Wpf.Ui.UnitTests.csproj
index 26408624f..c2e06abd5 100644
--- a/tests/Wpf.Ui.UnitTests/Wpf.Ui.UnitTests.csproj
+++ b/tests/Wpf.Ui.UnitTests/Wpf.Ui.UnitTests.csproj
@@ -1,7 +1,7 @@
- net7.0-windows
+ net9.0-windows
false