質問
ユーザーコントロールのいずれかのDependancyProperty
を、Width
のColumn
のGrid
プロパティにバインドしようとしています。
次のようなコードがあります:
<Grid x:Name="MyGridName">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="TitleSection" Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>...</Grid.RowDefinitions>
<GridSplitter x:Name="MyGridSplitter" Grid.Row="0" Grid.Column="0" ... />
</Grid>
別のユーザーコントロールに、次のTitleWidth
が定義されています。
public static readonly DependencyProperty TitleWidthProperty = DependencyProperty.Register("TitleWidth", typeof(int), typeof(MyUserControl));
public int TitleWidth
{
get { return (int)base.GetValue(TitleWidthProperty); }
set { base.SetValue(TitleWidthProperty, value); }
}
コードでUsercontrolのインスタンスを作成しているため、次のようなバインディングステートメントがあります:
MyUserControl Cntrl = new MyUserControl(/* Construction Params */);
BindingOperations.SetBinding(Cntrl , MyUserControl.AnotherProperty, new Binding { ElementName = "objZoomSlider", Path = new PropertyPath("Value"), Mode = BindingMode.OneWay });
BindingOperations.SetBinding(Cntrl , MyUserControl.TitleWidthProperty, new Binding { ElementName = "TitleSection", Path = new PropertyPath("ActualWidth"), Mode = BindingMode.OneWay });
/* Other operations on Cntrl */
最初に定義されたバインディングは素晴らしく機能しますが、実際のUIElement(この場合はSlider)にバインドされますが、Binding to <!> quot; TitleSection <!> quot; (Gridで定義されているColumnDefinition)は失敗します。コードにブレークポイントを設定し、<!> quot; TitleSection <!> quotを監視します。期待されるオブジェクトを返します。
x:Name'd ColumnDefinitionをバインドできないと疑い始めています。 グリッド内の最初の列の幅の変化にバインドする方法を誰か提案できますか?
編集#1-コメントに回答するには
Window_Loaded
プロパティのセッターにブレークポイントを設定し、GridSplitterコントロールを使用して最初の列のサイズを変更すると、ブレークポイントにヒットしないという意味で、データバインディングは「失敗」します。さらに、DependancyProperty TitleSection
の変更が実行されない場合に起動されると予想されるコード。
ユーザーコントロールが作成され、100
関数のグリッド内のStackpanelに追加されます。ユーザーコントロールが構築されるまでにグリッドがレンダリングされていることを期待します。確かにx:Name'd Element <=>は監視可能であり、構築中/バインディングが発生する前に<=>の値を持ちます。
編集#2-おそらくこれと何か関係がありますか
Grid ColumnDefinitionドキュメントのMSDNページをスニッフィングしてきましたが、 GridLength()ですが、バインディング式でこれをどのように使用するかについて頭を悩ますことはできません。関連するGridLengthConverterは、IValueConverterから派生していないため、バインディングコードのコンバーターとして使用できません。
グリッドオブジェクトのセルの1つのActualWidthプロパティに何らかの形でバインドすることに傾いています。列定義へのバインドほどきれいではないように見えますが、現時点では機能しません。
解決
まあ、ちょっとした手間がかかっています。将来の世代のためにどのように説明しますか
本質的に、最初の列に右揃えのスプリッターを備えた2列、複数行のグリッドがあるので、含まれるコンテンツにさらにスペースが必要な場合は、ユーザーがサイズを変更できます。物事を複雑にするために、レンダリングのためにcolumnSpanが2である行の一部にプログラムでロードされるユーザーコントロールがあります(1つのセルから次のセルにコンテンツがブリードします)。
最初の列のサイズが変更されると、これをユーザーコントロールに反映する必要があります。最初にColumnDefinitionにバインドしようとしましたが、実際にはボールをプレイしていませんでした。
修正方法/修正方法
最初の列のスペアセルに、アクセス可能にするためにx:Nameとともに<Label>
を追加しました。セル内にあるため、「ストレッチ」のデフォルトプロパティがあり、セルを完全に塗りつぶします。スプリッターを使用して列のサイズが変更されると、サイズが変更されます。ラベルのActualWidth
プロパティにバインドすることは、列のサイズの変更がcolumnSpannedユーザーコントロールのDependancyPropertyに正しく伝達されることを意味します。
思考
明らかに、ColumnDefinitionの変更時にPropertyChanged
プロパティが設定されているにもかかわらず、内部で<=>イベントを発生させるようには見えません(または、それが私の推測です)。これはバグかもしれませんし、設計上の問題かもしれませんが、私にとっては、あまりクリーンでないソリューションを使用しなければならなかったことを意味します。
他のヒント
xamlでバインディングを設定してみましたが、次のように動作します。
<ColumnDefinition
x:Name="TitleSection"
Width="{Binding
Path=TitleWidth,
RelativeSource={RelativeSource AncestorType=MyUserControl}}"
/>
それ以外の場合、提供したバインディングコードを見ると、間違った方向に見えます。バインディングのターゲットはグリッド列で、ソースは依存関係プロパティである必要があります。
上記のxamlに相当するコードは
BindingOperations.SetBinding(TitleSection, ColumnDefinition.WidthProperty,
new Binding()
{
RelativeSource= new RelativeSource(RelativeSourceMode.FindAncestor, typeof(MyUserControl),1),
Path = new PropertyPath("TitleWidth"),
});
関連するメモでは、GridSplitterの使用とWidthプロパティのバインドは相互に排他的です。スプリッターを使用して列のサイズを変更するとすぐに、バインディングはスプリッターからの値に置き換えられます。
これは、バインディングのターゲットであるプロパティを更新することで発生するものと似ています。コードでターゲット値を直接設定すると、バインディングオブジェクトを指定した値に本質的に置き換えます。
ColumnDefinition.Widthは整数ではなく、GridLengthです。 GridLengthを直接Integerにバインドすることはできません。コンバーターが必要です。
これも、コンバーターなしでControlのWidthプロパティ(double)をColumnDefinitionのWidthプロパティ(GridLength)にバインドできない理由です。