我的意图:点击“显示名称”按钮显示一个消息框,其中包含在“ 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);
}
答案 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