Saya memiliki beberapa objek yang dibuat dalam kode di belakang, misalnya, XAML disebut window.xaml dan di dalam window.xaml.cs
protected Dictionary<string, myClass> myDictionary;
Bagaimana cara mengikat objek ini ke, misalnya, tampilan daftar, hanya menggunakan markup XAML?
Memperbarui:
(Ini persis yang saya miliki di kode pengujian saya):
<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>
Dan di codebehind
public partial class Window1 : Window
{
public const string windowname = "ABCDEFG";
public Window1()
{
InitializeComponent();
}
}
Misalkan judul harus menjadi "ABCDEFG" kan? tapi akhirnya tidak menunjukkan apa-apa.
Jawaban:
Anda dapat mengatur DataContext untuk kontrol Anda, formulir, dll. Seperti:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Klarifikasi :
Konteks data yang disetel ke nilai di atas harus dilakukan pada elemen apa pun yang "memiliki" kode di belakang - jadi untuk Window, Anda harus menyetelnya di deklarasi Window.
Saya memiliki contoh Anda bekerja dengan kode ini:
<Window x:Class="MyClass" Title="{Binding windowname}" DataContext="{Binding RelativeSource={RelativeSource Self}}" Height="470" Width="626">
DataContext yang disetel pada level ini kemudian diwarisi oleh elemen apa pun di jendela (kecuali Anda secara eksplisit mengubahnya untuk elemen turunan), jadi setelah menyetel DataContext untuk Jendela Anda seharusnya dapat melakukan pengikatan langsung ke properti CodeBehind dari kontrol apa pun. di atas jendela.
sumber
Ada cara yang lebih mudah untuk melakukan ini. Anda dapat menetapkan Nama ke Window atau UserControl Anda, dan kemudian mengikat dengan 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(); } }
sumber
Meskipun jawaban Guy benar (dan mungkin cocok dengan 9 dari 10 kasus), perlu diperhatikan bahwa jika Anda mencoba melakukan ini dari kontrol yang sudah mengatur DataContext lebih lanjut, Anda akan menyetel ulang ini saat Anda menyetel DataContext kembali ke dirinya sendiri:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Ini tentu saja akan merusak binding yang ada.
Jika ini masalahnya, Anda harus menyetel RelativeSource pada kontrol yang Anda coba ikat, bukan induknya.
yaitu untuk mengikat properti UserControl:
Mengingat betapa sulitnya saat ini untuk melihat apa yang terjadi dengan data binding, ada baiknya mengingat hal ini bahkan jika Anda menemukan bahwa pengaturan
RelativeSource={RelativeSource Self}
saat ini berfungsi :)sumber
Sedikit penjelasan lagi: Properti tanpa 'get', 'set' tidak akan bisa diikat
Saya menghadapi kasus seperti kasus penanya. Dan saya harus memiliki hal-hal berikut agar pengikatan berfungsi dengan benar:
//(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>
sumber
Tentukan konverter:
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( ); } }
Mengikat ke definisi kustom dari sebuah Dictionary. Ada banyak penggantian yang telah saya hilangkan, tetapi pengindeks adalah yang terpenting, karena pengindeks memancarkan peristiwa properti yang diubah ketika nilainya diubah. Ini diperlukan untuk pengikatan sumber ke target.
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 } } }
Dalam file .xaml Anda, gunakan konverter ini. Referensi pertama itu:
<UserControl.Resources> <ViewModelHelpers:RowIndexConverter x:Key="RowIndexConverter"/> </UserControl.Resources>
Kemudian, misalnya, jika kamus Anda memiliki entri dengan kuncinya adalah "Nama", maka untuk mengikatnya: gunakan
<TextBlock Text="{Binding Dummy, Converter={StaticResource RowIndexConverter}, ConverterParameter=Name}">
sumber
Jadikan properti Anda "windowname" sebagai DependencyProperty dan pertahankan sisanya tetap sama.
sumber
Di belakang kode Anda, setel DataContext jendela ke kamus. Di XAML Anda, Anda dapat menulis:
<ListView ItemsSource="{Binding}" />
Ini akan mengikat ListView ke kamus.
Untuk skenario yang lebih kompleks, ini akan menjadi bagian dari teknik di balik pola MVVM .
sumber
Salah satu caranya adalah dengan membuat ObservableCollection (System.Collections.ObjectModel) dan memiliki data kamus Anda di sana. Maka Anda harus bisa mengikat ObservableCollection ke ListBox Anda.
Di XAML Anda, Anda harus memiliki sesuatu seperti ini:
<ListBox ItemsSource="{Binding Path=Name_of_your_ObservableCollection" />
sumber
Saya mengalami masalah yang sama persis tetapi masalah saya bukan karena saya menyetel variabel lokal ... Saya berada di jendela anak, dan saya perlu menyetel DataContext relatif yang baru saja saya tambahkan ke Jendela XAML.
<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">
sumber
Anda dapat mencoba x: Trik referensi
<Window ... x:Name="myWindow"><ListBox ItemsSource="{Binding Items, Source={x:Reference myWindow}}" /></Window>
sumber
Itulah cara saya mengikat kode di belakang (lihat properti
DataTemplateSelector
)public partial class MainWindow : Window { public MainWindow() { this.DataTemplateSelector = new MyDataTemplateSelector(); InitializeComponent(); // ... more initializations ... } public DataTemplateSelector DataTemplateSelector { get; } // ... more code stuff ... }
Di XAML akan direferensikan oleh
RelativeSource
melalui Ancestors hingga berisiWindow
, jadi saya berada diWindow
kelas saya dan menggunakan properti melaluiPath
deklarasi:<GridViewColumn Header="Value(s)" CellTemplateSelector="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataTemplateSelector}"/>
Pengaturan properti
DataTemplateSelector
sebelum panggilanInitializeComponent
bergantung pada implementasi yang hilangIPropertyChanged
atau penggunaan implementasiDependencyProperty
sehingga tidak ada komunikasi yang berjalan pada perubahan propertiDataTemplateSelector
.sumber