This project is read-only.

Display percentage text to ProgressBar

Feb 5, 2014 at 1:39 PM
Edited May 3, 2014 at 2:55 PM
Hi all,

in a project, I needed to display the percentage of increase in the progressbar.
Like this :
Image

Inspired by this post: [http://stackoverflow.com/questions/5167867/progress-bar-with-dynamic-text-text-color-update]

If it can help someone, below the code.

1) Add RectConverter.cs file in Windows->Converters

// Content RectConverter.cs
namespace FirstFloor.ModernUI.Windows.Converters
{
/// <summary>
/// Convert rectangle coordinate
/// </summary>
public class RectConverter : IMultiValueConverter
{
    /// <summary>
    /// Get coordinate of rectangle
    /// </summary>
    /// <param name="values"></param>
    /// <param name="targetType"></param>
    /// <param name="parameter"></param>
    /// <param name="culture"></param>
    /// <returns></returns>
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double width = (double)values[0];
        double height = (double)values[1];
        return new Rect(0, 0, width, height);
    }
    /// <summary>
    /// Convert back
    /// </summary>
    /// <param name="value"></param>
    /// <param name="targetTypes"></param>
    /// <param name="parameter"></param>
    /// <param name="culture"></param>
    /// <returns></returns>
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
2) In Assets->Converters.xaml add this.

<converters:RectConverter x:Key="RectConverter" />


3) Add this in Assets ->ProgressBar.xaml


<ResourceDictionary ..... >
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/FirstFloor.ModernUI;component/Assets/Converters.xaml" />
</ResourceDictionary.MergedDictionaries>

<Style TargetType="ProgressBar">
....
<Grid x:Name="DeterminateRoot">
<Border x:Name="PART_Indicator"
        Background="{TemplateBinding Foreground}"
        HorizontalAlignment="Left" >
</Border>
<!-- ADD THIS -->
<TextBlock Text="{TemplateBinding Tag}" 
           FontSize="{TemplateBinding FontSize}"
           FontWeight="{TemplateBinding FontWeight}"
           Grid.ZIndex="2" Foreground="{DynamicResource Accent}"
           TextAlignment="Center"
           HorizontalAlignment="Stretch"
           VerticalAlignment="Center" />
<TextBlock Text="{TemplateBinding Tag}" 
           FontSize="{TemplateBinding FontSize}"
           FontWeight="{TemplateBinding FontWeight}"
           Grid.ZIndex="3"
           TextAlignment="Center"
           HorizontalAlignment="Stretch"
           VerticalAlignment="Center">
     <TextBlock.Style>
      <Style TargetType="{x:Type TextBlock}">
       <Setter Property="Foreground" Value="{DynamicResource ItemTextSelected}" />
     </Style>
    </TextBlock.Style>
    <TextBlock.Clip>
     <RectangleGeometry >
      <RectangleGeometry.Rect>
       <MultiBinding Converter="{StaticResource RectConverter}">
           <Binding Path="ActualWidth"    Source="{x:Reference PART_Indicator}"/>
           <Binding  Path="ActualHeight"  Source="{x:Reference PART_Indicator}"/>
       </MultiBinding>
      </RectangleGeometry.Rect>
     </RectangleGeometry>
    </TextBlock.Clip>
</TextBlock>
<!-- END --> </Grid>

Usage :

<ProgressBar Maximum="100" Value="50" Width="300" Height="50" Tag="50%" FontSize="20"/>



best regards
Feb 10, 2014 at 5:39 PM
This is way more complicated than it needs to be. Why not just slap a textbox on top of your progress bar that shows the progress value? I do it all of the time.
<Grid Visibility="{Binding IsDownloading, Converter={StaticResource boolToVis}}">
            
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            
            <ProgressBar Value="{Binding DownloadProgress}"
                         Grid.ColumnSpan="2"/>

            <TextBlock Margin="10,0,0,0"
                       Grid.ColumnSpan="2"
                       Text="{Binding DownloadStatus}"      
                       Style="{StaticResource Small}"
                       VerticalAlignment="Center" />
        </Grid>
Of course, bind to properties that make sense for your scenario.
Feb 10, 2014 at 10:05 PM
Hi flyte,

to update the text color :)

Regard
May 2, 2014 at 1:41 PM
Thank you very much for your trick.

I just go a problem in Visual studio rendering xaml.

Each time I got a "System.Windows.ResourceReferenceExpression" for the property "Foreground" of the Textblock that have the clip.

Have you got the same Problem ?

Thanks you
May 2, 2014 at 8:08 PM
Edited May 2, 2014 at 10:15 PM
No it's work fine for me.
Follow exactly the code above and it should work.
You must add this code in FirstFloor.ModernUI project.
best regard
May 2, 2014 at 10:27 PM
Ok thanks you for your reply...

I still have the problem but maybe it's Visual 2013 .

I just past the XamlParseException in case of someone got the sameproblem ("In French")

XamlParseException : 'System.Windows.ResourceReferenceExpression' n'est pas une valeur valide pour la propriété 'Foreground'.

à System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlReader templateReader, XamlObjectWriter currentWriter)
à System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlObjectWriter objectWriter)
à System.Windows.FrameworkTemplate.LoadOptimizedTemplateContent(DependencyObject container, IComponentConnector componentConnector, IStyleConnector styleConnector, List1 affectedChildren, UncommonField1 templatedNonFeChildrenField)
à System.Windows.FrameworkTemplate.LoadContent(DependencyObject container, List1 affectedChildren)
à System.Windows.StyleHelper.ApplyTemplateContent(UncommonField
1 dataField, DependencyObject container, FrameworkElementFactory templateRoot, Int32 lastChildIndex, HybridDictionary childIndexFromChildID, FrameworkTemplate frameworkTemplate)
à System.Windows.FrameworkTemplate.ApplyTemplateContent(UncommonField`1 templateDataField, FrameworkElement container)
à System.Windows.FrameworkElement.ApplyTemplate()
à System.Windows.FrameworkElement.MeasureCore(Size availableSize)
à System.Windows.UIElement.Measure(Size availableSize)
à System.Windows.Controls.StackPanel.StackMeasureHelper(IStackMeasure measureElement, IStackMeasureScrollData scrollData, Size constraint)
à System.Windows.Controls.StackPanel.MeasureOverride(Size constraint)
à System.Windows.FrameworkElement.MeasureCore(Size availableSize)
à System.Windows.UIElement.Measure(Size availableSize)
à System.Windows.Controls.StackPanel.StackMeasureHelper(IStackMeasure measureElement, IStackMeasureScrollData scrollData, Size constraint)
à System.Windows.Controls.StackPanel.MeasureOverride(Size constraint)
à System.Windows.FrameworkElement.MeasureCore(Size availableSize)
à System.Windows.UIElement.Measure(Size availableSize)
à MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
à System.Windows.Controls.ContentPresenter.MeasureOverride(Size constraint)
à System.Windows.FrameworkElement.MeasureCore(Size availableSize)
à System.Windows.UIElement.Measure(Size availableSize)
à System.Windows.Controls.Border.MeasureOverride(Size constraint)
à System.Windows.FrameworkElement.MeasureCore(Size availableSize)
à System.Windows.UIElement.Measure(Size availableSize)
à System.Windows.Controls.StackPanel.StackMeasureHelper(IStackMeasure measureElement, IStackMeasureScrollData scrollData, Size constraint)
à System.Windows.Controls.StackPanel.MeasureOverride(Size constraint)
à System.Windows.FrameworkElement.MeasureCore(Size availableSize)
à System.Windows.UIElement.Measure(Size availableSize)
à System.Windows.Controls.Control.MeasureOverride(Size constraint)
à System.Windows.FrameworkElement.MeasureCore(Size availableSize)
à System.Windows.UIElement.Measure(Size availableSize)
à System.Windows.Controls.Grid.MeasureOverride(Size constraint)
à System.Windows.FrameworkElement.MeasureCore(Size availableSize)
à System.Windows.UIElement.Measure(Size availableSize)
à MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
à System.Windows.Controls.ContentPresenter.MeasureOverride(Size constraint)
à System.Windows.FrameworkElement.MeasureCore(Size availableSize)
à System.Windows.UIElement.Measure(Size availableSize)
à System.Windows.Controls.Border.MeasureOverride(Size constraint)
à System.Windows.FrameworkElement.MeasureCore(Size availableSize)
à System.Windows.UIElement.Measure(Size availableSize)
à System.Windows.Controls.Control.MeasureOverride(Size constraint)
à System.Windows.FrameworkElement.MeasureCore(Size availableSize)
à System.Windows.UIElement.Measure(Size availableSize)

Thx
May 3, 2014 at 10:19 AM
Hi Mudy

Paste the piece of code ProgressBar.xaml to see the problem or a link to a zip of project changed (FirstFloor.ModernUI).

Macgile
May 3, 2014 at 10:25 AM
Here the code I have implemented : ProgressBar.xaml

Just to clarify my problem : It works fine when I run the application, but not in the preview of xaml

Thanks you
Muby
May 3, 2014 at 10:43 AM
Edited May 3, 2014 at 10:57 AM
Hi Mudy

in line 151, uncomment </TextBlock.Clip> -->

regard
May 3, 2014 at 12:27 PM
Sorry,

Indeed this "-->" must be remove to compil.

I update the file and then look what's look like the Xaml render when I user ProgressBar

XamlRender

ErrorWindow
May 3, 2014 at 12:37 PM
Ok,

1) Poster le code de mise en oeuvre du progressbar!
2) quelle version du framwork.
3) version de VS.
May 3, 2014 at 12:51 PM
1)
Code :
 <ProgressBar Margin="20,0,0,0" Value="50" Width="300" Height="20" Tag="50%"/>
2) .net 4.5

3) Visual 2013 SP1
May 3, 2014 at 1:17 PM
Changer dans progressbar.xaml

Foreground="{DynamicResource Accent}" -> Foreground="{StaticResource Accent}"
Foreground="{DynamicResource ItemTextSelected}" -> Foreground="{StaticResource ItemTextSelected}"

et c'est bon
May 3, 2014 at 1:28 PM
Merci beaucoup pour ta réactivité ...

Une idée de pourquoi dans ma configuration il faut changer le Dynamic en Static ?

Encore merci pour ton aide :)
May 3, 2014 at 1:31 PM
Ta config a rien a voir, c'est moi qui n'est pas testé :)
May 3, 2014 at 1:32 PM
Ok

En tout cas sympa de m'avoir aidé ;) ton code marche super bien et super utile :)

Encore merci ;)
May 3, 2014 at 1:45 PM
Oups j'ai parlé un peu vite ...

En faite c'est un peu bizarre avec DynamicResource ça marche en exécution mais pas en visualisation dans Visual Studio.

Avec StaticResource ça marche en visualisation dans Visual Studio mais j'ai une exception à l’exécution ... :(
System.Windows.Markup.XamlParseException: Provide value on 'System.Windows.Markup.StaticResourceHolder' threw an exception. ---> System.Exception: Cannot find resource named 'Accent'. Resource names are case sensitive.
   at System.Windows.StaticResourceExtension.ProvideValueInternal(IServiceProvider serviceProvider, Boolean allowDeferredReference)
   at System.Windows.StaticResourceExtension.ProvideValue(IServiceProvider serviceProvider)
   at MS.Internal.Xaml.Runtime.ClrObjectRuntime.CallProvideValue(MarkupExtension me, IServiceProvider serviceProvider)
:(
May 3, 2014 at 1:47 PM
Edited May 3, 2014 at 1:48 PM
C'est la propriété Foreground="{StaticResource ItemTextSelected}" qui deconne, je suis en train de regarder et fait un retour quand ok.

avec une valeur en dur "White" pas de soucis, a prioris il ne trouve pas la ressource dynamiquement.
May 3, 2014 at 1:48 PM
Et si j'enlève :
<TextBlock.Clip>
                                            <RectangleGeometry >
                                                <RectangleGeometry.Rect>
                                                    <MultiBinding Converter="{StaticResource RectConverter}">
                                                        <Binding Path="ActualWidth"    Source="{x:Reference PART_Indicator}"/>
                                                        <Binding Path="ActualHeight"   Source="{x:Reference PART_Indicator}"/>
                                                    </MultiBinding>
                                                </RectangleGeometry.Rect>
                                            </RectangleGeometry>
                                        </TextBlock.Clip>
La j'arrive à avoir le rendu avec DynamicResource ...

Il semble que visual n'arrive pas à faire le rendu si y'a un TextBlock.Clip ?
May 3, 2014 at 1:50 PM
le clip sert a cacher le texte en noir au fur et a mesure de la progression, faut pas l'enlever !
May 3, 2014 at 1:52 PM
Oui c'est tout l'intérêt de ton code, mais il semble que ce soit ça qui empêche Visual Studio de faire le rendu Xaml avant l'éxécution.

Bizarre :(
May 3, 2014 at 2:37 PM
Edited May 3, 2014 at 2:46 PM
ok it's work :)
<TextBlock.Style>
 <Style TargetType="{x:Type TextBlock}">
  <Setter Property="Foreground" Value="{DynamicResource ItemTextSelected}" />
 </Style>
</TextBlock.Style>
I updated my first ProgressBar.xaml code above
May 3, 2014 at 2:43 PM
Indeed !!!! Nice !!

Encore merci et la dernière je pense :) Beau travail :

Here the final code for everyone who need it :
<TextBlock Text="{TemplateBinding Tag}" 
        FontSize="{TemplateBinding FontSize}"
        FontWeight="{TemplateBinding FontWeight}"
        Grid.ZIndex="2" Foreground="{DynamicResource Accent}"
        TextAlignment="Center"
        HorizontalAlignment="Stretch"
        VerticalAlignment="Center" />
    <TextBlock 
            Text="{TemplateBinding Tag}" 
            FontSize="{TemplateBinding FontSize}"
            FontWeight="{TemplateBinding FontWeight}"
            Grid.ZIndex="3" 
            TextAlignment="Center"
            HorizontalAlignment="Stretch"
            VerticalAlignment="Center">
        <TextBlock.Style>
            <Style TargetType="{x:Type TextBlock}">
                <Setter Property="Foreground" Value="{DynamicResource ItemTextSelected}" />
            </Style>
        </TextBlock.Style>
       <TextBlock.Clip>
            <RectangleGeometry >
                <RectangleGeometry.Rect>
                    <MultiBinding Converter="{StaticResource RectConverter}">
                        <Binding Path="ActualWidth"    Source="{x:Reference PART_Indicator}"/>
                        <Binding Path="ActualHeight"   Source="{x:Reference PART_Indicator}"/>
                    </MultiBinding>
                </RectangleGeometry.Rect>
            </RectangleGeometry>
        </TextBlock.Clip>
    </TextBlock>
May 3, 2014 at 2:50 PM
Pas de soucis :)

Et voilà :)