Change old WPF ProgressBar controltemplate to WPF4

2019-09-03 16:21发布

问题:

I want a thermometer in my WPF app and found a template in MSDN magazine


Edit start

I have found the reason why it doesn't work: http://connect.microsoft.com/VisualStudio/feedback/details/571674/issue-with-vertical-progress-bar-on-4-0-framework

But I/you? still have to figure out how to make it work with WPF4.

Edit end


The control looks fine, but it doesn't seem to update the indicator when setting Value.

I've pasted it into Kaxaml and also tried VS2010. Is the code buggy or am I doing something wrong with it?

<!-- ================================================
      ThermometerProgressBar.xaml by Charles Petzold
     ================================================ -->
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>

        <!-- Define template for thermometer progress bar -->
        <ControlTemplate x:Key="templateThermometer"
                         TargetType="{x:Type ProgressBar}">

            <!-- Define two brushes for the thermometer liquid -->
            <ControlTemplate.Resources>
                <LinearGradientBrush x:Key="brushStem"
                                     StartPoint="0 0" EndPoint="1 0">
                    <GradientStop Offset="0" Color="Red" />
                    <GradientStop Offset="0.3" Color="Pink" />
                    <GradientStop Offset="1" Color="Red" />
                </LinearGradientBrush>

                <RadialGradientBrush x:Key="brushBowl"
                                     GradientOrigin="0.3 0.3">
                    <GradientStop Offset="0" Color="Pink" />
                    <GradientStop Offset="1" Color="Red" />                        
                </RadialGradientBrush>
            </ControlTemplate.Resources>

            <!-- Two-row Grid divides thermometer into stem and bowl -->
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="*" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>

                <!-- Second grid divides stem area in three columns -->
                <Grid Grid.Row="0">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="25*" />
                        <ColumnDefinition Width="50*" />
                        <ColumnDefinition Width="25*" />
                    </Grid.ColumnDefinitions>

                    <!-- This border displays the stem -->
                    <Border Grid.Column="1" BorderBrush="SteelBlue" 
                            BorderThickness="3 3 3 0"
                            CornerRadius="6 6 0 0" >

                        <!-- Track and Indicator elements -->
                        <Decorator Name="PART_Track">
                            <Border Name="PART_Indicator"
                                    CornerRadius="6 6 0 0"
                                    VerticalAlignment="Bottom"
                                    Background="{StaticResource brushStem}" />
                        </Decorator>
                    </Border>
                </Grid>

                <!-- The bowl outline goes in the main Grid second row -->
                <Ellipse Grid.Row="1"
                         Width="{TemplateBinding Width}"
                         Height="{TemplateBinding Width}"
                         Stroke="SteelBlue" StrokeThickness="3" />

                <!-- Another grid goes in the same cell -->
                <Grid Grid.Row="1" >
                    <Grid.RowDefinitions>
                        <RowDefinition Height="50*" />
                        <RowDefinition Height="50*" />
                    </Grid.RowDefinitions>

                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="25*" />
                        <ColumnDefinition Width="50*" />
                        <ColumnDefinition Width="25*" />
                    </Grid.ColumnDefinitions>

                    <!-- This is to close up the gap between bowl and stem -->
                    <Border Grid.Row="0" Grid.Column="1"
                            BorderBrush="SteelBlue"
                            BorderThickness="3 0 3 0"
                            Background="{StaticResource brushStem}" />
                </Grid>

                <!-- Another ellipse to fill up the bowl -->
                <Ellipse Grid.Row="1"
                         Width="{TemplateBinding Width}"
                         Height="{TemplateBinding Width}"
                         Stroke="Transparent" StrokeThickness="6"
                         Fill="{StaticResource brushBowl}" />
            </Grid>
        </ControlTemplate>
    </Page.Resources>

    <StackPanel>

        <!-- Create Thermometer ProgressBar -->
        <ProgressBar Template="{StaticResource templateThermometer}" 
                     Orientation="Vertical" Minimum="0" Maximum="100"
                     Width="50" Height="350" Margin="50" 
                     Value="{Binding ElementName=scroll, Path=Value}" />

        <!-- ScrollBar to simulate progress -->
        <ScrollBar Name="scroll" Orientation="Horizontal" 
                   Minimum="0" Maximum="100"
                   SmallChange="1" LargeChange="10" 
                   Margin="50 0 50 0" />

        <TextBlock Text="Manipulate ScrollBar to test ProgressBar"
                   HorizontalAlignment="Center" />
    </StackPanel>
</Page>

回答1:

i found out that you need to add a template trigger to trigger when the orientation Property is set "Vertical" . The code i made some changes, and works fine.

<!-- Define template for thermometer progress bar -->
<ControlTemplate x:Key="ThermometerProgressBarStyle"
                     TargetType="{x:Type ProgressBar}">

    <!-- Define two brushes for the thermometer liquid -->
    <ControlTemplate.Resources>
        <LinearGradientBrush x:Key="brushStem"
                                 StartPoint="0 0" EndPoint="1 0">
            <GradientStop Offset="0" Color="Red" />
            <GradientStop Offset="0.3" Color="Pink" />
            <GradientStop Offset="1" Color="Red" />
        </LinearGradientBrush>
        <LinearGradientBrush x:Key="brushStemVertical"
                                 StartPoint="0 0" EndPoint="0 1">
            <GradientStop Offset="0" Color="Red" />
            <GradientStop Offset="0.3" Color="Pink" />
            <GradientStop Offset="1" Color="Red" />
        </LinearGradientBrush>
        <RadialGradientBrush x:Key="brushBowl"
                                 GradientOrigin="0.3 0.3">
            <GradientStop Offset="0" Color="Pink" />
            <GradientStop Offset="1" Color="Red" />
        </RadialGradientBrush>
    </ControlTemplate.Resources>

    <!-- Two-row Grid divides thermometer into stem and bowl -->
    <Grid ShowGridLines="False">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="auto" />
        </Grid.RowDefinitions>
        <!-- Second grid divides stem area in three columns -->
        <Grid Grid.Row="0" ShowGridLines="false">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="25*" />
                <ColumnDefinition Width="50*" />
                <ColumnDefinition Width="25*" />
            </Grid.ColumnDefinitions>
            <!-- This border displays the stem -->
                <!-- Track and Indicator elements -->

            <Border Grid.Column="1" BorderBrush="SteelBlue" 
                    BorderThickness="0 3 3 3"
                    CornerRadius="0 6 6 0"
                           Name="border">
                    <Grid>
                        <Rectangle Fill="{TemplateBinding Background}"
                                      Name="PART_Track" />
                        <Rectangle Name="PART_Indicator"
                            Fill="{StaticResource brushStemVertical }"
                               HorizontalAlignment="Left"/>
                    </Grid>
                </Border>
        </Grid>
        <!-- The bowl outline goes in the main Grid second row -->
        <Ellipse Grid.Row="1"
                     Width="{TemplateBinding Width}"
                     Height="{TemplateBinding Width}"
                     Stroke="SteelBlue" StrokeThickness="3" />
        <!-- Another grid goes in the same cell -->
        <Grid Grid.Row="1" >
            <Grid.RowDefinitions>
                <RowDefinition Height="50*" />
                <RowDefinition Height="50*" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="25*" />
                <ColumnDefinition Width="50*" />
                <ColumnDefinition Width="25*" />
            </Grid.ColumnDefinitions>
            <!-- This is to close up the gap between bowl and stem -->
            <Border Grid.Row="0" Grid.Column="1"
                        BorderBrush="SteelBlue"
                        BorderThickness="3 0 3 0"
                        Background="{StaticResource brushStem}" />
        </Grid>
        <!-- Another ellipse to fill up the bowl -->
        <Ellipse Grid.Row="1"
                     Width="{TemplateBinding Width}"
                     Height="{TemplateBinding Width}"
                     Stroke="Transparent" StrokeThickness="6"
                     Fill="{StaticResource brushBowl}" />
    </Grid>

    <!--add Orientation trigger-->
    <ControlTemplate.Triggers>
        <Trigger Property="Orientation" Value="Vertical">
            <Setter TargetName="border" Property="LayoutTransform">
                <Setter.Value>
                    <RotateTransform Angle="-90" />
                </Setter.Value>
            </Setter>
        </Trigger>
    </ControlTemplate.Triggers>    
</ControlTemplate>


回答2:

<Window x:Class="WpfApplication44.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="518" Width="542">
<Window.Resources>
<!-- Define template for thermometer progress bar -->
<ControlTemplate x:Key="templateThermometer"
                 TargetType="{x:Type ProgressBar}">

    <!-- Define two brushes for the thermometer liquid -->
    <ControlTemplate.Resources>
        <LinearGradientBrush x:Key="brushStem"
                             StartPoint="0 0"
                             EndPoint="1 0">
            <GradientStop Offset="0"
                          Color="Red" />
            <GradientStop Offset="0.3"
                          Color="Pink" />
            <GradientStop Offset="1"
                          Color="Red" />
        </LinearGradientBrush>

        <RadialGradientBrush x:Key="brushBowl"
                             GradientOrigin="0.3 0.3">
            <GradientStop Offset="0"
                          Color="Pink" />
            <GradientStop Offset="1"
                          Color="Red" />
        </RadialGradientBrush>
    </ControlTemplate.Resources>

    <!-- Two-row Grid divides thermometer into stem and bowl -->
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <!-- Second grid divides stem area in three columns -->
        <Grid Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="25*" />
                <ColumnDefinition Width="50*" />
                <ColumnDefinition Width="25*" />
            </Grid.ColumnDefinitions>

            <!-- This border displays the stem -->
            <Border Grid.Column="1"
                    BorderBrush="SteelBlue"
                    BorderThickness="3 3 3 0"
                    CornerRadius="6 6 0 0">

                <!-- Track and Indicator elements -->
                <Decorator Name="PART_Track">
                    <Border Name="PART_Indicator"
                            CornerRadius="6 6 0 0"
                            VerticalAlignment="Bottom"
                            Background="{StaticResource brushStem}" />
                </Decorator>
            </Border>
        </Grid>

        <!-- The bowl outline goes in the main Grid second row -->
        <Ellipse Grid.Row="1"
                 Width="{TemplateBinding Width}"
                 Height="{TemplateBinding Width}"
                 Stroke="SteelBlue"
                 StrokeThickness="3" />

        <!-- Another grid goes in the same cell -->
        <Grid Grid.Row="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="50*" />
                <RowDefinition Height="50*" />
            </Grid.RowDefinitions>

            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="25*" />
                <ColumnDefinition Width="50*" />
                <ColumnDefinition Width="25*" />
            </Grid.ColumnDefinitions>

            <!-- This is to close up the gap between bowl and stem -->
            <Border Grid.Row="0"
                    Grid.Column="1"
                    BorderBrush="SteelBlue"
                    BorderThickness="3 0 3 0"
                    Background="{StaticResource brushStem}" />
        </Grid>

        <!-- Another ellipse to fill up the bowl -->
        <Ellipse Grid.Row="1"
                 Width="{TemplateBinding Width}"
                 Height="{TemplateBinding Width}"
                 Stroke="Transparent"
                 StrokeThickness="6"
                 Fill="{StaticResource brushBowl}" />
    </Grid>
</ControlTemplate>
</Window.Resources>

<StackPanel>

    <!-- Create Thermometer ProgressBar -->
    <ProgressBar Template="{StaticResource templateThermometer}"
                 Orientation="Vertical"
                 Minimum="0"
                 Maximum="100"
                 Width="50"
                 Height="350"
                 Margin="50"
                 Value="{Binding ElementName=scroll, Path=Value}" />

    <!-- ScrollBar to simulate progress -->
    <ScrollBar Name="scroll"
               Orientation="Horizontal"
               Minimum="0"
               Maximum="100"
               Value="20"
               SmallChange="1"
               LargeChange="10"
               Margin="50 0 50 0" />

    <TextBlock Text="Manipulate ScrollBar to test ProgressBar"
               HorizontalAlignment="Center" />
</StackPanel>



标签: wpf wpf-4.0