在运行时通过foreach-command向网格添加多个控件(C#WPF)

1 c# wpf grid foreach

亲爱的开发者,这是美好的一天 我的名字是丹尼.

这是我在Stackoverflow上发表的第一篇文章......尽管我对.NET Framework很新.我通过几个论坛进行了相当彻底的搜索,但显然是我的鼻子.

我的问题是:我正在编写一段脚本,读出目录中存在多少.txt文件.

然后它创建了GroupBoxes(每个网格)的数量,因为.txt是通过'foreach'命令.在同一个foreach-command中,我使用:Grid.Children.Add(control).每次迭代时,有2个控件要添加到生成的网格中.

问题:它没有那样做......好吧.它只进行了2次迭代,无论有多少.txt.在输出对话框中,它说:A first chance exception of type 'System.ArgumentException' occurred in PresentationCore.dll.

如果我的解释不像我想的那样清楚,请按照我的脚本,并感谢阅读:

using System;
using System.IO;
using System.Linq;
using System.Windows;
using System.Threading;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Threading;
using System.Windows.Controls.Primitives;

namespace Notes
{
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }


    // Create Objects
    public TextBox tBox = new TextBox();
    public Label fLabel = new Label();
    public GroupBox group = new GroupBox();
    public Grid groupGrid = new Grid();


    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        // Global Variables
        int Increment = 1;
        string Dir = "DIRECTORY_HERE";
        int leftMargin = 10;
        int betweenMargin = 10;

        // GroupBox Initials
        group.Height = this.Height - 125;
        group.Margin = new Thickness(0, 75, 0, 0);
        group.HorizontalAlignment = HorizontalAlignment.Left;
        group.VerticalAlignment = VerticalAlignment.Top;

        // Grid Initials
        groupGrid.Width = leftMargin;
        groupGrid.Height = group.Height;
        groupGrid.Margin = new Thickness(0, 0, 0, 0);
        groupGrid.HorizontalAlignment = HorizontalAlignment.Left;
        groupGrid.VerticalAlignment = VerticalAlignment.Top;

        // Label Initials
        fLabel.Width = 260;
        fLabel.Height = 28;
        fLabel.HorizontalAlignment = HorizontalAlignment.Left;
        fLabel.VerticalAlignment = VerticalAlignment.Top;
        fLabel.Margin = new Thickness(0, 0, 0, 0);

        // TextBox Intitials
        tBox.Width = 100;
        tBox.Height = groupGrid.Height;
        tBox.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
        tBox.HorizontalAlignment = HorizontalAlignment.Left;
        tBox.VerticalAlignment = VerticalAlignment.Top;
        tBox.Foreground = new SolidColorBrush(Colors.DarkCyan);
        tBox.Background = new SolidColorBrush(Colors.Red);
        tBox.TextWrapping = TextWrapping.NoWrap;



        // Get paths of all files within given directory.
        string[] Notes = Directory.GetFiles(Dir, "*.*", SearchOption.TopDirectoryOnly).ToArray();

        foreach (string Note in Notes)
        {
            Console.WriteLine("NOTE: " + Note);

            // Text settings
            FileInfo fi = new FileInfo(Note);
            TextReader tr = new StreamReader(fi.ToString());
            tBox.Name = "tBox" + Increment.ToString();
            tBox.Text = tr.ReadToEnd();
            tBox.Margin = new Thickness(betweenMargin, 0, 0, 0);

            // FileLabel settings
            fLabel.Name = "fLabel" + Increment.ToString();

            // GroupGrid settings
            groupGrid.Name = "groupGrid" + Increment.ToString();
            groupGrid.Children.Add(tBox);               //error
            groupGrid.Children.Add(fLabel);             //error

            // group settings
            group.Width = leftMargin + (tBox.Width * Increment) + (betweenMargin * Increment);
            group.Content = groupGrid;

            // Increment
            Increment++;
        }


        NotesDoc.Children.Add(group);
    }
Run Code Online (Sandbox Code Playgroud)

小智 5

您正在尝试像编写Windows窗体应用程序一样编写WPF应用程序.相信我,如果您真正学习了一些WPF开发模式(例如MVVM),那么您可以更轻松地实现目标.

例如,使用ObservableCollection可以很容易地完成此操作(保存所有这些)(不确定如何执行此操作)FileInfo实例(每个文件一个).

然后,您可以绑定一个ItemsControl中的ItemsSource属性来此集合.现在,每当您向ObservableCollection添加新的FileInfo实例时,ItemsControl将添加一个新行并将该行绑定到该实例.

当然,每行的默认模板只是在每个实例上调用.ToString(),因此您将获得包含"System.IO.FileInfo"的一堆行.要显示有关每个FileInfo的信息,可以将DataTemplate添加到ItemsSource.ItemTemplate并添加绑定到FileInfo的公共属性的控件.

在开发WPF应用程序时,了解其中一些基本模式非常重要.尝试以您正在尝试的方式从代码隐藏中与UI进行交互是非常难做的.WPF应用程序的许多UI模式都经过优化,可用于XAML; 尝试与代码隐藏中的这些(例如附加属性)进行交互可能会非常混乱和违反直觉.


这是我更新的一个简单的MVVM示例.要使用它,请创建一个名为SimpleMVVM的新解决方案(3.5或更高版本).在项目的根目录中创建一个名为ViewModel的新类,并将以下代码添加到该文件中:

/// <summary>
/// A simple ViewModel to demonstrate MVVM
/// </summary>
public sealed class ViewModel : DependencyObject, IDataErrorInfo
{
    #region Properties
    #region DirectoryName
    /// <summary>
    /// The <see cref="DependencyProperty"/> for <see cref="DirectoryName"/>.
    /// </summary>
    public static readonly DependencyProperty DirectoryNameProperty =
        DependencyProperty.Register(
            DirectoryNameName,
            typeof(string),
            typeof(ViewModel),
            new UIPropertyMetadata(null));

    /// <summary>
    /// The name of the <see cref="DirectoryName"/> <see cref="DependencyProperty"/>.
    /// </summary>
    public const string DirectoryNameName = "DirectoryName";

    /// <summary>
    /// 
    /// </summary>
    public object DirectoryName
    {
        get { return (object)GetValue(DirectoryNameProperty); }
        set { SetValue(DirectoryNameProperty, value); }
    }
    #endregion

    #region SelectedFile
    /// <summary>
    /// The <see cref="DependencyProperty"/> for <see cref="SelectedFile"/>.
    /// </summary>
    public static readonly DependencyProperty SelectedFileProperty =
        DependencyProperty.Register(
            SelectedFileName,
            typeof(FileInfo),
            typeof(ViewModel),
            new UIPropertyMetadata(null));

    /// <summary>
    /// The name of the <see cref="SelectedFile"/> <see cref="DependencyProperty"/>.
    /// </summary>
    public const string SelectedFileName = "SelectedFile";

    /// <summary>
    /// 
    /// </summary>
    public FileInfo SelectedFile
    {
        get { return (FileInfo)GetValue(SelectedFileProperty); }
        set { SetValue(SelectedFileProperty, value); }
    }
    #endregion


    /// <summary>
    /// The files found under <see cref="DirectoryName"/>.
    /// </summary>
    public ObservableCollection<FileInfo> Files { get; private set; }

    /// <summary>
    /// Holds the last filename error for IDataErrorInfo
    /// </summary>
    private string _lastDirectoryNameError = null;
    #endregion

    #region ctor
    /// <summary>
    /// Initializes a new instance of the <see cref="ViewModel"/> class.
    /// </summary>
    public ViewModel()
    {
        Files = new ObservableCollection<FileInfo>();
    }
    #endregion

    #region methods
    /// <summary>
    /// Invoked whenever the effective value of any dependency property on this <see cref="T:System.Windows.DependencyObject"/> has been updated. The specific dependency property that changed is reported in the event data.
    /// </summary>
    /// <param name="e">Event data that will contain the dependency property identifier of interest, the property metadata for the type, and old and new values.</param>
    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
        base.OnPropertyChanged(e);
        if (e.Property == DirectoryNameProperty)
            UpdateFiles(e.OldValue as string, e.NewValue as string);
    }

    /// <summary>
    /// Updates <see cref="Files"/> when <see cref="DirectoryName"/> changes.
    /// </summary>
    /// <param name="oldDirectoryName">The old value of <see cref="DirectoryName"/></param>
    /// <param name="newDirectoryName">The new value of <see cref="DirectoryName"/></param>
    private void UpdateFiles(string oldDirectoryName, string newDirectoryName)
    {
        if (string.IsNullOrWhiteSpace(newDirectoryName))
        {
            Files.Clear();
            return;
        }
        if (!string.IsNullOrEmpty(oldDirectoryName) &&
            oldDirectoryName.Equals(newDirectoryName, StringComparison.OrdinalIgnoreCase))
            return;

        try
        {
            var di = new DirectoryInfo(Directory.Exists(newDirectoryName) ? newDirectoryName : Path.GetDirectoryName(newDirectoryName));
            // dirty hack
            if (di.ToString().Equals(".", StringComparison.OrdinalIgnoreCase))
            {
                _lastDirectoryNameError = "Not a valid directory name.";
                return;
            }
            Files.Clear();
            foreach (var file in di.GetFiles())
                Files.Add(file);
            _lastDirectoryNameError = null;
        }
        catch (Exception ioe)
        {
            _lastDirectoryNameError = ioe.Message;
        }
    }
    #endregion

    #region IDataErrorInfo
    /// <summary>
    /// Gets an error message indicating what is wrong with this object.
    /// </summary>
    /// <returns>An error message indicating what is wrong with this object. The default is an empty string ("").</returns>
    string IDataErrorInfo.Error
    {
        get
        {
            return _lastDirectoryNameError;
        }
    }

    /// <summary>
    /// Gets the error message for the property with the given name.
    /// </summary>
    /// <returns>The error message for the property. The default is an empty string ("").</returns>
    string IDataErrorInfo.this[string columnName]
    {
        get
        {
            if (columnName.Equals(DirectoryNameName, StringComparison.OrdinalIgnoreCase))
                return _lastDirectoryNameError;
            return null;
        }
    }
    #endregion
}
Run Code Online (Sandbox Code Playgroud)

接下来,打开MainWindow.xaml并使用以下内容替换xaml:

<Window
    x:Class="SimpleMVVM.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:t="clr-namespace:SimpleMVVM"
    Title="MainWindow"
    Height="350"
    Width="525">
    <Window.DataContext>
        <t:ViewModel />
    </Window.DataContext>
    <Window.Resources>
        <Style
            x:Key="alternatingListViewItemStyle"
            TargetType="{x:Type ListViewItem}">
            <Style.Triggers>
                <Trigger
                    Property="ItemsControl.AlternationIndex"
                    Value="1">
                    <Setter
                        Property="Background"
                        Value="LightGray"></Setter>
                </Trigger>
                <Trigger
                    Property="ItemsControl.AlternationIndex"
                    Value="2">
                    <Setter
                        Property="Background"
                        Value="White"></Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition
                Height="auto" />
            <RowDefinition />
            <RowDefinition
                Height="auto" />
        </Grid.RowDefinitions>
        <TextBox
            Margin="4"
            Text="{Binding DirectoryName, ValidatesOnDataErrors=True, ValidatesOnExceptions=True,UpdateSourceTrigger=PropertyChanged}">
            <TextBox.Style>
                <Style
                    TargetType="TextBox">
                    <Setter
                        Property="ToolTip"
                        Value="Please enter a directory name" />
                    <Style.Triggers>
                        <Trigger
                            Property="Validation.HasError"
                            Value="true">
                            <Setter
                                Property="ToolTip"
                                Value="{Binding (Validation.Errors)[0].ErrorContent, RelativeSource={x:Static RelativeSource.Self}}" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </TextBox.Style>
        </TextBox>
        <ListView
            Margin="4"
            Grid.Row="1"
            AlternationCount="2"
            ItemsSource="{Binding Files}"
            ItemContainerStyle="{StaticResource alternatingListViewItemStyle}"
            SelectedItem="{Binding SelectedFile}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition />
                            <RowDefinition />
                            <RowDefinition />
                            <RowDefinition />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition
                                Width="100" />
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <Label
                            Grid.Row="0">Name</Label>
                        <Label
                            Grid.Row="1">Size</Label>
                        <Label
                            Grid.Row="2">Read Only</Label>
                        <Label
                            Grid.Row="3">Type</Label>
                        <TextBlock
                            Grid.Row="0"
                            Grid.Column="1"
                            Text="{Binding Name}" />
                        <TextBlock
                            Grid.Row="1"
                            Grid.Column="1"
                            Text="{Binding Length}" />
                        <CheckBox
                            Grid.Row="2"
                            Grid.Column="1"
                            IsChecked="{Binding IsReadOnly}"
                            IsEnabled="False" />
                        <TextBlock
                            Grid.Row="3"
                            Grid.Column="1"
                            Text="{Binding Extension}" />
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <StatusBar
            Grid.Row="2">
            <StatusBarItem
                Content="{Binding SelectedFile.FullName, StringFormat='Selected: {0}', FallbackValue='Please enter a directory and select a file.'}" />
        </StatusBar>
    </Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)

(请原谅每个人的代码转储!)编译,修复错误并运行它.