Подтвердить что ты не робот

Связывание с Self/'this' в XAML

Простой вопрос WPF/XAML. В XAML, как я могу ссылаться на Self/this object в данном контексте? В очень базовом приложении с основным окном, одним элементом управления и закодированным свойством С# для окна я хочу привязать свойство элемента управления к свойству ручной кодировки окна.

В коде это очень просто - в конструкторе 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}"/> 

и т.д.

Спасибо

4b9b3361

Ответ 1

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

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

Во-вторых, RelativeSource привязывается к Button. Кнопка не имеет свойства ButtonWidth. Я предполагаю, что вам нужно связать свой родительский контроль.

Итак, попробуйте привязку RelativeSource:

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

Ответ 2

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

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

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

>

Ответ 3

Один из способов, с которым мне приходится иметь дело с 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.

Ответ 4

Проблема с именованием корневого элемента 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:: пространству имен global:: (хотя дизайнер VS2013, похоже, жалуется на это).

Результат:

enter image description here
Окно, содержимое которого связано с самим собой.


Н.Б.

Ответ 5

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