在 WPF 中动态添加网格和控件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1253744/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 20:49:24  来源:igfitidea点击:

Adding Grid and Controls dynamically in WPF

wpfxamltemplateswpf-controls

提问by Sauron

I am now doing an application that shows the HDD usage in the system. For that I want to generate the grid and the controls (like progress bar and labels) dynamically to show the usage. Is there any XAML template available for this purpose?

我现在正在做一个显示系统中硬盘使用情况的应用程序。为此,我想动态生成网格和控件(如进度条和标签)以显示用法。是否有任何 XAML 模板可用于此目的?

回答by Sauron

I use the folowing code to generate controls dynamically in my code

我使用以下代码在我的代码中动态生成控件

Label[] drivesLabel;
Label[] percentageLabel;
ProgressBar[] drivesProgress;
int drivesCount = 0;

private void DrawControls()
{
    try
    {
        // Getting drive list.
        List<DriveInfo> driveList = GetHardDiskDrives();
        drivesCount = driveList.Count;

        // Initializing new Grid.
        Grid drivesGrid = new Grid();
        drivesGrid.Children.Clear();
        DrivesBorder.Child = drivesGrid;

        // Adding Rows and Colums to Grid.
        RowDefinition[] rows = new RowDefinition[2*drivesCount + 1];
        ColumnDefinition[] columns = new ColumnDefinition[6];

        // Draw Rows.
        for (int i = 0; i < 2*drivesCount + 1; i++)
        {
            rows[i] = new RowDefinition();
            drivesGrid.RowDefinitions.Add(rows[i]);

            // Setting Row height.
            rows[i].Height = (0 == i % 2) ? new GridLength( 5 ): new GridLength( 25 );
        }
        // Draw Columns.
        for (int i = 0; i < 6; i++)
        {
            columns[i] = new ColumnDefinition();
            drivesGrid.ColumnDefinitions.Add(columns[i]);
            if (i % 2 == 0)
            {
                // Setting column width.
                columns[i].Width = new GridLength(5);
            }
        }

        // Setting column width.
        columns[1].Width = new GridLength(60);
        columns[3].Width = new GridLength(180);
        columns[5].Width = new GridLength(60);

        // Draw Labels to show drive letters.
        drivesLabel = new Label[drivesCount];

        // Draw Progress bar to show drive usage.
        drivesProgress = new ProgressBar[drivesCount];

        // Draw Labels to show drive usage.
        percentageLabel = new Label[drivesCount];

        // Adding Labels and Progressbars to Grid.
        for (int i = 0, j = 1; i < drivesCount; i++, j++)
        {
            // Initialize Labels to show drives.
            drivesLabel[i] = new Label();
            drivesLabel[i].Content = driveList[i].Name;
            drivesLabel[i].Foreground = Brushes.Navy;
            Grid.SetRow(drivesLabel[i], i + j);
            Grid.SetColumn(drivesLabel[i], 1);
            drivesGrid.Children.Add(drivesLabel[i]);

            // Initialize ProgressBar to show usage.
            drivesProgress[i] = new ProgressBar();
            drivesProgress[i].FlowDirection = FlowDirection.LeftToRight;
            drivesProgress[i].HorizontalAlignment = HorizontalAlignment.Center;
            drivesProgress[i].VerticalAlignment = VerticalAlignment.Center;
            drivesProgress[i].Orientation= Orientation.Horizontal;
            drivesProgress[i].Value = 0;
            drivesProgress[i].Maximum = 100;
            drivesProgress[i].Width = 180;
            drivesProgress[i].Height = 18;
            Grid.SetRow(drivesProgress[i], i + j);
            Grid.SetColumn(drivesProgress[i], 3);
            drivesGrid.Children.Add(drivesProgress[i]);

            // Initialize Labels  to show usage in percentage.
            percentageLabel[i] = new Label();
            percentageLabel[i].Content = "0 %";
            Grid.SetRow(percentageLabel[i], i + j);
            Grid.SetColumn(percentageLabel[i], 5);
            drivesGrid.Children.Add(percentageLabel[i]);

            // Setting window height.
            SetWindowHeight(30);
        }
    }
    catch(Exception Ex) {}
}

The functions GetHardDiskDrives() and SetWindowHeight() are user defined functions. The jpb is to get harddrives and Set the window height according to the new controls added.

函数 GetHardDiskDrives() 和 SetWindowHeight() 是用户定义的函数。jpb 是获取硬盘驱动器并根据添加的新控件设置窗口高度。

回答by name

I found the other answer confusing because of the inline-comments... adding a columnDEFINITION (for example) "draws" absolutely NOTHING - that's very misleading for beginners.

由于内联注释,我发现另一个答案令人困惑......添加一个 columnDEFINITION(例如)“绘制”绝对没有 - 这对初学者来说非常具有误导性。

Also : the rows are selected repeatedly even though they have already been selected ... that just adds useless overhead. This will make your app really really slow if you're using several hundred rows.

另外:即使已经选择了行,也会重复选择它们……这只会增加无用的开销。如果您使用数百行,这将使您的应用程序变得非常缓慢。

Same with setting the WindowHeight.

与设置 WindowHeight 相同。

Here's a (somewhat) more efficient solution for dynamic row&column-management in VB.NET: (use Dispatcher.BeginInvoke() instead of Invoke() if you want to switch to asynchronous processing)

这是 VB.NET 中动态行和列管理的(有点)更有效的解决方案:(如果要切换到异步处理,请使用 Dispatcher.BeginInvoke() 而不是 Invoke())

Private Delegate Sub MyDelegate3(ByVal iByte As Byte)
Private Delegate Function MyDelegate4() As Byte

Public Property GridColumns As Byte
        Get
            Dim del As New MyDelegate4(AddressOf GetColumns)
            Return grid.Dispatcher.Invoke(del)
        End Get

        Set(ByVal value As Byte)
            Dim del As MyDelegate3
            If GridColumns > 0 Then
                Dim diff As SByte = GridColumns - value
                If diff > 0 Then    'Spalten abziehen
                    del = New MyDelegate3(AddressOf RemColDefs)
                    grid.Dispatcher.Invoke(del, diff)
                Else                'Spalten hinzufügen
                    del = New MyDelegate3(AddressOf AddColDefs)
                    grid.Dispatcher.Invoke(del, Math.Abs(diff))
                End If
            Else
                del = New MyDelegate3(AddressOf AddColDefs)
                grid.Dispatcher.Invoke(del, value)
            End If
        End Set
    End Property

    Public Property GridRows As Byte
        Get
            Dim del As New MyDelegate4(AddressOf GetRows)
            Return grid.Dispatcher.Invoke(del)
        End Get
        Set(value As Byte)
            Dim del As MyDelegate3
            If GridRows > 0 Then
                Dim diff As SByte = GridRows - value
                If diff > 0 Then    'Zeilen abziehen
                    del = New MyDelegate3(AddressOf RemRowDefs)
                    grid.Dispatcher.Invoke(del, diff)
                Else                'Spalten hinzufügen
                    del = New MyDelegate3(AddressOf AddRowDefs)
                    grid.Dispatcher.Invoke(del, Math.Abs(diff))
                End If
            Else
                del = New MyDelegate3(AddressOf AddRowDefs)
                grid.Dispatcher.Invoke(del, value)
            End If
        End Set
    End Property

    Private Function GetRows() As Byte
        Return grid.RowDefinitions.Count
    End Function
    Private Function GetColumns() As Byte
        Return grid.ColumnDefinitions.Count
    End Function

    Private Sub AddRowDefs(ByVal iRows As Byte)
        For r As Byte = 1 To iRows
            Dim rowDef As New RowDefinition
            rowDef.Height = GridLength.Auto
            grid.RowDefinitions.Add(rowDef)
        Next         
    End Sub
    Private Sub RemRowDefs(ByVal iRows As Byte)
        For r As Byte = 1 To iRows
            If grid.RowDefinitions.Count > 0 Then
                grid.RowDefinitions.Remove(grid.RowDefinitions(0))
            End If
        Next            
    End Sub

    Private Sub AddColDefs(ByVal iCols As Byte)
        For r As Byte = 1 To iCols
            Dim colDef As New ColumnDefinition
            colDef.Width = GridLength.Auto
            grid.ColumnDefinitions.Add(colDef)
        Next            
    End Sub
    Private Sub RemColDefs(ByVal iCols As Byte)
        For r As Byte = 1 To iCols
            If grid.ColumnDefinitions.Count > 0 Then
                grid.ColumnDefinitions.Remove(grid.ColumnDefinitions(0))
            End If
        Next            
    End Sub