【问题标题】:Display shapes in WPF ListView dynamically在 WPF ListView 中动态显示形状
【发布时间】:2019-08-05 12:02:35
【问题描述】:

我想在 ListView 中可视化数据传输的进度。 一行是一个包含名称和状态的传输。 传输状态应以图形方式显示。 我想画一系列垂直线。一条线代表一段传输的状态,其颜色为段的状态(未传输、错误、传输完成)。

那么,如何在 WPF 中对此进行建模?我想将 WrapPanel 放入 XAML 中 GridViewColumn 内的 GridViewColumn.CellTemplate 内的 DataTemplate 中。这就是我在网络教程方面的进展。 将单个 Line 放入 Canvas 的表格中也可以,但正如您所见,我需要它更加动态。

现在我需要一些数据绑定来将不同数量的具有固定高度和一个像素宽度和可变颜色的线条形状放入 WrapPanel。我想到 WrapPanel 是为了自动环绕显示,以防窗口的宽度小于需要显示的段数。

另外:如何告诉 ListView 的最后一列占用窗口内的剩余空间?我不想要水平滚动条。

这一切的更新很频繁,两次更新之间可能不到一秒。所以我不想仅仅因为一个片段改变了它的颜色就重绘所有的东西。那么,在这种情况下如何访问单个 Line 呢?

【问题讨论】:

  • 我喜欢“形状的抽象表示(而不是 UI 元素列表)”,但我更喜欢线条的自动放置。而且我不明白 ItemsControl 部分 - 它如何知道要呈现什么样的形状?
  • 通过 ItemTemplate 中的<Path Data="{Binding Geometry}" ... />。您还可以使其更具体,例如:stackoverflow.com/a/22325266/1136211
  • 我根本不知道几何图形在哪里出现。它们不都是1px宽的矩形吗?更多“只是”一个水平列表视图,有点像i.imgur.com/3pC3yU6.png,但有不同的颜色和一个包装面板而不是一个堆栈面板来组织它们?

标签: c# wpf listview data-binding


【解决方案1】:

好的,我终于完成了我想看到的。首先让我们看看 XAML。这里只有 ListView 的部分,只有包含段的单列。当然,您需要一个窗口,并且可以添加更多列。

    <ListView Name="KnownImages" ItemsSource="{Binding FileViewModels}">
        <ListView.View>
            <GridView>

                <GridViewColumn Header="Segments" Width="100">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate DataType="local:FileViewModel">
                            <ItemsControl Width="auto" Height="auto" ItemsSource="{Binding Segments}">
                                <ItemsControl.ItemsPanel>
                                    <ItemsPanelTemplate>
                                        <WrapPanel/>
                                    </ItemsPanelTemplate>
                                </ItemsControl.ItemsPanel>
                                <ItemsControl.ItemTemplate>
                                    <DataTemplate DataType="local:SegmentViewModel">
                                        <Line ToolTip="{Binding ToolTip}" X1="1" X2="1" Y1="{Binding YTop}" Y2="15" StrokeThickness="3" Stroke="{Binding Stroke}"/>
                                    </DataTemplate>
                                </ItemsControl.ItemTemplate>
                            </ItemsControl>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>

            </GridView>
        </ListView.View>
    </ListView>

主窗口有一个视图模型,其中包含

    public ObservableCollection<FileViewModel> FileViewModels { get; set; }

ListView 绑定到该字段。 DataTemplate 有一个视图模型FileViewModel,其中包含列表视图中单行的内容,该视图可视化一个文件。它主要包含

public ObservableCollection<SegmentViewModel> Segments { get; set; }

所以我们可以将ItemsControl 绑定到该字段SegmentsItemsPanelTemplate 中的 WrapPanel 现在填充了一个知道其数据类型为 SegmentViewModelDataTemplate

/// <summary>
/// View model of a single file segment, which is represented with
/// a vertical line. The changeable parts of the line are stored here
/// and are directly derived from the state of the segment in the
/// constructor (ToolTip, Color and the upper Y coordinate of the line)
/// </summary>
public class SegmentViewModel
{
    private const int YTopEof=0;
    private const int YTopIntermediate=3;

    public string ToolTip { get; set; }
    public Brush Stroke { get; set; }
    public int YTop { get; set; }

    /// <summary>
    /// Derive appearance of the line from the business data received from queue
    /// if we already received data for the segment.
    /// </summary>
    /// <param name="fromQ">our knowledge about the segment state</param>
    public SegmentViewModel(SegmentState fromQ)
    {
        var sb = new StringBuilder();
        sb.Append("Seg ");
        sb.Append(fromQ.Number);
        if (fromQ.IsInMemory)
            sb.Append(", in memory");
        if (fromQ.IsOnDisk)
            sb.Append(", on disk");
        if (!fromQ.IsComplete)
            sb.Append(", INCOMPLETE!!!");

        ToolTip = sb.ToString();

        Color col;
        if (!fromQ.IsComplete)
            col = Colors.Magenta;
        else if (fromQ.IsInMemory)
            col = fromQ.IsOnDisk ? Colors.Black : Colors.Green;
        else
            col = fromQ.IsOnDisk ? Colors.RoyalBlue : Colors.Brown;

        Stroke = new SolidColorBrush(col);

        YTop = fromQ.EndOfFile ? YTopEof : YTopIntermediate;
    }

    /// <summary>
    /// This constructor is for segments that we did not receive so far.
    /// </summary>
    /// <param name="segmentNumber">We only know that we expect data from this index.</param>
    public SegmentViewModel(int segmentNumber)
    {
        ToolTip = $"Seg {segmentNumber} not yet seen";
        YTop = YTopIntermediate;
        Stroke = new SolidColorBrush(Colors.LightGray);
    }

对于Segments 数组中的每个SegmentViewModel 实例,我们将获得一个Line 的新实例作为可视化。可变视觉属性与绑定(工具提示、颜色、行长)映射。非可变视觉属性是 XAML 中的常量。注意:坐标不是像素,而是更小的东西——至少在我的屏幕上。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-05
    • 1970-01-01
    • 1970-01-01
    • 2018-06-06
    • 1970-01-01
    • 2021-02-07
    • 1970-01-01
    • 2012-08-24
    相关资源
    最近更新 更多