数据上下文冲突

问题描述 投票:0回答:2
<UserControl x:Class="WatermarkTextBox"
             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"
             mc:Ignorable="d"
             d:DesignHeight="30"
             d:DesignWidth="250">
    <UserControl.Resources>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
    </UserControl.Resources>
    <Border>
        <Grid x:Name="grid">
            <TextBlock Text="{Binding Watermark, FallbackValue=This prompt dissappears as you type...}"
                       Visibility="{Binding ElementName=txtUserEntry, Path=Text.IsEmpty, Converter={StaticResource BooleanToVisibilityConverter}}" />
            <TextBox Name="txtUserEntry"
                     Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" />
        </Grid>
    </Border>
</UserControl>

上面的代码显示了我的

WatermarkTextBox
控件。在文件后面的代码中,我设置了
DataContext
。我省略了控件 DP 的所有代码。

public WatermarkTextBox()
{
    InitializeComponent();
    grid.DataContext = this;
}

我必须将

DataContext
绑定到网格,否则水印和实际文本的
Text
属性将不会显示。现在的问题是我无法将
Background
Border
设置在
Grid
之外。

我尝试了下面的代码,但只设置了

Background
Border
,而不是水印和实际文本。

public WatermarkTextBox()
{
    InitializeComponent();
    this.DataContext = this;
    grid.DataContext = this;
}
wpf binding datacontext
2个回答
3
投票

在这样的 UserControl 中,您永远不应该将 DataContext 显式设置为

this
或其他任何值,因为当您在应用程序中的某个位置使用 UserControl 时,DataContext 通常是在外部设置的。外部应用的 DataContext 通常是应用程序视图模型(的一部分)。

您应该更改内部绑定,以便它们使用显式

RelativeSource
:

<TextBlock
    Text="{Binding Path=Watermark,
                   RelativeSource={RelativeSource AncestorType=UserControl},
                   FallbackValue=This prompt dissappears as you type...}"
    Visibility="{Binding ElementName=txtUserEntry,
                         Path=Text.IsEmpty,
                         Converter={StaticResource BooleanToVisibilityConverter}}" />
<TextBox
    Name="txtUserEntry"
    Text="{Binding Path=Text,
                   UpdateSourceTrigger=PropertyChanged,
                   RelativeSource={RelativeSource AncestorType=UserControl}}" />

然后从 UserControl 的构造函数中删除任何 DataContext 赋值。

参见例如这个答案(以及许多其他类似的答案)详细讨论了这个主题。


0
投票

@Clemens 答案的附录:

为了避免为每个控件设置

RelativeSource={RelativeSource AncestorType=UserControl}
,请在用户控件中提供一个根元素来获取 DataContext。

<UserControl x:Class="UserControlBindingIssue.TestUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:local="clr-namespace:UserControlBindingIssue"
             d:DataContext="{d:DesignInstance Type=local:TestUserControl,
                                              IsDesignTimeCreatable=True}"
             mc:Ignorable="d">
    <ContentControl DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:TestUserControl}}}">
        <TextBox Width="100"
                 Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" />

        <!--  Other controls  -->
    </ContentControl>
</UserControl>
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.