Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make a multi-colored segmented progress bar in wpf?

I'm trying to create a UserControl that acts as a sort of segmented progress bar. Input would be a collection of objects, each object would have a category, a duration property, and status property. The UserControl should stretch the width and height of the parent control. Each item in the collection should represent a segment of the progress bar; color of the segment is related to the status, the width of the segment is related to the duration, and the text overlaid on the segment would be related to the category or something.

Example custom progress bar: s

The text might be the collection item's ID, the top segment color would be related to status, the bottom color would be related to the category, and the width related to the duration.

Some of the options I've considered:

  • Make a stackpanel and somehow define each items width and wrap the whole thing in a viewbox to make it stretch the height and width. How could I control the text size, how do I make the content fit the height, how do I bind a stackpanel to a collection?
  • Make an attached property for a grid control that would dynamically create columns and map the collection items to the grids. Seems like a lot of work and I'm hoping theres a simpler solution since my requirements are pretty specific.
  • Maybe theres a way to override a uniform grid to make it non-uniform?
  • Maybe I should just go all code-behind and draw rectangles by iterating through my collection?

Either way, I am crossing my fingers that somebody might know a simple solution to my problem.

like image 433
ErpaDerp Avatar asked Nov 13 '15 06:11

ErpaDerp


People also ask

What is ProgressBar WPF?

WPF - Progressbar 1 A bar that displays a repeating pattern, or 2 A bar that fills based on a value. More ...

How to change the color of the progress bar in CSS?

These progress bars signify an emotion through their background colors such as success, danger, and neutrality. To create some portion of the progress bar in a different color just keep adding a new div with class progress-bar inside progress. Method 2: Using the background-color property of CSS:

What is ProgressBar in Revit?

ProgressBar is a control that indicates the progress of an operation, where the typical visual appearance is a bar that animates a filled area as the progress continues. It can show the progress in one of the two following styles − A bar that fills based on a value. Given below are the most commonly used properties of ProgressBar.

What are the properties of ProgressBar?

A bar that fills based on a value. Given below are the most commonly used properties of ProgressBar. Gets or sets a value that indicates whether the progress bar reports generic progress with a repeating pattern or reports progress based on the Value property. Identifies the IsIndeterminate dependency property.


Video Answer


1 Answers

Here is a full working proposition of solution to the custom progress bar.

Code is here : http://1drv.ms/1QmAVuZ

a customized progress bar

1 . If all the steps are not the same width, I prefer to use Grid with columns and different widths

The columns are built dynamically based upon following class :

public class StepItem
{
    public int Length { get; set; }
    public int Index { get; set; }
    public String  Label { get; set; }
    public Brush Brush { get; set; }
}

2. I chose to implement a CustomControl and inherit of ItemsControl

CustomControl because I don't want to take care of implementing of the parts of the template of the Progressbar.

ItemsControl because :

-I want to provide to ItemsSource property a collection of StepItems

-ItemsControl can have some DataTemplate as template for each item

-ItemsControl can have any Panel like Grid as template presenting the collection of items

3. The component has template in Generic.xaml

-layoutGrid wil have the "continuous rainbow"

-overlayGrid will be displayed partially over the steps depending on progression or totally over (if no progress)

-ItemsPresenter will present the collection of DataTemplates corresponding to each StepItem

<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type local:ProgressItemsControl}">
            <Border BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}">
                <Grid x:Name="layoutGrid">
                    <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                    <Grid x:Name="overlayGrid" Width="100" HorizontalAlignment="Right" Background="White"/>
                </Grid>
            </Border>
        </ControlTemplate>
    </Setter.Value>
</Setter>

4. Customisation of the ItemsPanel to use a Grid (instead of vertical layout)

<Setter Property="ItemsPanel">
    <Setter.Value>
        <ItemsPanelTemplate >
            <Grid x:Name="stepsGrid" IsItemsHost="True" />
        </ItemsPanelTemplate>
    </Setter.Value>
</Setter>

5. In code behind of components, setting of the column width

int i = 0;
foreach (StepItem stepItem in ItemsSource)
{
    total += stepItem.Length;
    var columnDefinition = new ColumnDefinition() { Width = new GridLength(stepItem.Length, GridUnitType.Star) };
    stepsGrid.ColumnDefinitions.Add(columnDefinition);
    Grid.SetColumn(stepsGrid.Children[i], stepItem.Index);
    i++;
}

6. Code behind for declaring Dependency properties that can be monitored

(excerpt)

public int Value
{
    get { return (int)GetValue(ValueProperty); }
    set { SetValue(ValueProperty, value); }
}
// Using a DependencyProperty as the backing store for Value.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty ValueProperty =
    DependencyProperty.Register("Value", typeof(int), typeof(ProgressItemsControl), new PropertyMetadata(0));

7. Usage of the component

<local:CustomProgressBar
    x:Name="customProgressBar1"
    HorizontalAlignment="Left" Height="50" Margin="32,49,0,0"      
    VerticalAlignment="Top" Width="379"/>

8. Feeding the component with data

private List<StepItem> stepItems = new List<StepItem>{
            new StepItem{
                Index=0,
                Label="Step1",
                Length=20,
                Brush = new SolidColorBrush(Color.FromArgb(255,255,0,0)),
            new StepItem{
                Index=4,
                Label="Step5",
                Length=25,
                Brush = new SolidColorBrush(Color.FromArgb(255,0,128,0)),
           },
        };
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    progressItemsControl1.ItemsSource = stepItems;
}

Regards

like image 121
Emmanuel DURIN Avatar answered Sep 24 '22 19:09

Emmanuel DURIN