none
WPF C#: ProgressBar - verteilte Grafikanzeige RRS feed

  • Frage

  • Hallo,

    gibt es eine Möglichkeit die prozentualen Anteile grafisch mit einem ProgressBar wie im Bild darzustellen?

    Die Werte für die Balken können jeweils immer unterschiedlich sein und werden während der Laufzeit bestimmt. Es können beliebig viele Balken vorkommen.

    Montag, 18. Januar 2016 20:36

Antworten

  • Hallo,

    als erstes sehe ich kein richtiges Problem, aber eine Unschönheit. Ich rate davon ab die ProgressBars im C# zu instanziieren und dann über eine Liste an die UI weiter zu reichen. Besser wäre es eine eigene kleine Klasse dafür anzulegen und davon eine Liste zu übergeben.

    Ich würde es wie Peter vorgeschlagen hat in ein eigenes Control auslagern. Das kapselt das Ganze einfach etwas ab.

    Das Problem bei deinem Code ist, dass _ProgressBars innerhalb des DataGrids im COntext des einzelnen Datensatzes gesucht wird und nicht im MainWindow. Entweder du navigierst per RelativeSource o.ä. diese eine Ebene höher oder aber lagerst _ProgressBars in die Datensatz-Klasse aus.

    Sollten wirklich alle Datensätze die selben Balken anzeigen sollen, so würde ich das sein lassen und den ProgressBar neben dem DG anzeigen.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    • Als Antwort markiert spry64 Donnerstag, 21. Januar 2016 20:37
    Donnerstag, 21. Januar 2016 14:17
    Moderator

Alle Antworten

  • Hallo,

    das standard-ProgressBar-Control kann so etwas nicht. Du kannst es dir aber recht leicht selbst bauen. Eine Möglichkeit wäre beispielsweise eine Liste mit Elementen, welche jeweils die berechneten Koordinaten der einzelnen Teile enthält. Im XAML kannst du dann ein ItemsControl an diese Liste binden und als ItemsPanel ein Canvas nutzen. Über das ItemContainerStyle ist es möglich die Left bzw. Top Eigenschaft an die Werte des jeweiligen Items zu binden.

    Wenn du ein eigenes Control daraus machen willst, empfehle ich dir nach außen hin nur eine Liste als Eigenschaft zu erstellen, die in Prozentualen (oder sonstigen Brüchen) die Größe und Position der Elemente entgegen nimmt.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Montag, 18. Januar 2016 21:59
    Moderator
  • Hi,
    mit einem horizontalen StackPanel wäre so etwas auch möglich.

    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    Montag, 18. Januar 2016 23:09
  • Hallo,

    also das ganze soll in eine DataGrid-Zelle angezeigt werden. Ich habe versucht das mit einem StackPanel zu machen und zwar wie folgt:

    public partial class MainWindow : Window
    {
            public ObservableCollection<ProgressBar> _ProgressBars { get; set; }
            public MainWindow()
            {
    
                _ProgressBars = new ObservableCollection<ProgressBar>();
                ProgressBar prgb1 = new ProgressBar { Background = Brushes.LightBlue, Width = 50, BorderThickness = new Thickness(0), Foreground = Brushes.Blue, Value = 34, Minimum = 0, Maximum = 100 };
                ProgressBar prgb2 = new ProgressBar { Background = Brushes.LightBlue, Width = 30, BorderThickness = new Thickness(0), Foreground = Brushes.Blue, Value = 50, Minimum = 0, Maximum = 100 };
                _ProgressBars.Add(prgb1);
                _ProgressBars.Add(prgb2);
            }
    }

    XAML-Code dazu:

        <Grid Name="Hauptfenster">
            <DataGrid x:Name="DataGridAnzeige" ItemsSource="{Binding _outputCollection}" HorizontalAlignment="Left" 
                      Margin="0,44,0,0" AutoGenerateColumns="False"  VerticalAlignment="Top" Height="Auto" Width="Auto"
                      IsReadOnly="True" VerticalScrollBarVisibility="Auto">
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding PCName}"  Header = "PC-Name"/>
                    <DataGridTextColumn Binding="{Binding WertEins}"  Header = "erster Wert"/>
                    <DataGridTextColumn Binding="{Binding WertZwei}"  Header = "letzter Wert"/>
                    <DataGridTextColumn Binding="{Binding Ein}"  Header = "% eingeschaltet"/>
                    <DataGridTextColumn Binding="{Binding Aus}"  Header = "% ausgeschaltet"/>
                    <DataGridTemplateColumn Header="Grafik" Width="300" Visibility="Visible">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <ItemsControl   ItemsSource="{Binding _ProgressBars}">
                                    <ItemsControl.ItemsPanel>
                                        <ItemsPanelTemplate>
                                            <StackPanel Orientation="Horizontal" MaxWidth="300" FlowDirection="LeftToRight" HorizontalAlignment="Stretch">
                                            </StackPanel>
                                        </ItemsPanelTemplate>
                                    </ItemsControl.ItemsPanel>
                                </ItemsControl>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
            </DataGrid>
        </Grid>

    Es wird aber nichts angezeigt in der Spalte "Grafik"

    So wird aber in der GUI was angezeigt:

    <Grid>
    	<ItemsControl   ItemsSource="{Binding _ProgressBars}">
    		<ItemsControl.ItemsPanel>
    			<ItemsPanelTemplate>
    				<StackPanel Orientation="Horizontal" MaxWidth="300" FlowDirection="LeftToRight" HorizontalAlignment="Stretch">
    				</StackPanel>
    			</ItemsPanelTemplate>
    		</ItemsControl.ItemsPanel>
    	</ItemsControl>
    </Grid>

    Woran könnte es liegen?


    • Bearbeitet spry64 Mittwoch, 20. Januar 2016 19:51
    Mittwoch, 20. Januar 2016 19:44
  • Hi,
    bei solcher Aufgabenstellung würde ich ein einfaches UserControl programmieren. Das UserControl wird in der DataGrid-Spalte zur Anzeige genutzt. Dem UserControl wird eine Liste übergeben. Anhand der Liste "malt" das UserControl farbige Rechtecke, z.B. in einem horizontal orientieren StackPanel. Alternativ kann auch ein Canvas mit absoluter Positionierung der farbigen Bereiche genutzt werden.

    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    Donnerstag, 21. Januar 2016 05:27
  • Ich komme mit dem UserControl leider nicht zurecht. Was ist denn an meinem Code falsch, dass es nicht funktioniert?
    Donnerstag, 21. Januar 2016 13:57
  • Hallo,

    als erstes sehe ich kein richtiges Problem, aber eine Unschönheit. Ich rate davon ab die ProgressBars im C# zu instanziieren und dann über eine Liste an die UI weiter zu reichen. Besser wäre es eine eigene kleine Klasse dafür anzulegen und davon eine Liste zu übergeben.

    Ich würde es wie Peter vorgeschlagen hat in ein eigenes Control auslagern. Das kapselt das Ganze einfach etwas ab.

    Das Problem bei deinem Code ist, dass _ProgressBars innerhalb des DataGrids im COntext des einzelnen Datensatzes gesucht wird und nicht im MainWindow. Entweder du navigierst per RelativeSource o.ä. diese eine Ebene höher oder aber lagerst _ProgressBars in die Datensatz-Klasse aus.

    Sollten wirklich alle Datensätze die selben Balken anzeigen sollen, so würde ich das sein lassen und den ProgressBar neben dem DG anzeigen.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    • Als Antwort markiert spry64 Donnerstag, 21. Januar 2016 20:37
    Donnerstag, 21. Januar 2016 14:17
    Moderator
  • Mit der Änderung

    <ItemsControl  ItemsSource="{Binding _ProgressBars, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">

    werden nun die ProgressBars angezeigt. Danke für die Hilfe.

    Donnerstag, 21. Januar 2016 20:42
  • Hallo ich habe noch ein Problem bezüglich dieser Aufgabe:

    Wenn ich folgenden Quellcode habe:

        public partial class MainWindow : Window
        {
            public ObservableCollection<Data> _dataCollection = new ObservableCollection<Data>();
            public ObservableCollection<ProgressBar> _ProgressBars { get; set; }
    		
            public MainWindow()
            {
                InitializeComponent();
                AddValues()
            }
    		
    	public class Data
            {
                public string PCName { get; set; }
                public string WertEins { get; set; }
                public string WertZwei { get; set; }
                public string Ein { get; set; }
                public string Aus { get; set; }
                public ObservableCollection<ProgressBar> progressBars { get; set; }
            }
    		
    	public void AddValues(){
    	     _ProgressBars = new ObservableCollection<ProgressBar>();
    	     ProgressBar prgb1 = new ProgressBar { Background = Brushes.LightBlue, Width = 50, Foreground = Brushes.Blue, Value = 34 };
                 ProgressBar prgb2 = new ProgressBar { Background = Brushes.LightBlue, Width = 30, Foreground = Brushes.Blue, Value = 50};
                 _ProgressBars.Add(prgb1);
                 _ProgressBars.Add(prgb2);
    			
    	     _dataCollection.Clear();
    	     _outputCollection.Add(new Data
    	     {
    		     PCName = "PC1234",
    		     WertEins = "Date1",
    		     WertZwei = "Date2",
    		     Ein = "45",
    		     Aus = "55",
    	             progressBars = _ProgressBars
    	      });		
    	}
    		
    	public ObservableCollection<Data> _outputCollection
            {
                get
                {
                    if (_dataCollection == null)
                    {
                        _dataCollection = new ObservableCollection<Data>();
                    }
                    return _dataCollection;
                }
            }
         }


    Und dazu diesen XAML Code:

    <Window x:Class="Test.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Test" Height="486" SizeToContent="WidthAndHeight" Width="650" DataContext="{Binding RelativeSource={RelativeSource Self}}">
        <Grid>
            <DataGrid x:Name="DataGridAnzeige" ItemsSource="{Binding _outputCollection}" HorizontalAlignment="Left" 
                      Margin="0,44,0,0" AutoGenerateColumns="False"  VerticalAlignment="Top" Height="Auto" Width="Auto"
                      IsReadOnly="True" VerticalScrollBarVisibility="Auto">
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding PCName}"  Header = "PC-Name"/>
                    <DataGridTextColumn Binding="{Binding WertEins}"  Header = "erster Wert"/>
                    <DataGridTextColumn Binding="{Binding WertZwei}"  Header = "letzter Wert"/>
                    <DataGridTextColumn Binding="{Binding Ein}"  Header = "% eingeschaltet"/>
                    <DataGridTextColumn Binding="{Binding Aus}"  Header = "% ausgeschaltet"/>
                    <DataGridTemplateColumn Header="Grafik" Width="300" Visibility="Visible">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <ItemsControl  ItemsSource="{Binding Source=Data, Path=progressBars}">
                                    <ItemsControl.ItemsPanel>
                                        <ItemsPanelTemplate>
                                            <StackPanel Orientation="Horizontal" MaxWidth="300" FlowDirection="LeftToRight" HorizontalAlignment="Stretch">
                                            </StackPanel>
                                        </ItemsPanelTemplate>
                                    </ItemsControl.ItemsPanel>
                                </ItemsControl>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
    </Window>

    Was müsste ich an dem XAML-Code ändern, damit die ProgresssBars, im DataGrid in der Spalte "Grafik" angezeigt werden können?

    Wie man an den Code sieht habe ich es mit 

    <ItemsControl  ItemsSource="{Binding Source=Data, Path=progressBars}">

    versucht. Es wird aber nichts angezeigt. Die Liste _dataCollection wird im DataGrid angezeigt. Nur nicht die ProgressBars. Woran könnte es liegen. Wäre für Hilfe oder Tipps dankbar.




    • Bearbeitet spry64 Mittwoch, 27. Januar 2016 20:58
    Mittwoch, 27. Januar 2016 20:52