TextBoxInputMaskBehavior涵盖了该值

时间:2015-06-01 06:40:45

标签: c# wpf xaml

我有一个Ip地址的TextBoxInputMaskBehavior,如下所示: enter image description here
和xaml代码:

<UserControl x:Class="Customizing.Views.IpRangeFields"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:ig="http://schemas.infragistics.com/xaml"
             xmlns:local="clr-namespace:Customizing.Views"
             xmlns:net="clr-namespace:System.Net;assembly=System"
             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
             xmlns:behaviors="clr-namespace:Customizing.Behaviors"
             xmlns:system="clr-namespace:System;assembly=mscorlib"
             mc:Ignorable="d"
             x:Name="Uc"
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.Resources>
        <system:String x:Key="InputMaskIp">000.000.000.000</system:String>
    </UserControl.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="60" />
            <RowDefinition Height="10" />
            <RowDefinition Height="60" />
            <RowDefinition Height="10" />
            <RowDefinition Height="60" />
            <RowDefinition Height="10" />
            <RowDefinition Height="60" />
            <RowDefinition Height="10" />
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="2.5*" />
        </Grid.ColumnDefinitions>

        <Label Grid.Row="0" Grid.Column="0" Content="Start" VerticalContentAlignment="Center" FontSize="18"
               HorizontalContentAlignment="Center" FontWeight="Bold" />
        <Label Grid.Row="2" Grid.Column="0" Content="End" VerticalContentAlignment="Center" FontSize="18"
               HorizontalContentAlignment="Center" FontWeight="Bold" />
        <Label Grid.Row="4" Grid.Column="0" Content="Subnet" VerticalContentAlignment="Center" FontSize="18"
               HorizontalContentAlignment="Center" FontWeight="Bold" />
        <Label Grid.Row="6" Grid.Column="0" Content="Gateway" VerticalContentAlignment="Center" FontSize="18"
               HorizontalContentAlignment="Center" FontWeight="Bold" />

        <TextBox VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Grid.Row="0" Grid.Column="1"
                 FontSize="22" Validation.Error="_ValidationError">
            <TextBox.Text>
                <Binding ElementName="Uc" Path="Start" ValidatesOnNotifyDataErrors="True"
                         UpdateSourceTrigger="PropertyChanged"
                         NotifyOnValidationError="true">
                    <Binding.ValidationRules>
                        <local:IpAddressRule />
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
            <i:Interaction.Behaviors>
                <behaviors:TextBoxInputMaskBehavior InputMask="{StaticResource InputMaskIp}" PromptChar="0" />
            </i:Interaction.Behaviors>
        </TextBox>

        <TextBox VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Grid.Row="2" Grid.Column="1"
                 FontSize="22" Validation.Error="_ValidationError">
            <Binding ElementName="Uc" Path="End" ValidatesOnNotifyDataErrors="True"
                     UpdateSourceTrigger="PropertyChanged"
                     NotifyOnValidationError="true">
                <Binding.ValidationRules>
                    <local:IpAddressRule />
                </Binding.ValidationRules>
            </Binding>
            <i:Interaction.Behaviors>
                <behaviors:TextBoxInputMaskBehavior InputMask="{StaticResource InputMaskIp}" PromptChar="0" />
            </i:Interaction.Behaviors>
        </TextBox>

        <TextBox VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Grid.Row="4" Grid.Column="1"
                 FontSize="22" Validation.Error="_ValidationError">
            <TextBox.Text>
                <Binding ElementName="Uc" Path="Subnet" ValidatesOnNotifyDataErrors="True"
                         UpdateSourceTrigger="PropertyChanged"
                         NotifyOnValidationError="true">
                    <Binding.ValidationRules>
                        <local:IpAddressRule />
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
            <i:Interaction.Behaviors>
                <behaviors:TextBoxInputMaskBehavior InputMask="{StaticResource InputMaskIp}" PromptChar="0" />
            </i:Interaction.Behaviors>
        </TextBox>

        <TextBox VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Grid.Row="6" Grid.Column="1"
                 FontSize="22" Validation.Error="_ValidationError">
            <TextBox.Text>
                <Binding ElementName="Uc" Path="Gateway" ValidatesOnNotifyDataErrors="True"
                         UpdateSourceTrigger="PropertyChanged"
                         NotifyOnValidationError="true">
                    <Binding.ValidationRules>
                        <local:IpAddressRule />
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
            <i:Interaction.Behaviors>
                <behaviors:TextBoxInputMaskBehavior InputMask="{StaticResource InputMaskIp}" PromptChar="0" />
            </i:Interaction.Behaviors>
        </TextBox>

    </Grid>
</UserControl>

和背后的代码:

using System.Globalization;
using System.Net;
using System.Windows;
using System.Windows.Controls;

namespace Customizing.Views
{
    /// <summary>
    ///     Interaction logic for IpRangeFields.xaml
    /// </summary>
    public partial class IpRangeFields : UserControl
    {
        public static readonly DependencyProperty StartProperty = DependencyProperty.Register("Start", typeof (string),
            typeof (IpRangeFields), new PropertyMetadata(null));

        public static readonly DependencyProperty EndProperty = DependencyProperty.Register("End", typeof (string),
            typeof (IpRangeFields), new PropertyMetadata(null));

        public static readonly DependencyProperty SubnetProperty = DependencyProperty.Register("Subnet", typeof (string),
            typeof (IpRangeFields), new PropertyMetadata(null));

        public static readonly DependencyProperty GatewayProperty = DependencyProperty.Register("Gateway",
            typeof (string),
            typeof (IpRangeFields), new PropertyMetadata(null));

        // Register the routed event
        public static readonly RoutedEvent ErrorEvent =
            EventManager.RegisterRoutedEvent("Error", RoutingStrategy.Bubble,
                typeof (RoutedEventHandler), typeof (IpRangeFields));

        public IpRangeFields()
        {
            InitializeComponent();
        }

        public string Start
        {
            get { return (string) GetValue(StartProperty); }
            set { SetValue(StartProperty, value); }
        }

        public string End
        {
            get { return (string) GetValue(EndProperty); }
            set { SetValue(EndProperty, value); }
        }

        public string Subnet
        {
            get { return (string) GetValue(SubnetProperty); }
            set { SetValue(SubnetProperty, value); }
        }

        public string Gateway
        {
            get { return (string) GetValue(GatewayProperty); }
            set { SetValue(GatewayProperty, value); }
        }

        public event RoutedEventHandler Error
        {
            add { AddHandler(ErrorEvent, value); }
            remove { RemoveHandler(ErrorEvent, value); }
        }

        private void _ValidationError(object sender, ValidationErrorEventArgs e)
        {
            RaiseEvent(new RoutedEventArgs(ErrorEvent, sender));
        }
    }

    public class IpAddressRule : ValidationRule
    {
        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            IPAddress ip;
            if (!IPAddress.TryParse(value.ToString(), out ip))
            {
                return new ValidationResult(false, "IP address is not valid.");
            }

            return new ValidationResult(true, null);
        }
    }
}

我的问题就像您在图片上看到的那样,只有子网字段显示值,但其他三个字段没有。

我确定
<behaviors:TextBoxInputMaskBehavior InputMask="{StaticResource InputMaskIp}" PromptChar="0" />

掩盖了三个字段的值,因此无法看到这些值 令我困惑的是,为什么子网字段上的值会出现?我在其他三个领域做错了什么?

Textboxmask类:

using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace Customizing.Behaviors
{
    /// <summary>
    ///     InputMask for Textbox with 2 Properties: <see cref="InputMask" />, <see cref="PromptChar" />.
    /// </summary>
    public class TextBoxInputMaskBehavior : Behavior<TextBox>
    {
        public MaskedTextProvider Provider { get; private set; }

        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.Loaded += AssociatedObjectLoaded;
            AssociatedObject.PreviewTextInput += AssociatedObjectPreviewTextInput;
            AssociatedObject.PreviewKeyDown += AssociatedObjectPreviewKeyDown;

            DataObject.AddPastingHandler(AssociatedObject, Pasting);
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.Loaded -= AssociatedObjectLoaded;
            AssociatedObject.PreviewTextInput -= AssociatedObjectPreviewTextInput;
            AssociatedObject.PreviewKeyDown -= AssociatedObjectPreviewKeyDown;

            DataObject.RemovePastingHandler(AssociatedObject, Pasting);
        }

        /*
        Mask Character  Accepts  Required?  
        0  Digit (0-9)  Required  
        9  Digit (0-9) or space  Optional  
        #  Digit (0-9) or space  Required  
        L  Letter (a-z, A-Z)  Required  
        ?  Letter (a-z, A-Z)  Optional  
        &  Any character  Required  
        C  Any character  Optional  
        A  Alphanumeric (0-9, a-z, A-Z)  Required  
        a  Alphanumeric (0-9, a-z, A-Z)  Optional  
           Space separator  Required 
        .  Decimal separator  Required  
        ,  Group (thousands) separator  Required  
        :  Time separator  Required  
        /  Date separator  Required  
        $  Currency symbol  Required  

        In addition, the following characters have special meaning:

        Mask Character  Meaning  
        <  All subsequent characters are converted to lower case  
        >  All subsequent characters are converted to upper case  
        |  Terminates a previous < or >  
        \  Escape: treat the next character in the mask as literal text rather than a mask symbol  

        */

        private void AssociatedObjectLoaded(object sender, RoutedEventArgs e)
        {
            Provider = new MaskedTextProvider(InputMask, CultureInfo.CurrentCulture);
            Provider.Set(AssociatedObject.Text);
            Provider.PromptChar = PromptChar;
            AssociatedObject.Text = Provider.ToDisplayString();

            //seems the only way that the text is formatted correct, when source is updated
            var textProp = DependencyPropertyDescriptor.FromProperty(TextBox.TextProperty, typeof (TextBox));
            if (textProp != null)
            {
                textProp.AddValueChanged(AssociatedObject, (s, args) => UpdateText());
            }
        }

        private void AssociatedObjectPreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            TreatSelectedText();

            var position = GetNextCharacterPosition(AssociatedObject.SelectionStart);

            if (Keyboard.IsKeyToggled(Key.Insert))
            {
                if (Provider.Replace(e.Text, position))
                    position++;
            }
            else
            {
                if (Provider.InsertAt(e.Text, position))
                    position++;
            }

            position = GetNextCharacterPosition(position);

            RefreshText(position);

            e.Handled = true;
        }

        private void AssociatedObjectPreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Space) //handle the space
            {
                TreatSelectedText();

                var position = GetNextCharacterPosition(AssociatedObject.SelectionStart);

                if (Provider.InsertAt(" ", position))
                    RefreshText(position);

                e.Handled = true;
            }

            if (e.Key == Key.Back) //handle the back space
            {
                if (TreatSelectedText())
                {
                    RefreshText(AssociatedObject.SelectionStart);
                }
                else
                {
                    if (AssociatedObject.SelectionStart != 0)
                    {
                        if (Provider.RemoveAt(AssociatedObject.SelectionStart - 1))
                            RefreshText(AssociatedObject.SelectionStart - 1);
                    }
                }

                e.Handled = true;
            }

            if (e.Key == Key.Delete) //handle the delete key
            {
                //treat selected text
                if (TreatSelectedText())
                {
                    RefreshText(AssociatedObject.SelectionStart);
                }
                else
                {
                    if (Provider.RemoveAt(AssociatedObject.SelectionStart))
                        RefreshText(AssociatedObject.SelectionStart);
                }

                e.Handled = true;
            }
        }

        /// <summary>
        ///     Pasting prüft ob korrekte Daten reingepastet werden
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Pasting(object sender, DataObjectPastingEventArgs e)
        {
            if (e.DataObject.GetDataPresent(typeof (string)))
            {
                var pastedText = (string) e.DataObject.GetData(typeof (string));

                TreatSelectedText();

                var position = GetNextCharacterPosition(AssociatedObject.SelectionStart);

                if (Provider.InsertAt(pastedText, position))
                {
                    RefreshText(position);
                }
            }

            e.CancelCommand();
        }

        private void UpdateText()
        {
            //check Provider.Text + TextBox.Text
            if (Provider.ToDisplayString().Equals(AssociatedObject.Text))
                return;

            //use provider to format
            var success = Provider.Set(AssociatedObject.Text);

            //ui and mvvm/codebehind should be in sync
            SetText(success ? Provider.ToDisplayString() : AssociatedObject.Text);
        }

        /// <summary>
        ///     Falls eine Textauswahl vorliegt wird diese entsprechend behandelt.
        /// </summary>
        /// <returns>true Textauswahl behandelt wurde, ansonsten falls </returns>
        private bool TreatSelectedText()
        {
            if (AssociatedObject.SelectionLength > 0)
            {
                return Provider.RemoveAt(AssociatedObject.SelectionStart,
                    AssociatedObject.SelectionStart + AssociatedObject.SelectionLength - 1);
            }
            return false;
        }

        private void RefreshText(int position)
        {
            SetText(Provider.ToDisplayString());
            AssociatedObject.SelectionStart = position;
        }

        private void SetText(string text)
        {
            AssociatedObject.Text = string.IsNullOrWhiteSpace(text) ? string.Empty : text;
        }

        private int GetNextCharacterPosition(int startPosition)
        {
            var position = Provider.FindEditPositionFrom(startPosition, true);

            if (position == -1)
                return startPosition;
            return position;
        }

        #region DependencyProperties

        public static readonly DependencyProperty InputMaskProperty =
            DependencyProperty.Register("InputMask", typeof (string), typeof (TextBoxInputMaskBehavior), null);

        public string InputMask
        {
            get { return (string) GetValue(InputMaskProperty); }
            set { SetValue(InputMaskProperty, value); }
        }

        public static readonly DependencyProperty PromptCharProperty =
            DependencyProperty.Register("PromptChar", typeof (char), typeof (TextBoxInputMaskBehavior),
                new PropertyMetadata('_'));

        public char PromptChar
        {
            get { return (char) GetValue(PromptCharProperty); }
            set { SetValue(PromptCharProperty, value); }
        }

        #endregion
    }
}

2 个答案:

答案 0 :(得分:1)

如果我正在解决这个问题,并且我想要一个带有IP地址的屏蔽文本框,我将自定义附加属性替换为另一家公司,如DevExpress或Telerik。

在我看来,much simpler to use one line of XAML解决了这个问题。

免责声明:我与这两家公司没有任何关系。

答案 1 :(得分:1)

我复制了你的代码,它运行没有错误。

设置值(ipRange是您的控件):

ipRange.Start = "123.456.789.000";
ipRange.End = "123.456.789.000";
ipRange.Subnet = "123.456.789.000";
ipRange.Gateway = "123.456.789.000";

结果:

Screenshot

我认为,绑定或其他问题,但不能控制。

一条评论。将您的掩码从000.000.000.000更改为000\.000\.000\.000,因为.是小数点分隔符(在我的国家/地区,它是逗号,而不是点,因此您可以在文化支持方面遇到麻烦)。