コードビハインドでインスタンス化されたオブジェクトがいくつかあります。たとえば、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」になるはずだと思いますか?しかし、何も表示されなくなります。
コントロール、フォームなどのDataContextを次のように設定できます。
DataContext="{Binding RelativeSource={RelativeSource Self}}"
明確化:
上記の値に設定するデータコンテキストは、コードビハインドを「所有する」要素で実行する必要があります。したがって、Windowの場合は、Window宣言で設定する必要があります。
このコードで動作するあなたの例があります:
<Window x:Class="MyClass"
Title="{Binding windowname}"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Height="470" Width="626">
このレベルで設定されたDataContextは、ウィンドウ内のすべての要素に継承されます(子要素に対して明示的に変更しない限り)。したがって、ウィンドウのDataContextを設定した後、CodeBehindに直接バインドできるようになりますプロパティウィンドウ上の任意のコントロールから。
これを行うには、はるかに簡単な方法があります。 WindowまたはUserControlにNameを割り当て、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();
}
}
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}
の設定が現在機能していることに気付いたとしても、これを覚えておく価値があります:)
もう少し明確に:「get」、「set」のないプロパティはバインドできません
私はアスカーのケースのようにケースに直面しています。そして、バインドが適切に機能するためには、次のものが必要です。
//(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>
コンバーターを定義します。
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}">
プロパティを "windowname"にDependencyPropertyにし、残りは同じままにします。
私はこれとまったく同じ問題を抱えていましたが、ローカル変数を設定していたためではありませんでした...私は子ウィンドウにいて、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">
コードビハインドで、ウィンドウのDataContextを辞書に設定します。 XAMLでは、次のように記述できます。
<ListView ItemsSource="{Binding}" />
これにより、ListViewが辞書にバインドされます。
より複雑なシナリオでは、これは MVVM パターンの背後にあるテクニックのサブセットになります。
1つの方法は、ObservableCollection(System.Collections.ObjectModel)を作成し、そこに辞書データを含めることです。その後、ObservableCollectionをListBoxにバインドできるはずです。
XAMLには次のようなものが必要です。
<ListBox ItemsSource="{Binding Path=Name_of_your_ObservableCollection" />
X:Referenceトリックを試すことができます
<Window ... x:Name="myWindow"><ListBox ItemsSource="{Binding Items, Source={x:Reference myWindow}}" /></Window>