簡體   English   中英

WPF UserControl 不繼承父 DataContext

[英]WPF UserControl doesn't inherit parent DataContext

我正在嘗試開發一個可重用的 UserControl,但遇到了綁定問題。 我創建了一個較小的應用程序來測試它,但無法解決它,或者至少理解為什么它沒有按我的預期工作。

代碼如下。 我期望的是我放在 MainWindow.xaml 上的 TestUserControl 的實例將繼承那里的 DataContext 就像下面的 TextBlock 一樣。 相反,它的 DataContext 似乎為空。 DataContext 沒有傳遞下去有什么原因嗎? 我必須自動設置嗎?

主窗口.xaml

<Window x:Class="WpfTestApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfTestApp"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel Orientation="Vertical">
        <local:TestUserControl TextFromParent="{Binding SomeText}" />
        <TextBlock Name="TestTextBlock" Text="{Binding SomeText}" />

    </StackPanel>
</Window>

主窗口.xaml.cs

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;

namespace WpfTestApp
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private string _someText;

        public MainWindow()
        {
            DataContext = this;

            InitializeComponent();

            SomeText = "New Text!";
        }

        public string SomeText
        {
            get { return _someText; }
            set
            {
                _someText = value;
                NotifyOnPropertyChanged();
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;

        protected void NotifyOnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

測試用戶控件.xaml

<UserControl x:Class="WpfTestApp.TestUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WpfTestApp"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <TextBlock Name="TheTextBlock" Text="{Binding TextFromParent}" />

    </Grid>
</UserControl>

測試用戶控件.xaml.cs

using System.Windows;
using System.Windows.Controls;

namespace WpfTestApp
{
    public partial class TestUserControl : UserControl
    {
        public TestUserControl()
        {
            InitializeComponent();
        }

        public string TextFromParent
        {
            get { return (string)GetValue(TextFromParentProperty); }
            set { SetValue(TextFromParentProperty, value); }
        }

        public static readonly DependencyProperty TextFromParentProperty = DependencyProperty.Register(
            "TextFromParent", typeof(string), typeof(TestUserControl), new PropertyMetadata());
    }
}

程序在運行時如下所示,第一個文本是空白的,然后是具有工作綁定的 TextBlock: 在此處輸入圖片說明

UserControl 實際上是從其父元素繼承 DataContext。 但是,該 DataContext 中沒有TextFromParent屬性(因為它是 MainWindow 實例)。

UserControl 的 XAML 中的 Binding 應該綁定到 UserControl 本身的屬性,而不是當前 DataContext 之一。 因此它必須使用 UserControl 實例作為源對象:

<TextBlock Text="{Binding TextFromParent,
                  RelativeSource={RelativeSource AncestorType=UserControl}}" />

將 UserControl 的 DataContext 設置為自身不是一個選項,因為它可以防止從控件的父元素繼承 DataContext 值。

但是,您可以在 UserControl 的 XAML 中設置根元素的 DataContext 以避免在潛在的許多綁定上設置 RelativeSource:

<UserControl ...>
    <Grid DataContext="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}">
        <TextBlock Text="{Binding TextFromParent}" />
    </Grid>
</UserControl>

試試這個,你不需要在綁定中使用任何 RelativeSource:

<Grid Name="GrdContent">
    <TextBlock Name="TheTextBlock" Text="{Binding TextFromParent}" />

</Grid>

...

public MainWindow()
        {
            GrdContent.DataContext = this;

            InitializeComponent();

            SomeText = "New Text!";
        }

我試圖實現上述解決方案(使用相同的代碼),但無法使其工作。

MainWindow XAML 和代碼隱藏:

<Grid>
    <StackPanel Orientation="Horizontal">
        <StackPanel Orientation="Vertical">
            <TextBlock Name="TestTextBlock1" Text="{Binding SomeText}" />
            <local:TestUserControl DataContext="{Binding SomeText}" />
            <TextBlock Name="TestTextBlock3" Text="{Binding SomeText}" />
        </StackPanel>
    </StackPanel>
</Grid>



public partial class MainWindow : Window, INotifyPropertyChanged
{
    private string _someText;

    public MainWindow()
    {
        DataContext = this;

        InitializeComponent();

        SomeText = "Hello World!";
    }
    public string SomeText
    {
        get { return _someText; }
        set
        {
            _someText = value;
            NotifyOnPropertyChanged();
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;

    protected void NotifyOnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

我的用戶控制

<UserControl x:Class="ControlDataContext.TestUserControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:ControlDataContext"
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800">
<Grid DataContext="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}">
    <TextBlock Text="{Binding TextFromParent}" />
</Grid>

用戶控制背后的代碼

public partial class TestUserControl : UserControl
{
    public TestUserControl()
    {
        InitializeComponent();
    }
    public string TextFromParent
    {
        get => (string)GetValue(TextFromParentProperty);
        set => SetValue(TextFromParentProperty, value);
    }

    public static readonly DependencyProperty TextFromParentProperty = DependencyProperty.Register(
        "TextFromParent", typeof(string), typeof(TestUserControl), new PropertyMetadata());
}

圖片顯示了帶有黃色突出顯示的缺失線

結果

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM