NFL ドライブ チャートをエミュレートして、ゲームのドライブ データを視覚化しようとしています。私が大まかにエミュレートしようとしているものの例は、nfl.com の厚意により、ここで見ることができます。私は次のことを達成しようとしています:
- 競技場を表示する
- 競技場の上にデータを描く
- 何かにマウスオーバーすると、イベントを発生させたい (例: ToolTip)
http://www.nfl.com/gamecenter/2011100909/2011/REG5/jets@patriots#menu=drivechart
これが私が今いる場所です。まず、xaml:
<StackPanel x:Name="myStackPanel" Orientation="Vertical">
<StackPanel.Background>
<ImageBrush ImageSource="{StaticResource PlayingField}" Stretch="Fill" />
</StackPanel.Background>
<ItemsControl Background="AliceBlue" Opacity="0.5"
ItemsSource="{Binding Path=DriveDetails}"
ItemTemplate="{StaticResource myDataTemplate}"
ItemsPanel="{StaticResource myItemsPanelTemplate}" />
</StackPanel>
その結果は次のとおりです。
(申し訳ありませんが、私は初心者なのでスクリーンショットを追加できません!)
私が見ているものを説明するために最善を尽くします.xamlを読んだ後、ほとんどの人がこれを理解していると確信しています. 基本的には、背景にフットボールの競技場が見え、左上隅に、私の ItemsControl コントロールがあります。
StackPanel は一目瞭然です。1 ヤードは 1 ピクセルを表していないため、後で画像のサイズ変更に問題が発生することになりますが、それは別の日に残します。私の主な関心事は、どのように視覚化できるかです。データ。また、ドライブの視覚化は左上隅から開始するべきではありません:D したがって、ItemsControl を純粋に扱うと、次のようになります。
(申し訳ありませんが、私は初心者なのでスクリーンショットを追加できません!)
もう一度、画像の説明を試みます。これは、前述の ItemsControl コントロールの拡大図で、背景 (サッカー場) の画像はありません。
注: ItemsControl の背景は、見やすいように AliceBlue に設定されています。これが機能すると、透明になります。
ItemsSource は「Play」クラスのリストにバインドされています。
public class Play
{
public int Quarter { get; set; }
public int Result { get; set; }
public PlayType TypeOfPlay { get; set; }
public double WidthOfPlay { get; set; }
}
PlayType は列挙型です:
public enum PlayType
{
Run,
Pass,
Penalty,
Punt,
FieldGoal
}
リストはいくつかのデータを取得します... (サンプル データ、1 番目のダウンが取得されていることはわかっています 笑)
List<Play> SamplePlays = new List<Play>()
{
new Play { Quarter = 1, Result = 5, TypeOfPlay = PlayType.Penalty, WidthOfPlay = 30 },
new Play { Quarter = 1, Result = 5, TypeOfPlay = PlayType.Run, WidthOfPlay = 30 },
new Play { Quarter = 1, Result = 5, TypeOfPlay = PlayType.Pass, WidthOfPlay = 30 },
new Play { Quarter = 1, Result = 40, TypeOfPlay = PlayType.Punt, WidthOfPlay = 240 }
};
…そして、転送パラメーター クラスの助けを借りて ViewModel に渡されます…</p>
ucHomeInstance = ucDriveChartInstance;
((ucDriveChart)ucHomeInstance).setViewModel(new ucDriveChartVM(new ucDriveChartTP()
{ Plays = SamplePlays }));
… DriveDetails プロパティに割り当てられている場所
public class ucDriveChartVM : ViewModelBase
{
public List<Play> DriveDetails { get; set; }
public ucDriveChartVM(ucDriveChartTP transferParameter)
{
this.DriveDetails = transferParameter.Plays;
}
}
ItemsPanel の xaml は次のとおりです。
<ItemsPanelTemplate x:Key="myItemsPanelTemplate">
<StackPanel Orientation="Horizontal" IsItemsHost="True" />
</ItemsPanelTemplate>
ItemTemplate の xaml は次のとおりです。1 ヤードは背景グラフィックで約 6 単位であるため、WidthOfPlay にバインドしていることに注意してください。グラフィックとサイズ変更を整理したら、実際の Result プロパティにバインドします。
<DataTemplate x:Key="myDataTemplate">
<StackPanel Orientation="Horizontal" Width="{Binding WidthOfPlay}"
SnapsToDevicePixels="True" Style="{StaticResource onMouseOver}">
<Border Padding="0,5,0,5">
<Grid>
<StackPanel Style="{StaticResource onMouseOver}">
<Rectangle Width="{Binding WidthOfPlay}" Height="10"
Fill="{Binding TypeOfPlay,
Converter={StaticResource PlayTypeToColourConverter}}" />
</StackPanel>
</Grid>
</Border>
</StackPanel>
</DataTemplate>
PlayType enum を Brush に変換しているため、サンプル データで表示される色を確認できます。
<converter:PlayToColour x:Key="PlayTypeToColourConverter"
ColourRun="Red" ColourPass="Blue" ColourPenalty="Yellow" ColourSpecial="Purple" />
したがって、これらすべてが正常に機能しています – しかし、明らかに表現は望みどおりではありません – 上の例を見ると、ドライブは多数のプレーで構成されており、それらは互いに隣り合って配置されていますが、プレーは負のヤード数になる可能性があるため、それらはまた、最後のプレイの終わりまでに相殺され、互いの下に配置されます!
だから私はこれが私の質問だと思います-ドライブの各再生がその特定のドライブの前の再生の下に配置されるだけでなく、その最後のドライブの終わりから始まるような形式でデータを表すにはどうすればよいですか? )
ゲームは複数のドライブで構成されているため、後の段階で、ドライブの開始位置とそのドライブのプレイのリストで構成される「ドライブ」のリストを渡します (この中のプレイの単純なリストの代わりに)例)。
これは、全体をスクロール可能にする必要があることを意味します。
私は、ItemTemplate および DataTemplate と共に ItemsControl コントロールを使用して正しい軌道に乗っていると思いますが、これを達成する方法については、専門家のアドバイスを確実に使用できます。
ここまで読んでくれたなら、時間を割いてくれてありがとう - GO PATS ;)
[編集]
AngelWPF (仮想化) とRachel (すべて!) のおかげで、少なくとも ItemsControl に提供していたプレイのリストについては、実際に機能させることができました。レイチェル、あなたは素晴らしいブログを持っています。AttachedProperties エントリは非常に役に立ちました。知識を共有していただきありがとうございます。
後の段階で、私が悩んでいることをよりよく示すスクリーンショットを 1 つか 2 つ追加できることを願っています ;)
示唆されているように、グリッドの配置のために (他のプロパティの中でも) PlayIndex を使用して Play クラスを変更しました。
public class Play
{
public int PlayIndex { get; set; }
public int Quarter { get; set; }
public int Down { get; set; }
public int YardsToGo { get; set; }
public int Position { get; set; }
public PlayType TypeOfPlay { get; set; }
public PlayDetail DetailsOfPlay { get; set; }
public PlayResult ResultOfPlay { get; set; }
public int YardsOfPlay { get; set; }
public double PlayLength { get; set; }
public string Player1 { get; set; }
public string Player2 { get; set; }
}
その PlayIndex を使用するために、ItemContainerStyle が ItemsControl に追加されました。
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Column" Value="{Binding PlayIndex}" />
<Setter Property="Grid.Row" Value="{Binding PlayIndex}" />
</Style>
</ItemsControl.ItemContainerStyle>
ItemsPanelTemplate を StackPanel から Grid に変更することもこれに役立ちました :) これで、各 Play がそれぞれの色で隣り合って表示されるだけでなく、互いの下にも表示されます。(Play クラスの他のプロパティを使用して) ItemsControl に ToolTip を追加すると、それが洗練されます。
すでに述べたように、これは Play アイテムのリスト (簡単にするために短縮されています) でうまく機能します:
List<Play> SamplePlays = new List<Play>()
{
new Play { PlayIndex = 0, Position = 30, YardsOfPlay = 5, PlayLength = 25 },
new Play { PlayIndex = 1, Position = 35, YardsOfPlay = 15, PlayLength = 75 },
new Play { PlayIndex = 2, Position = 50, YardsOfPlay = 0, PlayLength = 0 },
new Play { PlayIndex = 3, Position = 50, YardsOfPlay = 8, PlayLength = 40 },
new Play { PlayIndex = 4, Position = 58, YardsOfPlay = 1, PlayLength = 5 },
new Play { PlayIndex = 5, Position = 59, YardsOfPlay = 30, PlayLength = 150 }
};
しかし、「ドライブ」のリストを渡すことに関して、元の投稿の最後に書いたものをバインドするにはどうすればよいでしょうか?
注意してください-元の投稿にこれを書いたので、これにより、この投稿を編集して詳細情報を「許可」し、まったく新しい質問をしないことを願っています!
次の「Drive」クラスがあるとします。
public class Drive
{
public int DriveIndex { get; set; }
public int StartPos { get; set; }
public int EndPos { get; set; }
public double DriveLength { get; set; }
public DriveResult Result { get; set; }
public List<Play> DrivePlays { get; set; }
}
リストにデータを入力する (上記と同じプレイを使用)
List<Drive> SampleDrives = new List<Drive>()
{
new Drive { DriveIndex = 0, StartPos = 30, EndPos = 49, DriveLength = 19,
DrivePlays = new List<Play>()
{
// create plays here
}},
new Drive { DriveIndex = 1, StartPos = 30, EndPos = 49, DriveLength = 19,
DrivePlays = new List<Play>()
{
// create plays here
}}
};
ViewModel は次のようになります。
public class ucDriveChartVM : ViewModelBase
{
public List<Play> DriveDetails { get; set; }
public List<Drive> Drives { get; set; }
public ucDriveChartVM(ucDriveChartTP transferParameter)
{
this.DriveDetails = transferParameter.Plays;
this.Drives = transferParameter.Drives;
}
}
明らかに、この ItemsControl (ドライブを含む) を別の DataTemplate に提供する必要がありますが、この DataTemplate はそのドライブのリスト内で再生を保持する必要があります。私がすぐに見つけたのは、コンテンツを Rectangle に配置できないということです。
少し実験した後、DriveLength プロパティにバインドして特定のドライブの長さをグラフィカルに表示し、DataGridCell を作成して、そこにコンテンツ (StackPanel など) を配置できるようにしました。
(私は、ドライブの長さ以外には何も拘束していないことを知っています。この例の Rectangle は、テスト時に何かを示すためのものです!)
<DataTemplate x:Key="myDataTemplateDrives">
<StackPanel Orientation="Horizontal" Width="{Binding DriveLength}"
SnapsToDevicePixels="True" Margin="0,0,1,0">
<Border>
<Grid>
<StackPanel>
<DataGridCell>
<StackPanel Width="{Binding Path=DriveLength}">
<Rectangle Height="10" Fill="Gray" />
</StackPanel>
</DataGridCell>
</StackPanel>
</Grid>
</Border>
</StackPanel>
</DataTemplate>
しかし、私はすでに 4 杯目のコーヒーを飲んでおり、List オブジェクト内の List へのバインドに問題がありますか? Drives.DrivePlaysのようなもの?!
だから私は単純なものから行きます(ありがとうございます)
List<Play>
バインディング、への
List<Drive>
を含むバインディング
List<Play>!
「DrivePlays」と呼ばれる:D
明らかな何かが欠けているのでしょうか、それとももっとコーヒーが必要ですか?
編集
別の質問で問題の最後の部分を説明しました