在 Silverlight 中显示大量项目的网格的最佳方式是什么?

发布于 2024-07-29 02:35:07 字数 1736 浏览 8 评论 0原文

我目前正在开发基于 Silverlight2 的考勤登记系统。 我想为学生和班级创建随时间变化的出勤情况的可视化,但我正在努力想出一个好的方法来做到这一点。 我想象的那种事情是一个网格,学生在垂直轴上,日期在水平轴上,学生和日期的交叉点有一个符号指示存在或缺席。 理想情况下,用于生成可视化的方法也将用于生成印刷材料,但这不是必需的。 (Silverlight 没有内置的打印支持,因此它必须是 SQL Server Reporting Services 或类似的服务。)

下面是 Excel 中我需要显示的数据类型的简单模型: Mock-up Chart

(显然具有很棒的 Silverlight 样式)

以下是我目前关于如何进行操作的想法:

  • 带有 Canvas ItemsPanel 和数据绑定定位项的 ListBox。 在某些方面这将是最好的,因为它需要最少的代码,但是我无法在 Silverlight2 中很好地做到这一点(我最接近的)我们得到的是一个列表框,每个项目都有一个画布,项目内容位于其中)。 如果有数百或数千个项目都需要实例化,那么速度可能会非常慢。
  • 具有动态列的 DataGrid。 我还没有尝试过这个,但由于在某些情况下可能有 100 多个列,这似乎不是一个很好的解决方案。 我再次担心大量项目的性能。
  • 服务器端图像 (PNG) 生成。 这将解决打印问题,因为 Silverlight 客户端和 Reporting Services 都可以引用同一图像,但这会妨碍 Silverlight 客户端中的任何类型的交互。 图像分辨率也是打印质量的一个问题。 显示数千个项目时的负载将被推送到服务器,因此除了在服务器上生成图像的初始延迟之外,客户端的速度不会受到影响。
  • Silverlight 自定义控件。我可以构建一个自定义控件,将文本/符号放置在画布上。 这实际上是一个散点图。 这并不能解决打印问题。 由于开销较低,性能可能比列表框更好,但是任何数据绑定、项目选择等都必须手动编码。
  • 使用第三方散点图。这可能相对简单,但取决于图表库的功能。 为了打印目的,必须找到另一种解决方案。
  • 服务器端生成 SVG 或 XAML。与图像生成类似,但生成用于显示或打印的矢量数据。 SVG 最适合打印和导出,尽管 XPS 文档基于 XAML,因此可以工作。 在 Silverlight 中使用 SVG 需要转换为 XAML。 有离线工具可以执行此操作,但没有在 Silverlight 中转换或渲染 SVG 的功能。
  • 使用大量固定宽度文本。我们这里有一些旧报告,它们通过生成诸如 ......x...oo.ox.. 之类的字符串来执行此类操作。 .x.... 然后以固定宽度字体显示。 这个解决方案让我眼睛流血,因为它看起来像是回到了绿屏终端时代,尤其是当 Silverlight 是基于矢量的时候。

基本上,每一条思路都引导我编写自己的功能齐全的 Silverlight/报告引擎,这远远超出了我想要做的范围。 另外,我真的不想给未来的维护人员留下一些糟糕的定制的黑客显示器和显示器。 报告制度。 (我不想最终出现在 TheDailyWTF 上!)

Silverlight 就是为这种可视化而生的 - 我只是无法决定将我的努力指向何处。

I am currently working on a Silverlight2-based attendance register. I want to create a visualisation of attendance over time for students and classes, but am struggling to come up with a good way of doing it. The sort of thing I'm imagining is a grid with students on the vertical axis and date along the horizontal, with a symbol at the intersection of student and date indicating presence or absence. Ideally the method used to generate the visualisation would also be used to generate printed material, however this is not essential. (Silverlight has no built-in printing support, so it'd have to be SQL Server Reporting Services or similar.)

Here's a simple mock-up in Excel of the sort of data I need to display:
Mock-up chart

(Obviously with awesome Silverlight styling)

Here are my current thoughts on how to go about it:

  • ListBox with a Canvas ItemsPanel and data-bound positioned items. This would be the best in some ways because it requires the least amount of code, however I have not been able to do this nicely in Silverlight2 (The closest I've got is a ListBox with a Canvas per item and the item contents positioned within that). It would potentially be very slow with hundreds or thousands of items all needing to be instantiated.
  • DataGrid with dynamic columns. I havent tried this yet, but as there may be 100+ columns in some cases, it doesnt seem to be a nice solution. Again I'd be concerned about performance with a large number of items.
  • Server-side image (PNG) generation. This would solve the printing problem because both the Silverlight client and Reporting Services could reference the same image, however this would preclude any sort of interactivity in the Silverlight client. Image resolution would also be an issue for print quality. The load when displaying thousands of items would be pushed to the server, so the speed of the client would not be affected, aside from the initial delay in generating the image on the server.
  • Silverlight Custom Control. I could build a custom control that would place the text/symbols on a canvas. This would effectively be a scatter-chart. This wouldnt solve the printing problem. Performance would likely be better than a ListBox due to lower overhead, however any databinding, item selection etc would have to be coded manually.
  • Use a 3rd-party Scatterplot Chart. This could be relatively simple, but would depend on the features of the chart library. Another solution would have to be found for printing purposes.
  • Server-side generation of SVG or XAML. Similar to image generation, but instead generates vector data for display or printing. SVG would be best for printing and export, although XPS documents are based on XAML, so that could work. Using SVG in Silverlight would require conversion to XAML. There are offline tools to do this, but no function to convert or render SVG within Silverlight.
  • Use large amounts of fixed-width text. We have some old reports here that do this kind of thing by generating strings like ......x...oo.ox...x.... which are then displayed in a fixed-width font. This solution makes my eyes bleed because it seems like a throw-back to the green-screen terminal days, especially when Silverlight is vector-based.

Basically every train of thought leads me towards writing my own fully-featured Silverlight/Reporting engine, which is way beyond the scope of what I'm trying to do. Plus I dont really want to leave a future maintainer with some awful custom-built hacky display & reporting system. (I dont want to end up on TheDailyWTF!)

This is the sort of visualisation that Silverlight is made for - I just cant decide where to direct my efforts.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

孤千羽 2024-08-05 02:35:07

我只能想到一个简单的两级 ItemsControl(ListBox) 解决方案。 内部视觉元素可以是样式化的复选框,看起来像“O”或“X”,这是我刚刚为您制作的示例。 当然,您确实需要顶部的 DateHeader 集合与复选框对齐。

替代文本 http://img339.imageshack.us/img339/8695/grid.jpg< /a>

XAML

    <UserControl.Resources>
    <DataTemplate x:Key="CellTemplate">
        <Grid Width="25" Height="25">
            <CheckBox IsChecked="{Binding IsPresent}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        </Grid>
    </DataTemplate>
    <DataTemplate x:Key="RowTemplate">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="80"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <TextBlock Margin="4,0,0,0" Text="{Binding Name}" TextWrapping="Wrap"/>
            <ItemsControl ItemsSource="{Binding WorkingDays}" HorizontalAlignment="Left" VerticalAlignment="Top" ItemTemplate="{StaticResource CellTemplate}" Grid.Column="1" >
                <ItemsControl.ItemsPanel>   
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal"/>      
                    </ItemsPanelTemplate>               
                </ItemsControl.ItemsPanel>
            </ItemsControl>
        </Grid>
    </DataTemplate>
</UserControl.Resources>
<ItemsControl x:Name="lstWorkingDaysMain" ItemsSource="{Binding}" ItemTemplate="{StaticResource RowTemplate}" >
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Vertical"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl> 

C#

public class Student
{
    public Student()
    {
        WorkingDays = new List<WorkingDay>();
    }

    public string Name { get; set; }
    public List<WorkingDay> WorkingDays { get; set; }
}

public class WorkingDay
{
    public bool IsPresent{get; set;}
    public DateTime Date { get; set; }
}

以及 xaml.cs 后面代码中的测试数据填充

 List<Student> students = new List<Student>();

        Student student = new Student() { Name = "Aaaaaa" };
        student.WorkingDays.Add(new WorkingDay() { Date=new DateTime(2009,5,5), IsPresent=true} );
        student.WorkingDays.Add(new WorkingDay() { Date=new DateTime(2009,5,6), IsPresent=true} );
        student.WorkingDays.Add(new WorkingDay() { Date=new DateTime(2009,5,7), IsPresent=true} );
        student.WorkingDays.Add(new WorkingDay() { Date=new DateTime(2009,5,8), IsPresent=true} );
        student.WorkingDays.Add(new WorkingDay() { Date=new DateTime(2009,5,9), IsPresent=true} );
        student.WorkingDays.Add(new WorkingDay() { Date=new DateTime(2009,5,10), IsPresent=true} );
        student.WorkingDays.Add(new WorkingDay() { Date=new DateTime(2009,5,11), IsPresent=true} );
        student.WorkingDays.Add(new WorkingDay() { Date=new DateTime(2009,5,12), IsPresent=true} );
        students.Add(student);

        student = new Student() { Name = "Bbbbbb" };
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 5), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 6), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 7), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 8), IsPresent = false });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 9), IsPresent = false });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 10), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 11), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 12), IsPresent = true });
        students.Add(student);


        student = new Student() { Name = "Cccccc" };
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 5), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 6), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 7), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 8), IsPresent = false });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 9), IsPresent = false });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 10), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 11), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 12), IsPresent = false });
        students.Add(student);


        student = new Student() { Name = "Dddddd" };
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 5), IsPresent = false });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 6), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 7), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 8), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 9), IsPresent = false });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 10), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 11), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 12), IsPresent = true });
        students.Add(student);

        this.DataContext = students;

I can think only a simple two level ItemsControl(ListBox) solution for this. And the inner visual element can be a Styled CheckBox to look like 'O' or 'X' here is the sample I just made for you . Of course you do need to a DateHeader collection at the top aligned with the checkboxes.

alt text http://img339.imageshack.us/img339/8695/grid.jpg

XAML

    <UserControl.Resources>
    <DataTemplate x:Key="CellTemplate">
        <Grid Width="25" Height="25">
            <CheckBox IsChecked="{Binding IsPresent}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        </Grid>
    </DataTemplate>
    <DataTemplate x:Key="RowTemplate">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="80"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <TextBlock Margin="4,0,0,0" Text="{Binding Name}" TextWrapping="Wrap"/>
            <ItemsControl ItemsSource="{Binding WorkingDays}" HorizontalAlignment="Left" VerticalAlignment="Top" ItemTemplate="{StaticResource CellTemplate}" Grid.Column="1" >
                <ItemsControl.ItemsPanel>   
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal"/>      
                    </ItemsPanelTemplate>               
                </ItemsControl.ItemsPanel>
            </ItemsControl>
        </Grid>
    </DataTemplate>
</UserControl.Resources>
<ItemsControl x:Name="lstWorkingDaysMain" ItemsSource="{Binding}" ItemTemplate="{StaticResource RowTemplate}" >
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Vertical"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl> 

C#

public class Student
{
    public Student()
    {
        WorkingDays = new List<WorkingDay>();
    }

    public string Name { get; set; }
    public List<WorkingDay> WorkingDays { get; set; }
}

public class WorkingDay
{
    public bool IsPresent{get; set;}
    public DateTime Date { get; set; }
}

And the test data population at the code behind xaml.cs

 List<Student> students = new List<Student>();

        Student student = new Student() { Name = "Aaaaaa" };
        student.WorkingDays.Add(new WorkingDay() { Date=new DateTime(2009,5,5), IsPresent=true} );
        student.WorkingDays.Add(new WorkingDay() { Date=new DateTime(2009,5,6), IsPresent=true} );
        student.WorkingDays.Add(new WorkingDay() { Date=new DateTime(2009,5,7), IsPresent=true} );
        student.WorkingDays.Add(new WorkingDay() { Date=new DateTime(2009,5,8), IsPresent=true} );
        student.WorkingDays.Add(new WorkingDay() { Date=new DateTime(2009,5,9), IsPresent=true} );
        student.WorkingDays.Add(new WorkingDay() { Date=new DateTime(2009,5,10), IsPresent=true} );
        student.WorkingDays.Add(new WorkingDay() { Date=new DateTime(2009,5,11), IsPresent=true} );
        student.WorkingDays.Add(new WorkingDay() { Date=new DateTime(2009,5,12), IsPresent=true} );
        students.Add(student);

        student = new Student() { Name = "Bbbbbb" };
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 5), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 6), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 7), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 8), IsPresent = false });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 9), IsPresent = false });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 10), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 11), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 12), IsPresent = true });
        students.Add(student);


        student = new Student() { Name = "Cccccc" };
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 5), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 6), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 7), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 8), IsPresent = false });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 9), IsPresent = false });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 10), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 11), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 12), IsPresent = false });
        students.Add(student);


        student = new Student() { Name = "Dddddd" };
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 5), IsPresent = false });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 6), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 7), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 8), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 9), IsPresent = false });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 10), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 11), IsPresent = true });
        student.WorkingDays.Add(new WorkingDay() { Date = new DateTime(2009, 5, 12), IsPresent = true });
        students.Add(student);

        this.DataContext = students;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文