LR2のローカルのデータベースとWeb上の難易度表を読み込んでランプグラフを表示するアプリを作ったので、GUI部分について軽く説明する。


・動機

 リザルト画面でスコアキャッシュを有効にしていると、スコア未送信の曲が溜まってしまう。オンラインのランプグラフはLR2IRから情報を引っ張って来るので、スコアが未送信だと正しいデータが表示されないのだが、いちいちスコアを送信していくのが面倒なのでローカルのDBを読み込んでしまえということになった。ついでに任意の難易度表のランプグラフを表示できるようにしたいと思った。

・おおまかな仕組み

 適当に図にするとこんな感じ。
 ローカル(LR2files/Database/以下)にある.dbファイルは、SQLiteで保存されているので、C#のSQLiteライブラリを使って曲データとスコアデータを読み出す。
 難易度表については、GLAssist用?の難易度表新フォーマットに対応した難易度表のJSONファイルを読み込む。
 肝心のグラフ表示は、WPFでBindingの練習がてらカスタムコントロールを使って実装してみた。この記事ではランプグラフを表示するコントロールの実装について説明する。

・実装したカスタムコントロールについて

 このコントロールは、難易度を表示するラベルと、クリアした譜面数を表す帯グラフからなる。帯グラフの要素数は7で固定で、それぞれ①譜面未所持、②未プレイ、③Failed、④イージー、⑤ノマゲ、⑥ハード、⑦フルコン、と対応している。
 C#ソースの方では、ラベル用のLabelプロパティと、グラフデータ用のValueプロパティを用意した。一応、依存関係プロパティにしている(12~38行目)。また、帯の幅を数値に比例させるので、Widthを変更するための文字列(数値のあとに*をつけるだけ...)を返すGraphWidthプロパティも作った(39行目)。

public class GraphCC : Control
{
    public GraphCC(){
        Value = new int[] { 0, 0, 0, 0, 0, 0, 0 };
    }
    static GraphCC()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(GraphCC), 
            new FrameworkPropertyMetadata(typeof(GraphCC)));
    }
    
    //Dependency Properties
    public static readonly DependencyProperty LabelProperty = 
        DependencyProperty.Register(
            "Label",
            typeof(string), 
            typeof(GraphCC),
            new FrameworkPropertyMetadata("")
        );
    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register(
            "Value", 
            typeof(int[]), 
            typeof(GraphCC), 
            new FrameworkPropertyMetadata()
        );

    //Property Wrapper
    public string Label
    {
        get { return (string)GetValue(LabelProperty); }
        set { SetValue(LabelProperty, value); }
    }
    public int[] Value
    {
        get { return (int[])GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }
    public string[] GraphWidth
    {
        get
        {
            string[] w = new string[7];
            for (int i = 0; i < 7; i++)
                w[i] = String.Format("{0}*", Value[i]);
            return w;
        }
    }
}

 XAMLは長すぎるので少し端折った。なお、これはカスタムコントロールなのでThemes/Generic.xamlのリソースディクショナリの中に記述されている。
 Bindingがやたらくどくどしいが、しょうがない。型がGraphCCの親要素に対してBindingするようにしている。

<Style TargetType="{x:Type local:GraphCC}">
 <Setter Property="Template">
  <Setter.Value>
   <ControlTemplate TargetType="{x:Type local:GraphCC}">
    <Border>
     <Grid>

      <Grid.ColumnDefinitions>
       <ColumnDefinition Width="100"/>
       <ColumnDefinition Width="{Binding RelativeSource={RelativeSource 
         FindAncestor, AncestorType={x:Type local:GraphCC}},Path=GraphWidth[0]}"/>

       <!-- snip -->

       <ColumnDefinition Width="{Binding RelativeSource={RelativeSource 
         FindAncestor, AncestorType={x:Type local:GraphCC}},Path=GraphWidth[6]}"/>
      </Grid.ColumnDefinitions>

      <Grid Grid.Column="0">
       <Label Content="{Binding RelativeSource={RelativeSource FindAncestor,
         AncestorType={x:Type local:GraphCC}},Path=Label}"/>
      </Grid>
      <Grid Grid.Column="1">
       <Rectangle Fill="#999999"/>
       <TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor,
         AncestorType={x:Type local:GraphCC}},Path=Value[0]}"/>
      </Grid>

      <!-- snip -->
            
      <Grid Grid.Column="7">
       <Rectangle Fill="#f0ad4e"/>
       <TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor,
         AncestorType={x:Type local:GraphCC}},Path=Value[6]}"/>
      </Grid>

     </Grid>
    </Border>
   </ControlTemplate>
  </Setter.Value>
 </Setter>
</Style>

 あとは、インスタンスを生成してプロパティとしてLabelValueを代入し、StackPanelか何かにぶちこんでやればランプグラフになってくれる。
 今回は帯グラフの要素数が7で固定だったので楽だったが、そうでない場合についてはわからない( C#ソース側で動的にColumnDefinitionを追加して...といった感じだろうか)。


 以上。正直なところWPFはそこまできちんと理解できていないので実装も説明も雑だが、ちゃんと動くので良しとする。

【C#/WPF】BMSランプグラフアプリ(LR2用)

投稿ナビゲーション


コメントを残す

メールアドレスが公開されることはありません。