Mam obiekt, którego wystąpienie jest tworzone w kodzie za, na przykład, XAML nazywa się window.xaml i wewnątrz okna.xaml.cs
protected Dictionary<string, myClass> myDictionary;
Jak mogę powiązać ten obiekt, na przykład z widokiem listy, używając tylko znaczników XAML?
Aktualizacja:
(To jest dokładnie to, co mam w moim kodzie testowym):
<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>
I za kodem
public partial class Window1 : Window
{
public const string windowname = "ABCDEFG";
public Window1()
{
InitializeComponent();
}
}
Załóżmy, że tytuł powinien brzmieć „ABCDEFG”, prawda? ale ostatecznie nic nie pokazuje.
Odpowiedzi:
Możesz ustawić DataContext dla kontrolki, formularza itp. W następujący sposób:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Wyjaśnienie :
Kontekst danych ustawiony na powyższą wartość powinien być wykonany w jakimkolwiek elemencie „jest właścicielem” kodu znajdującego się za nim - więc w przypadku okna należy ustawić to w deklaracji Window.
Mam twój przykład pracy z tym kodem:
<Window x:Class="MyClass" Title="{Binding windowname}" DataContext="{Binding RelativeSource={RelativeSource Self}}" Height="470" Width="626">
DataContext ustawiony na tym poziomie jest następnie dziedziczony przez dowolny element w oknie (chyba że jawnie zmienisz go dla elementu podrzędnego), więc po ustawieniu DataContext dla okna powinieneś być w stanie wykonać proste powiązanie z właściwościami CodeBehind z dowolnej kontrolki na oknie.
źródło
Jest na to znacznie łatwiejszy sposób. Możesz przypisać nazwę do swojego okna lub UserControl, a następnie powiązać przez 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(); } }
źródło
Chociaż odpowiedź Guya jest poprawna (i prawdopodobnie pasuje do 9 na 10 przypadków), warto zauważyć, że jeśli próbujesz to zrobić z kontrolki, która ma już ustawiony DataContext na stosie, zresetujesz to po ustawieniu DataContext z powrotem do siebie:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
To oczywiście spowoduje zerwanie istniejących powiązań.
W takim przypadku należy ustawić RelativeSource na kontrolce, którą próbujesz powiązać, zamiast jej elementu nadrzędnego.
tj. do powiązania z właściwościami UserControl:
Biorąc pod uwagę, jak trudno jest obecnie zobaczyć, co się dzieje z wiązaniem danych, warto o tym pamiętać, nawet jeśli okaże się, że to ustawienie
RelativeSource={RelativeSource Self}
obecnie działa :)źródło
Jeszcze tylko trochę wyjaśnienia: właściwość bez „get”, „set” nie będzie mogła być związana
Stoję przed tą sprawą tak jak w przypadku pytającego. I muszę mieć następujące rzeczy, aby bind działał poprawnie:
//(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>
źródło
Zdefiniuj konwerter:
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( ); } }
Powiąż z niestandardową definicją słownika. Pominęłam wiele przesłonięć, ale indeksator jest ważny, ponieważ emituje zdarzenie zmiany właściwości, gdy wartość zostanie zmieniona. Jest to wymagane w przypadku powiązania źródła do celu.
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 } } }
W pliku .xaml użyj tego konwertera. Najpierw odwołaj się do tego:
<UserControl.Resources> <ViewModelHelpers:RowIndexConverter x:Key="RowIndexConverter"/> </UserControl.Resources>
Następnie, na przykład, jeśli twój słownik ma wpis, w którym kluczem jest "Nazwa", to aby się z nim powiązać: użyj
<TextBlock Text="{Binding Dummy, Converter={StaticResource RowIndexConverter}, ConverterParameter=Name}">
źródło
Ustaw właściwość „nazwa okna” na DependencyProperty, a pozostałe zachowaj bez zmian.
źródło
W swoim kodzie za ustawieniem DataContext okna na słownik. W swoim XAML możesz napisać:
<ListView ItemsSource="{Binding}" />
Spowoduje to powiązanie ListView ze słownikiem.
W przypadku bardziej złożonych scenariuszy byłby to podzbiór technik leżących u podstaw wzorca MVVM .
źródło
Jednym ze sposobów byłoby utworzenie ObservableCollection (System.Collections.ObjectModel) i umieszczenie w nim danych ze słownika. Następnie powinieneś być w stanie powiązać ObservableCollection z ListBox.
W swoim XAML powinieneś mieć coś takiego:
<ListBox ItemsSource="{Binding Path=Name_of_your_ObservableCollection" />
źródło
Miałem dokładnie ten sam problem, ale mój nie był, ponieważ ustawiałem zmienną lokalną ... Byłem w oknie podrzędnym i musiałem ustawić względny DataContext, który właśnie dodałem do XAML okna.
<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">
źródło
Możesz spróbować sztuczki x: Reference
<Window ... x:Name="myWindow"><ListBox ItemsSource="{Binding Items, Source={x:Reference myWindow}}" /></Window>
źródło
To mój sposób na powiązanie z kodem za (patrz właściwość
DataTemplateSelector
)public partial class MainWindow : Window { public MainWindow() { this.DataTemplateSelector = new MyDataTemplateSelector(); InitializeComponent(); // ... more initializations ... } public DataTemplateSelector DataTemplateSelector { get; } // ... more code stuff ... }
W języku XAML będzie odwoływać się za
RelativeSource
pośrednictwem Ancestors do zawierającegoWindow
, więc jestem w mojejWindow
klasie i używam właściwości za pośrednictwemPath
deklaracji:<GridViewColumn Header="Value(s)" CellTemplateSelector="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataTemplateSelector}"/>
Ustawienie właściwości
DataTemplateSelector
przed wywołaniemInitializeComponent
zależy od braku implementacjiIPropertyChanged
lub użycia implementacji, aDependencyProperty
więc nie ma komunikacji przy zmianie właściwościDataTemplateSelector
.źródło