using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace Developpez.Dotnet.Windows.Controls { /// /// Représente un contrôle qui peut être utilisé pour afficher et modifier une adresse IPv4 /// [TemplatePart(Name = "PART_AddressPart0", Type = typeof(TextBox))] [TemplatePart(Name = "PART_AddressPart1", Type = typeof(TextBox))] [TemplatePart(Name = "PART_AddressPart2", Type = typeof(TextBox))] [TemplatePart(Name = "PART_AddressPart3", Type = typeof(TextBox))] public class IPAddressBox : Control { private readonly TextBox[] _addressBoxes = new TextBox[4]; private bool _settingAddress; private bool _addressBoxChanged; static IPAddressBox() { DefaultStyleKeyProperty.OverrideMetadata(typeof(IPAddressBox), new FrameworkPropertyMetadata(typeof(IPAddressBox))); } /// /// Initialise une nouvelle instance de IPAddressBox /// public IPAddressBox() { CommandBinding copyBinding = new CommandBinding(ApplicationCommands.Copy); copyBinding.PreviewExecuted += IPAddressBox_PreviewCopy; copyBinding.Executed += delegate { }; copyBinding.PreviewCanExecute += IPAddressBox_PreviewCanCopy; this.CommandBindings.Add(copyBinding); CommandBinding pasteBinding = new CommandBinding(ApplicationCommands.Paste); pasteBinding.PreviewExecuted += IPAddressBox_PreviewPaste; pasteBinding.Executed += delegate { }; pasteBinding.PreviewCanExecute += IPAddressBox_PreviewCanPaste; this.CommandBindings.Add(pasteBinding); } /// /// Obtient ou définit la valeur de l'adresse /// public IPAddress Address { get { return (IPAddress)GetValue(AddressProperty); } set { SetValue(AddressProperty, value); } } /// /// Se produit quand la valeur de l'adresse change /// public event RoutedPropertyChangedEventHandler AddressChanged { add { AddHandler(AddressChangedEvent, value); } remove { RemoveHandler(AddressChangedEvent, value); } } /// /// Identifiant de l'évènement AddressChanged /// public static readonly RoutedEvent AddressChangedEvent = EventManager.RegisterRoutedEvent( "AddressChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(IPAddressBox)); /// /// Identifiant de la propriété Address /// public static readonly DependencyProperty AddressProperty = DependencyProperty.Register( "Address", typeof(IPAddress), typeof(IPAddressBox), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnAddressChanged)); private static void OnAddressChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { IPAddressBox box = d as IPAddressBox; if (box == null) return; IPAddress newAddress = (IPAddress)e.NewValue; IPAddress oldAddress = (IPAddress)e.OldValue; box.SetAddressCore(newAddress); if (!Equals(newAddress, oldAddress)) { var args = new RoutedPropertyChangedEventArgs(oldAddress, newAddress, AddressChangedEvent); box.OnAddressChanged(args); } } private void SetAddressCore(IPAddress address) { byte[] parts = new byte[4]; if (address != null) parts = address.GetAddressBytes(); try { _settingAddress = true; for (int i = 0; i < 4; i++) { if (_addressBoxes[i] != null) _addressBoxes[i].Text = parts[i].ToString(); } } finally { _settingAddress = false; } } /// /// Déclenche l'évènement AddressChanged /// /// Paramètres de l'évènement protected virtual void OnAddressChanged(RoutedPropertyChangedEventArgs e) { RaiseEvent(e); } /// /// Génère l'arbre visuel pour le contrôle lorsqu'un nouveau modèle est appliqué. /// public override void OnApplyTemplate() { for (int i = 0; i < 4; i++) { if (_addressBoxes[i] != null) UnsubscribeAddressBoxEvents(_addressBoxes[i]); } base.OnApplyTemplate(); for (int i = 0; i < 4; i++) { _addressBoxes[i] = Template.FindName("PART_AddressPart" + i, this) as TextBox; if (_addressBoxes[i] != null) SubscribeAddressBoxEvents(_addressBoxes[i]); } SetAddressCore(Address); } private void SubscribeAddressBoxEvents(TextBox textBox) { textBox.TextChanged += addressBox_TextChanged; textBox.GotFocus += addressBox_GotFocus; textBox.LostFocus += addressBox_LostFocus; textBox.PreviewTextInput += addressBox_PreviewTextInput; } private void UnsubscribeAddressBoxEvents(TextBox textBox) { textBox.TextChanged -= addressBox_TextChanged; textBox.GotFocus -= addressBox_GotFocus; textBox.LostFocus -= addressBox_LostFocus; textBox.PreviewTextInput -= addressBox_PreviewTextInput; } private void addressBox_TextChanged(object sender, TextChangedEventArgs e) { TextBox textBox = sender as TextBox; if (textBox == null) return; if (!_settingAddress) _addressBoxChanged = true; if (textBox.Text.Length > 3) { textBox.Text = textBox.Text.Left(3); } else if (textBox.Text.Length == 3) { MoveToNextField(textBox); } } private void addressBox_GotFocus(object sender, RoutedEventArgs e) { TextBox textBox = sender as TextBox; if (textBox == null) return; _addressBoxChanged = false; textBox.SelectAll(); } private void addressBox_LostFocus(object sender, RoutedEventArgs e) { if (_addressBoxChanged) { _addressBoxChanged = false; ParseAddress(); } } private void addressBox_PreviewTextInput(object sender, TextCompositionEventArgs e) { TextBox textBox = sender as TextBox; if (textBox == null) return; byte b; if (e.Text == ".") MoveToNextField(textBox); if (!byte.TryParse(e.Text, out b)) e.Handled = true; } private void MoveToNextField(TextBox textBox) { int n = int.Parse(textBox.Name.Right(1)); n = (n + 1) % 4; if (_addressBoxes[n] != null) _addressBoxes[n].Focus(); } private void ParseAddress() { byte[] parts = new byte[4]; for (int i = 0; i < 4; i++) { if (_addressBoxes[i] != null) { if (byte.TryParse(_addressBoxes[i].Text, out parts[i])) continue; } parts[i] = 0; } this.Address = new IPAddress(parts); } private const string IpAddressTypeName = "System.Net.IPAddress"; private bool CanCopy(out IPAddress address) { address = this.Address; return address != null; } private void IPAddressBox_PreviewCanCopy(object sender, CanExecuteRoutedEventArgs e) { IPAddress address; if (CanCopy(out address)) { e.CanExecute = true; e.Handled = true; } } private void IPAddressBox_PreviewCopy(object sender, ExecutedRoutedEventArgs e) { IPAddress address; if (CanCopy(out address)) { DataObject obj = new DataObject(); obj.SetData(IpAddressTypeName, address); obj.SetText(address.ToString()); Clipboard.SetDataObject(obj, true); e.Handled = true; } } private static bool CanPaste(out IPAddress address) { address = null; if (Clipboard.ContainsData(IpAddressTypeName)) { address = Clipboard.GetData(IpAddressTypeName) as IPAddress; return true; } if (Clipboard.ContainsText()) { string text = Clipboard.GetText(); if (IPAddress.TryParse(text, out address)) { return true; } } return false; } private static void IPAddressBox_PreviewCanPaste(object sender, CanExecuteRoutedEventArgs e) { IPAddress address; if (CanPaste(out address)) { e.CanExecute = true; e.Handled = true; } } private void IPAddressBox_PreviewPaste(object sender, ExecutedRoutedEventArgs e) { IPAddress address; if (CanPaste(out address)) { this.Address = address; e.Handled = true; } } } }