绑定不适用于ContentPresenter中的DataTemplate中的文本框

时间:2018-05-22 10:25:46

标签: c# wpf data-binding

我的意图:点击“显示名称”按钮显示一个消息框,其中包含在“ userdata ”控件中输入的文字(带有数据绑定的帮助,而不是直接访问“ userdata ”控件的 Text 属性)。我编写了这段代码来理解 WPF 中的模板概念。

以下代码的问题: 数据绑定未按预期发生。

注意:但是,如果我删除“ ContentPresenter ”和围绕“ userdata DataTemplate ” >“控制,数据绑定工作正常。任何导致此代码工作的导致都会有所帮助。

Mainwindow.xaml:

<StackPanel>
    <Button x:Name="openFile">
        <Button.Template>
            <ControlTemplate>
                <Grid Width="300" Height="150">
                    <Rectangle Fill="Aquamarine" RadiusX="20" RadiusY="20" />
                    <Ellipse Fill="Azure"></Ellipse>
                    <ContentPresenter>
                        <ContentPresenter.ContentTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal" Height="50">
                                    <TextBlock Text="Name" />
                                    <TextBox x:Name="userdata" Text="{Binding Name, Mode=TwoWay}" Margin="5" Width="100" />
                                    <Button Content="Show Name" Click="Button_Click"></Button>
                                </StackPanel>
                            </DataTemplate>
                        </ContentPresenter.ContentTemplate>
                    </ContentPresenter>
                </Grid>
            </ControlTemplate>
        </Button.Template>            
    </Button>
</StackPanel>

UserName.cs

public class UserName : INotifyPropertyChanged
{
    private string _name;

    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            FirePropertyChange("Name");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void FirePropertyChange(string propertyName)
    {
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

MainWindow.xaml.cs:

UserName user = new UserName();
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = user;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {           

        MessageBox.Show(user.Name);
    }

3 个答案:

答案 0 :(得分:1)

DataBinding并不像ContentTemplate中那样发生,因为未设置Content。添加内容绑定<ContentPresenter Content="{Binding}">,其余的将工作

<ContentPresenter Content="{Binding}">
    <ContentPresenter.ContentTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal" Height="50">
                <TextBlock Text="Name" />
                <TextBox x:Name="userdata" Text="{Binding Name, Mode=TwoWay}" Margin="5" Width="100" />
                <Button Content="Show Name" Click="Button_Click"></Button>
            </StackPanel>
        </DataTemplate>
    </ContentPresenter.ContentTemplate>
</ContentPresenter>

答案 1 :(得分:1)

这是因为DataTemplate是一个&#34;包装器&#34;围绕按钮的内容(Button.Content)并将此内容用作自己的DataContext。如果未指定Content,则DataTemplate的DataContext为null,绑定失败。

为了使代码正常工作,您应该指定Button.Content属性(它应该是UserName类的实例)。

您可以使用按钮的DataContext作为按钮的内容(这种方式很丑陋):

<Button Content="{Binding RelativeSource={RelativeSource Self}, Path=DataContext}">
<Button.Template>
    <ControlTemplate TargetType="Button">
        <Grid Width="300" Height="150">
            <ContentPresenter>
                <ContentPresenter.ContentTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal" Height="50">
                            <TextBlock Text="Name" />
                            <TextBox x:Name="userdata" Text="{Binding Name, Mode=TwoWay}" Margin="5" Width="100" />
                            <Button Content="Show Name"></Button>
                        </StackPanel>
                    </DataTemplate>
                </ContentPresenter.ContentTemplate>
            </ContentPresenter>
        </Grid>
    </ControlTemplate>
</Button.Template>

当您从树中删除DataTemplate和ContentPresenter时,TextBox只会继承父的DataContext(UserName的实例),因此绑定可以正常工作。

最好的方法是遵循MVVM模式。

窗口的DataContext:

public class MainWindowViewModel : INotifyPropertyChanged
{
    public UserName User { get; } = new UserName();
}

指定窗口数据上下文:

public MainWindow()
{
    InitializeComponent();
    this.DataContext = new MainWindowViewModel();
}

将按钮绑定到用户:

<Button Content="{Binding User}">
    <Button.ContentTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal" Height="50">
                <TextBlock Text="Name" />
                <TextBox x:Name="userdata" Text="{Binding Name, Mode=TwoWay}" Margin="5" Width="100" />
                <Button Content="Show Name"></Button>
            </StackPanel>
        </DataTemplate>
    </Button.ContentTemplate>
    <Button.Template>
        <ControlTemplate TargetType="Button">
            <Grid Width="300" Height="150">
                <ContentPresenter/>
            </Grid>
        </ControlTemplate>
    </Button.Template>
</Button>

答案 2 :(得分:0)

通过更改 userdata 控件的XAML定义解决了问题,如下所示:

<TextBox x:Name="userdata" Text="{Binding DataContext.Name, Mode=TwoWay, RelativeSource={RelativeSource AncestorType=Button,Mode=FindAncestor}}" Margin="5" Width="100" />

当存在嵌套模板时,编译器可能无法识别正确的父模板。因此,有必要提及具有祖先类型的相对源和带有* DataContext的路径。* bindingdata