需要非常大的自定义网格的WinForms [英] Need a very customized large Winforms grid

查看:155
本文介绍了需要非常大的自定义网格的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.

基本上我需要有大约50×50的网格,我需要从用户获取输入。那是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任何类型的控件会导致接口异常缓慢的。我试着与暂停/ resumeupdate功能的WinForms应用程序使用一个TableLayoutPanel,也doublebuffering和有点帮助,但它仍然非常缓慢。我不愿围棋DataGridView的路线,因为我需要非常自定义页眉和我需要的UI来自动更新一些百分比为用户在田里的变化值。但是,如果这是我唯一的选择,我不会反对。

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可能会更好,因为你可以有许多控制,每一个不走它自己的窗口办理,并有虚拟化(不知道这是多么难以实现)。

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.

谢谢!

推荐答案

这表现在@克里的回答中,WinForms的回答几乎一切的你不能这样做,在的WinForms,因此,你需要创建一个适合的贫困得多的替代品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 的行:

This is what I achieved in WPF in 10 minutes with some 20 lines of C# code and 50 lines of XAML:


  • 本WPF UI交互时的响应时间立即我的机器上(一个CPU I5和常规视频卡)。即使有没有虚拟化(因为我使用的是 UniformGrid 不虚拟化),这是比任何你所能希望实现更好的方式在的WinForms。

  • 我介绍了一个组合框用数字1-4你的要求。

  • 完全自定义(而不诉诸任何自绘黑客)。我甚至添加了这些行数和列数这当然是滚动区域的一部分

  • 触摸就绪 - 这种大滚动UI是真的更适合用于触摸设备。东西的WinForms的模式甚至不考虑。否则,你也可以实现使用箭头键网格类似于Excel的键盘导航,共创美好的非接触式的用户体验。

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

  • 这实际上是一个的ListBox ,这意味着它有的SelectedItem ,同时也默认展品列表框般的视觉风格(你可以看到所选项目的淡蓝色的背景和轮廓)。

  • 的逻辑脱钩从UI通过创建适当的视图模型与项目的集合,然后使用的 ItemsControls 让WPF做是创建用户界面的工作。这里没有的C#代码在这个例子中的任何操纵UI元素一行。它通过美丽的 数据绑定

  • 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:

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);
    }
}



数据项:

Data Item:

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);
      

      和获得的名单项目和获得 item.Row Item.Column 为他们每个人。

      and obtain a list of Items and get item.Row and Item.Column for each of them.

      忘记的WinForms。它是完全无用的 - 在这一点上,是的WinForms完全过时。不管你可以用的WinForms实现,可以实现在WPF中同样的事情用10%的代码量,并可能与更好的结果。不推荐任何新项目的WinForms,只有保持原有应用程序。这是一个古老的技术,不适合以迎合今天的UI需求。这就是为什么微软创建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岩。只需复制并粘贴文件在我的代码 - >新建项目 - > 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.

      重要提示:在Windows 8中的WPF默认控件模板是重量轻得多比他们的Windows 7的同行(以下的
      Windows 8的理念取出航空重的东西和实际
      所有的透明胶片有一个较小的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
      少量就必须引入(有些风格控件模板 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天全站免登陆