.net c#仅在列表视图中的最后一项上绘制边框

Drawing a border only on the last item inside my listview
2021-07-22
  •  译文(汉语)
  •  原文(英语)

我正在尝试创建一个像这样的控件: 仅在列表视图中的最后一项上绘制边框

该控件表示4个图块对象的状态完成(在上面的图片2中已完成,而2个尚未完成)

为了实现这一点,我创建了一个水平方向的ListView,并且创建了一个内部带有一些边框的数据模板.不确定这是正确的方法还是更简单的方法是可行的,但是我面临的问题是下列的:仅在列表视图中的最后一项上绘制边框

  1. 我无法关闭最后一个项目的边框.这是因为我在listview的itemsource中有4个项目,并且每个项目都在其左侧绘制了一个边框.问题是如何具体绘制最后一项的右边框.

  2. 穿过中间的线实际上应该在灰色阴影后面.如何实现?

代码如下:

        <Style x:Key="FishBoneStyle" TargetType="{x:Type Border}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=Completed}" Value="True">
                    <Setter Property="Background" Value="DarkGray"/>
                    <Setter Property="Margin" Value="0,3,-2,3"/>
                </DataTrigger>              
            </Style.Triggers>
        </Style>

        <DataTemplate x:Key="FishBoneTemplate">
            <Grid Height="25">
            <Border BorderThickness="1,0,0,0" BorderBrush="Black" Height="25" HorizontalAlignment="Left" VerticalAlignment="Stretch"/>
                <Border Style="{StaticResource FishBoneStyle}" x:Name="FishBoneBorder" Width="25">
            </Border>
            </Grid>         
        </DataTemplate>

<!-- The Main Grid-->
<Grid Grid.Row="1" Height="30" Width="130" HorizontalAlignment="Left">
<ListView BorderThickness="0,0,0,0" BorderBrush="Black" ItemsSource="{Binding ProgressTiles}" ItemTemplate="{StaticResource FishBoneTemplate}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
  <StackPanel Orientation="Horizontal"></StackPanel>
 </ItemsPanelTemplate>
   </ListView.ItemsPanel>
</ListView>

<!-- The line which passess through the center-->
  <Border VerticalAlignment="Center" HorizontalAlignment="Left" Width="100" Margin="3,0,2,0" BorderBrush="Black" BorderThickness="1"></Border>
</Grid>

..这是模型,它位于我的视图模型中的一个可观察的集合中.将始终有四个模型.

public class ProgressTile : INotifyPropertyChanged
    {
        private bool _completed;
        public bool Completed
        {
            get { return _completed; }
            set
            {
                _completed = value;
                InvokePropertyChanged("Completed");
            }
        }


        public event PropertyChangedEventHandler PropertyChanged;
        public void InvokePropertyChanged(string e)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(e));
        }
    }

请您提出建议,以使外观与所附图片保持一致.您还可以建议通过为最后一项绘制边框并将经过中间的线发送到背景来解决该问题吗?

解决过程1

可以做的简单得多:

<Window x:Class="So17362172FishBoneProgressBar.MainWindow" x:Name="root"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Fish Bone Progress Bar" Height="350" Width="525" SnapsToDevicePixels="True">
    <Grid Width="100" Height="20">
        <TickBar Fill="Gray" TickFrequency="25" Placement="Top"/>
        <TickBar Fill="Gray" TickFrequency="25" Placement="Bottom"/>
        <Line Stroke="Gray" X1="0" Y1="10" X2="100" Y2="10"/>
        <ItemsControl ItemsSource="{Binding Tiles, ElementName=root}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Rectangle x:Name="rect" Fill="Gray" VerticalAlignment="Center" Width="25" Height="10"/>
                    <DataTemplate.Triggers>
                        <DataTrigger Binding="{Binding Completed}" Value="False">
                            <Setter TargetName="rect" Property="Visibility" Value="Collapsed"/>
                        </DataTrigger>
                    </DataTemplate.Triggers>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>
  1. ListView是没有必要的.简单得多ItemsControl就可以了.
  2. 可以用绘制cks TickBar.随着内部刻度线的绘制变小,两个刻度线彼此重叠(这不成问题,因为它们非常轻巧).
  3. 绘制顺序由逻辑树中的顺序确定.如果要在其他对象上绘制内容,则将其放到XAML较低的位置.
  4. Grid 如果仅包含一个控件,则没有必要.

I'm trying to create a control like this: Drawing a border only on the last item inside my listview

The control denotes the status completion of 4 tile objects (in the above attached pic 2 is completed and 2 is not)

For achieving this I have created a ListView with horizontal orientation, and I'm creating a datatemplate which has some borders inside.Not sure whether this is the right approach or whether a simpler approach is possible, however the issue I'm facing is the following:Drawing a border only on the last item inside my listview

  1. I'm not able to close the border of the last item..this is because I have 4 items inside my itemsource of the listview and each item draws a border to it's left. Question is how do I specifically draw the right border for the last item.

  2. The line which passess through the middle should actually go behind the gray shading..how do I achieve that?

Code is as below:

        <Style x:Key="FishBoneStyle" TargetType="{x:Type Border}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=Completed}" Value="True">
                    <Setter Property="Background" Value="DarkGray"/>
                    <Setter Property="Margin" Value="0,3,-2,3"/>
                </DataTrigger>              
            </Style.Triggers>
        </Style>

        <DataTemplate x:Key="FishBoneTemplate">
            <Grid Height="25">
            <Border BorderThickness="1,0,0,0" BorderBrush="Black" Height="25" HorizontalAlignment="Left" VerticalAlignment="Stretch"/>
                <Border Style="{StaticResource FishBoneStyle}" x:Name="FishBoneBorder" Width="25">
            </Border>
            </Grid>         
        </DataTemplate>

<!-- The Main Grid-->
<Grid Grid.Row="1" Height="30" Width="130" HorizontalAlignment="Left">
<ListView BorderThickness="0,0,0,0" BorderBrush="Black" ItemsSource="{Binding ProgressTiles}" ItemTemplate="{StaticResource FishBoneTemplate}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
  <StackPanel Orientation="Horizontal"></StackPanel>
 </ItemsPanelTemplate>
   </ListView.ItemsPanel>
</ListView>

<!-- The line which passess through the center-->
  <Border VerticalAlignment="Center" HorizontalAlignment="Left" Width="100" Margin="3,0,2,0" BorderBrush="Black" BorderThickness="1"></Border>
</Grid>

..and here is the model which is lying inside an observable collection in my viewmodel.There will be always 4 of them.

public class ProgressTile : INotifyPropertyChanged
    {
        private bool _completed;
        public bool Completed
        {
            get { return _completed; }
            set
            {
                _completed = value;
                InvokePropertyChanged("Completed");
            }
        }


        public event PropertyChangedEventHandler PropertyChanged;
        public void InvokePropertyChanged(string e)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(e));
        }
    }

Please can you suggest how to get a look consistent to the attached picture. Also can you please suggest how to solve the issue with drawing a border for the last item and sending the line passing through the middle to background?

Solutions1

Can be done much simpler:

<Window x:Class="So17362172FishBoneProgressBar.MainWindow" x:Name="root"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Fish Bone Progress Bar" Height="350" Width="525" SnapsToDevicePixels="True">
    <Grid Width="100" Height="20">
        <TickBar Fill="Gray" TickFrequency="25" Placement="Top"/>
        <TickBar Fill="Gray" TickFrequency="25" Placement="Bottom"/>
        <Line Stroke="Gray" X1="0" Y1="10" X2="100" Y2="10"/>
        <ItemsControl ItemsSource="{Binding Tiles, ElementName=root}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Rectangle x:Name="rect" Fill="Gray" VerticalAlignment="Center" Width="25" Height="10"/>
                    <DataTemplate.Triggers>
                        <DataTrigger Binding="{Binding Completed}" Value="False">
                            <Setter TargetName="rect" Property="Visibility" Value="Collapsed"/>
                        </DataTrigger>
                    </DataTemplate.Triggers>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>
  1. ListView is unnecessary. Much simpler ItemsControl is enough for this.
  2. Ticks can be drawn with TickBar. As inner ticks are drawn smaller, two tick bars are put over each other (it shouldn't be an issue, as these are very lightweight).
  3. Order of drawing is determined by order in the logical tree. If you want something to be drawn over another, you put it into XAML lower.
  4. Grid is unnecessary if it contains only one control.
转载于:https://stackoverflow.com/questions/17362172/drawing-a-border-only-on-the-last-item-inside-my-listview

本人是.net程序员,因为英语不行,使用工具翻译,希望对有需要的人有所帮助
如果本文质量不好,还请谅解,毕竟这些操作还是比较费时的,英语较好的可以看原文

留言回复
我们只提供高质量资源,素材,源码,坚持 下了就能用 原则,让客户花了钱觉得值
上班时间 : 周一至周五9:00-17:30 期待您的加入