【问题标题】:Display progress with discrete color fill of an image in silverlight在 Silverlight 中显示图像的离散颜色填充进度
【发布时间】:2012-02-08 08:32:21
【问题描述】:

在 Silverlight 中,我想将上传过程的进度显示为图像上的一系列增量颜色填充。

例如,

这是进度为 0 时:

这是 30% 的时候:

100% 是全彩色图像:

如何控制颜色填充(我知道这将借助技巧,例如覆盖原始图像的最终图像或其他东西)以显示进度?

我的任务可能很棘手,因为图像是 Windows Phone 项目中按钮的 OpacityMask。

附:只是为了避免混淆,因为我关心的是设计方面的问题。将进度与某些操作联系起来的逻辑已经到位。我只需要布置一个进度的演示文稿。

【问题讨论】:

    标签: .net silverlight animation controls progress


    【解决方案1】:

    编辑

    我做了一个实现。 A more thorough explanation and download of the code can be found on my blog.

    C#:

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    
    namespace CustomControls
    {
        [TemplatePart(Name="CLIPRECTANGLE", Type=typeof(RectangleGeometry))]
        public class ImageProgressBar : ProgressBar
        {
            public ImageProgressBar()
            {
                this.DefaultStyleKey = typeof(ImageProgressBar);
            }
    
            public ImageSource Source
            {
                get { return (ImageSource)GetValue(SourceProperty); }
                set { SetValue(SourceProperty, value); }
            }
    
            public static readonly DependencyProperty SourceProperty =
                DependencyProperty.Register("Source", typeof(ImageSource), typeof(ImageProgressBar), new PropertyMetadata(null));
    
            public Brush Fill
            {
                get { return (Brush)GetValue(FillProperty); }
                set { SetValue(FillProperty, value); }
            }
    
            public static readonly DependencyProperty FillProperty =
                DependencyProperty.Register("Fill", typeof(Brush), typeof(ImageProgressBar), new PropertyMetadata(null));
    
            private RectangleGeometry _clip;
    
            public override void OnApplyTemplate()
            {
                base.OnApplyTemplate();
                _clip = this.GetTemplateChild("CLIPRECTANGLE") as RectangleGeometry;
                this.ValueChanged += ImageProgressBar_ValueChanged;
                this.SizeChanged += ImageProgressBar_SizeChanged;
            }
    
            void ImageProgressBar_SizeChanged(object sender, SizeChangedEventArgs e)
            {
                UpdateClip();
            }
    
            void ImageProgressBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
            {
                UpdateClip();
            }
    
            private void UpdateClip()
            {
                if (_clip != null)
                {
                    _clip.Rect = new Rect(0, 0, this.ActualWidth, this.ActualHeight * ((this.Value - this.Minimum) / (this.Maximum - this.Minimum)));
                }
            }
        }
    }
    

    模板:generic.xaml

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                        xmlns:local="clr-namespace:CustomControls">
        <Style TargetType="local:ImageProgressBar">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="local:ImageProgressBar">
                        <Border BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                Margin="{TemplateBinding Margin}"
                                Background="{TemplateBinding Background}"
                                Width="{TemplateBinding Width}"
                                Height="{TemplateBinding Height}">
                            <Grid>
                                <Image Source="{TemplateBinding Source}"
                                       Stretch="Fill" />
                                <Rectangle Fill="{TemplateBinding Fill}">
                                    <Rectangle.OpacityMask>
                                        <ImageBrush ImageSource="{Binding Path=Source, RelativeSource={RelativeSource TemplatedParent}}"
                                                    Stretch="Fill" />
                                    </Rectangle.OpacityMask>
                                    <Rectangle.Clip>
                                        <RectangleGeometry x:Name="CLIPRECTANGLE" />
                                    </Rectangle.Clip>
                                </Rectangle>
                            </Grid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    
    </ResourceDictionary>
    

    使用方法:

    <my:ImageProgressBar Width="100"
                            Height="100"
                            Fill="Red"
                            Source="ProgressBar.png"
                            Minimum="100"
                            Maximum="200"
                            Value="{Binding ElementName=slider1, Path=Value, Mode=TwoWay}" />
    <Slider Margin="0"
            Name="slider1"
            VerticalAlignment="Top"
            Minimum="100"
            Maximum="200"
            Value="125" />
    

    像魅力一样工作:

    原答案

    你可以像这样创建一个线性渐变画笔:

    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
        <GradientStop Color="Black" Offset="0"/>
        <GradientStop Color="Black" Offset="1"/>
        <GradientStop Color="Lime" Offset="1"/>
        <GradientStop Color="Lime" Offset="1"/>
    </LinearGradientBrush>
    

    然后使用这个画笔绘制形状/字符/文本/任何东西。

    要显示进度,只需更新中间两个渐变点的偏移量。您可以绑定这些以使其更容易。

    要制作一个真正的进度条:为 ProgressBar 制作一个模板并将偏移量(多)绑定到进度条的值、最小值和最大值,并通过(Value - Minimum)/(Maximum - Minimum) 计算偏移量

    使用位图 (PNG):

    <Grid HorizontalAlignment="Center"
            VerticalAlignment="Center">
        <Image Source="ProgressBar.png"
                Width="100"
                Height="100" />
        <Rectangle Fill="Lime">
            <Rectangle.OpacityMask>
                <ImageBrush ImageSource="ProgressBar.png" />
            </Rectangle.OpacityMask>
            <Rectangle.Clip>
                <RectangleGeometry Rect="0,25,100,75"/>
            </Rectangle.Clip>
        </Rectangle>
    </Grid>
    

    当进度改变时替换 Rect。切断正确的数量。

    请注意,蒙版使用相同的图像。

    【讨论】:

    • 厄诺,谢谢。我想我理解了这个想法。你提议的是,我需要有一个我的“区域”的矢量表示,它想要逐渐填充颜色。然后我只是用不同的偏移量应用这个渐变画笔来显示进度。我不能只在 PNG 图像上应用渐变,对吗?
    • @MaximV.Pavlov - 我做了一个实现/CustomControl 并将其添加到我的答案中。
    • Erno,如果您能多花几分钟时间,如果您能使用您的自定义控件分享一个演示项目(带有源代码),我将不胜感激?我已经根据您的原始答案自己实施了这项任务,但您的新解决方案显然更加优雅。
    • @MaximV.Pavlov - 我在我的博客中添加了一个链接,其中包含此答案顶部的代码下载。
    【解决方案2】:

    前几天我制作了一个自定义 ProgressBar。我不会告诉你具体怎么做(因为我不是设计师),但这并不难。

    创建模板

    <ControlTemplate x:Key="CustomProgressBarTemplate" TargetType="ProgressBar">
        <Grid>
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup x:Name="CommonStates">
                    <VisualState x:Name="Determinate"/>
                    <VisualState x:Name="Indeterminate">
                        <!--Modyify your Storyboard-->
                        <Storyboard RepeatBehavior="Forever">
                            <DoubleAnimation Storyboard.TargetName="IndeterminateGradientFill"
                                Storyboard.TargetProperty="(Shape.Fill).(LinearGradientBrush.Transform).(TransformGroup.Children)[0].X"
                                Duration="00:00:.5" From="0" To="20" />
                            <ObjectAnimationUsingKeyFrames Duration="00:00:00" Storyboard.TargetName="IndeterminateRoot" Storyboard.TargetProperty="(UIElement.Visibility)">
                                <DiscreteObjectKeyFrame KeyTime="00:00:00">
                                    <DiscreteObjectKeyFrame.Value>
                                        <Visibility>Visible</Visibility>
                                    </DiscreteObjectKeyFrame.Value>
                                </DiscreteObjectKeyFrame>
                            </ObjectAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames Duration="00:00:00" Storyboard.TargetName="DeterminateRoot" Storyboard.TargetProperty="(UIElement.Visibility)">
                                <DiscreteObjectKeyFrame KeyTime="00:00:00">
                                    <DiscreteObjectKeyFrame.Value>
                                        <Visibility>Collapsed</Visibility>
                                    </DiscreteObjectKeyFrame.Value>
                                </DiscreteObjectKeyFrame>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
            <!--Default Root Visuals for either type of ProgressBar-->
            <Border x:Name="ProgressBarTrack" CornerRadius="3" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" />
            <Grid x:Name="ProgressBarRootGrid" >
                <Grid Margin="1">
                </Grid>
                <!-- Beginning of Indeterminate Progress Bar Visuals-->
                <Grid x:Name="IndeterminateRoot" Opacity="0.88" Visibility="Collapsed">
                </Grid>
                <!-- Beginning of Determinate Progress Bar Visuals-->
                <Grid x:Name="DeterminateRoot" Margin="1" >   
                </Grid>
            </Grid>
        </Grid>
    </ControlTemplate>
    

    在行列式和非行列式网格中,只需使用路径和形状绘制图像 (Storyboard.TargetProperty="(Shape.Fill).(LinearGradientBrush.Transform).(TransformGroup.Children)[0].X" LinearGradientBrush 是我用来填充网格中对象的画笔。) em>

    应用模板

     <ProgressBar Template="{StaticResource CustomProgressBarTemplate}"/>
    

    您将不得不玩弄设计,确保您只填写正确的 UIElement。我希望这对你来说是一个好的开始

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-02
      • 2012-12-17
      • 2023-02-20
      • 2021-11-03
      • 1970-01-01
      • 2016-09-01
      • 1970-01-01
      • 2012-09-05
      相关资源
      最近更新 更多