2010-10-01 38 views
42

Câu hỏi WPF/XAML đơn giản. Trong XAML, làm thế nào để tôi tham chiếu đối tượng Self/this trong một ngữ cảnh cụ thể? Trong một ứng dụng rất cơ bản với một cửa sổ chính, một điều khiển và một thuộc tính C# được mã hóa của cửa sổ, tôi muốn ràng buộc thuộc tính của điều khiển với thuộc tính được mã hóa bằng tay của cửa sổ.Ràng buộc tự/'điều này' trong XAML

Trong mã, điều này rất dễ dàng - trong constructor của Window, tôi đã thêm này:

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

Rõ ràng, tôi có một tài sản gọi là ButtonWidth, và một điều khiển được gọi là button1. Tôi không thể tìm ra cách để làm điều này trong XAML. nỗ lực khác nhau như ví dụ sau đây chưa từng làm việc:

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

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

vv

Cảm ơn

Trả lời

66

đầu tiên sử dụng một dấu phẩy giữa RelativeSource và Path trong Ràng buộc của bạn:

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

Thứ hai, RelativeSource liên kết với nút. Nút không có thuộc tính nào được gọi là ButtonWidth. Tôi đoán bạn cần phải ràng buộc để kiểm soát cha mẹ của bạn.

Vì vậy, cố gắng RelativeSource này ràng buộc:

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

Cảm ơn bạn rất nhiều vì bài đăng này. Nó đã giúp tôi rất nhiều! Tôi đã tìm kiếm một giải pháp tốt 3 giờ. –

+0

Tôi có một DataGrid nơi nếu người dùng truy cập một trong những CommandItem của ContextMenu trong Command's thông qua KeyBinding của InputBinding có CommandParameter = "{Binding ElementName = MyDataGrid, Path = SelectedItems}", nó sẽ vượt qua SelectedItems đến Bound ICommand. Tuy nhiên, null được truyền nếu nó được truy cập thông qua ContextMenu. Tôi đã thử CommandParameter = "{Binding SelectedItems}", "{Binding ElementName = MyDataGrid, Đường dẫn = SelectedItems}", "Binding RelativeSource = {RelativeSource FindAncestor, AncestorType = {x: Loại DataGrid}}, Path = SelectedItems}" . Tôi đã đặt CommandParameter trước Command. – Tom

26

Một cách tôi nhận được xung quanh phải đối phó với RelativeSource và những thứ tương tự là để đặt tên cho nguyên tố XAML root:

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

Nếu bạn muốn thiết lập DataContext bạn cũng có thể làm điều này:

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

Tôi thấy đây là một mẹo hay để không phải nhớ mber tất cả các phức tạp của RelativeSource ràng buộc.

23

Tôi nghĩ rằng những gì bạn đang tìm kiếm là thế này:

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

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

> 
+0

Đã xác minh vẫn hoạt động trên ứng dụng Windows 10 trong phần tử chính . – Lavamantis

3

Vấn đề với cách đặt tên các yếu tố XAML gốc là, nếu bạn nhận được vào thói quen sử dụng cùng tên (ví dụ, "_this", "Gốc", vv) cho tất cả các gốc trong dự án của bạn, sau đó ràng buộc muộn trong các mẫu lồng nhau có thể truy cập phần tử sai. Điều này là do, khi {Binding}ElementName=... được sử dụng trong một Template, tên được giải quyết trong thời gian chạy bằng cách đi bộ lên cây NameScope cho đến khi tìm thấy kết quả phù hợp đầu tiên.

Giải pháp của Clint tránh đặt tên phần tử gốc, nhưng nó đặt phần tử gốc thành DataContext riêng của nó, có thể không phải là một tùy chọn nếu dữ liệu cần thiết cho DataContext. Nó cũng có vẻ hơi nặng để giới thiệu một ràng buộc khác về một yếu tố chỉ nhằm mục đích cung cấp sự truy cập vào nó. Sau đó, nếu truy cập không còn cần thiết, rằng {Binding} sẽ trở nên lộn xộn: trách nhiệm truy cập đúng với mục tiêu và ràng buộc.

Theo đó, đây là một phần mở rộng đánh dấu đơn giản để truy cập phần tử gốc XAML mà không đặt tên nó:

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> 

Kết quả:

enter image description here


n.b.

cho rõ ràng, không có clr-namespace được sử dụng, nhưng lưu ý rằng các XAML đưa ra ở đây không thực sự làm việc để truy cập vào namespace global (mặc dù các nhà thiết kế VS2013 phàn nàn)

0

Thật không may, đặt tên cho các phần tử gốc với "ElementName =. "dường như là cách duy nhất với UWP là {RelativeSource Self} không được hỗ trợ ở đó.

Rất kỳ lạ, điều này vẫn hoạt động khi tên bị ghi đè trong bố cục, ví dụ:

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

sau đó

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

</Page> 

BTW, Windows 10 cố định một lỗi (hiện nay Windows 8.1), khi cùng một tên nội bộ được sử dụng cho các yếu tố khác nhau trong cùng một bố trí.

Tuy nhiên, tôi muốn sử dụng {RelativeSource Self}, vì nó xuất hiện hợp lý hơn và an toàn hơn cho tôi.

Các vấn đề liên quan