0

編集:追加されたコード

また、DateTimesは実際にはDatetimes(hh:mm:ss形式のsTrings)ではないため、代わりに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>

塗りつぶしは、実際には棒グラフiselfの棒のサイズを示します。

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

もう1つの問題は、実際には幅(バーのサイズ)です。バー自体を視覚化するには、実際に*10000を実行する必要があります。


棒グラフのように見えるようにスタイル設定されたItemsControlを使用しています。

したがって、たとえば、1から5までの5つの値を持つ配列は、異なるバーサイズとそれぞれ異なる色の5つのバーを作成します。次の例とよく似ていますhttp://www.c-sharpcorner.com/uploadfile/mahesh/bar-chart-in-wpf/

問題:

私の問題は、バーのスケールサイズにあります(この場合はwidthプロパティなので、int / double値が必要です)。

  • 私のプログラムは、HH:mm:ss形式でいくつかのDateTimeを記録します
  • バーはこれらの日時にスケーリングする必要があります

たとえば、01:22:11のバー、または00:01:11のバーを最大6まで持つことができます。

これらのDateTime値を特定のdouble値にスケーリングするための最良のアプローチは何でしょうか?この値は、チャート上のバーのサイズを示すために使用されます。

すべての値をまったく同じように計算するある種の計算を探していると思います。そのため、突然大きくなり、UIから外れる値を取得することはありません。

最もクリーンな解決策は、すべてのバーを相互に比較し、一方を変更するともう一方が拡大/縮小することですが、思ったほど複雑でない限り、現時点では必要ありません。

バーチャー自体は過度に正確である必要はなく、状況の全体像を把握するのに役立つだけです。正確な値はデータベースに書き込まれます。

どんな提案でも大歓迎です!

PeterPに感謝します。

4

4 に答える 4

1

ノーマライズ。

  • 合計時間を秒に変換します。
  • (利用可能な合計幅を合計時間で割る)= factorA
  • 各バーの適切な幅を見つけるには、その時間をfactorAで乗算します

編集:ゼロを測定するのに適した日付/時刻を選択するか、DateTimeオブジェクトのtotalsecondsプロパティを使用することができます

于 2012-04-18T14:19:29.037 に答える
1

基準日を選択し、収集グラフを基準日とデータ日付の間の日数/時間/分数にします

コンバーターパラメーターとして基準日を渡すコンバーターを使用して、これを実行できる場合もあります。

2つの例の日付(01:22:1100:01:11)は実際には時間です。その場合、0からの分数をグラフ化するだけなので、グラフ化する実際のデータ値は82と1になります。

スケーリングについて尋ねる編集に応じて、すべてをパーセンテージでグラフ化します。その場合、最大数を取り、最大数のパーセンテージに基づいて1つおきの数をグラフ化します。

したがって、2つの例を使用して、それらを数値82と1に変換し、大きい方の数値(82)を100%として、すべての数値のパーセンテージを含むリストを82に返すので、戻りリストには10​​0が含まれます。 %および1.2%(1/82)。

ViewModelこれは、またはコンバーターのいずれかで引き続き実行できますItemsSource(コンバーターはリスト全体をパラメーターとして受け取り、リスト全体を戻り値として返します)


編集

以下のコメントに応えて、を使用して設定する方法をConverter次に示しItemsSourceます。コンバーターは単にデータ値を取得し、それを表示UIのみに固有の別の値に変換します。

最初のXAMLは次のようになります。

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

ここMyCollectionで、は、ObservableCollection<DateTime>でありMyTimeConverter、次のことを行います。

  1. すべてのコンバーターパラメータがとして渡されるため、渡されたをvalueとしてキャストしますObservableCollection<DateTime>object
  2. コレクションをループして、最大時間を把握します
  3. コレクションの中で最大の時間を取り、それが何分あるかを把握します。これは、他のすべての時間を基準とする100%の値になるため、最大時間の分数を変数に格納します
  4. List<decimal>戻り値の新しいを作成します
  5. コレクションの開始をループします。コレクション内の各時間について、ステップ3で保存した「100%値」で除算します。これにより、そのバーを最大値と比較する時間の割合がわかります。このパーセンテージを収益に追加しますList<decimal>
  6. に戻りList<decimal>ますItemsControl。これは実際List<decimal>の代わりに使用されますItemsSourceObservableCollection<DateTime>

これはItemsControl、1つの値が100%で画面の全幅を占める小数のコレクションにバインドされ、他のすべての値が最大値にスケーリングされることを意味します。

タイマーを使用してコレクションを更新することについての質問に関して、タイマーは、がバインドされているObservableCollection<DateTime>呼び出し先を更新する必要があります。タイマーはコンバーターコードをまったく知らないか、気にするべきではありません。MyCollectionItemsControl

たとえば、タイマーがまったく新しい時間のセットで再作成したい場合は、それが可能です。コレクションが変更されたときにUIに通知するため、UIMyCollectionはコンバーターコードを自動的に再実行し、棒グラフを更新します。ObservableCollectionsUIを更新する必要があります。

以下のコメントで言及している「基準日」については、時間ではなく一連の日付をグラフ化する場合は、グラフがに戻らないように基準日が必要になります1/1/0001。最小の日付を使用しないでください。最小値が棒グラフに0として表示されるため、Converterグラフの開始点として使用する特定の日付を渡すことになります。基準日が1/1/12で、最大日が3/1/12の場合、グラフは1/1/12から3/1/12に拡大します。

基準日は、コンバーターのステップ3と5で使用されます。たとえば、時間の分数を取得する代わりに、基準日とデータ日付の間の日数を取得する場合があります。

コンバーターで基準日を計算することもできます。たとえば、最低日の10日前などですが、データによっては、グラフが希望よりも歪む可能性があります。

于 2012-04-18T14:19:40.743 に答える
0

棒グラフ全体の背面にViewModelがあるはずです。このVMには、最大値を計算してからスケーリングを定義するロジックがあります。

于 2012-04-18T14:19:28.807 に答える
0

すべての値の最大値を追跡する必要があるようです。次に、この最大値に従って各値をスケーリングします。

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

もちろん、各アイテムの高さを実際に設定する方法は、バインディングを介することになるでしょう。

于 2012-04-18T14:18:49.703 に答える