這篇文章將為大家詳細講解有關(guān)WPF如何自定義實現(xiàn)IP地址輸入控件,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
成都創(chuàng)新互聯(lián)堅信:善待客戶,將會成為終身客戶。我們能堅持多年,是因為我們一直可值得信賴。我們從不忽悠初訪客戶,我們用心做好本職工作,不忘初心,方得始終。十年網(wǎng)站建設(shè)經(jīng)驗成都創(chuàng)新互聯(lián)是成都老牌網(wǎng)站營銷服務(wù)商,為您提供成都網(wǎng)站建設(shè)、成都網(wǎng)站制作、網(wǎng)站設(shè)計、H5網(wǎng)站設(shè)計、網(wǎng)站制作、品牌網(wǎng)站制作、微信小程序開發(fā)服務(wù),給眾多知名企業(yè)提供過好品質(zhì)的建站服務(wù)。一、前言
WPF沒有內(nèi)置IP地址輸入控件,因此我們需要通過自己定義實現(xiàn)。
我們先看一下IP地址輸入控件有什么特性:
輸滿三個數(shù)字焦點會往右移 鍵盤←→可以空光標移動 任意位置可復(fù)制整段IP地址,且支持x.x.x.x格式的粘貼賦值 刪除字符會自動向左移動焦點
知道以上特性,我們就可以開始動手了。
二、構(gòu)成
Grid+TextBox*4+TextBlock*3
通過這幾個控件的組合,我們完成IP地址輸入控件的功能。
界面代碼如下:
三、驗證輸入格式
界面中為TextBox添加了CustomTextBoxTextStyle及validationTemplate樣式,當輸入格式不正確時,控件就會應(yīng)用該樣式。
通過自定義規(guī)則IPRangeValidationRule來驗證輸入的內(nèi)容格式是否要求。
自定義規(guī)則代碼如下:
public class IPRangeValidationRule : ValidationRule{ private int _min; private int _max; public int Min { get { return _min; } set { _min = value; } } public int Max { get { return _max; } set { _max = value; } } public override ValidationResult Validate(object value, CultureInfo cultureInfo) { int val = 0; var strVal = (string)value; try { if (strVal.Length > 0) { if (strVal.EndsWith(".")) { return CheckRanges(strVal.Replace(".", "")); } // Allow dot character to move to next box return CheckRanges(strVal); } } catch (Exception e) { return new ValidationResult(false, "Illegal characters or " + e.Message); } if ((val < Min) || (val > Max)) { return new ValidationResult(false, "Please enter the value in the range: " + Min + " - " + Max + "."); } else { return ValidationResult.ValidResult; } } private ValidationResult CheckRanges(string strVal) { if (int.TryParse(strVal, out var res)) { if ((res < Min) || (res > Max)) { return new ValidationResult(false, "Please enter the value in the range: " + Min + " - " + Max + "."); } else { return ValidationResult.ValidResult; } } else { return new ValidationResult(false, "Illegal characters entered"); } }}
四、控制焦點變化
在界面代碼中我通過local:FocusChangeExtension.IsFocused附加屬性實現(xiàn)綁定屬性控制焦點的變化。
附加屬性的代碼如下:
public static class FocusChangeExtension{ public static bool GetIsFocused(DependencyObject obj) { return (bool)obj.GetValue(IsFocusedProperty); } public static void SetIsFocused(DependencyObject obj, bool value) { obj.SetValue(IsFocusedProperty, value); } public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.RegisterAttached( "IsFocused", typeof(bool), typeof(FocusChangeExtension), new UIPropertyMetadata(false, OnIsFocusedPropertyChanged)); private static void OnIsFocusedPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e) { var control = (UIElement)d; if ((bool)e.NewValue) { control.Focus(); } }}
五、VM+后臺代碼混合實現(xiàn)焦點控制及內(nèi)容復(fù)制粘貼
1、后臺代碼主要實現(xiàn)復(fù)制粘貼內(nèi)容,另外←→移動光標也需要后臺代碼控制。通過PreviewKeyDown事件捕獲鍵盤左移右移,復(fù)制,刪除等事件,做出相應(yīng)處理:
private void Part2_KeyDown(object sender, System.Windows.Input.KeyEventArgs e){ if (e.Key == Key.Back && part2.Text == "") { part1.Focus(); } if (e.Key == Key.Right && part2.CaretIndex == part2.Text.Length) { part3.Focus(); e.Handled = true; } if (e.Key == Key.Left && part2.CaretIndex == 0) { part1.Focus(); e.Handled = true; } if (e.KeyboardDevice.Modifiers.HasFlag(ModifierKeys.Control) && e.Key == Key.C) { if (part2.SelectionLength == 0) { var vm = this.DataContext as IpAddressViewModel; Clipboard.SetText(vm.AddressText); } }}
通過DataObject.AddPastingHandler(part1, TextBox_Pasting)添加粘貼事件。使控件賦值。
2、通過ViewModel方式實現(xiàn)屬性綁定通知,來控制焦點變化及內(nèi)容賦值。
ViewModel類要實現(xiàn)綁定通知需要實現(xiàn)INotifyPropertyChanged接口中的方法。
我們新建一個IpAddressViewModel類繼承INotifyPropertyChanged,代碼如下:
public class IpAddressViewModel : INotifyPropertyChanged{ public event EventHandler AddressChanged; public string AddressText { get { return $"{Part1??"0"}.{Part2??"0"}.{Part3??"0"}.{Part4??"0"}"; } } private bool isPart1Focused; public bool IsPart1Focused { get { return isPart1Focused; } set { isPart1Focused = value; OnPropertyChanged(); } } private string part1; public string Part1 { get { return part1; } set { part1 = value; SetFocus(true, false, false, false); var moveNext = CanMoveNext(ref part1); OnPropertyChanged(); OnPropertyChanged(nameof(AddressText)); AddressChanged?.Invoke(this, EventArgs.Empty); if (moveNext) { SetFocus(false, true, false, false); } } } private bool isPart2Focused; public bool IsPart2Focused { get { return isPart2Focused; } set { isPart2Focused = value; OnPropertyChanged(); } } private string part2; public string Part2 { get { return part2; } set { part2 = value; SetFocus(false, true, false, false); var moveNext = CanMoveNext(ref part2); OnPropertyChanged(); OnPropertyChanged(nameof(AddressText)); AddressChanged?.Invoke(this, EventArgs.Empty); if (moveNext) { SetFocus(false, false, true, false); } } } private bool isPart3Focused; public bool IsPart3Focused { get { return isPart3Focused; } set { isPart3Focused = value; OnPropertyChanged(); } } private string part3; public string Part3 { get { return part3; } set { part3 = value; SetFocus(false, false, true, false); var moveNext = CanMoveNext(ref part3); OnPropertyChanged(); OnPropertyChanged(nameof(AddressText)); AddressChanged?.Invoke(this, EventArgs.Empty); if (moveNext) { SetFocus(false, false, false, true); } } } private bool isPart4Focused; public bool IsPart4Focused { get { return isPart4Focused; } set { isPart4Focused = value; OnPropertyChanged(); } } private string part4; public string Part4 { get { return part4; } set { part4 = value; SetFocus(false, false, false, true); var moveNext = CanMoveNext(ref part4); OnPropertyChanged(); OnPropertyChanged(nameof(AddressText)); AddressChanged?.Invoke(this, EventArgs.Empty); } } public void SetAddress(string address) { if (string.IsNullOrWhiteSpace(address)) return; var parts = address.Split('.'); if (int.TryParse(parts[0], out var num0)) { Part1 = num0.ToString(); } if (int.TryParse(parts[1], out var num1)) { Part2 = parts[1]; } if (int.TryParse(parts[2], out var num2)) { Part3 = parts[2]; } if (int.TryParse(parts[3], out var num3)) { Part4 = parts[3]; } } private bool CanMoveNext(ref string part) { bool moveNext = false; if (!string.IsNullOrWhiteSpace(part)) { if (part.Length >= 3) { moveNext = true; } if (part.EndsWith(".")) { moveNext = true; part = part.Replace(".", ""); } } return moveNext; } private void SetFocus(bool part1, bool part2, bool part3, bool part4) { IsPart1Focused = part1; IsPart2Focused = part2; IsPart3Focused = part3; IsPart4Focused = part4; } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }}
到這里基本就完成了,生成控件然后到MainWindow中引用該控件
關(guān)于“WPF如何自定義實現(xiàn)IP地址輸入控件”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。