Связывание не работает для текстового поля в DataTemplate в ContentPresenter

Rajasri.J спросил: 28 апреля 2018 в 08:45 в: c#

Мое намерение: Отобразить окно сообщения с текстом, введенным в элементе управления userdata ​​em>"при нажатии кнопки Показать имя " (с помощь привязки данных вместо прямого доступа к свойству элемента управления userdata ​​em>"). Я написал этот код, чтобы понять концепцию шаблона в WPF .

Проблема с приведенным ниже кодом: Databinding не выполняются по назначению.

ПРИМЕЧАНИЕ: Однако, если я удалю " ContentPresenter " и " DataTemplate ", окружающий" userdata ​​em>", привязка данных работает нормально. Любое приводит к тому, что этот код будет работать.

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 ответа

Есть решение
ASh ответил: 28 апреля 2018 в 09:26

В ContentTemplate отсутствует привязка данных, поскольку контент не установлен. Добавьте привязку содержимого <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>
El Barrent ответил: 28 апреля 2018 в 09:28

Это происходит потому, что DataTemplate является "оберткой" вокруг содержимого кнопки (Button.Content) и использует этот контент как собственный DataContext. Когда Content не указан, DataContext из DataTemplate имеет значение null и привязка не работает.

Чтобы сделать код работать правильно, вы должны указать свойство Button.Content (это должен быть экземпляр класса UserName).

Вы можете использовать ButtonContext Button в качестве содержимого кнопки (этот путь уродливый как утка):

<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>
ASh ответил: 28 апреля 2018 в 05:32
{Binding RelativeSource={RelativeSource Self}, Path=DataContext} можно написать просто как {Binding}
El Barrent ответил: 29 апреля 2018 в 07:26
Вы правы, я использовал полную форму, чтобы дать понять, что происходит.
Rajasri.J ответил: 28 апреля 2018 в 09:12

Проблема была решена путем изменения определения XAML элемента управления userdata ​​em>, как показано ниже:

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

Когда есть вложенные шаблоны, compiler возможно, не сможет определить правильного родителя. Следовательно, необходимо указать относительный источник с типом предка и путь с DataContext. Bindingdata ​​p>