UserControl с несколькими текстовыми полями, которые объединяются в DependencyProperty

Я пытаюсь создать UserControl, который по сути является «текстовым полем» адреса IPv4.

В UserControl есть 4 текстовых поля, а TextBlock содержит один "." между каждым текстовым полем:

<Grid Grid.IsSharedSizeScope="True">
    <Grid.ColumnDefinitions>
        <ColumnDefinition SharedSizeGroup="GroupA" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition SharedSizeGroup="GroupA" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition SharedSizeGroup="GroupA" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition SharedSizeGroup="GroupA" />
    </Grid.ColumnDefinitions>
    <TextBox Grid.Column="0" TabIndex="0" x:Name="TextOctet1" />
    <TextBlock Grid.Column="1" Text="." />
    <TextBox Grid.Column="2" TabIndex="1" x:Name="TextOctet2" />
    <TextBlock Grid.Column="3" Text="." />
    <TextBox Grid.Column="4" TabIndex="2" x:Name="TextOctet3" />
    <TextBlock Grid.Column="5" Text="." />
    <TextBox Grid.Column="6" TabIndex="3" x:Name="TextOctet4" />
</Grid>

Я надеюсь, что у меня может быть DependencyProperty с именем IPAddress для элемента управления, к которому я могу привязаться, или установить значение по умолчанию в XAML «123.123.123.123».

<local:IPBox IPAddress="123.123.123.123" />

Я подумал, что могу использовать что-то вроде MultiBinding и IMultiValueConverter:

public class IPAddressConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return String.Format("{0}.{1}.{2}.{3}", values[0], values[1], values[2], values[3]);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        return ((string)value).Split('.');
    }
}

Но я считаю, что это было бы противоположным тому, что я хочу. MultiValueConverter объединит несколько свойств бизнес-логики в одно свойство, к которому привязывается TextBox.

Вместо этого я хочу связать одно свойство бизнес-логики (строку, представляющую адрес IPv4) и чтобы каждый октет отображался в своем собственном текстовом поле. Затем, если какое-либо из текстовых полей Octet изменится, свойство зависимости IPAddress будет обновлено.

Это возможно? Правильно ли я думаю об этой проблеме?


person Scott    schedule 16.05.2011    source источник


Ответы (1)


Есть много способов сделать это. Можно просто создать частные свойства для октета и привязать текстовые поля к этим свойствам, например:

<TextBox Text={Binding RelativeSource={AncestorType UserControl}, Path=Octet1}, Mode=TwoWay"/>

а затем реализуйте сеттеры, которые обновляют свойство зависимостей:

private int _Octet1;
private int Octet1
{
   get { return _Octet1; }
   set
   {
     _Octet1 = value;
     UpdateIPAddress();
   }
}

private void UpdateIPAddress()
{
   IPAddress = string.Format("{0}.{1}.{2}.{3}", _Octet1, _Octet2, _Octet3, _Octet4);
}

Изменить:

Двусторонняя привязка немного сложна, потому что вам нужно уведомление об изменении, чтобы обновить пользовательский интерфейс. Способ, которым я справился бы с этим, вероятно, состоит в том, чтобы создать класс модели представления, который имеет свойства октета и IP-адреса и реализует INotifyPropertyChanged, затем создайте его экземпляр в конструкторе UserControl и привяжите все элементы управления пользовательского интерфейса к свойствам. Таким образом, когда устанавливается IPAddress в модели представления, установщик может анализировать значение, обновлять свойства октета, поднимать PropertyChanged и обновлять пользовательский интерфейс.

Затем в UserControl я обрабатывал PropertyChanged в модели представления и устанавливал свойство зависимости IPAddress в элементе управления при изменении свойства IPAddress1 в модели представления. (Это не так странно, как кажется.)

Вам также потребуется написать функцию, которая устанавливает для свойства IPAddress модели представления значение свойства зависимостей IPAddress, и установить эту функцию в качестве обратного вызова при регистрации DP.

Таким образом, цепочка событий будет следующей: что-то устанавливает свойство IPAddress в элементе управления -> обратный вызов DP устанавливает свойство IPAddress в модели представления -> установщик IPAddress анализирует октеты и устанавливает свойства Octet -> свойства Octet повышают PropertyChanged - > привязка отправляет измененные значения в элементы управления пользовательского интерфейса в файле UserControl. И наоборот, это: пользователь вводит октет -> установщик октетов устанавливает IPAddress в модели представления -> пользовательский элемент управления обрабатывает PropertyChanged и устанавливает свойство зависимости IPAddress.

person Robert Rossney    schedule 16.05.2011
comment
Итак, если я привяжу свойство зависимости IPAddress моего UserControl к некоторой правильно отформатированной строке, как будут обновлены октеты? (двусторонняя привязка): ‹local:IPBox IPAddress=123.123.123.123 /› - person Scott; 16.05.2011
comment
Тогда я думаю, вам нужно реализовать модель представления. Смотрите мою правку. - person Robert Rossney; 17.05.2011
comment
Ха... итак, я попробовал все это в первый раз... и это просто не сработало. Позже я узнаю, что наличие данных по умолчанию в моем dp приводило к тому, что оно отображалось пустым, когда я связывался с данными, которые уже имели то же значение, что и данные по умолчанию: public static readonly DependencyProperty IPAddressProperty = DependencyProperty.Register(IPAddress, typeof( строка), typeof(IPBox), new UIPropertyMetadata(0.0.0.0, new PropertyChangedCallback(IPAddressChanged)));. Как только я удалил 0.0.0.0, все заработало. Спасибо, что нашли время, чтобы посмотреть на это и помочь мне! - person Scott; 17.05.2011