在 C# 中访问控件模板中的控件
Accessing a control within a control template in C#
这里是 WPF 新手。我正在尝试构建一个 table ,我想在一周中的每一天重复使用它。所以我把它移到一个控制模板。这是 XAML:
<ControlTemplate x:Key="defaultGridDesign" >
<Grid HorizontalAlignment="Center" Margin="0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="60"/>
<RowDefinition Height="60"/>
</Grid.RowDefinitions>
<Label x:Name="lblDayOfWeek" Style="{StaticResource BasicLabelLeft}" Grid.Row="0" Grid.Column="0" Grid.RowSpan="3" Content="Monday"/>
<Label x:Name="lblEmpty" Style="{StaticResource BasicLabelLeft}" Grid.Row="0" Grid.Column="1"/>
<Label x:Name="lblPlanned" Style="{StaticResource BasicLabelLeft}" Content="Planned" Grid.Row="1" Grid.Column="1"/>
<Label x:Name="lblProduced" Style="{StaticResource BasicLabelLeft}" Content="Produced" Grid.Row="2" Grid.Column="1"/>
<Label x:Name="lblPrevShift" Style="{StaticResource BasicLabelCenter}" Content="Previous Shift" Grid.Row="0" Grid.Column="2" />
<Label x:Name="lblPlannedPrevShift" Style="{StaticResource BasicLabelLeft}" Content="n/a" Grid.Row="1" Grid.Column="2" />
<Label x:Name="lblProducedPrevShift" Style="{StaticResource BasicLabelLeft}" Content="n/a" Grid.Row="2" Grid.Column="2" />
<Label x:Name="lbl1stHr" Style="{StaticResource BasicLabelCenter}" Content="01" Grid.Row="0" Grid.Column="3" />
<Label x:Name="lbl2ndHr" Style="{StaticResource BasicLabelCenter}" Content="02" Grid.Row="0" Grid.Column="4" />
<Label x:Name="lbl3rdHr" Style="{StaticResource BasicLabelCenter}" Content="03" Grid.Row="0" Grid.Column="5" />
<Label x:Name="lbl4thHr" Style="{StaticResource BasicLabelCenter}" Content="04" Grid.Row="0" Grid.Column="6" />
<Label x:Name="lbl5thHr" Style="{StaticResource BasicLabelCenter}" Content="05" Grid.Row="0" Grid.Column="7" />
<Label x:Name="lbl6thHr" Style="{StaticResource BasicLabelCenter}" Content="06" Grid.Row="0" Grid.Column="8" />
<Label x:Name="lbl7thHr" Style="{StaticResource BasicLabelCenter}" Content="07" Grid.Row="0" Grid.Column="9" />
<Label x:Name="lbl8thHr" Style="{StaticResource BasicLabelCenter}" Content="08" Grid.Row="0" Grid.Column="10"/>
<Label x:Name="lblTotal" Style="{StaticResource BasicLabelCenter}" Content="Total" Grid.Row="0" Grid.Column="11"/>
<Label x:Name="lblNextShift" Style="{StaticResource BasicLabelCenter}" Content="Next Shift" Grid.Row="0" Grid.Column="12"/>
<Label x:Name="lblPlannedTotal" Style="{StaticResource BasicLabelLeft}" Content="n/a" Grid.Row="1" Grid.Column="11"/>
<Label x:Name="lblPlannedNextShift" Style="{StaticResource BasicLabelLeft}" Content="n/a" Grid.Row="1" Grid.Column="12"/>
<Label x:Name="lblProducedTotal" Style="{StaticResource BasicLabelLeft}" Content="n/a" Grid.Row="2" Grid.Column="11"/>
<Label x:Name="lblShiftOEE" Style="{StaticResource BasicLabelLeft}" Content="n/a" Grid.Row="2" Grid.Column="12"/>
<StackPanel x:Name="stkPnlPlanned" Grid.Row="1" Grid.Column="3" Grid.ColumnSpan="8" Width="480"/>
<StackPanel x:Name="stkPnlProduced" Grid.Row="2" Grid.Column="3" Grid.ColumnSpan="8" Width="480"/>
</Grid>
</ControlTemplate>
这是我实例化它们的方式:
<StackPanel>
<ContentControl Template="{StaticResource defaultGridDesign}" x:Name="ccTuesday"></ContentControl>
<ContentControl Template="{StaticResource defaultGridDesign}" x:Name="ccWednesday" />
<ContentControl Template="{StaticResource defaultGridDesign}" x:Name="ccThursday" />
<ContentControl Template="{StaticResource defaultGridDesign}" x:Name="ccFriday" />
<ContentControl Template="{StaticResource defaultGridDesign}" x:Name="ccSaturday" />
<ContentControl Template="{StaticResource defaultGridDesign}" x:Name="ccMonday" />
</StackPanel>
现在我碰壁的地方是我想在控件模板中绑定标签。我在网上找到的每个绑定示例都使用了一个基本示例,但我还没有找到一个可以解决这种情况的示例。我基本上想在第一行中设置时间,在第一列中设置日期,但最终我需要根据我从 excel 文件中读取的内容用标签填充堆栈面板。我希望堆栈面板的 binding/filling 完全不同。 table 中的每一个都获得不同的信息。每个小时,我都需要更新它们中的每一个。
我已经试过了,但没有用:
Label test = (Label) this.ccTuesday.Template.FindName("lblDayOfWeek", ccTuesday);
但结果为空
我一直在看这里的讨论:
https://codereview.stackexchange.com/questions/44760/is-there-a-better-way-to-get-a-child
但为了访问一个标签,确实看起来开销很大。
同样,我是新手,所以我不知道我这样做是否正确。也许有更好、更优雅的方法来做到这一点。欢迎提出任何建议。
编辑 1:
下面的答案有效,但是当我尝试在视图和模型之间实现 viewModel class 时,如 link http://www.codeproject.com/Articles/819294/WPF-MVVM-step-by-step-Basics-to-Advance-Level#Level3:-Addingactionsand“INotifyPropertyChanged”接口
标签变回空的。
观点class:
public partial class MainWindow : Window
{
private TableViewModel tableViewModelMonday = null;
private TableViewModel tableViewModelTuesday = null;
public MainWindow()
{
InitializeComponent();
try
{
this.tableViewModelMonday = new TableViewModel("Monday");
this.tableViewModelTuesday = new TableViewModel("Tuesday");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void ccTuesday_Loaded(object sender, RoutedEventArgs e)
{
this.ccTuesday.DataContext = this.tableViewModelTuesday;
}
private void ccMonday_Loaded(object sender, RoutedEventArgs e)
{
this.ccMonday.DataContext = this.tableViewModelMonday;
}
绑定所在的app.xaml:
<Label x:Name="lblDayOfWeek" Style="{StaticResource BasicLabelLeft}" Grid.Row="0" Grid.Column="0" Grid.RowSpan="3" Content="{Binding dayOfWeek}"/>
ViewModel class:
public class TableViewModel : INotifyPropertyChanged
{
private TableModel tableModel = null;
public TableViewModel(string day)
{
tableModel = new TableModel(day);
}
public string lblDayOfWeek
{
get
{
return tableModel.dayOfWeek;
}
set
{
if (tableModel.dayOfWeek != value)
{
tableModel.dayOfWeek = value;
this.OnNotifyPropertyChanged("dayOfWeek");
}
}
}
private void OnNotifyPropertyChanged(string msg)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(msg));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
模型class:
public class TableModel
{
private string _dayOfWeek;
public string dayOfWeek
{
get
{
return this._dayOfWeek;
}
set
{
if (this._dayOfWeek != value)
{
this._dayOfWeek = value;
}
}
}
public TableModel(string day)
{
this._dayOfWeek = day;
}
}
我错过了什么?
您也可以通过 UserControl 实现这种可重用性。无论哪种方式,要获得绑定功能,您都可以定义一个模型类型并将其分配给 ContentControl(或 UserControl)的 DataContext 属性。
首先,在ContentTemplate里面绑定标签:
<Label x:Name="lblDayOfWeek"
Style="{StaticResource BasicLabelLeft}"
Grid.Row="0"
Grid.Column="0"
Grid.RowSpan="3"
Content="{Binding DayOfWeek}"/>
然后定义模型class:
public class Model : INotifyPropertyChanged {
private DayOfWeek dayOfWeek;
public DayOfWeek DayOfWeek {
get {
return this.dayOfWeek;
}
set {
if (this.dayOfWeek != value) {
this.dayOfWeek = value;
this.OnNotifyPropertyChanged("DayOfWeek");
}
}
}
private void OnNotifyPropertyChanged(string name) {
if (this.PropertyChanged != null) {
this.PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
然后您需要创建模型实例并将其分配给 DataContext:
public partial class MainWindow : Window {
private ModelClass model = new ModelClass();
public MainWindow() {
InitializeComponent();
this.customUserControl.DataContext = this.model;
}
private void button_Click(object sender, RoutedEventArgs e) {
this.model.DayOfWeek = DayOfWeek.Sunday;
}
}
现在,只要您更改模型对象的 DayOfWeek 属性,ContentTemplate 中的绑定标签就会更新。
关于动态向 StackPanel 添加项目,您可以考虑使用 ItemsControl class。
只想让您知道,MVVM 模式是用于设计 WPF 应用程序的最常见设计模式。遵循此模式可以让您更好地使用强大的 WPF 功能,例如绑定。
这里是 WPF 新手。我正在尝试构建一个 table ,我想在一周中的每一天重复使用它。所以我把它移到一个控制模板。这是 XAML:
<ControlTemplate x:Key="defaultGridDesign" >
<Grid HorizontalAlignment="Center" Margin="0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="60"/>
<RowDefinition Height="60"/>
</Grid.RowDefinitions>
<Label x:Name="lblDayOfWeek" Style="{StaticResource BasicLabelLeft}" Grid.Row="0" Grid.Column="0" Grid.RowSpan="3" Content="Monday"/>
<Label x:Name="lblEmpty" Style="{StaticResource BasicLabelLeft}" Grid.Row="0" Grid.Column="1"/>
<Label x:Name="lblPlanned" Style="{StaticResource BasicLabelLeft}" Content="Planned" Grid.Row="1" Grid.Column="1"/>
<Label x:Name="lblProduced" Style="{StaticResource BasicLabelLeft}" Content="Produced" Grid.Row="2" Grid.Column="1"/>
<Label x:Name="lblPrevShift" Style="{StaticResource BasicLabelCenter}" Content="Previous Shift" Grid.Row="0" Grid.Column="2" />
<Label x:Name="lblPlannedPrevShift" Style="{StaticResource BasicLabelLeft}" Content="n/a" Grid.Row="1" Grid.Column="2" />
<Label x:Name="lblProducedPrevShift" Style="{StaticResource BasicLabelLeft}" Content="n/a" Grid.Row="2" Grid.Column="2" />
<Label x:Name="lbl1stHr" Style="{StaticResource BasicLabelCenter}" Content="01" Grid.Row="0" Grid.Column="3" />
<Label x:Name="lbl2ndHr" Style="{StaticResource BasicLabelCenter}" Content="02" Grid.Row="0" Grid.Column="4" />
<Label x:Name="lbl3rdHr" Style="{StaticResource BasicLabelCenter}" Content="03" Grid.Row="0" Grid.Column="5" />
<Label x:Name="lbl4thHr" Style="{StaticResource BasicLabelCenter}" Content="04" Grid.Row="0" Grid.Column="6" />
<Label x:Name="lbl5thHr" Style="{StaticResource BasicLabelCenter}" Content="05" Grid.Row="0" Grid.Column="7" />
<Label x:Name="lbl6thHr" Style="{StaticResource BasicLabelCenter}" Content="06" Grid.Row="0" Grid.Column="8" />
<Label x:Name="lbl7thHr" Style="{StaticResource BasicLabelCenter}" Content="07" Grid.Row="0" Grid.Column="9" />
<Label x:Name="lbl8thHr" Style="{StaticResource BasicLabelCenter}" Content="08" Grid.Row="0" Grid.Column="10"/>
<Label x:Name="lblTotal" Style="{StaticResource BasicLabelCenter}" Content="Total" Grid.Row="0" Grid.Column="11"/>
<Label x:Name="lblNextShift" Style="{StaticResource BasicLabelCenter}" Content="Next Shift" Grid.Row="0" Grid.Column="12"/>
<Label x:Name="lblPlannedTotal" Style="{StaticResource BasicLabelLeft}" Content="n/a" Grid.Row="1" Grid.Column="11"/>
<Label x:Name="lblPlannedNextShift" Style="{StaticResource BasicLabelLeft}" Content="n/a" Grid.Row="1" Grid.Column="12"/>
<Label x:Name="lblProducedTotal" Style="{StaticResource BasicLabelLeft}" Content="n/a" Grid.Row="2" Grid.Column="11"/>
<Label x:Name="lblShiftOEE" Style="{StaticResource BasicLabelLeft}" Content="n/a" Grid.Row="2" Grid.Column="12"/>
<StackPanel x:Name="stkPnlPlanned" Grid.Row="1" Grid.Column="3" Grid.ColumnSpan="8" Width="480"/>
<StackPanel x:Name="stkPnlProduced" Grid.Row="2" Grid.Column="3" Grid.ColumnSpan="8" Width="480"/>
</Grid>
</ControlTemplate>
这是我实例化它们的方式:
<StackPanel>
<ContentControl Template="{StaticResource defaultGridDesign}" x:Name="ccTuesday"></ContentControl>
<ContentControl Template="{StaticResource defaultGridDesign}" x:Name="ccWednesday" />
<ContentControl Template="{StaticResource defaultGridDesign}" x:Name="ccThursday" />
<ContentControl Template="{StaticResource defaultGridDesign}" x:Name="ccFriday" />
<ContentControl Template="{StaticResource defaultGridDesign}" x:Name="ccSaturday" />
<ContentControl Template="{StaticResource defaultGridDesign}" x:Name="ccMonday" />
</StackPanel>
现在我碰壁的地方是我想在控件模板中绑定标签。我在网上找到的每个绑定示例都使用了一个基本示例,但我还没有找到一个可以解决这种情况的示例。我基本上想在第一行中设置时间,在第一列中设置日期,但最终我需要根据我从 excel 文件中读取的内容用标签填充堆栈面板。我希望堆栈面板的 binding/filling 完全不同。 table 中的每一个都获得不同的信息。每个小时,我都需要更新它们中的每一个。
我已经试过了,但没有用:
Label test = (Label) this.ccTuesday.Template.FindName("lblDayOfWeek", ccTuesday);
但结果为空
我一直在看这里的讨论: https://codereview.stackexchange.com/questions/44760/is-there-a-better-way-to-get-a-child
但为了访问一个标签,确实看起来开销很大。
同样,我是新手,所以我不知道我这样做是否正确。也许有更好、更优雅的方法来做到这一点。欢迎提出任何建议。
编辑 1:
下面的答案有效,但是当我尝试在视图和模型之间实现 viewModel class 时,如 link http://www.codeproject.com/Articles/819294/WPF-MVVM-step-by-step-Basics-to-Advance-Level#Level3:-Addingactionsand“INotifyPropertyChanged”接口
标签变回空的。
观点class:
public partial class MainWindow : Window
{
private TableViewModel tableViewModelMonday = null;
private TableViewModel tableViewModelTuesday = null;
public MainWindow()
{
InitializeComponent();
try
{
this.tableViewModelMonday = new TableViewModel("Monday");
this.tableViewModelTuesday = new TableViewModel("Tuesday");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void ccTuesday_Loaded(object sender, RoutedEventArgs e)
{
this.ccTuesday.DataContext = this.tableViewModelTuesday;
}
private void ccMonday_Loaded(object sender, RoutedEventArgs e)
{
this.ccMonday.DataContext = this.tableViewModelMonday;
}
绑定所在的app.xaml:
<Label x:Name="lblDayOfWeek" Style="{StaticResource BasicLabelLeft}" Grid.Row="0" Grid.Column="0" Grid.RowSpan="3" Content="{Binding dayOfWeek}"/>
ViewModel class:
public class TableViewModel : INotifyPropertyChanged
{
private TableModel tableModel = null;
public TableViewModel(string day)
{
tableModel = new TableModel(day);
}
public string lblDayOfWeek
{
get
{
return tableModel.dayOfWeek;
}
set
{
if (tableModel.dayOfWeek != value)
{
tableModel.dayOfWeek = value;
this.OnNotifyPropertyChanged("dayOfWeek");
}
}
}
private void OnNotifyPropertyChanged(string msg)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(msg));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
模型class:
public class TableModel
{
private string _dayOfWeek;
public string dayOfWeek
{
get
{
return this._dayOfWeek;
}
set
{
if (this._dayOfWeek != value)
{
this._dayOfWeek = value;
}
}
}
public TableModel(string day)
{
this._dayOfWeek = day;
}
}
我错过了什么?
您也可以通过 UserControl 实现这种可重用性。无论哪种方式,要获得绑定功能,您都可以定义一个模型类型并将其分配给 ContentControl(或 UserControl)的 DataContext 属性。
首先,在ContentTemplate里面绑定标签:
<Label x:Name="lblDayOfWeek"
Style="{StaticResource BasicLabelLeft}"
Grid.Row="0"
Grid.Column="0"
Grid.RowSpan="3"
Content="{Binding DayOfWeek}"/>
然后定义模型class:
public class Model : INotifyPropertyChanged {
private DayOfWeek dayOfWeek;
public DayOfWeek DayOfWeek {
get {
return this.dayOfWeek;
}
set {
if (this.dayOfWeek != value) {
this.dayOfWeek = value;
this.OnNotifyPropertyChanged("DayOfWeek");
}
}
}
private void OnNotifyPropertyChanged(string name) {
if (this.PropertyChanged != null) {
this.PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
然后您需要创建模型实例并将其分配给 DataContext:
public partial class MainWindow : Window {
private ModelClass model = new ModelClass();
public MainWindow() {
InitializeComponent();
this.customUserControl.DataContext = this.model;
}
private void button_Click(object sender, RoutedEventArgs e) {
this.model.DayOfWeek = DayOfWeek.Sunday;
}
}
现在,只要您更改模型对象的 DayOfWeek 属性,ContentTemplate 中的绑定标签就会更新。
关于动态向 StackPanel 添加项目,您可以考虑使用 ItemsControl class。
只想让您知道,MVVM 模式是用于设计 WPF 应用程序的最常见设计模式。遵循此模式可以让您更好地使用强大的 WPF 功能,例如绑定。