Skip to content

Commit 83ab505

Browse files
author
Corvin Szimion
committed
2 parents 649b234 + 5015fdf commit 83ab505

24 files changed

+779
-296
lines changed

Directory.packages.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@
2626
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
2727
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
2828
<PackageVersion Include="VirtualizingWrapPanel" Version="1.5.8" />
29-
<PackageVersion Include="XAMLTest" Version="1.2.1" />
29+
<PackageVersion Include="XAMLTest" Version="1.2.2" />
3030
<PackageVersion Include="xunit" Version="2.6.2" />
3131
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.4" />
3232
<PackageVersion Include="Xunit.StaFact" Version="1.1.11" />
3333
</ItemGroup>
34-
</Project>
34+
</Project>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[Home](..\README.md) > Using `Freezable` Objects for Enhanced Performance
2+
3+
---
4+
5+
# Using `Freezable` Objects for Enhanced Performance
6+
7+
## Background information
8+
9+
WPF provides the `Freezable` class for objects that can be made immutable to optimize performance, such as brushes, pens, and transforms.
10+
11+
## Setting Objects as `Freezable`
12+
13+
When an object is frozen, it becomes immutable, which reduces memory usage and allows WPF to optimize rendering.
14+
15+
```csharp
16+
SolidColorBrush myBrush = new SolidColorBrush(Colors.Blue);
17+
if (myBrush.CanFreeze)
18+
{
19+
myBrush.Freeze();
20+
}
21+
```
22+
23+
Frozen objects cannot be modified, so only freeze objects that don’t require changes.
24+
25+
## Benefits of Freezable Objects
26+
27+
Freezable objects improve rendering speed, especially for large visuals or repeated animations. This technique is particularly useful in complex UIs with many reused resources.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
[Home](..\README.md) > How to Optimize UI Thread Performance?
2+
3+
---
4+
5+
# How to Optimize UI Thread Performance?
6+
7+
## Background information
8+
9+
The UI thread in WPF is responsible for rendering controls and handling user interactions. Heavy computations or complex bindings on the UI thread can lead to sluggish performance and poor user experience.
10+
11+
## Using `Dispatcher.BeginInvoke`
12+
13+
For non-UI-intensive tasks that still need to interact with the UI, use `Dispatcher.BeginInvoke` to move tasks off the UI thread without blocking it:
14+
15+
```csharp
16+
// Execute this in the background without freezing the UI
17+
Dispatcher.BeginInvoke((Action)(() =>
18+
{
19+
// Update UI elements here
20+
}));
21+
```
22+
23+
## Avoiding Complex Bindings
24+
25+
Complex bindings, especially with large data sets, can slow down the UI. Consider simplifying bindings, reducing converters, or using `INotifyPropertyChanged` with view models to optimize data flow.
26+
27+
```xaml
28+
<!-- Avoid multi-level bindings when possible -->
29+
<TextBlock Text="{Binding User.Name}" />
30+
```
31+
32+
> [!NOTE]
33+
> Always test performance impacts when using nested or complex bindings.
34+
35+
## Use `VirtualizingStackPanel` for Large Lists
36+
37+
For large collections, use `VirtualizingStackPanel` to only create visuals for items in view:
38+
39+
```xaml
40+
<ListBox VirtualizingStackPanel.IsVirtualizing="True" />
41+
```
42+
43+
This reduces memory usage and improves scrolling performance in lists.
44+
45+

docs/Reducing_Layout_Complexity.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Reducing Layout Complexity
2+
3+
## Background information
4+
5+
Complex layouts can slow down WPF performance, especially with nested controls or excessive use of `Grid` and `StackPanel`.
6+
7+
## Avoid Nested Grids and StackPanels
8+
9+
Overuse of nested layouts can create rendering bottlenecks. Try to simplify the structure or use a `UniformGrid` or `DockPanel` for simpler arrangements.
10+
11+
```xaml
12+
<!-- Instead of nesting multiple StackPanels, use a single DockPanel -->
13+
<DockPanel>
14+
<TextBlock Text="Header" DockPanel.Dock="Top" />
15+
<ListView DockPanel.Dock="Bottom" />
16+
</DockPanel>
17+
```
18+
19+
## Prefer Static Resources Over Dynamic Resources
20+
21+
Static resources are faster to load compared to dynamic ones. Use dynamic resources only if you need runtime changes in resource values.
22+
23+
```xaml
24+
<!-- Use StaticResource instead of DynamicResource for better performance -->
25+
<Style x:Key="ButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseButtonStyle}" />
26+
```
27+
28+
> [!NOTE]
29+
> Dynamic resources are reevaluated each time they’re used, which may impact performance.

src/MainDemo.Wpf/Domain/MainWindowViewModel.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,9 @@ private static IEnumerable<DemoItem> GenerateDemoItems(ISnackbarMessageQueue sna
475475
{
476476
DocumentationLink.DemoPageLink<NumericUpDown>(),
477477
DocumentationLink.StyleLink(nameof(NumericUpDown)),
478-
DocumentationLink.ApiLink<NumericUpDown>()
478+
DocumentationLink.ApiLink<NumericUpDown>(),
479+
DocumentationLink.ApiLink<DecimalUpDown>(),
480+
DocumentationLink.ApiLink<UpDownBase>()
479481
});
480482
}
481483

src/MainDemo.Wpf/Domain/TabsViewModel.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ internal class TabsViewModel : ViewModelBase
2323

2424
public TabsViewModel()
2525
{
26-
var closeCommand = new AnotherCommandImplementation(_ =>
26+
var closeCommand = new AnotherCommandImplementation(tab =>
2727
{
28-
if (SelectedTab is { } selectedTab)
29-
CustomTabs?.Remove(selectedTab);
28+
if (tab is CustomTab castedTab)
29+
CustomTabs?.Remove(castedTab);
3030
});
3131

3232
CustomTabs = new()

src/MainDemo.Wpf/NumericUpDown.xaml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<UserControl x:Class="MaterialDesignDemo.NumericUpDown"
1+
<UserControl x:Class="MaterialDesignDemo.NumericUpDown"
22
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
33
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
44
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
@@ -25,12 +25,19 @@
2525
<StackPanel Margin="0,16,0,0"
2626
DockPanel.Dock="Top"
2727
Orientation="Horizontal">
28+
2829
<smtx:XamlDisplay Margin="10,5"
2930
VerticalAlignment="Top"
3031
UniqueKey="numericUpDown_default">
3132
<materialDesign:NumericUpDown />
3233
</smtx:XamlDisplay>
3334

35+
<smtx:XamlDisplay Margin="10,5"
36+
VerticalAlignment="Top"
37+
UniqueKey="decimalUpDown_default">
38+
<materialDesign:DecimalUpDown ValueStep="0.5" Minimum="-2.5" Maximum="2.5" />
39+
</smtx:XamlDisplay>
40+
3441
<smtx:XamlDisplay Margin="10,5"
3542
VerticalAlignment="Top"
3643
UniqueKey="numericUpDown_customButtonContent">

src/MainDemo.Wpf/Tabs.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,7 @@
732732
<DataTemplate>
733733
<StackPanel Orientation="Horizontal">
734734
<TextBlock Text="{Binding CustomHeader}" />
735-
<Button Command="{Binding CloseCommand}">
735+
<Button Command="{Binding CloseCommand}" CommandParameter="{Binding}">
736736
<Button.Template>
737737
<ControlTemplate>
738738
<materialDesign:PackIcon Kind="Close"
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#if !NET8_0_OR_GREATER
2+
using System.Globalization;
3+
#endif
4+
5+
namespace MaterialDesignThemes.Wpf;
6+
7+
public class DecimalUpDown
8+
#if NET8_0_OR_GREATER
9+
: UpDownBase<decimal>
10+
#else
11+
: UpDownBase<decimal, DecimalArithmetic>
12+
#endif
13+
{
14+
static DecimalUpDown()
15+
{
16+
DefaultStyleKeyProperty.OverrideMetadata(typeof(DecimalUpDown), new FrameworkPropertyMetadata(typeof(DecimalUpDown)));
17+
}
18+
}
19+
20+
#if !NET8_0_OR_GREATER
21+
public class DecimalArithmetic : IArithmetic<decimal>
22+
{
23+
public decimal Add(decimal value1, decimal value2) => value1 + value2;
24+
25+
public decimal Subtract(decimal value1, decimal value2) => value1 - value2;
26+
27+
public int Compare(decimal value1, decimal value2) => value1.CompareTo(value2);
28+
29+
public decimal MinValue() => decimal.MinValue;
30+
31+
public decimal MaxValue() => decimal.MaxValue;
32+
33+
public decimal One() => 1m;
34+
35+
public decimal Max(decimal value1, decimal value2) => Math.Max(value1, value2);
36+
37+
public decimal Min(decimal value1, decimal value2) => Math.Min(value1, value2);
38+
39+
public bool TryParse(string text, IFormatProvider? formatProvider, out decimal value)
40+
=> decimal.TryParse(text, NumberStyles.Number, formatProvider, out value);
41+
}
42+
#endif

src/MaterialDesignThemes.Wpf/HintAssist.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,17 @@ public static void SetHintPaddingBrush(DependencyObject obj, Brush? value)
130130
=> obj.SetValue(HintPaddingBrushProperty, value);
131131
#endregion
132132

133+
#region AttachedProperty: ApplyHintPaddingBrush
134+
public static readonly DependencyProperty ApplyHintPaddingBrushProperty =
135+
DependencyProperty.RegisterAttached("ApplyHintPaddingBrush", typeof(bool), typeof(HintAssist), new PropertyMetadata(false));
136+
137+
public static bool GetApplyHintPaddingBrush(DependencyObject obj)
138+
=> (bool)obj.GetValue(ApplyHintPaddingBrushProperty);
139+
140+
public static void SetApplyHintPaddingBrush(DependencyObject obj, bool value)
141+
=> obj.SetValue(ApplyHintPaddingBrushProperty, value);
142+
#endregion
143+
133144
#region AttachedProperty : HelperTextProperty
134145
public static readonly DependencyProperty HelperTextProperty
135146
= DependencyProperty.RegisterAttached("HelperText", typeof(string), typeof(HintAssist),

0 commit comments

Comments
 (0)