0

编辑:添加代码

此外,由于 DateTimes 不是真正的 Datetimes(hh:mm:ss 格式的 sStrings),我决定只使用字符串并使用 TimeSpan 来检索总分钟数。

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

    <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>

Fill 实际上给出了条形图本身的大小。

项目控制:

<ItemsControl x:Name="icGrafiek"  
            Margin="20,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>

在数据绑定中调用以下方法。那里 bar.Value 给出了数据模板中 Width 值的值,该值给出了条的大小。

    public ObservableCollection<GrafiekBar> GetDataGrafiek()
    {
        var converter = new System.Windows.Media.BrushConverter();

        Double maxValueStilstanden = GetLargestValueStilstanden();

        TimeSpan tsMaxValue = TimeSpan.Parse(maxValueStilstanden.ToString());
        totalMinutesMaxValue = tsMaxValue.TotalMinutes; 

        //calculate % of stilstanden Values
        foreach(String t in stilStandenList)
        {
            TimeSpan ts = TimeSpan.Parse(t);
            Double totalMin = ts.TotalMinutes;

            totalMin = totalMin / totalMinutesMaxValue * 100;

            valuesChartPercentage.Add(totalMin);
        }

        for (int j = 0; j < valuesChartPercentage.Count; j++)
        {
            GrafiekBar bar = new GrafiekBar();
            bar.Value = valuesChartPercentage[j];
            bar.Fill = converter.ConvertFromString(kleuren[j]) as Brush;
            listGrafiek.Add(bar);
        }

        return listGrafiek;
    }

另一个问题实际上是宽度(条的大小)。我实际上必须做 * 10000 才能获得酒吧本身的任何视觉效果。


我使用的ItemsControl的样式看起来像条形图。

例如,一个包含 5 个值从 1 到 5 的数组会创建 5 个具有不同大小且每个颜色不同的条。与以下示例非常相似http://www.c-sharpcorner.com/uploadfile/mahesh/bar-chart-in-wpf/

问题:

我的问题是条的比例大小(在这种情况下为 width 属性,因此需要 int/double 值)。

  • 我的程序以 HH:mm:ss 格式记录了几个 DateTimes
  • 条形图应在这些日期时间进行缩放

例如,我可以有一个 01:22:11 的条形图或一个 00:01:11 的条形图,最大数量为 6。

将这些 DateTime 值缩放到某个 double 值的最佳方法是什么?该值将用于给出图表上条形的大小。

猜猜我正在寻找某种计算方法来计算我所有的值都一样,所以我不会突然得到一个非常大的值并超出我的 UI。

最干净的解决方案是将所有条相互比较,当一个改变时,另一个会增长/缩小,但这不是必需的,除非它不像听起来那么复杂。

条形字符本身不需要过于精确,它仅用于大致了解情况。确切的值将写入数据库。

欢迎任何建议!

谢谢彼得P。

4

4 回答 4

1

标准化。

  • 将总时间转换为秒。
  • (总可用宽度除以总时间)=因子A
  • 要找到每个条的适当宽度,请将其时间乘以 factorA

编辑:选择一个合适的日期/时间来测量零,或者您可以只使用 DateTime 对象的总秒数属性

于 2012-04-18T14:19:29.037 回答
1

我会选择一个基准日期,并让您的收藏图表显示基准日期和数据日期之间的天数/小时/分钟数

您甚至可以使用转换器来执行此操作,将基准日期作为转换器参数传入。

您的两个示例日期(01:22:1100:01:11)实际上是时间,所以在这种情况下,我只需绘制自 0 以来的分钟数,因此您要绘制的实际数据值为 82 和 1

为了响应您询问缩放的编辑,您将以百分比的形式绘制所有内容。在这种情况下,取最大的数字并根据最大数字的百分比每隔一个数字绘制图表。

因此,使用您的两个示例时间,我会将它们转换为数字 82 和 1,将较大的数字 (82) 作为 100%,并返回一个包含每个数字到 82 的百分比的列表,因此返回列表将包含 100 % 和 1.2% (1/82)。

您仍然可以在 theViewModelItemsSourceConverter 中执行此操作(转换器会将整个列表作为参数,并返回整个列表作为返回值)


编辑

为了回应您在下面的评论,这是我将如何Converter使用ItemsSource. 转换器只是获取一个数据值,并将其转换为另一个仅特定于显示 UI 的值。

初始 XAML 如下所示:

<ItemsControl ItemsSource="{Binding MyCollection, 
    Converter="{StaticResource MyTimeConverter}}" />

哪里MyCollectionObservableCollection<DateTime>, 并MyTimeConverter执行以下操作:

  1. 将传入的转换value为 as ObservableCollection<DateTime>,因为所有转换器参数都传入 asobject
  2. 循环遍历集合并找出最大的时间
  3. 取集合中最长的时间,并计算它有多少分钟。这将是您将基于所有其他时间的 100% 值,因此将您最大时间的分钟数存储在一个变量中
  4. List<decimal>为返回值创建一个新的
  5. 循环开始收集。对于集合中的每个时间,将其除以您在步骤 3 中存储的“100% 值”,这将为您提供该条应与最大值进行比较的百分比。将此百分比添加到回报中List<decimal>
  6. 返回List<decimal>ItemsControl. 这List<decimal>将用作ItemsSource代替实际的ObservableCollection<DateTime>

这意味着您ItemsControl现在绑定到一组小数,其中一个值为 100% 并将占据屏幕的整个宽度,所有其他值都缩放到最大值。

关于您关于使用计时器更新集合的问题,您的计时器应该更新绑定到的ObservableCollection<DateTime>调用。计时器根本不应该知道或关心转换器代码。MyCollectionItemsControl

例如,如果您的计时器想要重新创建MyCollection一组全新的时间,那么它可以,并且 UI 将自动重新运行转换器代码并更新条形图,因为ObservableCollections当集合发生更改时会告诉 UI 并且UI 需要更新。

至于我在下面的评论中提到的“基准日期”,如果您要绘制一组日期而不是时间,您将需要一个基准日期,这样您的图表就不会回溯到1/1/0001. 您不想使用最小日期,因为这会导致您的最低值在条形图中显示为 0,因此您将传递Converter特定日期以用作图表中的起点。如果基准日期是 2012 年 1 月 1 日,而您的最大日期是 12 年 3 月 1 日,那么您的图表将从 2012 年 1 月 1 日延伸到 2012 年 3 月 1 日。

基准日期将在转换器的第 3 步和第 5 步中使用。例如,您可以获取基准日期和数据日期之间的天数,而不是获取时间中的分钟数。

您还可以在转换器中计算基准日期,例如最低日期前 10 天,尽管根据数据,这可能会比您希望的更偏斜图表。

于 2012-04-18T14:19:40.743 回答
0

听起来您只需要跟踪所有值的最大值。然后,根据此最大值缩放每个值:

var scale = value / maximum;
var height = scale * ActualHeight;

当然,您实际设置每个项目高度的方式可能是通过绑定。

于 2012-04-18T14:18:49.703 回答
0

恕我直言,整个条形图的背面应该有一个 ViewModel,这个 VM 具有计算最大值然后定义缩放的逻辑。

于 2012-04-18T14:19:28.807 回答