WPF以图形方式显示序列开/关持续时间的提示

时间:2011-01-04 02:32:47

标签: wpf graphics

我正在开发一个应用程序,用户可以在多个开/关持续时间序列之间进行选择。序列始终以开启周期开始,并且可以具有变化的长度(但总是在开/关对中):例如

var sequences = new []
{
    new int[] { 10, 15 },        // 10 ms on, 15 ms off
    new int[] { 15, 10, 5, 10 }  // 15 ms on, 10 ms off, 5 ms on, 10 ms off
};

序列的最长持续时间为10秒,并将重复进行。一个特殊的序列定义没有开/关持续时间:它始终打开(虽然我可以将其更改为{1,0}或其他)。

不是在屏幕上显示数字,而是希望在整个10秒的持续时间内显示一些小图形表示(重复较短的序列),以便用户可以比较模式。这些将显示在一个随窗口调整大小的组合框中。对于上面的示例,它看起来类似于以下(其中X是填充背景)

xx   xx   xx   xx   xx   xx   xx...
xxx  x  xxx  x  xxx  x  xxx  x  ...

我想我必须使用值转换器(如果仅用于特殊值),但不确定创建图形的最佳/最简单方法是什么,特别是调整大小要求并重复较短的序列。画布,还有什么?

我非常感谢任何提示!

1 个答案:

答案 0 :(得分:1)

我会遵循这个基本方法:

  1. 写一个值转换器,它接受每个序列并将序列重复到整个10秒,用一个类来编码每个块的时间,该类指定周期是“开”还是持续时间。

    < / LI>
  2. 对于每个序列,绑定到ItemsControl的ItemsSource。对于ItemsPanel,使用具有水平方向的StackPanel。对于ItemTemplate,在一段时间内使用矩形或任何其他视觉效果,并将宽度绑定到持续时间。您现在还包含了一个方便的'IsOn'属性,以便您可以轻松地显示开/关状态。此时不要担心缩放宽度。

  3. 将ItemsControl放在ViewBox中,可以将其拉伸到其父容器。现在,您有一个视觉效果,可以提供正确的持续时间比例和尺寸比例。


  4. 这是一个简单的实现(没有错误处理或任何尝试使它漂亮):

    UDPATE:修复了在10秒内没有正确截断重复序列的错误。

    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Windows;
    using System.Windows.Data;
    
    namespace TestWpf
    {
        public class SeqSegment
        {
            public bool IsOn { get; set; }
            public int Duration { get; set; }
        }
    
        public class SeqConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                var result = new List<SeqSegment>();
                var seq = (int[]) value;
                int time = 0;
                int i = 0;
                bool isOn = true;
                while (time < 10000)
                {
                    result.Add(new SeqSegment { Duration = Math.Min(seq[i], 10000 - time), IsOn = isOn });
                    isOn = !isOn;
                    time += seq[i];
                    i++;
                    if (i >= seq.Length)
                        i = 0;
                }
    
                return result;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                throw new NotSupportedException();
            }
        }
    
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public IEnumerable<int[]> TestSequences
            {
                get
                {
                    yield return new[] {10, 5000, 10, 8};
                    yield return new[] {500, 5000};
                    yield return new[] {50, 400, 30, 10};
                }
            }
    
            public MainWindow()
            {
                InitializeComponent();
                DataContext = this;
            }
        }
    }
    

    XAML:

    <Window x:Class="TestWpf.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:TestWpf="clr-namespace:TestWpf" Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <TestWpf:SeqConverter x:Key="SeqConverter"/>
            <DataTemplate x:Key="SeqSegTemplate">
                <Rectangle x:Name="Rect" Width="{Binding Duration}" Fill="Blue"/>
                <DataTemplate.Triggers>
                    <DataTrigger Binding="{Binding IsOn}" Value="True">
                        <Setter TargetName="Rect" Property="Fill" Value="Green"/>
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
            <DataTemplate x:Key="SeqTemplate">
                <Viewbox Height="50" Stretch="Fill">
                    <ItemsControl ItemsSource="{Binding Converter={StaticResource SeqConverter}}" ItemTemplate="{StaticResource SeqSegTemplate}">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel Orientation="Horizontal" Height="1"/>
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                    </ItemsControl>
                </Viewbox>
            </DataTemplate>
        </Window.Resources>
        <Grid>
            <ItemsControl ItemsSource="{Binding TestSequences}" ItemTemplate="{StaticResource SeqTemplate}"/>
        </Grid>
    </Window>