Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Ok, so the core of the problem was trivial (see accepted answer): I needed to call <code>DependencyProperty.RegisterAttached(...)</code> (as opposed to <code>DependencyProperty.Register(...)</code>.</p> <p>Just wanted to share the result. I decided to scrap the use of a simple <code>enum</code> to specify input type and decided to use markup extensions instead.</p> <p>The attached property implementation now looks like this:</p> <pre><code>public static class IsValid { public static readonly DependencyProperty InputProperty = DependencyProperty.RegisterAttached( "Input", typeof(IsValidInputExtension), typeof(IsValid), new UIPropertyMetadata(onInput)); public static IsValidInputExtension GetInput(DependencyObject d) { return (IsValidInputExtension)d.GetValue(InputProperty); } public static void SetInput(DependencyObject d, IsValidInputExtension value) { d.SetValue(InputProperty, value); } private static void onInput(DependencyObject d, DependencyPropertyChangedEventArgs e) { var textBox = (TextBox)d; var value = (IsValidInputExtension)e.NewValue; if (value == null) { textBox.PreviewTextInput -= validateInput; textBox.PreviewKeyDown -= validateKeyDown; return; } textBox.PreviewTextInput += validateInput; textBox.PreviewKeyDown += validateKeyDown; } private static void validateInput(object sender, TextCompositionEventArgs e) { // dispatch validation to specified markup class ... var textBox = (TextBox) sender; var markup = (IsValidInputExtension)textBox.GetValue(InputProperty); markup.ValidateInput(sender, e); } private static void validateKeyDown(object sender, KeyEventArgs e) { // dispatch validation to specified markup class ... var textBox = (TextBox)sender; var markup = (IsValidInputExtension)textBox.GetValue(InputProperty); markup.ValidateKeyDown(sender, e); } } </code></pre> <p>And here's part of the markup extension classes:</p> <pre><code>public abstract class IsValidInputExtension : MarkupExtension { internal abstract void ValidateInput(object sender, TextCompositionEventArgs e); internal abstract void ValidateKeyDown(object sender, KeyEventArgs e); } public class NumericExtension : IsValidInputExtension { public double Minimum { get; set; } public double Maximum { get; set; } public uint Decimals { get; set; } public override object ProvideValue(IServiceProvider serviceProvider) { return this; } internal override void ValidateInput(object sender, TextCompositionEventArgs e) { var textBox = (TextBox) sender; if (isDecimalSeparator(e.Text) &amp;&amp; Decimals == 0) { e.Handled = true; return; } // todo: honor Minimum and Maximum ... } private static bool isDecimalSeparator(string s) { return CultureInfo.CurrentUICulture.NumberFormat.CurrencyDecimalSeparator == s; } internal override void ValidateKeyDown(object sender, KeyEventArgs e) { // block [SPACE] when numeric input is expected ... e.Handled = e.Key == Key.Space; } } public class StringExtension : IsValidInputExtension { public double MaximumLength { get; set; } public override object ProvideValue(IServiceProvider serviceProvider) { return this; } internal override void ValidateInput(object sender, TextCompositionEventArgs e) { // (nop) } internal override void ValidateKeyDown(object sender, KeyEventArgs e) { // todo: honor MaximumLength here } } </code></pre> <p>The end result, in XAML, is quite nice and easy to read...</p> <pre><code>&lt;TextBox v:IsValid.Input="{v:Numeric Minimum=0, Maximum=99, Decimals=0}" /&gt; </code></pre> <p>It all seems to work as I hoped. Thanks for all input</p> <p>Cheers</p> <p>/Jonas</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload