Свързване към Self/'this' в XAML

Прост WPF/XAML въпрос. В XAML, как да направя препратка към Self/this обект в даден контекст? В много основно приложение с основен прозорец, една контрола и кодирано C# свойство на прозореца, искам да свържа свойство на контролата с ръчно кодираното свойство на прозореца.

В код това е много лесно - в конструктора на Window добавих това:

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

Очевидно имам свойство, наречено ButtonWidth, и контрола, наречено button1. Не мога да разбера как да направя това в XAML. Различни опити като следния пример не са работили:

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

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

и т.н

Благодаря


person Tom Davies    schedule 01.10.2010    source източник


Отговори (5)


Първо използвайте запетая между RelativeSource и Path във вашето обвързване:

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

Второ, RelativeSource се свързва с бутона. Бутонът няма свойство, наречено ButtonWidth. Предполагам, че трябва да се свържете с вашия родителски контрол.

Така че опитайте това свързване на RelativeSource:

<Button x:Name="button1" Width="{Binding RelativeSource=
    {RelativeSource FindAncestor, AncestorType={x:Type YourNamespace:YourParentControl}}, 
    Path=ButtonWidth}"/> 
person Arcturus    schedule 01.10.2010
comment
Благодаря ви много за тази публикация. Много ми помогна! Вече 3 часа търся добро решение. - person Mr Tangjai; 17.03.2017
comment
Имам DataGrid, при който, ако потребителят получи достъп до една от неговите вградени команди на ContextMenu's MenuItem чрез KeyBinding на InputBinding, чийто CommandParameter={Binding ElementName=MyDataGrid, Path=SelectedItems}, той ще предаде SelectedItems на Bound ICommand. Въпреки това, null се предава, ако е достъпен чрез ContextMenu. Опитах CommandParameter= {Binding SelectedItems}, {Binding ElementName=MyDataGrid, Path=SelectedItems}, {Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=SelectedItems}. Зададох CommandParameter преди командата. - person Tom; 09.05.2017
comment
отговорът е правилен, гласуван за, защото работи. но очевидно това е друг пример за захарен синтаксис на xaml... - person mike; 08.07.2020

Мисля, че това, което търсите, е това:

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

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

>
person Clint StLaurent    schedule 07.11.2012
comment
Verified все още работи в приложението Windows 10 в главния елемент ‹Page›. - person Lavamantis; 26.09.2016

Един от начините, по които се справям с RelativeSource и други подобни, е да наименувам коренния XAML елемент:

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

Ако искате да зададете DataContext, можете също да направите това:

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

Намирам това за добър трик, за да не се налага да помним всички сложности на свързването на RelativeSource.

person Damian    schedule 29.11.2010

Проблемът с именуването на коренния елемент XAML е, че ако придобиете навика да използвате същото име (т.е., " _this", "Root" и т.н.) за всички корени във вашия проект, тогава късното свързване във вложени шаблони може да получи достъп до грешен елемент. Това е така, защото когато {Binding} ElementName=... се използва в Template, имената се разрешават по време на изпълнение чрез ходене нагоре по дървото NameScope, докато се намери първото съвпадение.

Решението на Clint избягва наименуването на коренния елемент, но настройва коренния елемент в собствен DataContext, което може да не е опция, ако DataContext е необходим, да речем, за данни. Също така изглежда малко трудно да се въведе друго обвързване на елемент само с цел осигуряване на достъп до него. По-късно, ако достъпът вече не е необходим, този {Binding} ще се превърне в бъркотия: отговорността за достъп правилно принадлежи на целта и обвързването.

Съответно, тук е просто разширение за маркиране за достъп до коренния елемент на XAML, без да го наименувате:

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>

забележка: за по-голяма яснота, не съм дефинирал MarkupExtension в пространство от имена; използване на празен псевдоним clr-namespace, както е показано тук d̲o̲e̲s̲ всъщност работи за достъп до пространството от имена global:: (въпреки че дизайнерът на VS2013 изглежда се оплаква от това).

Резултат:

въведете описание на изображението тук
Прозорец, чието съдържание е обвързано със самия себе си.


N.b.

person Glenn Slayden    schedule 19.12.2014

За съжаление, именуването на основния елемент с "ElementName=.." изглежда е единственият начин с UWP, тъй като {RelativeSource Self} не се поддържа там.

Колкото и да е странно, това все още работи, когато името е заменено в оформлението, напр.

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

тогава

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

</Page>

Между другото, Windows 10 поправи грешка (съществува в Windows 8.1), когато едно и също вътрешно име се използва за различни елементи в едно и също оформление.

Все пак бих предпочел да използвам {RelativeSource Self}, тъй като ми изглежда по-логично и по-безопасно.

person cyanide    schedule 15.02.2017