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

时间:2009-07-28 04:38:43

标签: silverlight xaml reporting silverlight-2.0 visualization

我目前正在开发基于Silverlight2的考勤记录。我想为学生和班级创建一个随时间出勤的可视化,但我很难想出一个好的方法。我想象的那种东西是一个网格,学生在垂直轴上,日期沿水平方向,在学生和日期交叉处的符号表示是否存在。理想情况下,用于生成可视化的方法也可用于生成打印材料,但这不是必需的。 (Silverlight没有内置的打印支持,所以它必须是SQL Server Reporting Services或类似的。)

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

(显然有很棒的Silverlight样式)

以下是我目前关于如何解决这个问题的想法:

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

基本上每一道思路都会引导我编写自己的全功能Silverlight /报告引擎,这超出了我想要做的范围。另外,我真的不想让未来的维护者留下一些可怕的定制黑客显示器和放大器。报告系统。 (我不想结束TheDailyWTF!)

这就是Silverlight的可视化形式 - 我无法决定在哪里指导我的工作。

1 个答案:

答案 0 :(得分:4)

我只能想到一个简单的两级ItemsControl(ListBox)解决方案。内部视觉元素可以是一个看起来像'O'或'X'的Styled CheckBox,这里是我刚刚为你制作的样本。当然,您需要在顶部与复选框对齐的DateHeader集合。

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

测试数据填充在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;