![]() |
VOOZH | about |
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" />Directory.Packages.props
<PackageReference Include="OutWit.Common.MVVM.WPF" />Project file
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.4Install as a Cake Addin
#tool nuget:?package=OutWit.Common.MVVM.WPF&version=2.0.4Install as a Cake Tool
WPF-specific MVVM components and utilities, including source generator for automatic DependencyProperty generation.
Command and DelegateCommand with CommandManager integrationBindableAttribute for backward compatibilitydotnet 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.LoggingThe 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 = ...;
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
}
}
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:
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" />
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;
}
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);
}
}
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>();
<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>
| 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 |
| 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 |
See for detailed instructions.
Quick summary:
[Bindable] to [StyledProperty]DependencyProperty declarationspartialThe 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.
OutWit.Common.MVVM - Cross-platform base classesOutWit.Common.MVVM.Avalonia - Avalonia-specific implementationOutWit.Common.MVVM.Blazor - Blazor-specific implementationLicensed under the Apache License, Version 2.0. See LICENSE.
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/)".
"OutWit" and the OutWit logo are used to identify the official project by Dmitry Ratner.
You may:
You may not:
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0-windows7.0 net6.0-windows7.0 is compatible. net7.0-windows net7.0-windows was computed. net7.0-windows7.0 net7.0-windows7.0 is compatible. net8.0-windows net8.0-windows was computed. net8.0-windows7.0 net8.0-windows7.0 is compatible. net9.0-windows net9.0-windows was computed. net9.0-windows7.0 net9.0-windows7.0 is compatible. net10.0-windows net10.0-windows was computed. net10.0-windows7.0 net10.0-windows7.0 is compatible. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.