行。删除所有代码并重新开始。
如果您正在使用 WPF,那么您确实需要具备WPF 心态
作为一般规则,您几乎从不在 WPF 的过程代码中创建或操作 UI 元素。这就是 XAML 的用途。
这是在 WPF 中执行您所要求的正确方法(在一个完整的工作示例中):
<Window x:Class="MiscSamples.ItemsControlSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
Title="ItemsControlSample" Height="300" Width="300">
<DockPanel>
<Button Content="Add New Row" Command="{Binding AddNewRowCommand}"
DockPanel.Dock="Bottom"/>
<ItemsControl ItemsSource="{Binding Data}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black" Background="Gainsboro" BorderThickness="1" Margin="2">
<!-- This is the Inner Grid for each element, which is represented in Brown color in your picture -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width=".2*"/>
<ColumnDefinition Width=".2*"/>
</Grid.ColumnDefinitions>
<Label Content="{Binding Label1Text}"
Margin="2"/>
<Button Content="Button1"
Command="{Binding DataContext.Command1, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}"
Grid.Column="1" Margin="2"/>
<Button Content="Button2"
Command="{Binding DataContext.Command2, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}"
Grid.Column="2" Margin="2"/>
<dxe:TextEdit Text="{Binding Text}"
Grid.Row="1" Grid.ColumnSpan="3"
Margin="2"/>
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer CanContentScroll="True">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DockPanel>
</Window>
代码背后:
public partial class ItemsControlSample : Window
{
public ItemsControlSample()
{
InitializeComponent();
DataContext = new ItemsControlSampleViewModel();
}
}
视图模型:
public class ItemsControlSampleViewModel
{
public ObservableCollection<ItemsControlSampleData> Data { get; set; }
public Command AddNewRowCommand { get; set; }
public Command<ItemsControlSampleData> Command1 { get; set; }
public Command<ItemsControlSampleData> Command2 { get; set; }
public ItemsControlSampleViewModel()
{
var sampledata = Enumerable.Range(0, 10)
.Select(x => new ItemsControlSampleData()
{
Label1Text = "Label1 " + x.ToString(),
Text = "Text" + x.ToString()
});
Data = new ObservableCollection<ItemsControlSampleData>(sampledata);
AddNewRowCommand = new Command(AddNewRow);
Command1 = new Command<ItemsControlSampleData>(ExecuteCommand1);
Command2 = new Command<ItemsControlSampleData>(ExecuteCommand2);
}
private void AddNewRow()
{
Data.Add(new ItemsControlSampleData() {Label1Text = "Label 1 - New Row", Text = "New Row Text"});
}
private void ExecuteCommand1(ItemsControlSampleData data)
{
MessageBox.Show("Command1 - " + data.Label1Text);
}
private void ExecuteCommand2(ItemsControlSampleData data)
{
MessageBox.Show("Command2 - " + data.Label1Text);
}
}
数据项:
public class ItemsControlSampleData
{
public string Label1Text { get; set; }
public string Text { get; set; }
}
助手类:
public class Command : ICommand
{
public Action Action { get; set; }
public string DisplayName { get; set; }
public void Execute(object parameter)
{
if (Action != null)
Action();
}
public bool CanExecute(object parameter)
{
return IsEnabled;
}
private bool _isEnabled = true;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
}
public event EventHandler CanExecuteChanged;
public Command(Action action)
{
Action = action;
}
}
public class Command<T>: ICommand
{
public Action<T> Action { get; set; }
public void Execute(object parameter)
{
if (Action != null && parameter is T)
Action((T)parameter);
}
public bool CanExecute(object parameter)
{
return IsEnabled;
}
private bool _isEnabled = true;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
}
public event EventHandler CanExecuteChanged;
public Command(Action<T> action)
{
Action = action;
}
}
结果:
- 请注意,我不是在过程代码中处理 UI,而是使用DataBinding和简单、简单的属性。这就是您在 WPF 中编程的方式。这就是 WPF 的心态。
- 我正在使用 XAML 中定义的ItemsControl和DataTemplate让 WPF 为我的每个数据项创建 UI。
- 还要注意我的代码除了公开数据和定义可重用的命令之外什么都不做,这些命令用作对用户操作(如按钮单击)的抽象。通过这种方式,您可以专注于编写业务逻辑,而不是为如何使 UI 工作而苦苦挣扎。
- 每个项目内的按钮都使用相对源绑定绑定到命令,以便在可视树中向上导航并找到 ItemsControl 的 DataContext,其中实际定义了命令。
- 当您需要添加新项目时,您只需向
ObservableCollection
包含您的数据的新项目添加一个新项目,WPF 会自动创建绑定到该项目的新 UI 元素。
- 尽管这看起来像是“代码过多”,但我在此处发布的大部分代码都具有高度可重用性,并且可以在通用
ViewModel<T>
中实现,然后可重用于任何类型的数据项。Command
并且Command<T>
也是可在任何 MVVM 框架(如Prism、MVVM Light或Caliburn.Micro )中找到的一次性可重用类。
- 这种方法在 WPF 中非常受欢迎,因为它可以在 UI 和业务逻辑之间实现大量的可伸缩性和独立性,并且还可以实现 ViewModel 的可测试性。
- 我建议您阅读帖子中链接的所有材料,最重要的是 Rachel 的 WPF Mentality 和相关博客文章。如果您需要进一步的帮助,请告诉我。
- WPF 摇滚。只需将我的代码复制并粘贴到 a 中
File -> New Project -> WPF Application
,然后自己查看结果。