需要一个非常定制的大型Winforms网格 [英] Need a very customized large Winforms grid

查看:214
本文介绍了需要一个非常定制的大型Winforms网格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我即将开发Windows PC应用程序(可以是winforms或WPF),而我的主要关注点是我将不得不解决的UI问题。

I am about to develop a windows PC application (it can be winforms or WPF) and my main concern is a UI problem I will have to address.

我需要一个大约50x50的网格,我需要从用户的输入。那是2500字段。实际上大部分将被留空,约10%将被用户填写。每个字段可以是空白的,或者有一个从1到4的数字。我想要简单的输入 - 一个下拉框可能(因为通过键盘来标记所有的2500个字段是没有意义的,我希望用户填写使用鼠标的值)。

Basically I need to have a grid of about 50x50 that I need to get input from the user for. That's 2500 fields. Realistically most will be left blank, about 10% will be filled out by a user. Each field can be blank or have a number from 1 to 4. I want easy input - a drop down box perhaps (since it doesn't make sense to tab through all 2500 fields when with the keyboard, I want the user to fill out the values with the mouse).

我正在考虑下拉框或甚至可以在点击它们时改变价值的标签,但问题是(从测试我'已经完成)添加2500个任意类型的控件将使界面可怕的慢。我尝试在一个winforms应用程序中使用一个tablelayoutpan和suspend / resumeupdate函数,还有doublebuffering和帮助一点,但它还是非常慢。我不愿意去DataGridView路由,因为我需要非常自定义的标题,我需要用户界面来自动更新一些百分比,因为用户更改字段中的值。但是我不会反对,如果这是我唯一的选择。

I was thinking drop down boxes or maybe even labels that change value when you click them, but the problem is (from the tests I've done) adding 2500 of ANY type of control will make the interface horribly slow. I tried using a tablelayoutpanel in a winforms app with the suspend/resumeupdate functions, and also doublebuffering and that helps a bit, but it's still terribly slow. I am reluctant go go the DataGridView route because I need VERY custom headers and I need the UI to auto update some percentages as the user changes values in the fields. But I will not be opposed if that's my only option.

我听说WPF可能会更好,因为你可以有很多控件,每个人都不会拥有自己的Windows句柄,有虚拟化(不知道实施有多难)。

I heard WPF may be better since you can have many controls and each one doesn't take it's own windows handle, and there's virtualization (not sure how hard that is to implement).

我可以接受建议。我知道有人会建议打破电网,我可能会这样做。无论哪种方式,我想知道Windows应用程序中具有许多控件的大型网格的最有效的方法,就像我要开发的那样,而不会分解网格。

I'm open to suggestions. I know someone will suggest to break up the grid, which I may end up doing. Either way I'd like to know the most efficient method for a large grid with many controls in a windows app as if I were going to develop this without breaking up the grid.

我正在使用VS 2013,在C#,.NET 4.0中开发。

I'm using VS 2013, developing in C#, .NET 4.0.

谢谢!

推荐答案

正如@ Kerry的回答所表明的那样,Winforms几乎可以回答一切都是你不能在winform中做到这一点,因此你需要创建一个更差的替代UI设计, winforms限制。 - 这不是我期望从任何体面的UI框架。

As demonstrated by @Kerry's answer, the winforms answer to almost everything is "you can't do that in winforms, therefore you need to create a much poorer substitute UI design that fits into winforms limitations." - that is not what I would expect from any decent UI framework.

这是我在 WPF 10分钟,一些 20行C#代码 50行XAML


  • 与此WPF UI进行交互的响应时间是 Immediate 在我的机器上(一个I5 CPU和一个常规的视频卡)。即使使用无虚拟化(因为我正在使用不虚拟化的 UniformGrid ),这比任何希望实现的任何事情都会好一些在winforms。

  • 我按照您的要求推出了一个 ComboBox ,号码为1-4。

  • 完全可定制(不诉诸任何所有者绘制黑客)。我甚至添加了这些行和列号,这当然都是可滚动区域的一部分。

  • 触摸就绪 - 这种大滚动UI真的是更适合触摸设备。 winforms范式甚至没有考虑到的东西。否则,您还可以使用箭头键在网格中实现类Excel键盘导航,以创建更好的非触摸用户体验。

  • 通过较小的努力,您还可以使行和列标题固定,同时保持与整个滚动偏移的一致性网格。

  • 这实际上是一个 ListBox ,这意味着它的概念是 SelectedItem 它也默认展示了类似ListBox的视觉风格(您可以看到所选项目上的浅蓝色背景和大纲)。

  • 逻辑是解耦通过创建一个适当的 ViewModel 与一个项目集合,然后使用 ItemsControls ,让WPF做创建UI的工作。在这个例子中没有一行C#代码操纵任何UI元素。这些都是通过美丽的 DataBinding

  • The response time when interacting with this WPF UI is Immediate on my machine (an I5 CPU and a regular video card). Even with no virtualization (since I'm using an UniformGrid which does not virtualize), this is way better than anything you can ever hope to achieve in winforms.
  • I introduced a ComboBox with numbers 1-4 as you requested.
  • Fully customizable (without resorting to any "owner draw" hacks). I even added these Row and Column numbers which of course are all part of the scrollable area.
  • Touch-Ready - this kind of big-scrolling UI is really better suited for a touch device. Something that the winforms paradigm does not even take into account. Otherwise, you could also implement Excel-like keyboard navigation in the grid with the arrow keys to create a better non-touch user experience.
  • With a small effort you could also make the row and column headers fixed while retaining their consistency with the scroll offset of the entire grid.
  • This is actually a ListBox, which means it has the concept of SelectedItem and it also by default exhibits the ListBox-like visual style (you can see the light-blue background and outline on the selected item).
  • The logic is decoupled from the UI by creating a proper ViewModel with a collection of Items and then using ItemsControls to let WPF do it's job of creating the UI. There's not a single line of C# code in this example that manipulates any UI element. It's all done via beautiful DataBinding.

完整来源:

<Window x:Class="WpfApplication3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <DataTemplate x:Key="MarkerTemplate">
            <Border BorderBrush="Gray" BorderThickness="1" Margin="1" Background="Gainsboro">
                <Grid Width="50" Height="30">
                    <TextBlock Text="{Binding}" FontWeight="Bold" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                </Grid>
            </Border>
        </DataTemplate>

        <Style TargetType="ListBoxItem">
            <Setter Property="Padding" Value="0"/>
        </Style>
    </Window.Resources>

    <DockPanel>
        <ListBox ItemsSource="{Binding Items}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Border BorderBrush="Gray" BorderThickness="1">
                    <Grid Width="50" Height="30">
                        <TextBlock Text="{Binding Value}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                        <ComboBox x:Name="ComboBox" SelectedItem="{Binding Value}" 
                                  IsDropDownOpen="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
                                  Visibility="Collapsed">
                            <sys:Int32>1</sys:Int32>
                            <sys:Int32>2</sys:Int32>
                            <sys:Int32>3</sys:Int32>
                            <sys:Int32>4</sys:Int32>
                        </ComboBox>
                    </Grid>
                    </Border>
                    <DataTemplate.Triggers>
                        <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem}}" Value="True">
                            <Setter TargetName="ComboBox" Property="Visibility" Value="Visible"/>
                        </DataTrigger>
                    </DataTemplate.Triggers>
                </DataTemplate>
            </ListBox.ItemTemplate>

            <ListBox.Template>
                <ControlTemplate TargetType="ListBox">
                    <ScrollViewer CanContentScroll="True" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
                        <DockPanel>
                            <ItemsControl DockPanel.Dock="Top" ItemsSource="{Binding ColumnMarkers}"
                                ItemTemplate="{StaticResource MarkerTemplate}">
                                <ItemsControl.ItemsPanel>
                                    <ItemsPanelTemplate>
                                        <VirtualizingStackPanel Orientation="Horizontal"/>
                                    </ItemsPanelTemplate>
                                </ItemsControl.ItemsPanel>
                            </ItemsControl>

                            <ItemsControl DockPanel.Dock="Left" ItemsSource="{Binding RowMarkers}"
                                          ItemTemplate="{StaticResource MarkerTemplate}">
                                <ItemsControl.ItemsPanel>
                                    <ItemsPanelTemplate>
                                        <VirtualizingStackPanel Orientation="Vertical"/>
                                    </ItemsPanelTemplate>
                                </ItemsControl.ItemsPanel>
                            </ItemsControl>

                            <UniformGrid Rows="50" Columns="50" IsItemsHost="True"/>
                        </DockPanel>
                    </ScrollViewer>
                </ControlTemplate>
            </ListBox.Template>
        </ListBox>
    </DockPanel>
</Window>

代码背后:

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;

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

            DataContext = new ViewModel();
        }
    }
}

ViewModel:

ViewModel:

public class ViewModel
{
    public List<string> RowMarkers { get; set; }

    public List<string> ColumnMarkers { get; set; }

    public ObservableCollection<Item> Items { get; set; }

    public ViewModel()
    {
        RowMarkers = Enumerable.Range(1, 50).Select(x => x.ToString()).ToList();
        ColumnMarkers = new[] { " " }.Concat(Enumerable.Range(1, 50).Select(x => x.ToString())).ToList();

        var list = new List<Item>();

        for (int i = 0; i < 50; i++)
        {
            for (int j = 0; j < 50; j++)
            {
                list.Add(new Item());
            }
        }

        Items = new ObservableCollection<Item>(list);
    }
}

数据项:

public class Item
{
    public int? Value { get; set; }
}




  • 你可能会想将属性添加到项目类中,以便您可以跟踪行/列实际包含的值。那么你可以像这样使用LINQ:

    • You will probably want to add Row and Column properties to the Item class so that you can keep track of what rows/columns actually contain values. Then You could use LINQ like so:

      var values = Items.Where(x => Value != null);
      

      并获得项目 s和 c $ c $和$ code> Item.Column 。

      忘记winforms。这完全没有用。 - 在这一点上,winforms是完全过时的。无论您使用winforms实现什么,您都可以在WPF中实现相同的功能,其中10%的代码量可能会获得更好的结果。对于任何新项目,不建议使用winforms,只能维护旧版应用程序。这是一种古老的技术,不适合满足当今的UI需求。这就是为什么Microsoft创建WPF来替换它。

      Forget winforms. It's completely useless. - at this point, winforms is completely obsolete. Whatever you can achieve with winforms, you can achieve the same thing in WPF with 10% the amount of code and probably with much better results. winforms is not recommended for any new projects, only to maintain legacy applications. It is an ancient technology that is not suited to cater for today's UI needs. That's why Microsoft created WPF to replace it.

      WPF Rocks 。只需将我的代码复制并粘贴到文件 - >新项目 - > WPF应用程序,并自行查看结果。

      WPF Rocks. Just copy and paste my code in a File -> New Project -> WPF Application and see the results for yourself.

      如果您需要进一步的帮助,请通知我。

      Let me know if you need further help.


      重要提示: WPF默认控件模板在Windows 8中的重量要轻得多他们的Windows 7同行(遵循
      Windows 8的理念,删除重的Aero东西,实际上
      所有透明胶片具有更小的UI占用空间)。

      Important Note: the WPF default control templates are much lighter weight in Windows 8 than their Windows 7 counterparts (following the Windows 8 philosophy of removing the heavy Aero stuff and practically all transparencies to have a smaller UI footprint).

      这意味着在Windows 7上测试我的代码可能不会在性能方面产生
      的预期结果。如果碰巧是
      的情况,别担心。它是可固定的必须引入少量额外的XAML
      (一些 Style s和 ControlTemplate s)
      将Windows 7默认值替换为更快。

      This means that testing my code on Windows 7 might not yield the expected results in terms of performance. If that happens to be the case, Don't worry. It is fixable. A small amount of additional XAML would have to be introduced (some Styles and ControlTemplates) to replace the Windows 7 defaults by something "faster".

      这篇关于需要一个非常定制的大型Winforms网格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆