【问题标题】:Populate WPF DataGrid dynamically动态填充 WPF DataGrid
【发布时间】:2011-09-24 14:28:01
【问题描述】:

我的程序需要通过串行连接从火警面板获取输入,并根据它填充一个列表。当面板上报新设备时,解析语句并将设备添加到设备列表中。

我的程序的那部分工作正常而且花花公子。现在的问题是向用户显示火警设备列表。

我希望使用 DataGrid 来执行此操作(除非有更好的方法?),但我无法在 WPF DataGrids 上找到很多与我相关的有用文档。那里的大部分内容似乎都在显示来自数据库的数据。但是,我的每次面板吐出新的设备描述并附加我的程序中的设备列表时都需要更新。

我知道我可以将 AutoGenerateColumns 设置为 true 并最初显示我的列表就好了。但是,我想自定义列标题。此外,添加列表时这不会更新,所以我不确定如何“刷新”它。

当 AutoGenerateColumns 为 false 时,我没有显示任何数据。当程序运行时,它会显示与列表中的项目数相对应的正确行数,但没有数据。想知道如何/是否需要将每列与其相应的设备数据成员链接?

最后,如何通过重新调整大小来格式化 DataGrid 以使其看起来更漂亮?我可以设置列宽等等,但我想要的是一些列的宽度是固定的,中间的列要扩展以填充剩余的可用区域。

这是我第一次尝试 WPF。任何帮助将不胜感激!

【问题讨论】:

    标签: c# wpf dynamic datagrid formatting


    【解决方案1】:

    我个人不太喜欢 DataGrid。是的,它们更容易绑定,并且它们提供内置的调整大小和排序选项,但它们不像 ItemsControl 那样灵活,并且在您的对象上具有良好的 DataTemplating。让我自己解释一下。

    我倾向于使用 ObservableCollection 填充我的 ItemsControl。然后,我使用 DataTemplate 来告诉我的 ItemsControl 如何显示我的自定义项目。

    如果您使用 MVVM,您的 CustomObjects 可以是 Modeles 对象。 如果您的列表绑定到 ObservableCollection,添加和删除的项目将动态显示在您的列表中,我相信您正在尝试这样做。 对于列大小,您可以将 Grid 指定为 GridColumns 宽度,以固定 Width 用于某些列,将 * 用于其他列,以便它们填充剩余空间。

    这是 GridView 的替代方案 我在 ItemControl 周围使用 ScrollViewer,因此如果 ItemsControl 太大,您可以滚动它。 ItemsControl 的 ItemSource 绑定到 FireAlarms 的 ObservableCollection。 ItemsControl 中的 WrapPanel 将包含每个 DataTemplate。它的 Width 绑定到他的父级(或祖先,如果你愿意的话),它是一个 ItemsControl

    <ScrollViewer
        Grid.Row="x"
        Grid.Column="y"
        VerticalScrollBarVisibility="Auto"
        Margin="5">
    
        <ItemsControl
        BorderBrush="DarkBlue"
        BorderThickness="2"
        ItemsSource="{Binding Path=FireAlarms}"
        ItemTemplate="{StaticResource FireAlarmsTemplate}"
        >
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel 
                            Orientation="Horizontal"
                            Width="{Binding RelativeSource=
                                {RelativeSource FindAncestor,
                                AncestorType={x:Type ItemsControl}},
                                Path=ActualWidth}"
                            >
                    </WrapPanel>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </ScrollViewer>
    

    好的,那么您需要一个 DataTemplate。您可以将 DataTemplate 放在 Windows 的资源或 DataDictionnary 中。假设你有一堂课:

    FireAlarm
    {
        Public String AlarmInfo1;
        Public String AlarmInfo2;
        Public String AlarmInfo3;
    }
    

    这可能是一个不错的 DataTemplate 开头:

    <DataTemplate x:Key="FireAlarms">
        <Border 
            BorderBrush="SteelBlue" 
            Background="LightBlue" 
            BorderThickness="2" 
            Margin="10" 
            Padding="10">
            <StackPanel 
                Orientation="Vertical"
                >
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition></ColumnDefinition>
                        <ColumnDefinition Width="5"></ColumnDefinition>
                        <ColumnDefinition></ColumnDefinition>
                    </Grid.ColumnDefinitions>
    
    
                    <Label 
                        Grid.ColumnSpan="3"
                        Grid.Row="0"
                        Content="{Binding Path=AlarmName}"
                        Margin="5,-5,5,10"
                        FontWeight="Bold"
                        FontSize="16"
                        HorizontalContentAlignment="Center"
                        HorizontalAlignment="Center">
                    </Label>
    
                    <TextBlock  
                        Text="Alarm information 1" Grid.Row="1" Grid.Column="0" />
                    <TextBox 
                        Text="{Binding Path=AlarmInfo1}"
                        Grid.Column="2"
                        Grid.Row="1"
                        >
                    </TextBox>
    
                    <TextBlock 
                        Text="Alarm information 2" Grid.Row="2" Grid.Column="0" />
                    <TextBox 
                        Text="{Binding Path=AlarmInfo2}"
                        Grid.Column="2"
                        Grid.Row="2"
                        >
                    </TextBox>
    
                    <TextBlock  
                        Text="Alarm information 3" Grid.Row="3" Grid.Column="0" />
                    <TextBox 
                        Text="{Binding Path=AlarmInfo3}"
                        Grid.Column="2"
                        Grid.Row="3"
                        >
                    </TextBox>
                </Grid>
            </StackPanel>
        </Border>
    </DataTemplate>
    

    好的,我希望这对您有用。我的模板将为每个警报生成 1 个方块。如果您希望将它放在像 GridView 这样的表格中,您可以使用垂直方向的堆栈面板对其进行修改,并使用具有可变列宽的网格 // 不变的列宽,但是由于您要求任何有用的东西,我很难告诉您一些有趣的工作!

    享受吧!

    【讨论】:

    • WPF 中的一切似乎都比应有的复杂程度至少高出 10 倍。
    【解决方案2】:

    前段时间我写了一个帖子Create DataGrid in WPF using code看看它,它将帮助您在像您这样的动态场景中创建数据网格

    【讨论】:

      【解决方案3】:

      如果您是动态网格(意味着在设计时列的数量和设计是未知的),我会使用绑定的代码隐藏来实现。我通常使用 MVVM 模式(如果你不熟悉这个,我真的建议你阅读它,因为它是使用 WPF 时的模式)。

      1) 当然,您必须将自动生成列设置为 false,并为网格命名(此处为 myDataGrid)

      GridViewDataColumn newColumn= new GridViewDataColumn();
      myDataGrid.Columns.Add(newColumn)
      

      这会将列添加到您的网格中。现在该列将为空。现在取决于您的数据如何填充数据。如果您绑定到项目的已知属性,请执行以下操作:

       newColumn.Binding = new Binding("knownPropertyName");
      

      但在大多数情况下,您不知道属性名称并绑定到集合中的元素。 然后它想要更多:

       myDoubleCollection.Add(someDoubleValue); //do this for each item in the itemssource of the grid
         int index=myDoubleCollection.Count-1;
         newColumn.Binding = new Binding(string.Format("myDoubleCollection[{0}]",index));
      

      所以这也有效。 要记住的另一件事是删除列。这需要一些额外的工作。

      【讨论】:

        【解决方案4】:

        很多问题合二为一!我建议你在提问之前做更多的背景调查。我建议您阅读我不久前写的关于 WPF DataGrid 的 codeproject 文章:

        http://www.codeproject.com/KB/WPF/WPFDataGridExamples.aspx

        它将为您解答大部分问题!

        【讨论】:

          【解决方案5】:

          看看MVVM 模式,它会对您创建这个应用程序有很大帮助。

          您想要的是 ViewModel 中的 ObservableCollection。您将数据网格的 ItemsSource 属性绑定到此集合。然后让您的列绑定到各种属性以显示它们。每当此 ObservableCollection 附加了一个项目时,您的前端应该会自动更新。

          要让列自动调整大小,请设置 Width="*"。

          这是一个带有 MVVM 的数据网格示例

          <DataGrid ItemsSource="{Binding FireAlarmCollection}" SelectedItem="{Binding SelectedFireAlarm, Mode=TwoWay}" AutoGenerateColumns="True" CanUserSortColumns="True" HorizontalScrollBarVisibility="Visible" CanUserResizeColumns="True">
          </DataGrid>
          

          随着您继续努力,为每个问题发布单独的问题。

          【讨论】:

            猜你喜欢
            • 2012-11-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-03-01
            • 1970-01-01
            相关资源
            最近更新 更多