My ProgressBar XAML:
<Window ...>
<ProgressBar Value="{Binding Path=Progress}"/>
</Window>
Code-Behind:
internal int Progress { get; set; }
This progress variable is in multiples of 1, so values will be 1, 2, 3, so on...
Now I decided to use the same Progress property for TaskBarItemInfo's ProgressValue. However, I find it accepts a range of only 0.0 to 1.0 (i.e. normalised values). Is there a way I can bind the same Progress property while specifying some sort of conversion like a division by a number to make it normalised?
CodePudding user response:
There are multiple options. You could expose a separate (probably computed) double property that is updated each time the Progress property is changed, e.g. through raising a PropertyChanged (INotifyPropertyChanged) event in its setter for the computed property.
Another option is creating a custom value or multi-value converter. If there is a hardcoded or predefined range for your int progress values you can create a value converter like this.
public class AbsoluteToRelativeProgressConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is int progress) ||
!(parameter is string maximumText) ||
!int.TryParse(maximumText, out var maximum))
return Binding.DoNothing;
if (maximum < progress)
throw new ArgumentException("Progress must not exceed maximum.");
return progress / (double)maximum;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return new NotImplementedException();
}
}
This converter gets the bound progress value passed in as value. This value is checked if it is really an int. As parameter, you can pass the maximum value. It is passed as string to simplify the syntax in XAML (assigning an int is verbose). The converter returns the relative progress as double in range [0.0, 1.0]. As said before, if the maximum is hardcoded, you could remove the parameter usage and replace the maximum with the value.
Next, create an instance of the converter in the Window.Resources or any other resource dictionary in scope.
<Window.Resources>
<local:AbsoluteToRelativeProgressConverter x:Key="AbsoluteToRelativeProgressConverter"/>
</Window.Resources>
Then bind the Progress in the TaskBarItemInfo to the ProgressValue using the converter. The ConverterParameter is used to pass the maximum, here 100 as example. Note that you need to set the ProgressState to e.g. Normal, Error or Paused, otherwise the progress bar will not be shown.
<Window.TaskbarItemInfo>
<TaskbarItemInfo ProgressState="Normal"
ProgressValue="{Binding Progress, Converter={StaticResource AbsoluteToRelativeProgressConverter}, ConverterParameter=100}"/>
</Window.TaskbarItemInfo>
<Window.Resources>
<local:AbsoluteToRelativeProgressMultiConverter x:Key="AbsoluteToRelativeProgressMultiConverter"/>
</Window.Resources>
If you want to bind the maximum value, too, you need to create a IMultiValueConverter like this.
public class AbsoluteToRelativeProgressMultiConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values is null ||
values.Length != 2 ||
!(values[0] is int progress) ||
!(values[1] is int maximum))
return Binding.DoNothing;
if (maximum < progress)
throw new ArgumentException("Progress must not exceed maximum.");
return progress / (double)maximum;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
It works the same but allows for binding multiple values. Here, the progress is the first value for the converter and the maximum is the second. You could easily extend this converter, to bind a minium value, too.
In XAML, you create an instance, too, but this time you use a MultiBinding.
<Window.Resources>
<local:AbsoluteToRelativeProgressMultiConverter x:Key="AbsoluteToRelativeProgressMultiConverter"/>
</Window.Resources>
<Window.TaskbarItemInfo>
<TaskbarItemInfo ProgressState="Normal">
<TaskbarItemInfo.ProgressValue>
<MultiBinding Converter="{StaticResource AbsoluteToRelativeProgressMultiConverter}">
<Binding Path="Progress"/>
<Binding Path="Maximum"/>
</MultiBinding>
</TaskbarItemInfo.ProgressValue>
</TaskbarItemInfo>
</Window.TaskbarItemInfo>
As a note, if you wanted to make the ProgressState depend on the Progress property, like setting Normal if the progress is >= 0 and <= maximum, guess what, you could use create a converter...or a separate property of course.
CodePudding user response:
xaml code:
<Window.Resources>
<local:DataConverter x:Key="dataConverter " />
</Window.Resources>
<ProgressBar Value={Binding Path=Progress, Converter={StaticResource dataConverter }}/>
converter code
public class DataConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// read the input from value and cast it
// return your object;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
