2011-02-02 6 views

答えて

21

いくつかのオプションがあります。最初は、ProgressBarコントロールをテンプレートすることです。これはやや難解です。私はどのようにuse an attached ViewModel to achieve the required effectを説明するブログ記事を書いた。

また、独自のコントロールを最初から作成することもできます。あなたは、次の操作を実行できます。

  1. 新しいユーザーコントロール
  2. を作成し、それに新しい値、最大値と最小値の依存関係プロパティを追加します。
  3. Angleプロパティを計算するために、ユーザーコントロール内のValue、MaximumおよびMinimumのプロパティ変更イベントを処理します。
  4. 2つの「パイの部分」をコードの背後に構築して(this postを参照)、それらをUIに追加します。
+3

既存のProgressBarをテンプレート化してみませんか?この目的のためにWPFのCustomControlsは正確に見えません。あなたが必要なときに再利用するつもりがないときに、無意味なコントロールを作成するという、あらゆる面倒を見逃してしまったという点は、UIでそれを別の表現にしているのでしょうか? – NVM

+2

@NVM、私は原則としてあなたに同意しますが、ここではいくつかのコードが必要になるでしょう。純粋なXAMLを使用してWPFの組み込みの図形を使用して切り抜き円弧を作成する簡単な方法はありません。 Expression Blend SDKを使用している場合は、非常に簡単に行うことができる弧型があります。したがって、OPはおそらく、パイを描くことができる何らかの制御を作成する必要があります。しかし、プログレスバーの実装は、この新しい「パイ」コントロールを使用するテンプレートでなければなりません。 – Josh

+0

私の編集した答えを見てください。あなたがそれをあなたが提案する方法で行うことはできません。私は一般的にあなたが離れていくことができるように小さなコードを書く方が良いと思う。 – NVM

6

ValueConverterを見ましたか? TemplateBindingを使用してテンプレートのValueプロパティにバインドし、適切な値コンバーターを使用して、値をCircularプログレスバーに役立つ値に変更することができます。

EDIT:テンプレートで

  1. は円が黄色で塗りつぶします。

  2. 色のオレンジ色の上にもう1つの円を追加します。

  3. に加え円は3で返さジオメトリと2の円をクリップの(おそらくは円弧セグメントを使用して)クリッピングジオメトリを返すために値変換(又は多値変換器)を使用。

  4. Downvoterは私に私のrepzを返します。

+0

-1、これはバリューコンバータでは達成できません。ビジュアルツリーで対処する必要があります。 – Josh

+0

新しい編集内容をご覧ください。 – NVM

+0

私はあなたが技術的にそうすることができると思うので、私はdownvoteを削除しました。 :)しかし、UIElementのサブクラスでこれを行うと、ProgressBarのテンプレートに貼り付けるほうがずっと簡単になります。 – Josh

6

これは少し難解ですが不可能ではありません。ここでは、滑らかなアニメーションを使用して私の実装をガイドしています。 CircularProgressBarを作成するには、値コンバーターを使用する必要があります。

enter image description here

CircularProgressBar.cs

public partial class CircularProgressBar : ProgressBar 
{ 
    public CircularProgressBar() 
    { 
     this.ValueChanged += CircularProgressBar_ValueChanged; 
    } 

    void CircularProgressBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) 
    { 
     CircularProgressBar bar = sender as CircularProgressBar; 
     double currentAngle = bar.Angle; 
     double targetAngle = e.NewValue/bar.Maximum * 359.999; 

     DoubleAnimation anim = new DoubleAnimation(currentAngle, targetAngle, TimeSpan.FromMilliseconds(500)); 
     bar.BeginAnimation(CircularProgressBar.AngleProperty, anim, HandoffBehavior.SnapshotAndReplace); 
    } 

    public double Angle 
    { 
     get { return (double)GetValue(AngleProperty); } 
     set { SetValue(AngleProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for Angle. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty AngleProperty = 
     DependencyProperty.Register("Angle", typeof(double), typeof(CircularProgressBar), new PropertyMetadata(0.0)); 

    public double StrokeThickness 
    { 
     get { return (double)GetValue(StrokeThicknessProperty); } 
     set { SetValue(StrokeThicknessProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for StrokeThickness. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty StrokeThicknessProperty = 
     DependencyProperty.Register("StrokeThickness", typeof(double), typeof(CircularProgressBar), new PropertyMetadata(10.0)); 
} 

AngleToPointConverter.cs

class AngleToPointConverter : IValueConverter 
{ 

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     double angle = (double)value; 
     double radius = 50; 
     double piang = angle * Math.PI/180; 

     double px = Math.Sin(piang) * radius + radius; 
     double py = -Math.Cos(piang) * radius + radius; 

     return new Point(px, py); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

AngleToIsLargeConverter。CS

class AngleToIsLargeConverter : IValueConverter 
{ 

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     double angle = (double)value; 

     return angle > 180; 
    } 

    public object ConvertBack(object value, Type targetTypes, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

App.xaml

<Application x:Class="WpfApplication1.App" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     StartupUri="MainWindow.xaml" 
     xmlns:my="clr-namespace:WpfApplication1"> 
<Application.Resources> 
    <my:AngleToPointConverter x:Key="prConverter"/> 
    <my:AngleToIsLargeConverter x:Key="isLargeConverter"/> 

    <Style x:Key="circularProgressBar" TargetType="my:CircularProgressBar"> 
     <Setter Property="Value" Value="10"/> 
     <Setter Property="Maximum" Value="100"/> 
     <Setter Property="StrokeThickness" Value="10"/> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="my:CircularProgressBar"> 
         <Canvas Width="100" Height="100"> 
         <Ellipse Width="100" Height="100" Stroke="LightGray" 
            StrokeThickness="1"/> 

         <Path Stroke="{TemplateBinding Background}" 
            StrokeThickness="{TemplateBinding StrokeThickness}"> 
           <Path.Data> 
            <PathGeometry> 
             <PathFigure x:Name="fig" StartPoint="50,0"> 
              <ArcSegment RotationAngle="0" SweepDirection="Clockwise" 
                 Size="50,50" 
                 Point="{Binding Path=Angle, Converter={StaticResource prConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType=ProgressBar}}" 
                 IsLargeArc="{Binding Path=Angle, Converter={StaticResource isLargeConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType=ProgressBar}}" 
                 > 
              </ArcSegment> 
             </PathFigure> 
            </PathGeometry> 
           </Path.Data> 
          </Path> 
          <Border Width="100" Height="100"> 
           <TextBlock Foreground="Gray" HorizontalAlignment="Center" VerticalAlignment="Center" 
             Text="{Binding Path=Value, StringFormat={}%{0}, 
           RelativeSource={RelativeSource TemplatedParent}}" 
              FontSize="{TemplateBinding FontSize}"/> 
          </Border> 
         </Canvas> 

       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 
</Application.Resources> 

それはより多くの私はこれを知っているなど

0

InnerRadius、RADIUSなどのいくつかのより多くのプロパティを追加することでカスタマイズすることができます古い問題ですが、とにかく私の解決策です:

WinFormsのFOR

using System; 
using System.Drawing; 
using System.Drawing.Drawing2D; 
using System.Windows.Forms; 

public class CircularProgressBar : Control 
{ 
    /* CREDITS: 
    * Autor: Sajjad Arif Gul/October 12, 2016/C#, Source Codes 
    * https://www.csharpens.com/c-sharp/circular-progress-bar-in-c-sharp-windows-form-applications-23/ 
    * Modified by Jhollman Chacon, 2017 */ 

#region Enums 

public enum _ProgressShape 
{ 
    Round, 
    Flat 
} 

#endregion 

#region Variables 

private long _Value; 
private long _Maximum = 100; 
private Color _ProgressColor1 = Color.Orange; 
private Color _ProgressColor2 = Color.Orange; 
private Color _LineColor = Color.Silver; 
private _ProgressShape ProgressShapeVal; 

#endregion 

#region Custom Properties 

public long Value 
{ 
    get { return _Value; } 
    set 
    { 
     if (value > _Maximum) 
      value = _Maximum; 
     _Value = value; 
     Invalidate(); 
    } 
} 

public long Maximum 
{ 
    get { return _Maximum; } 
    set 
    { 
     if (value < 1) 
      value = 1; 
     _Maximum = value; 
     Invalidate(); 
    } 
} 

public Color ProgressColor1 
{ 
    get { return _ProgressColor1; } 
    set 
    { 
     _ProgressColor1 = value; 
     Invalidate(); 
    } 
} 

public Color ProgressColor2 
{ 
    get { return _ProgressColor2; } 
    set 
    { 
     _ProgressColor2 = value; 
     Invalidate(); 
    } 
} 

public Color LineColor 
{ 
    get { return _LineColor; } 
    set 
    { 
     _LineColor = value; 
     Invalidate(); 
    } 
} 

public _ProgressShape ProgressShape 
{ 
    get { return ProgressShapeVal; } 
    set 
    { 
     ProgressShapeVal = value; 
     Invalidate(); 
    } 
} 

#endregion 

#region EventArgs 

protected override void OnResize(EventArgs e) 
{ 
    base.OnResize(e); 
    SetStandardSize(); 
} 

protected override void OnSizeChanged(EventArgs e) 
{ 
    base.OnSizeChanged(e); 
    SetStandardSize(); 
} 

protected override void OnPaintBackground(PaintEventArgs p) 
{ 
    base.OnPaintBackground(p); 
} 

#endregion 

#region Methods 
public CircularProgressBar() 
{ 
    Size = new Size(130, 130); 
    Font = new Font("Segoe UI", 15); 
    MinimumSize = new Size(100, 100); 
    DoubleBuffered = true; 
    Value = 57; 
    ProgressShape = _ProgressShape.Flat; 
    this.ForeColor = Color.DimGray; 
} 

private void SetStandardSize() 
{ 
    int _Size = Math.Max(Width, Height); 
    Size = new Size(_Size, _Size); 
} 

public void Increment(int Val) 
{ 
    this._Value += Val; 
    Invalidate(); 
} 

public void Decrement(int Val) 
{ 
    this._Value -= Val; 
    Invalidate(); 
} 
#endregion 

#region Events 
protected override void OnPaint(PaintEventArgs e) 
{ 
    base.OnPaint(e); 
    using (Bitmap bitmap = new Bitmap(this.Width, this.Height)) 
    { 
     using (Graphics graphics = Graphics.FromImage(bitmap)) 
     { 
      graphics.SmoothingMode = SmoothingMode.AntiAlias; 
      graphics.Clear(this.BackColor); 

      // Dibuja la Linea 
      using (Pen pen2 = new Pen(LineColor)) 
      { 
       graphics.DrawEllipse(pen2, 0x18 - 6, 0x18 - 6, (this.Width - 0x30) + 12, (this.Height - 0x30) + 12); 
      } 

      //Dibuja la Barra de Progreso 
      using (LinearGradientBrush brush = new LinearGradientBrush(this.ClientRectangle, this._ProgressColor1, this._ProgressColor2, LinearGradientMode.ForwardDiagonal)) 
      { 
       using (Pen pen = new Pen(brush, 14f)) 
       { 
        switch (this.ProgressShapeVal) 
        { 
         case _ProgressShape.Round: 
          pen.StartCap = LineCap.Round; 
          pen.EndCap = LineCap.Round; 
          break; 

         case _ProgressShape.Flat: 
          pen.StartCap = LineCap.Flat; 
          pen.EndCap = LineCap.Flat; 
          break; 
        } 
        //Aqui se dibuja el Progreso 
        graphics.DrawArc(pen, 0x12, 0x12, (this.Width - 0x23) - 2, (this.Height - 0x23) - 2, -90, (int)Math.Round((double)((360.0/((double)this._Maximum)) * this._Value))); 
       } 
      } 

      //Dibuja el Texto de Progreso: 
      Brush FontColor = new SolidBrush(this.ForeColor); 
      SizeF MS = graphics.MeasureString(Convert.ToString(Convert.ToInt32((100/_Maximum) * _Value)), Font); 
      graphics.DrawString(Convert.ToString(Convert.ToInt32((100/_Maximum) * _Value)), Font, FontColor, Convert.ToInt32(Width/2 - MS.Width/2), Convert.ToInt32(Height/2 - MS.Height/2)); 
      e.Graphics.DrawImage(bitmap, 0, 0); 
      graphics.Dispose(); 
      bitmap.Dispose(); 
     } 
    } 
} 
#endregion 
} 

IMPLEMENTATION:

  1. 場所どこでもあなたのWinFormsプロジェクトで新しいクラスへのソースコードは、クラスのCircularProgressBar.cs」を名前を付けます。
  2. プロジェクトをコンパイルします。
  3. コンパイル後、ツールバーに新しいコントロールまたは 'コンポーネント'が表示されます。
  4. この新しいコントロールを任意のフォームにドラッグアンドドロップし、そのプロパティをカスタマイズします。

    をお楽しみ

    Control Preview

コントロールは次のようになります。

関連する問題