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