EDIT2: Quando la tabella viene popolata non riesco più a modificare i valori. Anche quando cambio i valori nell'elenco (da cui gli ItemControls ottengono i valori) il grafico non sembra aggiornarsi con i nuovi valori.Databinding ItemsControl (DataTemplate) non si aggiorna/riceve solo i valori all'avvio del programma
Invito al metodo GetDataGrafiek() nel timer per aggiornare il mio grafico ogni x secondi.
Grafiek graf = new Grafiek();
graf.GetDataGrafiek();
Questo è dovuto il Timer Threading in esecuzione in un thread separato (IsAsynchronous
metodo nel ObjectDataProvider
) oppure ho bisogno di accedere al DataContext
del ItemsControl nel mio metodo timer?
EDIT: ero in grado in grado di popolare il grafico quando il programma era già in esecuzione così ho fatto il ObservableCollection<GrafiekBar>
statico (lista che contiene il riempimento e il valore delle barre) e inizializzata è la seguente:
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])}
};
Da MSDN: ObjectDataProvider: "Tuttavia, se si esegue il binding a un oggetto che è già stato creato, è necessario impostare DataContext nel codice, come nell'esempio seguente."
Ho un ItemsControl che viene visualizzato come un semplice grafico a barre. Quando assegno i valori (hardcoded nel mio codiceBehind) il grafico viene popolato correttamente.
Quello che faccio è in pratica ottenere il valore più grande impostandolo su 100% e calcolare la lunghezza del resto delle barre.
Problema: Non voglio i valori della barra del grafico codificati, ma le barre devono cambiare runtime. Per questo io uso un Threading.Timer
che viene eseguito ogni secondo finché il mio programma è in esecuzione (altri calcoli si verificano anche in questo timer).
I valori della barra del grafico vengono aggiornati in base ai calcoli che avvengono all'interno di questo timer ogni x secondi.
Ho provato tutto e non riesco a ottenere i valori visualizzati quando il mio programma è in esecuzione. Posso vedere solo le barre quando le hardcode (vedi regione GetDataGrafiek()
alla fine del thread). Cosa sto facendo di sbagliato/mancante?
Il GetDataGrafiek()
(calcoli per popolare il grafico) viene chiamato in uno ObjectDataProvider
.
Questo metodo richiede TimeSpan come input e quindi esegue i calcoli in modo da ottenere un valore doppio (basato sul valore 100% spiegato sopra) che viene quindi inserito nel valore della barra (= larghezza della dataTemplate).
<ObjectDataProvider x:Key="odpLbGrafiek" ObjectType="{x:Type myClasses:GrafiekBar}" MethodName="GetDataGrafiek"/>
DataTemplate per la mia ItemsControl (questo utilizza il valore per il valore delle barre di mia tabella)
<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>
ItemsControl:
<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() La regione mantiene i valori codificati, quando ciò viene eseguito il mio grafico mostra 6 barre con successo. Quando commento la regione non ho più barre visibili.
Questo metodo restituisce un elenco con i valori Double
. Ogni valore rappresenta una barra che viene rappresentata come Larghezza nello DataTemplate
e il Riempimento gli conferisce solo un determinato colore.
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));
}
}
}
il timer Threading che passa ogni secondo (che ha la logica di calcolo e la getDataGrafiek() chiamato ci fa un invocare al thread GUI per gli aggiornamenti.
private void MyTimerCallBack(object state)
{
DisplayWegingInfo();
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background,
new Action(() =>
{
//actions that involve updating the UI
CaculateTimeBetweenWegingen();
}));
}
migliori saluti Peter.
Non sono sicuro di seguire quello che stai facendo qui, ma avere un timer che corre sembra super strano. Non puoi rispondere agli eventi, invece? – Oliver
Il grafico deve cambiare (o non cambiare se non richiesto) in base a calcoli che si verificano ogni secondo in quel timer. Non sono sicuro di come risolvere questo problema. – PeterP
Solo un'ipotesi approssimativa: hai provato a usare DispatcherTimer invece di un normale Timer. Questo timer è stato ottimizzato per il dispacciamento WPF – SvenG