具有多个文本框的用户控件'聚合成 DependencyProperty

发布于 2024-11-07 09:51:58 字数 2008 浏览 3 评论 0原文

我正在尝试构建一个本质上是 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 地址的字符串)并使每个八位字节显示在其自己的文本框中。然后,如果任何八位字节文本框发生更改,IPAddress 依赖属性将更新。

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

I'm trying to build a UserControl that is essentially an IPv4 Address 'text box'.

In the UserControl there are 4 TextBoxes, with a TextBlock containing a single "." between each 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>

My hope is that I can have a DependencyProperty called IPAddress on the control that I can bind to, or set a default value in XAML "123.123.123.123".

<local:IPBox IPAddress="123.123.123.123" />

I thought that I could use something like MultiBinding and an 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('.');
    }
}

But I believe that would be doing the opposite of what I want. A MultiValueConverter would merge multiple business logic properties into a single property for a TextBox to bind to.

Instead, I want to bind a single business logic property (a string representing an IPv4 Address) and have each Octet show up in its own TextBox. Then if any of the Octet TextBoxes change, the IPAddress dependency property will update.

Is this possible? Am I thinking about this problem in the right way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

风铃鹿 2024-11-14 09:51:59

有很多方法可以做到这一点。只需为八位位组创建私有属性并将文本框绑定到这些属性,例如:

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

编辑:

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

然后在 UserControl 中,我将处理视图模型上的 PropertyChanged 并在控件上设置 IPAddress 依赖属性 > 当视图模型上的IPAddress1属性发生变化时。 (这并不像听起来那么奇怪。)

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

因此,事件链将是:设置控件上的 IPAddress 属性 -> DP 回调在视图模型上设置 IPAddress 属性 -> IPAddress setter 解析八位字节并设置 Octet 属性 -> Octet 属性引发 PropertyChanged ->绑定将更改的值推送到 UserControl 中的 UI 控件。换句话说,就是:用户输入一个八位字节 ->八位字节设置器在视图模型上设置 IPAddress ->用户控件处理 PropertyChanged 并设置 IPAddress 依赖属性。

There are a lot of ways to do this. One's simply to create private properties for the octet and bind the text boxes to those properties, e.g.:

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

and then implement setters that update the dependency property:

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

Edit:

Two-way binding is a little tricky because you need change notification in order to update the UI. The way I'd handle this, probably, is to create a view model class that has octet and IP address properties and implements INotifyPropertyChanged, then create an instance of it in the UserControl's constructor and bind all the UI controls to the properties. That way when the IPAddress on the view model gets set, the setter can parse the value, update the octet properties, and they raise PropertyChanged and the UI gets updated.

Then in the UserControl, I'd handle PropertyChanged on the view model and set the IPAddress dependency property on the control when the IPAddress1 property on the view model changes. (That isn't as weird as it sounds.)

You'll also need to write a function that sets the view model's IPAddress property to the value of the IPAddress dependency property, and set that function as a callback when you
register the DP.

So the chain of events will be: something sets the IPAddress property on the control -> the DP callback sets the IPAddress property on the view model -> the IPAddress setter parses the octets and sets the Octet properties -> the Octet properties raise PropertyChanged -> binding pushes the changed values out to the UI controls in your UserControl. Going the other way, it's: user enters an octet -> octet setter sets IPAddress on the view model -> user control handles PropertyChanged and sets the IPAddress dependency property.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文