it-swarm.com.ru

Привязка к себе/"это" в XAML

Простой вопрос WPF/XAML. В XAML, как я могу ссылаться на Self/этот объект в данном контексте? В очень простом приложении с главным окном, одним элементом управления и закодированным свойством 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}"/> 

так далее

Спасибо

46
Tom Davies

Сначала используйте запятую между RelativeSource и Path в вашем Binding:

<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}"/> 
76
Arcturus

Я думаю, что вы ищете это:

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

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

>
29
Clint StLaurent

Один из способов справиться с 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.

28
Damian

Проблема с именованием корневого элемента XAML заключается в том, что, если вы привыкли использовать одно и то же имя (т. Е. «_This», «Root» и т.д.) Для всех корней в вашем проекте, тогда поздняя привязка во вложенном шаблоны могут получить доступ не к тому элементу. Это связано с тем, что, когда {Binding}ElementName=... используется в Template, имена разрешаются во время выполнения путем обхода дерева NameScope до тех пор, пока не будет найдено первое совпадение.

Решение Клинта позволяет избежать присвоения имени корневому элементу, но оно устанавливает корневой элемент в свой собственный 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>

Результат:

enter image description here


нет.

для ясности, clr-namespace не используется, но обратите внимание, что показанный здесь XAML действительно работает для доступа к пространству имен global (хотя разработчик VS2013 жалуется)

3
Glenn Slayden

К сожалению, наименование корневого элемента с помощью «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}, так как он кажется мне более логичным и безопасным.

0
cyanide