FlexGrid for WPF
カスタムセル
株価情報サンプル > カスタムセル

サンプルを実行すると、既にグリッドが機能して、予期したとおりにデータが更新されることがわかります。更新パラメータを変更すると、更新の頻度を調節し、更新中にグリッドをスクロールできるようになります。

ただし、更新はされますが確認は困難です。画面上の至る所で数値が点滅し、その数が多すぎるためです。

そこで、カスタムセルを使用して、点滅とスパークラインによってユーザーエクスペリエンスを高めます。

セルに含まれる値が変化すると、点滅によってセルの背景が一時的に変更されます。株価が上昇するとセルは瞬時に緑に変化し、ゆっくりと白に戻ります。

スパークラインは、各セルに表示されるマイクロチャートです。このマイクロチャートにはセルの直近 5 つの値が表示されるので、ユーザーは即座にトレンド(株価が上昇しているか、下落しているか、または安定しているか)を識別できます。

カスタムセルを使用するには、前のサンプルと同様の手順に従います。FinancialCellFactory のクラスの作成から開始し、そのクラスのインスタンスをグリッドの CellFactory プロパティに割り当てます。

コードのコピー
// カスタムセルファクトリーを使用します。
_flexFinancial.CellFactory = new FinancialCellFactory();
public class FinancialCellFactory : CellFactory
{
  static Thickness _thicknessEmpty = new Thickness(0);
  // セルをティッカーに連結します。
  public override void CreateCellContent(
               C1FlexGrid grid, Border bdr, CellRange range)
  {
    // セルに連結します。
    var r = grid.Rows[range.Row];
    var c = grid.Columns[range.Column];
    var pi = c.PropertyInfo;
    if (r.DataItem is FinancialData &&
      (pi.Name == "LastSale" || pi.Name == "Bid" || pi.Name == "Ask"))
    {
      // ティッカーセルを作成します。
      StockTicker ticker = new StockTicker();
      bdr.Child = ticker;
      bdr.Padding = _thicknessEmpty;
      // スパークラインを表示します。
      ticker.Tag = r.DataItem;
      ticker.BindingSource = pi.Name;
      // 標準の連結方法
      var binding = new Binding(pi.Name);
      binding.Source = r.DataItem;
      binding.Mode = BindingMode.OneWay;
      ticker.SetBinding(StockTicker.ValueProperty, binding);
    }
    else
    {
      // デフォルトの実装方法を使用します。
      base.CreateCellContent(grid, bdr, range);
    }
  }
}

このカスタムセルファクトリは、行データが FinancialData 型かどうかと、列がデータオブジェクトの LastSaleBid、または Ask プロパティに連結されているかどうかをチェックします。以上の条件がすべて満たされる場合、セルファクトリは、新しい StockTicker 要素を作成してデータに連結します。

StockTicker 要素は、ユーザーにデータを表示するために使用します。これは、次の子要素を含む 4 列の Grid 要素で構成されます。

要素の説明 タイプ 名前
現在の値 TextBlock _txtValue
最新の変化率(% TextBloc _txtChange
アップ/ダウンアイコン Polygon _arrow
スパークライン Polyline _sparkLine

これらの要素は StockTicker.xaml ファイルで定義されますが、ここでは、そのリストは示しません。

StockTicker.xaml ファイルで最も注目する部分は、点滅を実装するために使用する Storyboard の定義です。Storyboard は、Background コントロールを現在の値から透明まで徐々に変化させるために使用します。

コードのコピー
<UserControl.Resources>
  <Storyboard x:Key="_sbFlash" >
    <ColorAnimation
      Storyboard.TargetName="_root"
      Storyboard.TargetProperty=
               "(Grid.Background).(SolidColorBrush.Color)"
      To="Transparent"
      Duration="0:0:1"
    />
  </Storyboard>
</UserControl.Resources>

StockTicker コントロールの実装は、StockTicker.cs ファイルにあります。ここで、注目する部分にはコメントが付けられています。

コードのコピー
/// <summary>
/// StockTicker.xaml の相互作用ロジック
/// </summary>
public partial class StockTicker : UserControl
{
  public static readonly DependencyProperty ValueProperty =
    DependencyProperty.Register(
      "Value",
      typeof(double),
      typeof(StockTicker),
      new PropertyMetadata(0.0, ValueChanged));

ここでは、コントロールをその基底のデータ値に連結するために使用する ValueProperty という DependencyProperty の定義から開始します。Value プロパティは次のように実装されます。

コードのコピー
public double Value
{
  get { return (double)GetValue(ValueProperty); }
  set { SetValue(ValueProperty, value); }
}
private static void ValueChanged(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
{
  var ticker = d as StockTicker;
  var value = (double)e.NewValue;
  var oldValue = (double)e.OldValue;

スパークラインを実装するために、コントロールは現在の値と前の値以外にもアクセスする必要があります。これは、コントロールの Tag プロパティに FinancialData オブジェクトを格納し、FinancialData.GetHistory メソッドを呼び出して実行します。

この場合、イベントの OldValue プロパティによって提供される前の値は信頼できません。グリッドによってセルが仮想化され、コントロールはセルがビューに表示されるようにスクロールされたときに作成されたので、StockTicker.Value プロパティが変更されている可能性があります。その場合、コントロールに前の値はありません。この問題は、FinancialData オブジェクトから前の値を取得しても解決できます。

コードのコピー
// 履歴を取得します。
  var data = ticker.Tag as FinancialData;
  var list = data.GetHistory(ticker.BindingSource);
  if (list != null && list.Count > 1)
  {
    oldValue = (double)list[list.Count - 2];
  }

値が使用できるようになると、コントロールは最新の変化をパーセンテージとして計算し、コントロールのテキストを更新します。

コードのコピー
  // 変化率を計算します。
  var change = oldValue == 0 || double.IsNaN(oldValue)
    ? 0
    : (value - oldValue) / oldValue;
  // テキストを更新します。
  ticker._txtValue.Text = value.ToString(ticker._format);
  ticker._txtChange.Text = string.Format("({0:0.0}%)", change * 100);

変化率(%)は、アップ/ダウンの記号、テキスト、および点滅の色の更新にも使用されます。変化がない場合、アップ/ダウンの記号は表示されず、テキストはデフォルト色に設定されます。

変化が負の場合は、ScaleY を -1 に変更してアップ/ダウンの記号が下を示すようにし、記号、テキスト、点滅のアニメーションの色を赤に設定します。

変化が正の場合は、ScaleY を +1 に変更してアップ/ダウンの記号が上を示すようにし、記号、テキスト、点滅のアニメーションの色を緑に設定します。

コードのコピー
// 点滅色を更新します。
  var ca = ticker._flash.Children[0] as ColorAnimation;
  // シンボルを更新します。
  if (change == 0)
  {
    ticker._arrow.Fill = null;
    ticker._txtChange.Foreground = ticker._txtValue.Foreground;
  }
  else if (change < 0)
  {
    ticker._stArrow.ScaleY = -1;
    ticker._txtChange.Foreground = ticker._arrow.Fill = _brNegative;
    ca.From = _clrNegative;
  }
  else
  {
    ticker._stArrow.ScaleY = +1;
    ticker._txtChange.Foreground = ticker._arrow.Fill = _brPositive;
    ca.From = _clrPositive;
  }

次に、以前の FinancialData.GetHistory メソッドの呼び出しによって提供される値履歴配列によってスパークライン多角形の Points プロパティに値を設定して、スパークラインを更新します。スパークライン多角形の Stretch プロパティが Fill に設定されるので、ラインは使用できるスペースに合わせて自動的にスケールします。

コードのコピー
  // スパークラインを更新します。
  if (list != null)
  {
    var points = ticker._sparkLine.Points;
    points.Clear();
    for (int x = 0; x < list.Count; x++)
    {
      points.Add(new Point(x, (double)list[x]));
    }
  }

最後に、値が実際に変化し、コントロールがまだ作成されていない場合は、StoryBoard.Begin メソッドを呼び出すことによってセルを点滅させます。

コードのコピー
// 新規値を点滅します(コントロール作成直後に点滅しません)。
  if (!ticker._firstTime && change != 0)
  {
    ticker._flash.Begin();
  }
  ticker._firstTime = false;
}

これで StockTicker コントロールは完成しました。ここでサンプルアプリケーションを実行し、[カスタムセル]チェックボックスを確認すると、今までよりもはるかに有用な情報が表示されていることがすぐにわかります。セルは値が変化すると点滅し、スパークラインには値のトレンドが迅速に表示されます。