0

I made a custom UserControl showing Text in a ProgressBar that shows percentage or time defined by the 'showPercentage' boolean.

XAML

<UserControl x:Class="ProgressBar.ProgressBarText"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:ProgressBar"
             mc:Ignorable="d" 
             d:DesignHeight="20" d:DesignWidth="100">
    <Grid>
        <Rectangle x:Name="pBorder" Fill="LightGray" HorizontalAlignment="Stretch"  VerticalAlignment="Stretch" Stroke="Black" StrokeThickness="1"/>
        <Rectangle x:Name="pFill" Fill="Green" Stroke="Transparent" StrokeThickness="2" HorizontalAlignment="Left" VerticalAlignment="Stretch" Width="100"/>
        <Viewbox>
            <Label x:Name="pLabel" HorizontalAlignment="Center" VerticalAlignment="Center" Content="Test"/>
        </Viewbox>
    </Grid>
</UserControl>

C# Code

using ...

namespace ProgressBar
{
    /// <summary>
    /// Interaktionslogik für ProgressBarText.xaml
    /// </summary>
    public partial class ProgressBarText : UserControl
    {


        public int Value { get; set; }
        public bool showPercentage { get; set; }
        public double percentage { get; set; }
        public int Maximum { get; set; }


        public ProgressBarText()
        {
            InitializeComponent();
        }

        public void getValues()
        {
            if (Maximum != 0)
            {
                percentage = ((double)Value / Maximum) * 100;
                pFill.Width = this.Width * percentage / 100;

                if (showPercentage == true)
                {
                    pLabel.Content = percentage.ToString() + "%";
                }
                else
                {
                    int Days = (int)(Maximum - Value) / 60 / 24;
                    int Hours = (int)((Maximum - Value) - (Days * 24 * 60))/60;
                    int Minutes = (int)((Maximum - Value) - (Hours * 60) - (Days * 24 * 60));

                    if (Days > 0)
                    {
                        pLabel.Content = Days.ToString() + "d " + Hours.ToString() + "h " + Minutes.ToString() + "m";

                    }
                    else
                    {
                        if (Hours > 0)
                        {
                            pLabel.Content = Hours.ToString() + "h " + Minutes.ToString() + "m";
                        }
                        else
                        {
                            pLabel.Content = Minutes.ToString() + "m";
                        }
                    }

                }
            }
        }
    }
}

In my MainWindow I got a ListView that should show a line per Name with my custom control. I made a custom class named "Progress"

ListView XAML

 <ListView x:Name="lvProgress" Grid.Column="1" Margin="10">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}">
                    </GridViewColumn>
                    <GridViewColumn Header="ProgressValue">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <local:ProgressText Value="{Binding ProgressValue}" Maximum="{Binding ProgressMax}"  Width="100" Height="15" showPercentage="false"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Header="Date" DisplayMemberBinding="{Binding Datum}"/>
                </GridView>
            </ListView.View>
        </ListView>

C# Progress-class

 List<Progress> SeriesCollection = new List<Progress>();


public class Progress{
            public string pbName { get; set; }
            public string Name { get; set; }
            public DateTime CreateDate { get; set; }
            public int ProgressValue { get; set; }
            public int ProgressMax { get; set; }
            public string DateFinished { get; set; }

       public void GetChanges()
        {
           foreach(Progress progress in SeriesCollection)
            {
                progress.Update();
            }
            lvProgress.ItemsSource = SeriesCollection;

        }

       public void AddListItem(string name, int baketime, DateTime date)
        {
            SeriesCollection.Add(new Progress() {pbName="pb"+name, Name = name,CreateDate = date, ProgressMax = baketime, ProgressValue = (int)TimeSpan.FromTicks(DateTime.UtcNow.Ticks - date.Ticks).TotalMinutes, DateFinished = date.AddDays((int)(baketime/60/24)).ToString("dd.MM.yyyy HH:mm") });
        }
}

This doesn't work for me. I tried setting up the ProgressText attributes as DependencyProperties but that didn't work either.

Is there an easy way to fix this. Articles or books explaining custom UserControls are also appreciated.

Thanks Max

  • "I tried setting up the ProgressText attributes as DependencyProperties" - if done properly, it should work – ASh Dec 12 '19 at 11:16
  • 1
    A Binding expression like `Value="{Binding ProgressValue}"` requires that `Value` is a dependency property. You have no choice about that. Start reading here: [Custom Dependency Properties](https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/custom-dependency-properties). Pay special attention to the implementation of PropertyChangedCallbacks, because that is where your control can react on value changes of its properties. – Clemens Dec 12 '19 at 11:16
  • 2
    Just in case you come across blogs on the internet where they tell you to add a view model to the UserControl and to assign its DataContext, ignore that. They are all wrong and written by dorks. – Clemens Dec 12 '19 at 11:20
  • See e.g. [this answer](https://stackoverflow.com/a/40184402/1136211) for short sample. – Clemens Dec 12 '19 at 11:22
  • Thanks Clemens! I set the values in **both** classes to DependencyProperty and it works like a charm now! Thank you again! – FlamingFlamingo42 Dec 12 '19 at 12:05

0 Answers0