我在网格中有一行有5个文本框,其中2个是通过复选框启用的。我想在单击按钮时动态地向网格添加其他行。我添加的eventhandler只会启用第一行中的文本框,但不会启用当前行(2nd)中的文本框。还有另一个事件处理程序处理第一行中的框,这是一个新的。 (顺便说一下,我只编写了第二行的一部分)。不确定我是否应该尝试为复选框创建模板,然后使用绑定到文本框?如果是这样的话,我读到的关于连接绑定的说明是模糊和混乱的。或者我可以直接进行绑定吗?还是?
public partial class Window2 : Window
{
int currentColumn = 0;
int currentRow = 1;
int timesCalled = 1;
public Window2()
{
InitializeComponent();
}
private void AddLevelButton_Click(object sender, RoutedEventArgs e)
{
string level = this.Level.Content.ToString(); //label for the row
string[] splitLevel = level.Split(' ');
int levelNum = int.Parse(splitLevel[1]);
levelNum = timesCalled + 1;
int nextRow = currentRow + 1;
int nextColumn = currentColumn + 1;
Label levelLabel = new Label();
levelLabel.Content = "Level " + levelNum.ToString();
Grid.SetRow(levelLabel, nextRow);
Grid.SetColumn(levelLabel, currentColumn);
FlowGrid.Children.Add(levelLabel);
currentColumn++;
CheckBox antesBox = new CheckBox(); //the checkbox to enable the
antesBox.Name = "AntesBox"; //textbox which follows
antesBox.VerticalAlignment = VerticalAlignment.Bottom;
antesBox.HorizontalAlignment = HorizontalAlignment.Right;
antesBox.FontSize = 16;
antesBox.Width = 20;
antesBox.Height = 20;
antesBox.Checked += AntesBox_Checked1; //eventhandler
Grid.SetRow(antesBox, nextRow);
Grid.SetColumn(antesBox, currentColumn);
FlowGrid.Children.Add(antesBox);
nextColumn = ++currentColumn;
TextBox enterAntes = new TextBox(); //the textbox to be enabled
enterAntes.Name = "EnterAntes";
enterAntes.Margin = new Thickness(5, 0, 5, 0);
enterAntes.FontSize = 16;
enterAntes.FontFamily = new FontFamily("Verdana");
enterAntes.IsEnabled = false;
enterAntes.KeyDown += EnterAntes_KeyDown1; //tested; this works
Grid.SetRow(EnterAntes, nextRow);
Grid.SetColumn(EnterAntes, nextColumn);
FlowGrid.Children.Add(EnterAntes);
nextColumn = ++currentColumn;
}
private void enterAntes_KeyDown1(object sender, KeyEventArgs e)
{
int key = (int)e.Key;
e.Handled = !(key >= 34 && key <= 43 ||
key >= 74 && key <= 83 || key == 2);
}
private void AntesBox_Checked1(object sender, RoutedEventArgs e)
{
EnterAntes.IsEnabled = true;
}
答案 0 :(得分:2)
您需要添加以下代码才能启用文本框。
以下是datagrid的xaml视图。
<DataGrid x:Name="gvTest" AutoGenerateColumns="False" ItemsSource="{Binding}" HorizontalAlignment="Left" Margin="86,204,0,0" VerticalAlignment="Top" Height="132" Width="436">
<DataGrid.Columns>
<DataGridTemplateColumn Header="TextBox 01">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox x:Name="txt01" Width="50" Text="{Binding TxtBox01}"></TextBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="TextBox 02">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox x:Name="txtbox02" Width="50" Text="{Binding TxtBox02}"></TextBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="TextBox 03">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox x:Name="txtbox03" Width="50" Text="{Binding TxtBox03}"></TextBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="TextBox 04">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox x:Name="txtbox04" Width="50" IsEnabled="False" Text="{Binding TxtBox04}" Loaded="txtbox04_Loaded"></TextBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="TextBox 05">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox x:Name="txtbox05" Text="{Binding TxtBox05}" Loaded="txtbox05_Loaded"></TextBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Enable" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="chk01" Checked="chk01_Checked" IsChecked="{Binding IsActive}"></CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
添加以下代码以声明所需文本框的实例并声明可观察集合。
TextBox txt04;
TextBox txt05;
ObservableCollection<TestItem> TestItemList = new ObservableCollection<TestItem>();
将以下代码添加到所需文本框的已加载事件中。
private void txtbox04_Loaded(object sender, RoutedEventArgs e)
{
txt04 = (sender as TextBox);
//txt04.IsEnabled = false;
}
private void txtbox05_Loaded(object sender, RoutedEventArgs e)
{
txt05 = (sender as TextBox);
}
现在,创建一个包含以下代码段的模型类,以便将值绑定到数据网格。
public class TestItem
{
public string TxtBox01 { get; set; }
public string TxtBox02 { get; set; }
public string TxtBox03 { get; set; }
public string TxtBox04 { get; set; }
public string TxtBox05 { get; set; }
public bool IsActive { get; set; }
public TestItem()
{
IsActive = false;
}
}
我使用了一个按钮向数据网格添加新行。将以下代码添加到按钮单击以添加行。
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
TestItemList.Add(new TestItem());
gvTest.ItemsSource = TestItemList;
}
最后,将以下代码添加到复选框选中的事件
CheckBox c = (sender as CheckBox);
if (c.IsChecked==true)
{
txt04.IsEnabled = true;
txt05.IsEnabled = true;
}
希望这可以帮助您满足您的要求。
答案 1 :(得分:1)
冒着使错误方法永久化的风险,在我看来,解决特定需要的最直接方法是修复事件处理程序,使其始终特定于文本框这对应于相关的复选框。通过将事件处理程序订阅移动到局部变量enterAntes
的声明之下,然后在事件处理程序中使用该变量(即,以便通过匿名方法捕获它),可以轻松完成此操作。事件处理程序)。例如:
TextBox enterAntes = new TextBox(); //the textbox to be enabled
antesBox.Checked += (sender, e) => enterAntes.IsEnabled = true;
现在,我说,我全心全意地同意评论员Mark Feldman的观点,他建议您编写的代码不是在WPF中实现目标的正确方法。
我不确定我是否同意这种特征&#34;更难&#34;。这是一个如此负载和主观的术语,在很大程度上取决于你找到的容易或困难。作为WPF的新手,您几乎可以肯定地找到数据绑定和基于声明XAML的编码概念&#34; hard&#34;以及直接的过程代码,例如在您的示例中&#34; easy&#34; (或至少&#34;更容易&#34; :))。
但他绝对正确的是,从长远来看,你会更好地通过做事和#34; WPF方式&#34;。您可能会或可能不会使用更少的代码,但WPF API旨在尽可能地从XAML中使用,并且最低限度地使用代码隐藏(当然不是为了构建UI)。
那么对你的代码来说意味着什么呢?好吧,我絮絮叨叨,这将超出一个好的,简洁的Stack Overflow的范围,让我尝试从头开始重写你的整个代码以适应WPF范例。但我会就如何处理这个问题提出一些建议。
bool
属性(以反映复选框状态)和string
属性(以反映文本框值)。这是你的&#34;型号&#34 ;;即每个类都是一个单独的模型类,同时您可以将整个类集合视为UI的模型。ListBox
,ListView
,DataGrid
或甚至ItemsControl
这样的类(许多面向列表的控件的基类)。将列表控件的来源绑定到您在上一步中创建的模型列表。DataTemplate
(同样,在XAML中)。这将声明列表中单行的UI。您的模板可能如下所示:<!-- Make sure you defined the "local" XML namespace for your project using the
xmlns declaration -->
<DataTemplate DataType="{x:Type local:MyRowModel}">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Text}" IsEnabled={Binding IsEnabled}"/>
<Checkbox Checked="{Binding IsEnabled}"/>
</StackPanel>
</DataTemplate>
DataTemplate
元素中的所有XAML都会在呈现行模型的控件中告诉WPF您希望单行看起来像什么。该控件将为模板定义的列表项设置DataContext
,以便{Binding...}
声明可以直接按名称引用行模型的属性。
该行模型反过来可能如下所示:
class MyRowModel : INotifyPropertyChanged
{
private string _text;
private bool _isEnabled;
public string Text
{
get { return _text; }
set
{
if (_text != value)
{
_text = value;
OnPropertyChanged();
}
}
}
public bool IsEnabled
{
get { return _isEnabled; }
set
{
if (_isEnabled != value)
{
_isEnabled = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
备注:强>
StackPanel
作为数据模板。如果您想要在列中排列的内容,您可能希望使用Grid
并使用SharedSizeGroup
声明其列。DataGrid
,假设它的默认值是可以接受的,它可以简单而自动地处理这种类型的布局。INotifyPropertyChanged
。还有一个接口INotifyCollectionChanged
;通常你不必自己实现这个,因为WPF的类型ObservableCollection<T>
可以像List<T>
一样使用,来存储数据列表但是有一种方法可以通知更改向WPF汇报。
我知道要立刻采取这一切是很重要的。不幸的是,尝试在一个答案中解释所有你需要学习的东西是不可行的。坦率地说,即使是上述内容也在限制Stack Overflow答案范围内的限制。但我希望我能够找到正确的亮点,让您了解WPF文档的正确部分,并了解WPF API的基本原理。