0

I have a TextBox which is bound to a IPAddress property. For that I've implemented a IValueConverter which tries to parse the string of the TextBox to a IPAddress. When the conversion fails, a red border is automatically painted around the TextBox, indicating that the given value is incorrect. That is working so far and like intended.

My question is if there is a way to get somehow this failed state of the conversion to bind it to a IsEnabled property of a Button. And all that in XAML.

Here the IValueConverter:

public class IpAddressConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is IPAddress)
        {
            return ((IPAddress)value).ToString();
        }

        return false;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is string)
        {
            IPAddress ipAddress;
            if (IPAddress.TryParse((string)value, out ipAddress))
            {
                return ipAddress;
            }
        }

        return false;
    }
}

EDIT: I have implemented logic to validate the input already. But because of the failed conversion, the property doesn't get updated. And that means the property still holds the "old" value, which is of course correct, but doesn't need to be validated.

pseudorian
  • 184
  • 1
  • 9
FredM
  • 454
  • 9
  • 20
  • You can return `UnsetValue` from your converter, indicating the it can't convert the value and use it in validation logic. [here](https://learn.microsoft.com/en-us/dotnet/api/system.windows.dependencyproperty.unsetvalue?view=netframework-4.7.2) is an article for that – Pavel Anikhouski Apr 10 '19 at 10:53
  • @PavelAnikhouski unfortunately it isn't working. The backing field of the property still holds the value which was set before. – FredM Apr 10 '19 at 13:55
  • Probably it is working correctly, but it doesn't achieve the results I'm looking for. – FredM Apr 10 '19 at 14:03

2 Answers2

1

Maybe you can use Validation Attached Properties and a DataTrigger placed on your Button, just by acting on your XAML:

<TextBox Name="ipAddressTextBox" Text="{Binding IP, Converter={StaticResource IpAddressConverter}}" />
<Button Content="Ok">
    <Button.Style>
        <Style BasedOn="{StaticResource {x:Type Button}}" TargetType="{x:Type Button}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding ElementName=ipAddressTextBox, Path=(Validation.HasError)}" Value="True">
                    <Setter Property="IsEnabled" Value="False" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>

Of course supposing that ipAddressTextBox is your TextBox. I hope it helps.

Il Vic
  • 5,576
  • 4
  • 26
  • 37
  • That looks quite interesting. The `Validation.HasError` property I was searching for. Is there a reason why it is placed in brackets? Will try that out. Does this require only the `IValueConverter` or also the validation logic of `INotifyDataErrorInfo`? – FredM Apr 10 '19 at 15:00
  • @FredM `Validation.HasError` is placed between round brackets since it is an [attached property](https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/attached-properties-overview), so that is the correct syntax. If you set the IP address value by code, it requires `INotifyDataErrorInfo`. If you use just the textbox for digiting an IP there is no need. – Il Vic Apr 10 '19 at 15:07
  • So your answer did helped me to achieve what I want. I've added two more `DataTrigger` bound to two seperat `TextBox`. If now just one has an error on `Validation`, the button gets disabled. Thanks! – FredM Apr 11 '19 at 07:50
0

In cases like this, inserting the conversion logic from string to IPAdress in your ViewModel would allow you to remove the conversion markup from your XAML while, simultaneously, giving you a handle on the success/failure state of the conversion.

For example:

public class IPAddressEntryViewModel : ViewModel
    {
        private IPAddress ip;

        private bool isValidIp;
        public bool IsValidIp
        {
            get { return isValidIp; }
            set
            {
                if(isValidIp!= value)
                {
                    isValidIp= value;
                    NotifyPropertyChanged("IsValidIp");
                }
            }
        }

        private string ipAddressText;
        public string IPAddressText
        {
            get { return ipAddressText; }
            set
            {
                if(ipAddressText != value)
                {
                    ipAddressText = value;
                    NotifyPropertyChanged("IPAddressText");

                    //Parsing
                    IsValidIp= IPAddress.TryParse(ipAddressText, out ip);
                }
            }
        }
    }

Then simply bind your button's IsEnabled to IsValidIp and your TextBox's Text to IPAddressText. You can also set the border style to follow IsValidIp with a DataTrigger, saving you a lot of XAML markup.

This also allows you to perform any other processing you may need to do given the TextBox text in the future.

pseudorian
  • 184
  • 1
  • 9