5

EDIT2:当图表被填充时,我无法再更改这些值。即使我更改列表中的值(ItemControls 从中获取值),图表似乎也不会使用新值进行更新。

我调用计时器中的 GetDataGrafiek() 方法每 x 秒更新一次图表。

        Grafiek graf = new Grafiek();
        graf.GetDataGrafiek();

这是由于线程计时器在单独的线程中运行(IsAsynchronous中的方法ObjectDataProvider)还是我需要DataContext在我的计时器方法中访问 ItemsControl 的?

编辑:当程序已经运行时,我无法填充图表,所以我制作了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%,然后计算其余条形的长度。

问题: 我不想硬编码图表条形值,但条形必须更改运行时间。为此Threading.Timer,只要我的程序正在运行,我就会使用每秒运行的 a (其他计算也发生在这个计时器中)。

图表条值会根据此计时器内每 x 秒发生的计算进行更新。

我已经尝试了一切,但我的程序运行时无法显示值。当我对它们进行硬编码时,我只能看到条形(参见GetDataGrafiek()线程末尾的区域)。我到底做错了什么/错过了什么?

GetDataGrafiek()(填充我的图表的 计算)在ObjectDataProvider.

此方法将 TimeSpan 作为输入,然后执行计算,因此我得到一个双值(基于上面解释的 100% 值),然后放置在条的值中(= dateTemplate 的宽度)。

<ObjectDataProvider x:Key="odpLbGrafiek" ObjectType="{x:Type myClasses:GrafiekBar}" MethodName="GetDataGrafiek"/>

我的 ItemsControl 的 DataTemplate(这使用 Width 作为我的图表条形的值)

<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 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值的列表。每个值代表一个在 中表示为 Width 的条DataTemplate,而 Fill 只是给它一种特定的颜色。

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();
            }));
    }

最好的问候彼得。

4

2 回答 2

0

如果您从另一个线程访问以下代码,这将导致问题:

private void NotifyPropertyChanged(String info)
{
    PropertyChangedEventHandler handler = PropertyChanged;
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(info));
    }
}

因为另一个线程将引发一个事件,这将导致 Dispatcher 线程(如果它订阅了该事件)出错。

试试吧

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。

于 2012-12-14T01:11:26.300 回答
0

这是在黑暗中拍摄的,因为我没有阅读你所有的代码,但这里有一个想法:你正在绑定到一个静态资源,对吧?它被阅读一次,就是这样,是吗?请改用 DynamicResource。

于 2012-05-02T21:54:31.770 回答