it-swarm.com.de

Binden von Objekten, die im Code-Behind definiert sind

Ich habe ein Objekt, das im Code hinter dem Objekt instanziiert wird. Die XAML heißt beispielsweise window.xaml und innerhalb der window.xaml.cs

protected Dictionary<string, myClass> myDictionary;

Wie kann ich dieses Objekt beispielsweise an eine Listenansicht binden, indem nur XAML-Markierungen verwendet werden?

Update:

(Genau das habe ich in meinem Testcode):

<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>

Und im Codebehind

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

    public Window1()
    {
        InitializeComponent();
    }
}

Angenommen, der Titel sollte "ABCDEFG" werden, oder? Aber es zeigt nichts.

76
xandy

Sie können den DataContext wie folgt für Ihr Steuerelement, Formular usw. festlegen:

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

Klarstellung:

Der Datenkontext, der auf den obigen Wert gesetzt wird, sollte an dem Element erfolgen, das den Code hinter sich "besitzt". Für ein Fenster sollten Sie es also in der Window-Deklaration festlegen.

Ich habe Ihr Beispiel, das mit diesem Code arbeitet:

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

Der auf dieser Ebene festgelegte DataContext wird dann von jedem Element im Fenster geerbt (sofern Sie es nicht explizit für ein untergeordnetes Element ändern). Nach dem Festlegen des DataContext für das Fenster sollten Sie also in der Lage sein, eine direkte Bindung an CodeBehind properties von einem beliebigen Steuerelement im Fenster aus.

93
Guy Starbuck

Es gibt einen viel einfacheren Weg, dies zu tun. Sie können Ihrem Window oder UserControl einen Namen zuweisen und anschließend an ElementName binden.

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();
    }
}
116
Saad Imran.

Obwohl Guys Antwort richtig ist (und wahrscheinlich in 9 von 10 Fällen passt), ist es erwähnenswert, dass Sie, wenn Sie dies mit einem Steuerelement versuchen, dessen DataContext bereits weiter oben im Stack eingestellt ist, dies beim Setzen von DataContext zurücksetzen zurück zu sich selbst:

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

Dadurch werden Ihre vorhandenen Bindungen natürlich gebrochen.

Wenn dies der Fall ist, sollten Sie RelativeSource für das Steuerelement festlegen, das Sie binden möchten, und nicht dessen übergeordnetes Element.

für die Bindung an die Eigenschaften eines UserControls:

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

Angesichts dessen, wie schwierig es derzeit sein kann, zu sehen, was mit der Datenbindung geschieht, ist es zu berücksichtigen, auch wenn Sie feststellen, dass die Einstellung RelativeSource={RelativeSource Self} aktuell funktioniert :)

23
CatBusStop

Noch ein paar Erläuterungen: Eine Eigenschaft ohne 'get', 'set' kann nicht gebunden werden

Ich stehe dem Fall genau wie der Fall des Fragestellers gegenüber. Und ich muss die folgenden Dinge haben, damit die Bindung richtig funktioniert:

//(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>
5
jondinham

Definieren Sie einen 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( );
    }
}

Binden Sie an eine benutzerdefinierte Definition eines Wörterbuchs. Es gibt viele Überschreibungen, die ich weggelassen habe, aber der Indexer ist der wichtigste, da er das geänderte Eigenschaftsereignis ausgibt, wenn der Wert geändert wird. Dies ist für die Zielbindung erforderlich.

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
        }
    }


}

Verwenden Sie in Ihrer XAML-Datei diesen Konverter. Zuerst verweisen Sie darauf:

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

Wenn zum Beispiel in Ihrem Wörterbuch ein Eintrag mit dem Schlüssel "Name" vorhanden ist, verwenden Sie, um eine Bindung herzustellen

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

Machen Sie aus Ihrer Eigenschaft "windowname" eine DependencyProperty und behalten Sie das gleiche bei.

1
viky

Ich hatte genau das gleiche Problem, aber meines lag nicht daran, dass ich eine lokale Variable einrichtete.

<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
davesbrain

Setzen Sie in Ihrem Code dahinter den DataContext des Fensters auf das Wörterbuch. In Ihrer XAML können Sie schreiben:

<ListView ItemsSource="{Binding}" />

Dadurch wird die ListView an das Wörterbuch gebunden.

Für komplexere Szenarien wäre dies eine Teilmenge von Techniken hinter dem Muster MVVM

0
Szymon Rozga

Eine Möglichkeit wäre, eine ObservableCollection (System.Collections.ObjectModel) zu erstellen und Ihre Wörterbuchdaten dort zu haben. Dann sollten Sie die ObservableCollection an Ihre ListBox binden können.

In Ihrer XAML sollten Sie so etwas haben:

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

Sie können den x: Reference-Trick ausprobieren

<Window ... x:Name="myWindow"><ListBox ItemsSource="{Binding Items, Source={x:Reference myWindow}}" /></Window>