コードビハインドで定義されたバインディングオブジェクト


88

コードビハインドでインスタンス化されているオブジェクトがあります。たとえば、XAMLはwindow.xamlと呼ばれ、window.xaml.cs内にあります。

protected Dictionary<string, myClass> myDictionary;

XAMLマークアップのみを使用して、このオブジェクトをリストビューなどにバインドするにはどうすればよいですか?

更新:

(これはまさに私のテストコードにあります):

<Window x:Class="QuizBee.Host.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="{Binding windowname}" Height="300" Width="300"
    DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
    </Grid>
</Window>

そして分離コードで

public partial class Window1 : Window
{
    public const string windowname = "ABCDEFG";

    public Window1()
    {
        InitializeComponent();
    }
}

タイトルが「ABCDEFG」になるはずだとしたら?しかし、何も表示されなくなります。


1
不思議なことに、ウィンドウのプロパティ割り当ての順序を変更すると機能しません。「Title」プロパティの後に「DataContext」プロパティを設定した場合、バインドが行われません。誰かがこれを説明できますか?<Window x:Class = "INotifyPropertyTest.MainWindow" xmlns = " schemas.microsoft.com/winfx/2006/xaml/presentation " xmlns:x = " schemas.microsoft.com/winfx/2006/xaml " xmlns:local = " clr-namespace:INotifyPropertyTest "Height =" 350 "Width =" 525 "DataContext =" {Binding RelativeSource = {RelativeSource self}} "Title =" {Binding WindowName} ">
Ramesh

回答:


109

次のように、コントロールやフォームなどのDataContextを設定できます。

DataContext="{Binding RelativeSource={RelativeSource Self}}"

明確化

上記の値に設定されるデータコンテキストは、背後のコードを「所有する」要素で実行する必要があります。そのため、ウィンドウの場合は、ウィンドウ宣言で設定する必要があります。

私はあなたの例がこのコードで働いています:

<Window x:Class="MyClass"
  Title="{Binding windowname}"
  DataContext="{Binding RelativeSource={RelativeSource Self}}"
  Height="470" Width="626">

このレベルで設定されたDataContextは、ウィンドウの任意の要素によって継承されます(子要素に対して明示的に変更しない限り)。したがって、ウィンドウのDataContextを設定した後は、任意のコントロールからCodeBehind プロパティに直接バインドできます。ウィンドウに。


1
ここでの「自己」とは、ウィンドウクラス全体ではなく、コントロールを意味します。
xandy 2009年

奇妙なことに、以下は私のコードであり、期待どおりに機能しません。public partial class Window1:Window {public const string windowname = "ABCDEFG"; public Window1(){InitializeComponent(); }} <ウィンドウは、x:クラス= "QuizBee.Host.Window1"のxmlns = " schemas.microsoft.com/winfx/2006/xaml/presentation "のxmlns:X =" schemas.microsoft.com/winfx/2006/xaml "タイトル= "{Binding windowname}" Height = "300" Width = "300" DataContext = "{Binding RelativeSource = {RelativeSource Self}}"> </ Window>
xandy 2009年

9
ああ、大丈夫です。ウィンドウ名を純粋なパブリック変数ではなくプロパティに変更しました。これで表示できます!ありがとう!
xandy

1
これがデフォルトで設定されていないのはなぜでしょうか。
お好み焼き3000

122

これを行うにははるかに簡単な方法があります。ウィンドウまたはユーザーコントロールに名前を割り当て、ElementNameでバインドできます。

Window1.xaml

<Window x:Class="QuizBee.Host.Window1"
        x:Name="Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <ListView ItemsSource="{Binding ElementName=Window1, Path=myDictionary}" />
</Window>

Window1.xaml.cs

public partial class Window1:Window
{
    // the property must be public, and it must have a getter & setter
    public Dictionary<string, myClass> myDictionary { get; set; }

    public Window1()
    {
        // define the dictionary items in the constructor
        // do the defining BEFORE the InitializeComponent();

        myDictionary = new Dictionary<string, myClass>()
        {
            {"item 1", new myClass(1)},
            {"item 2", new myClass(2)},
            {"item 3", new myClass(3)},
            {"item 4", new myClass(4)},
            {"item 5", new myClass(5)},
        }; 

        InitializeComponent();
    }
}

3
x:Nameを変更する必要がありました(コンパイラエラーCS0542)。次に、ElementNameをそれに応じて変更する必要があります。
ジャックミラー、

25

Guyの答えは正しいです(おそらく10ケース中9ケースに当てはまります)が、DataContextがスタックをさらに設定しているコントロールからこれを行おうとしている場合、DataContextを設定するときにこれをリセットすることに注意してください。それ自体に戻る:

DataContext="{Binding RelativeSource={RelativeSource Self}}"

もちろん、これは既存のバインディングを壊します。

この場合、親ではなく、バインドしようとしているコントロールにRelativeSourceを設定する必要があります。

つまり、UserControlのプロパティにバインドします。

Binding Path=PropertyName, 
        RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}

現在データバインディングで何が起こっているかを確認するのがどれほど難しいかを考えると、その設定がRelativeSource={RelativeSource Self}現在機能していることがわかったとしても、これを覚えておくことは価値があります:)


1
Silverlight 4はFindAncestorをサポートしていません。ただし、このサイトで説明されているようにFindAncestorを実装できるこの方法で行う必要があります。http://blog.thekieners.com/2010/09/08/relativesource-binding-with-findancestor-mode-in-silverlight/
ShawnFeatherly

7

もう少し明確化: 「取得」、「設定」のないプロパティはバインドできません

私はちょうどアスカーのケースのようにケースに直面しています。バインドを正しく機能させるには、次のものが必要です。

//(1) Declare a property with 'get','set' in code behind
public partial class my_class:Window {
  public String My_Property { get; set; }
  ...

//(2) Initialise the property in constructor of code behind
public partial class my_class:Window {
  ...
  public my_class() {
     My_Property = "my-string-value";
     InitializeComponent();
  }

//(3) Set data context in window xaml and specify a binding
<Window ...
DataContext="{Binding RelativeSource={RelativeSource Self}}">
  <TextBlock Text="{Binding My_Property}"/>
</Window>

9
「取得」および「設定」なしでどのように正確にプロパティを持つことができますか?それはフィールドではなく、プロパティではないでしょうか?
kjbartel 2014年

1

コンバーターを定義します。

public class RowIndexConverter : IValueConverter
{
    public object Convert( object value, Type targetType,
                           object parameter, CultureInfo culture )
    {
        var row = (IDictionary<string, object>) value;
        var key = (string) parameter;
        return row.Keys.Contains( key ) ? row[ key ] : null;
    }

    public object ConvertBack( object value, Type targetType,
                               object parameter, CultureInfo culture )
    {
        throw new NotImplementedException( );
    }
}

辞書のカスタム定義にバインドします。省略したオーバーライドはたくさんありますが、値が変更されたときにプロパティ変更イベントを発行するため、インデクサーは重要です。これは、ソースからターゲットへのバインディングに必要です。

public class BindableRow : INotifyPropertyChanged, IDictionary<string, object>
{
    private Dictionary<string, object> _data = new Dictionary<string, object>( );

    public object Dummy   // Provides a dummy property for the column to bind to
    {
        get
        {
            return this;
        }
        set
        {
            var o = value;
        }
    }


    public object this[ string index ]
    {
        get
        {
            return _data[ index ];
        }
        set
        {
            _data[ index ] = value;
            InvokePropertyChanged( new PropertyChangedEventArgs( "Dummy" ) ); // Trigger update
        }
    }


}

.xamlファイルでこのコンバーターを使用します。最初にそれを参照してください:

<UserControl.Resources>
    <ViewModelHelpers:RowIndexConverter x:Key="RowIndexConverter"/>
</UserControl.Resources>

次に、たとえば、辞書にキーが「名前」であるエントリがある場合、それにバインドするには:

<TextBlock  Text="{Binding Dummy, Converter={StaticResource RowIndexConverter}, ConverterParameter=Name}">

1

プロパティ「ウィンドウ名」をDependencyPropertyにして、残りは同じままにします。


0

コードビハインドで、ウィンドウのDataContextを辞書に設定します。XAMLでは、次のように記述できます。

<ListView ItemsSource="{Binding}" />

これにより、ListViewが辞書にバインドされます。

より複雑なシナリオでは、これはMVVMパターンの背後にある技術のサブセットになります。


0

1つの方法は、ObservableCollection(System.Collections.ObjectModel)を作成し、そこに辞書データを置くことです。その後、ObservableCollectionをListBoxにバインドできるはずです。

XAMLには次のようなものが必要です。

<ListBox ItemsSource="{Binding Path=Name_of_your_ObservableCollection" />

0

私はこれとまったく同じ問題を抱えていましたが、ローカル変数を設定していたので私はそうではありませんでした...私は子ウィンドウにいて、Window XAMLに追加したばかりの相対DataContextを設定する必要がありました。

<Window x:Class="Log4Net_Viewer.LogItemWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    Title="LogItemWindow" Height="397" Width="572">

0

あなたはx:Referenceトリックを試すことができます

<Window ... x:Name="myWindow"><ListBox ItemsSource="{Binding Items, Source={x:Reference myWindow}}" /></Window>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.