スケーラブルなピアノキーボードを作成するために、添付プロパティを使用してItemsControlとしてWPFグリッドを使用しようとしています。キーボードの各キーは、先行するものと後続するものに応じて1〜3列にわたり、シャープの場合は1行、自然の場合は2行にまたがります。グリッドの列数と行数を動的に設定するための2つのプロパティが既に用意されています(これらは各列/行の幅/高さの設定をサポートするために調整する必要があります)。ItemTemplateとItemsSourceのアタッチ可能なプロパティを実装する方法
実装する必要があるのは、ItemsSource
(鍵)とItemTemplate
(PianoKeyView)の2つの接続可能なプロパティです。 ItemsControl
はItemsPanel
のグリッドとしてUniformGrid
しかサポートしておらず、特定の列/行に特定の項目を割り当てていないため、Gridコントロールでこれを使用する必要があります。私のピアノのキーボードは1オクターブあたり17列のキーを必要としますが、ItemsControlはUniformGrid
に12列しか作成しません。私は1オクターブのピアノ・キーボードのイメージを含め、必要な各列の索引を含めました。
それが現在私がGridExtensions.ItemsSource
とGridExtensions.ItemTemplate
の実装をしないのです、立っているように、これはキーボードのために私のコードです。 GridExtensions
は、アタッチ可能なプロパティを含む静的クラスです。
<UserControl x:Class="SphynxAlluro.Music.Wpf.PianoKeyboard.View.PianoKeyboardView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:converters="http://schemas.sphynxalluro.com/converters"
xmlns:local="clr-namespace:SphynxAlluro.Music.Wpf.PianoKeyboard.View"
xmlns:prism="http://www.codeplex.com/prism"
xmlns:sphynxAlluroControls="http://schemas.sphynxalluro.com/controls"
xmlns:wpfBindingExtensions="http://schemas.sphynxalluro.com/bindingExtensions"
mc:Ignorable="d"
d:DesignHeight="200" d:DesignWidth="600">
<UserControl.Resources>
<converters:KeysToColumnsCountConverter x:Key="keysToColumnsCountConverter"/>
<converters:KeysToRowsCountConverter x:Key="keysToRowsCountConverter"/>
<converters:IsSharpToRowSpanConverter x:Key="isSharpToRowSpanConverter"/>
<converters:KeysCollectionAndKeyToColumnIndexConverter x:Key="keysCollectionAndKeyToColumnIndexConverter"/>
<converters:KeysCollectionAndKeyToColumnSpanConverter x:Key="keysCollectionAndKeyToColumnSpanConverter"/>
</UserControl.Resources>
<Grid wpfBindingExtensions:GridExtensions.ItemsSource="{Binding Keys}"
wpfBindingExtensions:GridExtensions.ItemsOrientation="Horizontal"
wpfBindingExtensions:GridExtensions.ColumnCount="{Binding Keys, Converter={StaticResource keysToColumnsCountConverter}}"
wpfBindingExtensions:GridExtensions.RowCount="{Binding Keys, Converter={StaticResource keysToRowsCountConverter}}">
<wpfBindingExtensions:GridExtensions.ItemTemplate>
<DataTemplate>
<local:PianoKeyView Grid.RowSpan="{Binding Note.IsSharp, Mode=OneTime, Converter={StaticResource isSharpToRowSpanConverter}}"
DataContext="{Binding}">
<Grid.Column>
<MultiBinding Converter="{StaticResource keysCollectionAndKeyToColumnIndexConverter}" Mode="OneTime">
<Binding RelativeSource="{RelativeSource AncestorType=ItemsControl}" Path="Items"/>
<Binding/>
</MultiBinding>
</Grid.Column>
<Grid.ColumnSpan>
<MultiBinding Converter="{StaticResource keysCollectionAndKeyToColumnSpanConverter}" Mode="OneTime">
<Binding RelativeSource="{RelativeSource AncestorType=ItemsControl}" Path="Items"/>
<Binding/>
</MultiBinding>
</Grid.ColumnSpan>
</local:PianoKeyView>
</DataTemplate>
</wpfBindingExtensions:GridExtensions.ItemTemplate>
</Grid>
そして、これはGridExtensionsでItemTemplateに取り付け可能なプロパティのItemTemplateChangedハンドラのコードで、コンパイルされませんライン上の2 TODOの点に注意してください。私が直接Grid
のItemsPanel
でItemsControl
で達成することができGrid
で達成しようとしていた何
private static void ItemTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var itemTemplate = (DataTemplate)e.NewValue;
var itemsSource = GetItemsSource(d);
var itemsSourceCount = itemsSource.Count();
var itemsOrientation = GetItemsOrientation(d);
var gridChildren = ((Grid)d).Children;
gridChildren.Clear();
switch (itemsOrientation)
{
case Orientation.Horizontal:
foreach (var item in itemsSource)
{
var itemFactory = new FrameworkElementFactory(item.GetType());
//TODO: Find out where the ContentProperty for Grid is.
itemFactory.SetValue(d.ContentProperty, item);
itemTemplate.VisualTree = itemFactory;
//TODO: Find out how to add the applied itemTemplate.
gridChildren.Add(itemTemplate);
}
break;
case Orientation.Vertical:
break;
default:
throw new EnumValueNotSupportedException(itemsOrientation, nameof(itemsOrientation).ToPascalCase());
}
}
5コンバータおよびDP付属の4でしたか?私はビューを複雑にするのではなく、ItemsControlのバインディングに便利な形式でデータを表示するためにビューモデルを簡素化するべきだと言います。 – ASh
もう一つのオプションは、ItemsPanelTemplateで水平StackPanelを使用して負のマージンとPanel.ZIndexスタイル/バインディング/それ以外の白いキーが黒いキーの「下」に出会うようにするために使用します。 –
@Ed Plunkett @ASh ItemsControlを使用したいのですが、12個の項目に対して17個の列を生成するにはどうすればよいですか?私は元々 'ItemsControl'としてこれを持っていましたが、' PianoKey'の 'Grid.Column'と' Grid.Row'プロパティは 'UniformGrid'で動作しませんでした。 'ItemsPanelTemplate'は列を生成しませんでした。 – Sphynx