OutWit.Common.MVVM.WPF
2.0.4
dotnet add package OutWit.Common.MVVM.WPF --version 2.0.4
NuGet\Install-Package OutWit.Common.MVVM.WPF -Version 2.0.4
<PackageReference Include="OutWit.Common.MVVM.WPF" Version="2.0.4" />
<PackageVersion Include="OutWit.Common.MVVM.WPF" Version="2.0.4" />
<PackageReference Include="OutWit.Common.MVVM.WPF" />
paket add OutWit.Common.MVVM.WPF --version 2.0.4
#r "nuget: OutWit.Common.MVVM.WPF, 2.0.4"
#:package OutWit.Common.MVVM.WPF@2.0.4
#addin nuget:?package=OutWit.Common.MVVM.WPF&version=2.0.4
#tool nuget:?package=OutWit.Common.MVVM.WPF&version=2.0.4
OutWit.Common.MVVM.WPF
WPF-specific MVVM components and utilities, including source generator for automatic DependencyProperty generation.
Features
- Source Generator for DependencyProperty: Automatically generate DependencyProperty from attributes
- WPF Commands:
CommandandDelegateCommandwithCommandManagerintegration - Binding Utilities: Helper methods for DependencyProperty registration
- Visual Tree Traversal: Extension methods for navigating WPF visual tree
- BindingProxy: Freezable binding proxy for DataContext access
- Legacy Support: Obsolete
BindableAttributefor backward compatibility
Installation
dotnet add package OutWit.Common.MVVM.WPF
This automatically includes:
OutWit.Common.MVVM(base cross-platform package)OutWit.Common.MVVM.WPF.Generator(source generator)OutWit.Common.Logging
Quick Start
Source Generator for DependencyProperty
The simplest way to create DependencyProperties:
using System.Windows.Controls;
using OutWit.Common.MVVM.WPF.Attributes;
namespace MyApp.Controls
{
public partial class CustomButton : Button
{
[StyledProperty(DefaultValue = "Click Me")]
public string Label { get; set; }
[StyledProperty(AffectsMeasure = true)]
public double IconSize { get; set; }
}
}
Important: Mark your class as partial to allow source generator to add code.
The generator automatically creates:
// Generated code (you don't write this):
public static readonly DependencyProperty LabelProperty = ...;
public static readonly DependencyProperty IconSizeProperty = ...;
Advanced Property Generation
public partial class AdvancedControl : Control
{
// Full explicit configuration
[StyledProperty(
DefaultValue = 100.0,
AffectsMeasure = true,
AffectsArrange = true,
BindsTwoWayByDefault = true,
OnChanged = nameof(OnWidthChanged))]
public double CustomWidth { get; set; }
private static void OnWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (AdvancedControl)d;
// Handle change
}
}
Convention-Based Callbacks
The generator automatically discovers callback methods by naming convention:
public partial class SmartControl : Control
{
// No need to specify OnChanged - automatically discovered!
[StyledProperty(DefaultValue = "Hello")]
public string Title { get; set; }
// Convention: On{PropertyName}Changed
private static void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (SmartControl)d;
// Handle title change
}
// No need to specify Coerce - automatically discovered!
[StyledProperty(DefaultValue = 100.0)]
public double Width { get; set; }
// Convention: {PropertyName}Coerce
private static object WidthCoerce(DependencyObject d, object value)
{
return Math.Max(0, (double)value); // Ensure non-negative
}
}
Benefits:
- ? Less boilerplate code
- ? Cleaner attributes
- ? Compile-time safety
- ? Override with explicit parameter when needed
Attached Properties
using OutWit.Common.MVVM.WPF.Attributes;
public static partial class MyAttachedProperties
{
[AttachedProperty(DefaultValue = false)]
public static bool IsHighlighted { get; set; }
}
// Usage in XAML:
// <Button local:MyAttachedProperties.IsHighlighted="True" />
WPF Commands
using OutWit.Common.MVVM.WPF.Commands;
public class MyViewModel
{
public DelegateCommand SaveCommand { get; }
public MyViewModel()
{
SaveCommand = new DelegateCommand(
execute: _ => Save(),
canExecute: _ => CanSave());
}
private void Save() { }
private bool CanSave() => true;
}
Binding Utilities
Manual DependencyProperty registration (for when you can't use source generator):
using OutWit.Common.MVVM.WPF.Utils;
public class MyControl : Control
{
public static readonly DependencyProperty TextProperty =
BindingUtils.Register<MyControl, string>(nameof(Text), "Default");
public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
}
Visual Tree Traversal
using OutWit.Common.MVVM.WPF.Utils;
// Find first child of specific type
var button = myPanel.FindFirstChildOf<Button>();
// Find with predicate
var redButton = myPanel.FindFirstChildOf<Button>(b => b.Background == Brushes.Red);
// Find all children
var allButtons = myPanel.FindAllChildrenOf<Button>();
// Find parent
var window = myButton.FindFirstParentOf<Window>();
BindingProxy for DataContext Access
<Window.Resources>
<local:BindingProxy x:Key="Proxy" Data="{Binding}" />
</Window.Resources>
<DataGrid>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Command="{Binding Data.DeleteCommand, Source={StaticResource Proxy}}"
CommandParameter="{Binding}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGrid.Columns>
</DataGrid>
</Window.Resources>
StyledProperty Options
| Option | Type | Description |
|---|---|---|
PropertyName |
string |
Override property name (default: {Name}Property) |
DefaultValue |
object |
Default value |
BindsTwoWayByDefault |
bool |
Enable two-way binding by default |
AffectsMeasure |
bool |
Invalidate measure on change |
AffectsArrange |
bool |
Invalidate arrange on change |
AffectsRender |
bool |
Invalidate render on change |
Inherits |
bool |
Value inherited by child elements |
OnChanged |
string |
PropertyChangedCallback method name |
Coerce |
string |
CoerceValueCallback method name |
AttachedProperty Options
| Option | Type | Description |
|---|---|---|
PropertyName |
string |
Override property name |
DefaultValue |
object |
Default value |
Inherits |
bool |
Value inherited by child elements |
OnChanged |
string |
PropertyChangedCallback method name |
Coerce |
string |
CoerceValueCallback method name |
Migration from Old BindableAttribute
See Migration Guide for detailed instructions.
Quick summary:
- Change
[Bindable]to[StyledProperty] - Remove manual
DependencyPropertydeclarations - Mark class as
partial - Move options to attribute parameters
Legacy BindableAttribute (Deprecated)
The old BindableAttribute using AspectInjector is still available but deprecated:
[Obsolete("Use StyledPropertyAttribute instead")]
public class BindableAttribute : Attribute { }
Recommendation: Migrate to StyledPropertyAttribute for better IDE support and debugging.
Related Packages
OutWit.Common.MVVM- Cross-platform base classesOutWit.Common.MVVM.Avalonia- Avalonia-specific implementationOutWit.Common.MVVM.Blazor- Blazor-specific implementation
License
Licensed under the Apache License, Version 2.0. See LICENSE.
Attribution (optional)
If you use OutWit.Common.MVVM.WPF in a product, a mention is appreciated (but not required), for example: "Powered by OutWit.Common.MVVM.WPF (https://ratner.io/)".
Trademark / Project name
"OutWit" and the OutWit logo are used to identify the official project by Dmitry Ratner.
You may:
- refer to the project name in a factual way (e.g., "built with OutWit.Common.MVVM.WPF");
- use the name to indicate compatibility (e.g., "OutWit.Common.MVVM.WPF-compatible").
You may not:
- use "OutWit.Common.MVVM.WPF" as the name of a fork or a derived product in a way that implies it is the official project;
- use the OutWit.Common.MVVM.WPF logo to promote forks or derived products without permission.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0-windows7.0 is compatible. net7.0-windows was computed. net7.0-windows7.0 is compatible. net8.0-windows was computed. net8.0-windows7.0 is compatible. net9.0-windows was computed. net9.0-windows7.0 is compatible. net10.0-windows was computed. net10.0-windows7.0 is compatible. |
-
net10.0-windows7.0
- OutWit.Common.Logging (>= 1.2.3)
- OutWit.Common.MVVM (>= 2.0.2)
-
net6.0-windows7.0
- OutWit.Common.Logging (>= 1.2.3)
- OutWit.Common.MVVM (>= 2.0.2)
-
net7.0-windows7.0
- OutWit.Common.Logging (>= 1.2.3)
- OutWit.Common.MVVM (>= 2.0.2)
-
net8.0-windows7.0
- OutWit.Common.Logging (>= 1.2.3)
- OutWit.Common.MVVM (>= 2.0.2)
-
net9.0-windows7.0
- OutWit.Common.Logging (>= 1.2.3)
- OutWit.Common.MVVM (>= 2.0.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.