РЕДАКТИРОВАТЬ
Я сделал реализацию. Более подробное объяснение и скачать код можно найти в моем блоге .
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>
И нарисовать фигуру / символ / текст / что угодно с помощью этой кисти.
Чтобы показать прогресс, просто обновите смещения средних двухgradientstops.Вы можете связать их, чтобы было проще.
Чтобы создать реальный индикатор выполнения: Создайте шаблон для ProgressBar и (multi) привяжите смещения к значению, минимуму и максимуму индикатора выполнения и рассчитайте смещение с помощью(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 при изменении прогресса.Чтобы обрезать правильное количество.
Обратите внимание, что то же изображение используется для маски.