it-swarm.com.de

An sich selbst binden/'this' in XAML

Einfache WPF/XAML-Frage. Wie verweise ich in XAML auf das Selbst/dieses Objekt in einem bestimmten Kontext? In einer sehr einfachen App mit einem Hauptfenster, einem Steuerelement und einer codierten C # -Eigenschaft des Fensters möchte ich eine Eigenschaft des Steuerelements an die handcodierte Eigenschaft des Fensters binden. 

Im Code ist dies sehr einfach - im Konstruktor des Fensters habe ich Folgendes hinzugefügt:

Binding bind = new Binding();
bind.Source = this;
bind.Path = new PropertyPath("ButtonWidth");
button1.SetBinding(WidthProperty, bind);

Offensichtlich habe ich eine Eigenschaft namens ButtonWidth und ein Steuerelement namens button1. Ich kann nicht herausfinden, wie man dies in XAML macht. Verschiedene Versuche wie das folgende Beispiel haben nicht funktioniert:

<Button x:Name="button1" Width="{Binding Source=Self Path=ButtonWidth}"/>

<Button x:Name="button1" Width="{Binding RelativeSource={RelativeSource Self} Path=ButtonWidth}"/> 

usw

Vielen Dank

46
Tom Davies

Verwenden Sie zuerst ein Komma zwischen RelativeSource und Path in Ihrer Bindung:

<Button x:Name="button1" Width="{Binding RelativeSource={RelativeSource Self}, 
                                Path=ButtonWidth}"/> 

Zweitens bindet die RelativeSource an die Schaltfläche. Button hat keine Eigenschaft namens ButtonWidth. Ich vermute, Sie müssen an Ihre übergeordnete Kontrolle binden.

Versuchen Sie also diese RelativeSource-Bindung:

<Button x:Name="button1" Width="{Binding RelativeSource=
    {RelativeSource FindAncestor, AncestorType={x:Type YourNamespace:YourParentControl}}, 
    Path=ButtonWidth}"/> 
76
Arcturus

Ich denke, was Sie suchen, ist folgendes:

<Window x:Class = "blah blah all the regular stuff"

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

>
29
Clint StLaurent

Eine Möglichkeit, mich mit RelativeSource und dergleichen zu beschäftigen, besteht darin, das XAML-Stammelement zu benennen:

<Window x:Class="TestApp2.MainWindow"
    xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525"
    x:Name="_this"
    >
    <Grid>
        <Button x:Name="button" Width="{Binding ElementName=_this,Path=ButtonWidth}" />
    </Grid>
</Window>

Wenn Sie den DataContext festlegen möchten, können Sie auch Folgendes tun:

<Window x:Class="TestApp2.MainWindow"
    xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525"
    x:Name="_this"
    >
    <Grid DataContext="{Binding ElementName=_this}">        
        <Button x:Name="button" Width="{Binding Path=ButtonWidth}" />
    </Grid>
</Window>

Ich finde, dass dies ein guter Trick ist, um sich nicht an alle Komplexitäten der RelativeSource-Bindung erinnern zu müssen.

28
Damian

Das Problem bei der Benennung des XAML root-Elements besteht darin, dass, wenn Sie sich daran gewöhnen, denselben Namen (dh "_this", "Root" usw.) für alle Roots in Ihrem Projekt zu verwenden, dann zu spät -Bindungen in verschachtelten Vorlagen können auf das falsche Element zugreifen. Dies liegt daran, dass, wenn {Binding}ElementName=... in einer Template verwendet wird, die Namen zur Laufzeit aufgelöst werden, indem der NameScope Baum nach oben verschoben wird, bis die erste Übereinstimmung gefunden wird.

Die Lösung von Clint vermeidet die Benennung des Root-Elements, setzt jedoch das Root-Element in seine eigene DataContext, die möglicherweise keine Option ist, wenn DataContext beispielsweise für Daten benötigt wird. Es scheint auch etwas schwerfällig, eine andere Bindung für ein Element einzuführen, nur um den Zugriff darauf zu ermöglichen. Wenn später kein Zugriff mehr erforderlich ist, wird dieser {Binding} zu einem Durcheinander: Die Verantwortung für den Zugriff gehört ordnungsgemäß zum Ziel und zur Bindung.

Dementsprechend ist hier eine einfache Markup-Erweiterung, um auf das XAML-Stammelement zuzugreifen, ohne es zu benennen:

using System.Xaml;
using System.Windows.Markup;

public sealed class XamlRootExtension : MarkupExtension
{
    public override Object ProvideValue(IServiceProvider sp)
    {
        var rop = sp.GetService(typeof(IRootObjectProvider)) as IRootObjectProvider;
        return rop == null ? null : rop.RootObject;
    }
};

XAML:

<Window x:Class="MainWindow"
        xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
        xmlns:global="clr-namespace:">

    <TextBlock Text="{Binding Source={global:XamlRoot},Mode=OneTime}" />

</Window>

Ergebnis:

enter image description here


n.b.

der Klarheit halber wird kein clr-namespace verwendet. Beachten Sie jedoch, dass die hier gezeigte XAML tatsächlich für den Zugriff auf den Namespace global funktioniert (obwohl sich der VS2013-Designer beschwert).

3
Glenn Slayden

Leider scheint die Bezeichnung des Wurzelelements mit "ElementName = .." die einzige Möglichkeit bei UWP zu sein, da {RelativeSource Self} dort nicht unterstützt wird.

Seltsamerweise funktioniert das immer noch, wenn der Name im Layout überschrieben wird, z.

<UserControl x:Class="Path.MyClass" x:Name="internalName">
   <Border Background={Binding Path=Background, ElementName=internalName}" ...

dann

<Page>
   <local:MyClass x:Name=externalName />

</Page>

Übrigens, Windows 10 hat einen Fehler behoben (bei Windows 8.1 vorhanden), wenn derselbe interne Name für verschiedene Elemente in demselben Layout verwendet wird.

Ich würde jedoch lieber {RelativeSource Self} verwenden, da es mir logischer und sicherer erscheint.

0
cyanide