n0kx
n0kx

Reputation: 81

Updating the value of another property when a DependencyProperty changes

I have a DependencyProperty in my UserControl with a property changed callback. The property works as expected and the callback works as expected.

public double CurrentFlow
{
    get { return (double)GetValue(CurrentFlowProperty); }
    set { SetValue(CurrentFlowProperty, value); }
}
public static readonly DependencyProperty CurrentFlowProperty = DependencyProperty.Register("CurrentFlow", typeof(double), typeof(MyUserControl), new PropertyMetadata(0.0, OnCurrentFlowPropertyChanged));

private static void OnCurrentFlowPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
    Console.WriteLine("CurrentFlow changed.");
}

However, I have a TextBlock in my UserControl where I want to display CurrentFlow as a formatted string. Currently, I have the Text property of the TextBlock binded to CurrentFlow, and it works, but I'm not getting the format I need. (Too many numbers after the decimal.)

<TextBlock Text="{Binding Path=CurrentFlow, RelativeSource={RelativeSource AncestorType=UserControl}}" />

Ideally, I'd like to have a property named CurrentFlowString that takes the value from CurrentFlow and formats it to what I want. For example: CurrentFlow.ToString("0.00");

What's the best way to go about this with DependencyProperties? I know how to do this with regular properties but I'm kinda stuck here.

Thanks!

Upvotes: 1

Views: 544

Answers (1)

redcurry
redcurry

Reputation: 2497

If you want to have more flexibility than using StringFormat, you can also use a custom converter. For example,

public class MyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is double d)
            return $"{d:f2}";
        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}

Then add it to your UserControl.Resources, and use it in your Binding:

<UserControl.Resources>
    <local:MyConverter x:Key="MyConverter" />
</UserControl.Resources>

<Grid>
    <TextBlock Text="{Binding Path=CurrentFlow, RelativeSource={RelativeSource AncestorType=UserControl}, Converter={StaticResource MyConverter}}" />
</Grid>

Solution 2: Based on your comment below, here's an alternative solution. First, create a new dependency property; for example, FormattedCurrentFlow:

public static readonly DependencyProperty FormattedCurrentFlowProperty = DependencyProperty.Register(
    "FormattedCurrentFlow", typeof(string), typeof(MyControl), new PropertyMetadata(default(string)));

public string FormattedCurrentFlow
{
    get { return (string)GetValue(FormattedCurrentFlowProperty); }
    set { SetValue(FormattedCurrentFlowProperty, value); }
}

Since you already have a method to handle changes in CurrentFlow, update the new FormattedCurrentFlow when CurrentFlow changes:

private static void OnCurrentFlowPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
    var myControl = (MyControl)source;
    myControl.FormattedCurrentFlow = $"{myControl.CurrentFlow:f2}";
}

The TextBox in the UserControl can now bind to FormattedCurrentFlow:

<TextBlock Text="{Binding Path=FormattedCurrentFlow, RelativeSource={RelativeSource AncestorType=UserControl}}" />

Upvotes: 2

Related Questions