带有多个TextBoxes的UserControl,它们聚合成DependencyProperty

时间:2011-05-16 17:05:52

标签: wpf user-controls binding ip-address dependency-properties

我正在尝试构建一个基本上是IPv4地址'文本框'的UserControl。

在UserControl中有4个TextBox,其中TextBlock包含单个“。”。在每个TextBox之间:

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

我希望我可以在我可以绑定的控件上有一个名为IPAddress的DependencyProperty,或者在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显示在自己的TextBox中。然后,如果任何Octet TextBox更改,则IPAddress依赖项属性将更新。

这可能吗?我是否以正确的方式思考这个问题?

1 个答案:

答案 0 :(得分:1)

有很多方法可以做到这一点。一个是简单地为八位字节创建私有属性并将文本框绑定到那些属性,例如:

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

然后实现更新依赖项属性的setter:

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

修改

双向绑定有点棘手,因为您需要更改通知才能更新UI。我处理这个问题的方法可能是创建一个具有八位字节和IP地址属性并实现INotifyPropertyChanged的视图模型类,然后在UserControl的构造函数中创建它的实例并将所有UI控件绑定到属性。这样,当视图模型上的IPAddress被设置时,setter可以解析该值,更新八位字节属性,然后它们会引发PropertyChanged并且UI会更新。

然后在UserControl中,我在视图模型上处理PropertyChanged并在{{1>时设置IPAddress依赖属性在控件视图模型上的属性更改。 (这并不像听起来那么奇怪。)

您还需要编写一个函数,将视图模型的IPAddress1属性设置为IPAddress依赖项属性的值,并将该函数设置为回调 注册DP。

所以事件链将是:某些东西在控件上设置IPAddress属性 - &gt; DP回调在视图模型上设置IPAddress属性 - &gt; IPAddress setter解析八位字节并设置IPAddress属性 - &gt; Octet属性提升Octet - &gt;绑定将更改后的值推送到PropertyChanged中的UI控件。另一方面,它是:用户输入一个八位位组 - &gt; octet setter在视图模型上设置UserControl - &gt;用户控件处理IPAddress并设置PropertyChanged依赖项属性。