EDIT2: Wenn das Diagramm ausgefüllt wird, kann ich die Werte nicht mehr ändern. Selbst wenn ich die Werte in der Liste ändere (woher die ItemControls die Werte beziehen), scheint das Diagramm nicht mit den neuen Werten zu aktualisieren.Datenbindung ItemsControl (DataTemplate) wird nicht aktualisiert/erhält nur Werte beim Programmstart
Ich rufe die GetDataGrafiek() Methode im Timer auf, um mein Diagramm alle x Sekunden zu aktualisieren.
Grafiek graf = new Grafiek();
graf.GetDataGrafiek();
Ist dies aufgrund des Threading-Timer in einem separaten Thread ausgeführt wird (IsAsynchronous
Methode im ObjectDataProvider
) oder muß ich zugreifen müssen, um die DataContext
des Itemscontrol in meiner Timer-Methode?
EDIT: Ich konnte nicht der Lage, die Grafik zu füllen, wenn das Programm bereits ausgeführt wird, so habe ich die ObservableCollection<GrafiekBar>
statische (Liste, die die Fill und Wert der Stäbe halten) und initialisiert ist, wie folgend:
public static ObservableCollection<GrafiekBar> listGrafiek = new ObservableCollection<GrafiekBar>()
{
new GrafiekBar() {Value = 0, Fill = (Brush)convertor.ConvertFromString(kleuren[0])},
new GrafiekBar() {Value = 0, Fill = (Brush)convertor.ConvertFromString(kleuren[1])},
new GrafiekBar() {Value = 0, Fill = (Brush)convertor.ConvertFromString(kleuren[2])}
};
Von MSDN: ObjectDataProvider: "Wenn Sie jedoch an ein Objekt binden, das bereits erstellt wurde, müssen Sie den DataContext im Code wie im folgenden Beispiel festlegen."
Ich habe eine Items, die als einfache Balkendiagramm angezeigt wird. Wenn ich Werte (hartcoded in meinem CodeBehind) zuweisen, wird das Diagramm erfolgreich ausgefüllt.
Was ich tue, ist im Grunde, den größten Wert zu erhalten, stellen Sie es auf 100% und berechnen Sie die Länge des Rests der Bars durch das.
Problem: Ich möchte nicht, dass die Balkenwerte hartcodierte, aber die Balken müssen runTime ändern. Dafür verwende ich eine Threading.Timer
, die jede Sekunde läuft, solange mein Programm läuft (andere Berechnungen passieren auch in diesem Timer).
Die Werte der Diagrammleiste erhalten Aktualisierungen basierend auf den Berechnungen, die innerhalb dieses Timers alle x Sekunden stattfinden.
Ich habe alles versucht und ich kann Werte nicht angezeigt bekommen, wenn mein Programm läuft. Ich kann nur Balken sehen, wenn ich sie fest codiere (siehe Region von GetDataGrafiek()
am Ende des Threads). Was genau mache ich falsch/fehlt?
Die GetDataGrafiek()
(Berechnungen, um mein Diagramm zu füllen) wird in einem ObjectDataProvider
aufgerufen.
Diese Methode verwendet TimeSpan als Eingabe und führt dann Berechnungen durch, sodass ich einen Double Value (basierend auf dem oben erläuterten 100% -Wert) erhält, der dann in den Wert des Balkens (= Breite des dateTemplate) gesetzt wird.
<ObjectDataProvider x:Key="odpLbGrafiek" ObjectType="{x:Type myClasses:GrafiekBar}" MethodName="GetDataGrafiek"/>
Datatemplate für meine Items (dies verwendet die Breite für den Wert der Stäbe meiner Grafik)
<DataTemplate x:Key="GrafiekItemTemplate">
<Border Width="Auto" Height="Auto">
<Grid>
<Rectangle StrokeThickness="0" Height="30"
Margin="15"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Width="{Binding Value}"
Fill="{Binding Fill}">
<Rectangle.LayoutTransform>
<ScaleTransform ScaleX="20" />
</Rectangle.LayoutTransform>
</Rectangle>
</Grid>
</Border>
</DataTemplate>
Items:
<ItemsControl x:Name="icGrafiek"
Margin="50,3,0,0"
ItemsSource="{Binding Source={StaticResource odpLbGrafiek}}"
ItemTemplate="{DynamicResource GrafiekItemTemplate}"
RenderTransformOrigin="1,0.5" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.RowSpan="6">
<ItemsControl.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleY="-1" ScaleX="1"/>
<SkewTransform AngleY="0" AngleX="0"/>
<RotateTransform Angle="180"/>
<TranslateTransform/>
</TransformGroup>
</ItemsControl.RenderTransform>
</ItemsControl>
GetDataGrafiek() Die Region enthält fest codierte Werte, wenn dies erfolgt ist Mein Diagramm zeigt 6 Balken erfolgreich an. Wenn ich die Region kommentiere, bekomme ich keine sichtbaren Balken mehr.
Diese Methode gibt eine Liste mit Double
Werten zurück. Jeder Wert repräsentiert einen Balken, der als Breite in DataTemplate
dargestellt wird, und die Füllung gibt ihm nur eine bestimmte Farbe.
ObservableCollection<GrafiekBar> listGrafiek = new ObservableCollection<GrafiekBar>();
public ObservableCollection<GrafiekBar> GetDataGrafiek()
{
var converter = new System.Windows.Media.BrushConverter();
#region ***TEST HARDCODED BAR VALUES***
int[] testWaardenUren = new int[] { 2, 1, 0, 1, 2, 0 };
int[] testWaardenMinuten = new int[] { 58, 2, 55, 55, 2, 20 };
for (int j = 0; j < 6; j++)
{
TimeSpan ts = new TimeSpan(testWaardenUren[j], testWaardenMinuten[j], 0);
GlobalObservableCol.regStilstanden[j].Value = ts;
GlobalObservableCol.regStilstanden[j].Name = "";
}
#endregion
totalMinutesMaxValue = GetLargestValueStilstanden(); //= "100%" value
//calculate % of stilstanden Values
for (int i = 0; i < GlobalObservableCol.regStilstanden.Count; i++)
{
Double totalMin = GlobalObservableCol.regStilstanden[i].Value.TotalMinutes;
totalMin = totalMin/totalMinutesMaxValue * 10;
valuesChartPercentage.Add(totalMin);
}
//the barChart (itemsControl) gets its final values here
for (int j = 0; j < GlobalObservableCol.regStilstanden.Count; j++)
{
GrafiekBar bar = new GrafiekBar();
bar.Value = valuesChartPercentage[j];
bar.Fill = converter.ConvertFromString(kleuren[j]) as Brush;
listGrafiek.Add(bar);
}
return listGrafiek;
}
GrafiekBar.cls
public class GrafiekBar : INotifyPropertyChanged
{
private double value;
private Brush fill;
public GrafiekBar()
{
}
public double Value
{
get { return this.value; }
set
{
this.value = value;
NotifyPropertyChanged("Value");
}
}
public Brush Fill
{
get { return this.fill; }
set
{
this.fill = value;
NotifyPropertyChanged("Fill");
}
}
//interface INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
//interface INotifyPropertyChanged
private void NotifyPropertyChanged(String info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
das Einfädeln Timer, der jede Sekunde läuft (die Berechnungslogik aufweist und der getDataGrafiek() aufgerufen Aktualisierungen eine Invoke zum GUI-Thread es tut.
private void MyTimerCallBack(object state)
{
DisplayWegingInfo();
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background,
new Action(() =>
{
//actions that involve updating the UI
CaculateTimeBetweenWegingen();
}));
}
Mit freundlichen Grüßen Peter.
Ich bin mir nicht sicher, ob ich dem, was du hier machst, folge, aber das Laufen eines Timers klingt super komisch. Kannst du nicht auf Ereignisse reagieren? – Oliver
Das Diagramm muss basierend auf Berechnungen, die jede Sekunde in diesem Timer ausgeführt werden, geändert werden (oder nicht geändert werden, wenn dies nicht erforderlich ist). Ich bin mir nicht sicher, wie ich das lösen soll. – PeterP
Nur eine ungefähre Vermutung: Haben Sie versucht, DispatcherTimer anstelle eines normalen Timers zu verwenden. Dieser Timer wurde für die WPF-Verteilung – SvenG