1

いくつかのボタンを持つ GridView があります。それらの 1 つは、次のテンプレートによって定義されます。

<DataTemplate x:Name="SubjectItemTemplate">
        <Canvas Width="340" Height="170" VerticalAlignment="Top">
            <Controls:ThreeImageButton HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,0,0,0"
                                              NormalStateImageSource="{Binding NormalImage}"
                                              HoverStateImageSource="{Binding HoverImage}"
                                              PressedStateImageSource="{Binding PressedImage}" Command="{Binding Path=NavigateToUnitsPage}"
                CommandParameter="{Binding}" Canvas.Left="0" Canvas.Top="0">


        </Controls:ThreeImageButton>
    </Canvas>
</DataTemplate>

ご覧のとおり、ThreeImageButton というカスタム コントロールができました。ボタンは単体で使うと問題なく動きます。しかし、それを DataTemplate に入れると、プロパティがコード ビハインドにバインドされません。

今、私は持っています

x:Name="MyThreeImageButton"

カスタム ボタン定義で。そして、次のようにコード ビハインドに接続します。

<TextBlock Text="{Binding ElementName=MyThreeImageButton, Path=NormalStateImageSource}"/>

(これはテキストを表示するための単なるテストです。実際のコードでは、要素によって参照される別のプロパティに画像ソースを割り当てます)。

現在、TextBlock には何も表示されていません。プロパティに到達するために使用する正しいバインディング構文は何ですか?

ありがとう!

編集: InitializeComponent 関数で変数を設定しており、DependencyProperty で SetValue を使用しています。

編集:より明確にするために、次の情報を追加させてください

シナリオ I: GridView の DataTemplate で:

<UserControl CustomParameter="Literal Text">

ユーザーコントロールで:

<TextBlock Text="{Binding CustomParameter}">

UserControl .cs: this.DataContext = これは機能します!

シナリオ II: GridView の DataTemplate で:

<UserControl CustomParameter="{Binding ValueFromDataItem">

ユーザーコントロールで:

<TextBlock Text="{Binding CustomParameter}">

UserControl .cs: this.DataContext = this nope!

4

2 に答える 2

0

そうですか、

そのため、ユーザー コントロールは CLR プロパティにバインドできないため、ユーザー コントロールのカスタム プロパティへの双方向バインディングを設定するのは難しい場合があります。それだけでなく、ユーザー コントロールにデータ コンテキストを設定すると、その内部のバインドに予期しない影響があります。

これらの問題は、わずかなコードで解決できます。基本的に、依存関係プロパティを使用して CLR プロパティをバックアップし、ルート ユーザー コントロールではなく子要素にデータ コンテキストを設定します。

このサンプルを見てください。次の MainPage があるとします。その MainPage は、最終的にカスタム ユーザー コントロールを使用します。それでは、舞台を整えましょう。

コードビハインドは次のとおりです。

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        this.DataContext = new /* your view model */
        {
            Title = Guid.NewGuid().ToString(),
        };
    }
}

上記のコードでは、単純な匿名クラスを使用して複雑なビュー モデルをシミュレートしています。このように独自のものを実装するのはばかげていますが、同時に、完全な足場を備えた単純なサンプルを作成するのはばかげています。私はあなたを混乱させないようにこれを持ち出します.

XAML は次のとおりです。

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <local:MyUserControl Text="{Binding Title}" />
</Grid>

上記の XAML には、特別なことは何もありません。既にローカル名前空間にユーザー コントロールへの参照があり、ここで宣言するだけです。

さて、これでコントロールのコンシューマーができました。テストの際、開発者は、リテラル値でテストするため、バインディングが機能していると誤って考える可能性があることを指摘しておく価値があります。リテラル値は正常にバインドされます。ヒックアップするのは、基礎となるビューモデルからのバインディングです。

別のことを言いましょう。一部の開発者は、もう少し入力が必要なため、依存関係プロパティを避ける傾向があります。[kbd]propdp[/kbd] は、依存関係プロパティをスタブ化する便利な Visual Studio スニペットであることを人々は覚えています。

このユーザー コントロールを見てください。このバインディング アプローチの OneWay 機能と TwoWay 機能を示すために、TextBox と TextBlock の 2 つのコントロールがあります。また、ユーザー コントロールに INotifyPropertyChanged を実装します。ほとんどの場合、ユーザー コントロールの場合にビュー モデルを追加するのはやり過ぎです。これは、ユーザー コントロールが既にビュー モデルのように機能しているためです。開発者次第ですが、私にはばかげているようです。

コードビハインドは次のとおりです。

public sealed partial class MyUserControl : UserControl, INotifyPropertyChanged
{
    public MyUserControl()
    {
        this.InitializeComponent();
    }

    // text property

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValueDp(TextProperty, value); }
    }
    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(string), typeof(MyUserControl), null);

    // bindable

    public event PropertyChangedEventHandler PropertyChanged;
    void SetValueDp(DependencyProperty property, object value,
        [System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
    {
        SetValue(property, value);
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

上記の頌歌では、"Text" プロパティを作成し、依存関係プロパティでサポートしています。再利用のために、複数のプロパティがある場合に何度も使用できる SetValueDp() も実装しました。このデモには 1 つしかありませんが、繰り返しのロジックはこのように抽象化する必要があるため、これを含めたいと思いました。

XAML は次のとおりです。

<Grid Background="Black" DataContext="{Binding ElementName=userControl}">
    <StackPanel>
        <TextBox Text="{Binding Text, Mode=TwoWay}"
            MinHeight="100" Padding="15" FontWeight="Light" FontSize="50" />
        <TextBlock Text="{Binding Text}"
            MinHeight="100" Padding="15" FontWeight="Light" FontSize="50" />
    </StackPanel>
</Grid>

上記の XAML では、バインディングに関する限り、特別なことは何もしていません。この構文は、コントロールに適した Mode を使用して Text プロパティにバインドするだけです。いつもと同じように。ただし、注目に値するのは、DataContext がユーザー コントロールに設定されていないことです。代わりに、グリッドに設定されます。実際のところ、ユーザー コントロール以外のツリー内の任意のコントロールをこのように使用できます。ユーザー コントロールのデータ コンテキストを設定しないでください。

ちなみにそれです。

動作することを確認するためにテストしました。ここでは、一方向バインディングと双方向バインディングの両方のデモンストレーションが非常に便利です。他の開発者がそれを見つけたいと思っていて、この質問を見つけられない場合に備えて、これをブログに変えることさえあります. ご質問ありがとうございます。

頑張ってください!

于 2013-06-24T22:06:55.420 に答える
-1

コメントが暗示しているように、DataTemplate は項目のデータコンテキストを、リストに追加するオブジェクトに配置しています。これは、周囲のユーザー コントロールのデータ コンテキストと同じではありません。そのデータ コンテキストのコマンドを参照する場合は、DataTemplate のバインディングで次の操作を行います。

{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.NormalImage}

これが言っていることは、外に出てユーザー コントロールの祖先を見つけ、そのデータ コンテキストを使用してから、NormalImage プロパティを探すことです。問題が発生した場合は、出力ウィンドウでバインド エラーを確認してください。バインディングの問題を見つけるのに非常に役立ちます。

于 2013-06-19T14:21:40.820 に答える