我正在开发一个应用程序,用户可以在多个开/关持续时间序列之间进行选择。序列始终以开启周期开始,并且可以具有变化的长度(但总是在开/关对中):例如
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 ...
我想我必须使用值转换器(如果仅用于特殊值),但不确定创建图形的最佳/最简单方法是什么,特别是调整大小要求并重复较短的序列。画布,还有什么?
我非常感谢任何提示!
答案 0 :(得分:1)
我会遵循这个基本方法:
写一个值转换器,它接受每个序列并将序列重复到整个10秒,用一个类来编码每个块的时间,该类指定周期是“开”还是持续时间。
< / LI>对于每个序列,绑定到ItemsControl的ItemsSource。对于ItemsPanel,使用具有水平方向的StackPanel。对于ItemTemplate,在一段时间内使用矩形或任何其他视觉效果,并将宽度绑定到持续时间。您现在还包含了一个方便的'IsOn'属性,以便您可以轻松地显示开/关状态。此时不要担心缩放宽度。
将ItemsControl放在ViewBox中,可以将其拉伸到其父容器。现在,您有一个视觉效果,可以提供正确的持续时间比例和尺寸比例。
这是一个简单的实现(没有错误处理或任何尝试使它漂亮):
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>