2010-10-01 14 views
42

Proste pytanie WPF/XAML. W XAML, jak mogę odwołać się do Self/tego obiektu w danym kontekście? W bardzo prostej aplikacji z głównym oknem, jednym sterowaniem i zakodowaną własnością C# okna, chcę powiązać właściwość kontrolki z właściwością kodowaną ręcznie okna.Wiązanie do siebie/"to" w XAML

W kodzie, to jest bardzo proste - w konstruktorze na Windows, dodałem to:

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

Oczywiście, mam właściwość o nazwie ButtonWidth oraz kontrolę nazwie button1. Nie mogę wymyślić, jak to zrobić w XAML. Różne próby, jak w poniższym przykładzie nie pracowali:

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

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

itp

Dzięki

Odpowiedz

66

Pierwsze użycie przecinka między RelativeSource i ścieżka w swojej Oprawa:

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

drugie, RelativeSource wiąże się z przyciskiem. Przycisk nie ma właściwości o nazwie ButtonWidth. Zgaduję, że musisz przywiązać się do kontroli nad rodzicem.

Więc spróbuj tego RelativeSource oprawa:

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

Dziękuję bardzo za ten wpis. Pomogło mi to dużo! Szukałem dobrego rozwiązania 3 godziny. –

+0

Mam DataGrid, gdzie, jeśli użytkownik uzyskuje dostęp do jednego z wbudowanych poleceń MenuItem w MenuItem poprzez KeyBinding InputBinding, którego CommandParameter = "{Binding ElementName = MyDataGrid, Path = SelectedItems}", przekaże SelectedItems do Związanej ICommand. Jednak wartość null jest przekazywana, jeśli jest dostępna przez ContextMenu. Próbowałem już CommandParameter = "{Binding SelectedItems}", "{Binding ElementName = MyDataGrid, Path = SelectedItems}", "{Binding RelativeSource = {RelativeSource FindAncestor, AncestorType = {x: Type DataGrid}}, Path = SelectedItems}" . Ustawiłem CommandParameter przed Command. – Tom

26

Jednym ze sposobów, ja obejść mając do czynienia z RelativeSource i jak to nazwać elementu głównego 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> 

Jeśli chcesz ustawić DataContext można również wykonać:

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

Uważam, że to dobra sztuczka, aby nie musieć mber wszystkie złożoności wiązania RelativeSource.

23

myślę co szukasz to:

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

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

> 
+0

Zweryfikowany wciąż działa w aplikacji Windows 10 w głównym elemencie. – Lavamantis

3

Problem nazewnictwa element XAML korzeniowy jest to, że jeśli masz w zwyczaju przy użyciu tej samej nazwy (czyli „_this” "Root" itp.) Dla wszystkich korzeni w projekcie, późniejsze wiązanie w szablonach zagnieżdżonych może uzyskać dostęp do niewłaściwego elementu. Dzieje się tak dlatego, że gdy {Binding}ElementName=... jest używane w Template, nazwy są rozwiązywane w środowisku wykonawczym przez podchodzenie do drzewa NameScope aż do znalezienia pierwszego dopasowania.

Rozwiązanie Clinta unika nazywania elementu głównego, ale ustawia element główny na własny DataContext, co może nie być opcją, jeśli DataContext jest potrzebny dla, powiedzmy, danych. Wydaje się również, że nieco trudniej jest wprowadzić inne wiązanie elementu tylko w celu zapewnienia dostępu do niego. Później, jeśli dostęp nie jest już potrzebny, to {Binding} stanie się bałaganem: odpowiedzialność za dostęp właściwie należy do celu i powiązania.

związku z tym, tu jest prostym rozszerzeniem znaczników aby uzyskać dostęp do elementu głównego XAML bez nazywania go:

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> 

Wynik:

enter image description here


n.b.

dla jasności, nie clr-namespace jest używany, należy jednak pamiętać, że XAML pokazany tutaj jest faktycznie pracują dostępu do przestrzeni nazw global (choć projektant VS2013 narzeka)

0

Niestety, nazywając element główny z „ElementName =. . "wydaje się być jedynym sposobem w przypadku UWP, ponieważ {RelativeSource Self} nie jest tam obsługiwany.

To dziwne, nadal działa, gdy nazwa jest nadpisana w układzie, np.

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

następnie

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

</Page> 

BTW, Windows 10 naprawiono błąd (obecny w Windows 8.1), gdy sama nazwa wewnętrzna służy do różnych elementów w tym samym układzie.

Mimo to wolałbym używać {RelativeSource Self}, ponieważ wydaje mi się to bardziej logiczne i bezpieczniejsze.