如何在<div class="col-md-6 fieldHeight">
<div class="form-group">
<label for="issueFromDate" class="col-md-5">Issue Date
Range:</label>
<div class="col-md-7">
<div class="row">
<div class="col-md-5 changeWdh">
<input type="text" class="form-control"
ng-model="riskAssessmentDTO.issueFromDate"
name="issueFromDate" id="issueFromDate" disabled />
</div>
<div class="col-md-1">
<label class="control-label padd15"> To:</label>
</div>
<div class="col-md-5 changeWdh">
<input type="text" class="form-control"
ng-model="riskAssessmentDTO.issueToDate" name="issueToDate"
id="issueToDate" disabled />
</div>
</div>
</div>
</div>
</div>
中创建类似于Windows IP地址字段的numeric Masked TextBox
,在点击WPF
按钮后跳转到下一个区域
答案 0 :(得分:19)
我为此使用了UserControl
。我确定它不是最完美的一个,但也许这对你来说是一个很好的起点。
UserControl
XAML:
<UserControl x:Class="IPTextBoxDemo.IPTextBox"
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"
mc:Ignorable="d"
d:DesignHeight="50" d:DesignWidth="300"
FocusManager.IsFocusScope="True">
<UserControl.Resources>
<Style x:Key="{x:Type TextBox}" TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBoxBase">
<Border BorderThickness="{TemplateBinding Border.BorderThickness}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}"
Name="border"
SnapsToDevicePixels="True">
<ScrollViewer HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
Name="PART_ContentHost"
Focusable="False" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" TargetName="border" Value="0.56" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBox x:Name="FirstSegment" Grid.Column="0" TextAlignment="Center" MaxLength="3" BorderThickness="1,1,0,1" VerticalContentAlignment="Center"
TextChanged="TextBoxBase_OnTextChanged" PreviewKeyDown="UIElement_OnPreviewKeyDown" DataObject.Pasting="DataObject_OnPasting" />
<TextBox Grid.Column="1" Text="." TextAlignment="Center" IsReadOnly="True" Focusable="False" BorderThickness="0,1,0,1" VerticalContentAlignment="Center"
IsReadOnlyCaretVisible="False"/>
<TextBox x:Name="SecondSegment" Grid.Column="2" TextAlignment="Center" MaxLength="3" BorderThickness="0,1,0,1" VerticalContentAlignment="Center"
TextChanged="TextBoxBase_OnTextChanged" PreviewKeyDown="UIElement_OnPreviewKeyDown" DataObject.Pasting="DataObject_OnPasting" />
<TextBox Grid.Column="3" Text="." TextAlignment="Center" IsReadOnly="True" Focusable="False" BorderThickness="0,1,0,1" VerticalContentAlignment="Center"
IsReadOnlyCaretVisible="False"/>
<TextBox x:Name="ThirdSegment" Grid.Column="4" TextAlignment="Center" MaxLength="3" BorderThickness="0,1,0,1" VerticalContentAlignment="Center"
TextChanged="TextBoxBase_OnTextChanged" PreviewKeyDown="UIElement_OnPreviewKeyDown" DataObject.Pasting="DataObject_OnPasting" />
<TextBox Grid.Column="5" Text="." TextAlignment="Center" IsReadOnly="True" Focusable="False" BorderThickness="0,1,0,1" VerticalContentAlignment="Center"
IsReadOnlyCaretVisible="False" />
<TextBox x:Name="LastSegment" Grid.Column="6" TextAlignment="Center" MaxLength="3" BorderThickness="0,1,1,1" VerticalContentAlignment="Center"
TextChanged="TextBoxBase_OnTextChanged" PreviewKeyDown="UIElement_OnPreviewKeyDown" DataObject.Pasting="DataObject_OnPasting" />
</Grid>
</UserControl>
XAML由一个主Grid
组成,其中有七列,其中四列用于TextBox
es,您将输入您的号码,三个用于IP地址中的固定点。
UserControl
代码隐藏:
namespace IPTextBoxDemo
{
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
/// <summary>
/// Interaction logic for IPTextBox.xaml
/// </summary>
public partial class IPTextBox : UserControl
{
private static readonly List<Key> DigitKeys = new List<Key> { Key.D0, Key.D1, Key.D2, Key.D3, Key.D4, Key.D5, Key.D6, Key.D7, Key.D8, Key.D9 };
private static readonly List<Key> MoveForwardKeys = new List<Key> { Key.Right };
private static readonly List<Key> MoveBackwardKeys = new List<Key> { Key.Left };
private static readonly List<Key> OtherAllowedKeys = new List<Key> { Key.Tab, Key.Delete };
private readonly List<TextBox> _segments = new List<TextBox>();
private bool _suppressAddressUpdate = false;
public IPTextBox()
{
InitializeComponent();
_segments.Add(FirstSegment);
_segments.Add(SecondSegment);
_segments.Add(ThirdSegment);
_segments.Add(LastSegment);
}
public static readonly DependencyProperty AddressProperty = DependencyProperty.Register(
"Address", typeof (string), typeof (IPTextBox), new FrameworkPropertyMetadata(default(string), AddressChanged)
{
BindsTwoWayByDefault = true
});
private static void AddressChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
var ipTextBox = dependencyObject as IPTextBox;
var text = e.NewValue as string;
if (text != null && ipTextBox != null)
{
ipTextBox._suppressAddressUpdate = true;
var i = 0;
foreach (var segment in text.Split('.'))
{
ipTextBox._segments[i].Text = segment;
i++;
}
ipTextBox._suppressAddressUpdate = false;
}
}
public string Address
{
get { return (string) GetValue(AddressProperty); }
set { SetValue(AddressProperty, value); }
}
private void UIElement_OnPreviewKeyDown(object sender, KeyEventArgs e)
{
if (DigitKeys.Contains(e.Key))
{
e.Handled = ShouldCancelDigitKeyPress();
HandleDigitPress();
}
else if(MoveBackwardKeys.Contains(e.Key))
{
e.Handled = ShouldCancelBackwardKeyPress();
HandleBackwardKeyPress();
}
else if (MoveForwardKeys.Contains(e.Key))
{
e.Handled = ShouldCancelForwardKeyPress();
HandleForwardKeyPress();
} else if (e.Key == Key.Back)
{
HandleBackspaceKeyPress();
}
else if (e.Key == Key.OemPeriod)
{
e.Handled = true;
HandlePeriodKeyPress();
}
else
{
e.Handled = !AreOtherAllowedKeysPressed(e);
}
}
private bool AreOtherAllowedKeysPressed(KeyEventArgs e)
{
return e.Key == Key.C && ((e.KeyboardDevice.Modifiers & ModifierKeys.Control) != 0) ||
e.Key == Key.V && ((e.KeyboardDevice.Modifiers & ModifierKeys.Control) != 0) ||
e.Key == Key.A && ((e.KeyboardDevice.Modifiers & ModifierKeys.Control) != 0) ||
e.Key == Key.X && ((e.KeyboardDevice.Modifiers & ModifierKeys.Control) != 0) ||
OtherAllowedKeys.Contains(e.Key);
}
private void HandleDigitPress()
{
var currentTextBox = FocusManager.GetFocusedElement(this) as TextBox;
if (currentTextBox != null && currentTextBox.Text.Length == 3 &&
currentTextBox.CaretIndex == 3 && currentTextBox.SelectedText.Length == 0)
{
MoveFocusToNextSegment(currentTextBox);
}
}
private bool ShouldCancelDigitKeyPress()
{
var currentTextBox = FocusManager.GetFocusedElement(this) as TextBox;
return currentTextBox != null &&
currentTextBox.Text.Length == 3 &&
currentTextBox.CaretIndex == 3 &&
currentTextBox.SelectedText.Length == 0;
}
private void TextBoxBase_OnTextChanged(object sender, TextChangedEventArgs e)
{
if (!_suppressAddressUpdate)
{
Address = string.Format("{0}.{1}.{2}.{3}", FirstSegment.Text, SecondSegment.Text, ThirdSegment.Text, LastSegment.Text);
}
var currentTextBox = FocusManager.GetFocusedElement(this) as TextBox;
if (currentTextBox != null && currentTextBox.Text.Length == 3 && currentTextBox.CaretIndex == 3)
{
MoveFocusToNextSegment(currentTextBox);
}
}
private bool ShouldCancelBackwardKeyPress()
{
var currentTextBox = FocusManager.GetFocusedElement(this) as TextBox;
return currentTextBox != null && currentTextBox.CaretIndex == 0;
}
private void HandleBackspaceKeyPress()
{
var currentTextBox = FocusManager.GetFocusedElement(this) as TextBox;
if (currentTextBox != null && currentTextBox.CaretIndex == 0 && currentTextBox.SelectedText.Length == 0)
{
MoveFocusToPreviousSegment(currentTextBox);
}
}
private void HandleBackwardKeyPress()
{
var currentTextBox = FocusManager.GetFocusedElement(this) as TextBox;
if (currentTextBox != null && currentTextBox.CaretIndex == 0)
{
MoveFocusToPreviousSegment(currentTextBox);
}
}
private bool ShouldCancelForwardKeyPress()
{
var currentTextBox = FocusManager.GetFocusedElement(this) as TextBox;
return currentTextBox != null && currentTextBox.CaretIndex == 3;
}
private void HandleForwardKeyPress()
{
var currentTextBox = FocusManager.GetFocusedElement(this) as TextBox;
if (currentTextBox != null && currentTextBox.CaretIndex == currentTextBox.Text.Length)
{
MoveFocusToNextSegment(currentTextBox);
}
}
private void HandlePeriodKeyPress()
{
var currentTextBox = FocusManager.GetFocusedElement(this) as TextBox;
if (currentTextBox != null && currentTextBox.Text.Length > 0 && currentTextBox.CaretIndex == currentTextBox.Text.Length)
{
MoveFocusToNextSegment(currentTextBox);
}
}
private void MoveFocusToPreviousSegment(TextBox currentTextBox)
{
if (!ReferenceEquals(currentTextBox, FirstSegment))
{
var previousSegmentIndex = _segments.FindIndex(box => ReferenceEquals(box, currentTextBox)) - 1;
currentTextBox.SelectionLength = 0;
currentTextBox.MoveFocus(new TraversalRequest(FocusNavigationDirection.Previous));
_segments[previousSegmentIndex].CaretIndex = _segments[previousSegmentIndex].Text.Length;
}
}
private void MoveFocusToNextSegment(TextBox currentTextBox)
{
if (!ReferenceEquals(currentTextBox, LastSegment))
{
currentTextBox.SelectionLength = 0;
currentTextBox.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
}
private void DataObject_OnPasting(object sender, DataObjectPastingEventArgs e)
{
var isText = e.SourceDataObject.GetDataPresent(DataFormats.UnicodeText, true);
if (!isText)
{
e.CancelCommand();
return;
}
var text = e.SourceDataObject.GetData(DataFormats.UnicodeText) as string;
int num;
if (!int.TryParse(text, out num))
{
e.CancelCommand();
}
}
}
}
代码隐藏主要处理不同的事件:
依旧等等。
用法如下:
<ipTextBoxDemo:IPTextBox Width="150" Address="{Binding AddressInVM}"></ipTextBoxDemo:IPTextBox>
正如您所看到的,UserControl
公开了一个名为string
的{{1}}属性(默认情况下绑定为双向)。
如果绑定的来源发生变化(此处Address
,那么来自VM的更改)则AddressInVm
将按点分割文本,并将结果值放入四个{{ 1}} ES。
如果绑定的目标发生变化(用户输入框中的某些内容),则会发现四个UserControl
es&#39; TextBox
属性将被连接。
为了使这一点正确,你还必须实现验证,因为TextBox
中没有这个,但我把它留给你作为练习;)
结果: