EDIT2:当图表填充后,我无法再更改值。即使我更改列表中的值(ItemControls从中获取值),图表似乎也不会使用新值更新。
我调用计时器中的GetDataGrafiek()方法每隔x秒更新一次我的图表。
Grafiek graf = new Grafiek();
graf.GetDataGrafiek();
这是因为线程计时器在单独的线程(IsAsynchronous
中的ObjectDataProvider
方法)中运行还是需要在我的计时器方法中访问ItemsControl的DataContext
? / p>
编辑:我无法在程序运行时填充图表,因此我创建了ObservableCollection<GrafiekBar>
静态(包含条形的填充和值的列表)并初始化如下:
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])}
};
来自MSDN: ObjectDataProvider:“但是,如果要绑定到已创建的对象,则需要在代码中设置DataContext,如下例所示。”
我有一个ItemsControl,显示为一个简单的条形图。 当我分配值(在我的codeBehind 中硬编码)时,图表会成功填充。
我所做的基本上是将最大值设置为100%并计算其余条形的长度。
问题:
我不希望图表栏值硬编码,但条形图必须更改runTime。
为此,我使用Threading.Timer
,每当我的程序运行时每秒运行一次(此计时器也会发生其他计算)。
图表栏值根据此计时器每x秒发生的计算得到更新。
我已尝试过所有内容,但在程序运行时无法显示值。当我对它们进行硬编码时,我只能看到条形图(参见线程末尾的GetDataGrafiek()
区域)。我到底做错了什么/错过了什么?
在GetDataGrafiek()
中调用ObjectDataProvider
(填充我的图表的计算)。
此方法将TimeSpan作为输入,然后执行计算,以便获得Double Value(基于上面解释的100%值),然后将其放置在bar的值中(= dateTemplate的宽度)。
<ObjectDataProvider x:Key="odpLbGrafiek" ObjectType="{x:Type myClasses:GrafiekBar}" MethodName="GetDataGrafiek"/>
我的ItemsControl的DataTemplate (这使用宽度作为我图表条形的值)
<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()该区域包含硬编码值,完成此操作后,我的图表会成功显示6个条形图。当我评论该地区时,我不再有任何可见的酒吧。
此方法返回包含Double
值的列表。每个值代表一个条形,在DataTemplate
中表示为宽度,而填充只是给它一定的颜色。
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));
}
}
}
每秒运行的线程计时器(具有计算逻辑和调用的getDataGrafiek()会调用GUI线程进行更新。
private void MyTimerCallBack(object state)
{
DisplayWegingInfo();
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background,
new Action(() =>
{
//actions that involve updating the UI
CaculateTimeBetweenWegingen();
}));
}
最好的问候彼得。
答案 0 :(得分:0)
这是一个黑暗中的镜头,因为我没有阅读你的所有代码,但这里有一个想法:你绑定到一个静态资源吧?它被读了一次,就是这样,是吗?请尝试使用DynamicResource。
答案 1 :(得分:0)
如果您从另一个线程访问以下代码,则会导致问题:
private void NotifyPropertyChanged(String info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
由于另一个线程将引发一个事件,该事件将导致Dispatcher Thread(如果它订阅了该事件)发生错误。
尝试改为
private void NotifyPropertyChanged(String info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (PropertyChanged != null)
{
if (System.Threading.Thread.CurrentThread == System.Windows.Application.Current.Dispatcher.Thread)
PropertyChanged(this, new PropertyChangedEventArgs(info));
else
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => PropertyChanged(this,new PropertyChangedEventArgs(info));
}
}
另外,请确保在WPF中使用UpdateSourceMethod = PropertyChanged。