【问题标题】:ItemsControl Bar Chart Scaling of the barsItemsControl 条形图 条形的缩放
【发布时间】:2012-04-18 14:10:01
【问题描述】:

编辑:添加代码

此外,由于 DateTimes 不是真正的 Datetimes(hh:mm:ss 格式的 sStrings),我决定只使用 Strings 并使用 TimeSpan 来检索 totalMinutes。

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

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

最干净的解决方案是将所有条形图相互比较,当一个条形图发生变化时,另一个条形图会增长/缩小,但目前还不需要这样做,除非它不像听起来那么复杂。

bar char 本身不需要过于精确,它只是用来大致了解情况。确切的值将写入数据库。

欢迎提出任何建议!

谢谢彼得P。

【问题讨论】:

    标签: c# wpf charts itemscontrol


    【解决方案1】:

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

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

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

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

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

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


    编辑

    作为对您下面的 cmets 的回应,以下是我将如何在 ItemsSource 上使用 Converter 进行设置。转换器只是获取一个数据值,并将其转换为另一个仅特定于显示 UI 的值。

    初始 XAML 如下所示:

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

    其中MyCollectionObservableCollection&lt;DateTime&gt;MyTimeConverter 执行以下操作:

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

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

    关于您关于使用计时器更新集合的问题,您的计时器应该更新 ItemsControl 绑定到的名为 MyCollectionObservableCollection&lt;DateTime&gt;。计时器根本不应该知道或关心转换器代码。

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

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

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

    您还可以在转换器中计算基准日期,例如最低日期前 10 天,尽管根据数据,这可能会使图表的偏斜程度超出您的预期。

    【讨论】:

    • 谢谢回复,能不能用代码说明一部分?我的程序运行一个计时器,并且这些值可能每 5 秒更新一次。几秒钟的时间也是可能的。
    • @PeterP 我会使用一个ItemsSource 转换器,它需要一个ObservableCollection&lt;DateTime&gt;,以及一个基本的日期时间参数。在转换器中,我将首先遍历列表并找到最大的日期。取基准日期和最大日期之间的分钟/天/小时/秒差,并将其存储在某个地方以用作 100%。现在创建一个新列表来保存您的返回值。循环遍历原始列表,获取该日期与基准日期之间的分钟/天/小时/秒数,并将其除以 100% 的数字,并将结果添加到返回列表。将新列表返回给 IC
    • @PeterP 如果您使用ObservableCollection&lt;DateTime&gt; 而不是List&lt;DateTime&gt;,计时器不会有问题,因为ObservableCollection 将响应计时器可以触发的更改通知。
    • 好的,谢谢,稍后会调查,你对基本日期时间参数的确切含义是什么?这是最大值(82)吗?我认为这个方法应该放在每 5 秒检查一次值的计时器中?
    • @PeterP 由于您只处理时间而不是日期,因此您甚至可能不需要转换器参数中的基准日期。它只是在您的条形图中给出一个起点,因此它不会尝试从1/1/0001 开始图表。让我更新我的答案,试图澄清你关于计时器的问题
    【解决方案2】:

    标准化。

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

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-06-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多