2011-08-18 78 views
0

我寫了一個小的附加屬性叫做「的IsValid」爲WPF文本框,就像這樣:這裏無法獲得的DependencyProperty工作

public enum InputTypes 
{ 
    Any, 

    Integer, 

    Double, 

    Float 
} 

/// <summary> 
/// This attached property can be used to validate input for <see cref="TextBox"/>. 
/// </summary> 
public class IsValid : DependencyObject 
{ 
    public static readonly DependencyProperty InputProperty = DependencyProperty.Register(
     "Input", 
     typeof(InputTypes), 
     typeof(IsValid), 
     new UIPropertyMetadata(InputTypes.Any, onInput)); 

    public static InputTypes GetInput(DependencyObject d) 
    { 
     return (InputTypes)d.GetValue(InputProperty); 
    } 

    public static void SetInput(DependencyObject d, InputTypes value) 
    { 
     d.SetValue(InputProperty, value); 
    } 

    private static void onInput(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var textBox = (TextBox)d; 
     var value = (InputTypes)e.NewValue; 
     switch (value) 
     { 
      case InputTypes.Any: 
       textBox.PreviewTextInput -= validateInput; 
       textBox.PreviewKeyDown -= validateKeyDown; 
       break; 

      default: 
       textBox.PreviewTextInput += validateInput; 
       textBox.PreviewKeyDown += validateKeyDown; 
       break; 
     } 
    } 

    private static void validateInput(object sender, TextCompositionEventArgs e) 
    { 
     // enforce numeric input when configured ... 
     var textBox = (TextBox) sender; 
     var inputTypes = (InputTypes) textBox.GetValue(InputProperty); 
     foreach (var c in e.Text) 
     { 
      switch (inputTypes) 
      { 
       case InputTypes.Integer: 
        if (!char.IsDigit(c)) 
        { 
         e.Handled = true; 
         return; 
        } 
        break; 

       case InputTypes.Double: 
       case InputTypes.Float: 
        if (!char.IsNumber(c)) 
        { 
         e.Handled = true; 
         return; 
        } 
        break; 

       default: 
        throw new ArgumentOutOfRangeException(); 
      } 
     } 
    } 

    private static void validateKeyDown(object sender, KeyEventArgs e) 
    { 
     // block [SPACE] when numeric input is expected ... 
     var textBox = (TextBox)sender; 
     var inputTypes = (InputTypes)textBox.GetValue(InputProperty); 
     if (inputTypes != InputTypes.Any && e.Key == Key.Space) 
      e.Handled = true; 
    } 
} 

末是如何我已經用它:

<Window x:Class="Spike.Wpf.Controls.TestApp.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:values="clr-namespace:Spike.Wpf.Controls.Input;assembly=Spike.Wpf.Controls" 
    Title="MainWindow" Height="350" Width="525"> 
<Grid> 
    <TextBox values:IsValid.Input="Double" /> 
</Grid> 

在初始化(DependencyProperty的)初始化後,IsValid中沒有任何方法被調用。我錯過了什麼?

+0

你可以驗證屬性被越來越賦予'InputTypes.Double'而不是字符串'「雙師型」'? – Rachel

+0

我會再看看你對輸入的處理。我不認爲你的支票正在做你認爲他們的。 http://stackoverflow.com/questions/228532/difference-between-char-isdigit-and-char-isnumber-in-c –

+0

@Rachel:是的,解決了這個問題(看到答案)我可以非常認真的獲得預期的價值。 WPF負責解析。 @Brent:的確,你是對的。我也意識到我的解決方案是不夠的。只需指定「double」或「integer」是不夠的。我還需要指定允許的小數位數以及通常的最小值和最大值。所以,我決定繼續並建立幾個'MarkupExtension'類。由此產生的語法非常愉快。我對WPF很新,但到目前爲止,我不得不說它非常強大... –

回答

2

此前你可能有一個錯誤,告訴你IsValid需要從DependecyObject派生,所以你補充說,你應該問自己爲什麼這樣。答案就在這裏:

public static readonly DependencyProperty InputProperty = DependencyProperty.Register(... 

您嘗試註冊在IsValid類型的對象正常的財產,將其更改爲RegisterAttached,它應該工作。 (我也想刪除的繼承,使IsValid靜態類)

+0

Duh!我感覺就像一個混帳。謝謝! :O) –

0

好了,問題的核心是微不足道的(見接受的答案):我需要調用DependencyProperty.RegisterAttached(...)(相對於DependencyProperty.Register(...)

剛。想和大家分享的結果,我決定放棄使用簡單enum指定的輸入類型和決定使用標記擴展,而不是

附加屬性的實現,現在看起來是這樣的:

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); 
    } 
} 

而這裏的標記擴展類的一部分:

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) && 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 
    } 
} 

最終的結果,在XAML,是相當不錯的,易於閱讀...

<TextBox v:IsValid.Input="{v:Numeric Minimum=0, Maximum=99, Decimals=0}" /> 

這一切似乎工作,我希望。感謝所有輸入

乾杯

/喬納斯