项目中经常使用需要根据搜索条件查询数据,然后用卡片来展示数据。用卡片展示数据时,界面的宽度发生变化,希望显示的卡片数量也跟随变化。WrapPanel虽然也可以实现这个功能,但是将多余的部分都留在行尾,十分不美观,最好是能够将多余的宽度平分在每个ListBoxItem之间,比较美观,也符合项目需求。如下便是我自己实现的Panel:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls; namespace WpfDemo
{
public class MyWrapPanel : Panel
{
protected override System.Windows.Size MeasureOverride(System.Windows.Size availableSize)
{
Size currentLineSize = new Size();
Size panelSize = new Size(); foreach (UIElement element in base.InternalChildren)
{
element.Measure(availableSize);
Size desiredSize = element.DesiredSize; if (currentLineSize.Width + desiredSize.Width > availableSize.Width)
{
panelSize.Width = Math.Max(currentLineSize.Width, panelSize.Width);
panelSize.Height += currentLineSize.Height;
currentLineSize = desiredSize; if (desiredSize.Width > availableSize.Width)
{
panelSize.Width = Math.Max(desiredSize.Width, panelSize.Width);
panelSize.Height += desiredSize.Height;
currentLineSize = new Size();
}
}
else
{
currentLineSize.Width += desiredSize.Width;
currentLineSize.Height = Math.Max(desiredSize.Height, currentLineSize.Height);
}
} panelSize.Width = Math.Max(currentLineSize.Width, panelSize.Width);
panelSize.Height += currentLineSize.Height; return panelSize;
} protected override System.Windows.Size ArrangeOverride(System.Windows.Size finalSize)
{
int firstInLine = ;
int lineCount = ; Size currentLineSize = new Size(); double accumulatedHeight = ; UIElementCollection elements = base.InternalChildren;
double interval = 0.0;
for (int i = ; i < elements.Count; i++)
{ Size desiredSize = elements[i].DesiredSize; if (currentLineSize.Width + desiredSize.Width > finalSize.Width) //need to switch to another line
{
interval = (finalSize.Width - currentLineSize.Width) / (i - firstInLine + );
arrangeLine(accumulatedHeight, currentLineSize.Height, firstInLine, i, interval); accumulatedHeight += currentLineSize.Height;
currentLineSize = desiredSize; if (desiredSize.Width > finalSize.Width) //the element is wider then the constraint - give it a separate line
{
arrangeLine(accumulatedHeight, desiredSize.Height, i, ++i, );
accumulatedHeight += desiredSize.Height;
currentLineSize = new Size();
}
firstInLine = i;
lineCount++;
}
else //continue to accumulate a line
{
currentLineSize.Width += desiredSize.Width;
currentLineSize.Height = Math.Max(desiredSize.Height, currentLineSize.Height);
}
} if (firstInLine < elements.Count)
{
if (lineCount == )
{
interval = (finalSize.Width - currentLineSize.Width) / (elements.Count - firstInLine + );
}
arrangeLine(accumulatedHeight, currentLineSize.Height, firstInLine, elements.Count, interval);
} return finalSize;
} private void arrangeLine(double y, double lineHeight, int start, int end, double interval)
{
double x = ;
UIElementCollection children = InternalChildren;
for (int i = start; i < end; i++)
{
x += interval;
UIElement child = children[i];
child.Arrange(new Rect(x, y, child.DesiredSize.Width, lineHeight));
x += child.DesiredSize.Width;
}
}
}
}

接下来,便是将这个MyWrapPanel作为ListBox的ItemsPanelTemplate即可:

 <Window x:Class="WpfDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:comm="clr-namespace:WpfDemo.CommonControls;assembly=WpfDemo.CommonControls"
xmlns:local="clr-namespace:WpfDemo"
Title="MainWindow" Height="" Width=""> <Grid>
<ListBox ItemsSource="{Binding DataSource}" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
VerticalAlignment="Center" BorderThickness="">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<local:MyWrapPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Green" BorderBrush="Yellow" BorderThickness="">
<TextBlock Text="{Binding CameraName}" Width="" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.Style>
<Style TargetType="{x:Type ListBox}"> </Style>
</ListBox.Style>
</ListBox>
</Grid>
</Window>

界面对应的ViewModel:

 using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Threading; namespace WpfDemo
{
public class MainWindowVM : NotifyPropertyBase
{
private DispatcherTimer timer;
public MainWindowVM()
{
DataSource = new ObservableCollection<WndViewModel>();
Colums = ;
for(int i =; i < ; ++i)
{
var temp = new WndViewModel()
{
CameraName = string.Format("Camera {0}", ++count),
};
DataSource.Add(temp);
}
//timer = new DispatcherTimer();
//timer.Interval = new TimeSpan(0, 0, 1);
//timer.Tick += timer_Tick;
//timer.Start();
} private int count = ;
void timer_Tick(object sender, EventArgs e)
{
var temp = new WndViewModel()
{
CameraName = string.Format("Camera {0}", ++count),
};
DataSource.Add(temp);
Console.WriteLine(temp.CameraName);
if (count <= )
{
Colums = count;
}
else if (count > )
{
count = ;
DataSource.Clear();
Colums = ;
}
} private int colums;
public int Colums
{
get { return colums; }
set
{
SetProperty(ref colums, value);
}
} private ObservableCollection<WndViewModel> dataSource;
public ObservableCollection<WndViewModel> DataSource
{
get { return dataSource; }
set
{
SetProperty(ref dataSource, value);
}
}
}
}

运行结果:

拉伸后:

WPF ListBox的进阶使用(二)的更多相关文章

  1. WPF ListBox的进阶使用(一)

    公司项目有个需求,UI界面支持动态平均分割界面,想了想便想到用ListBox来实现,用UniformGrid作为ListBox的ItemsPanelTemplate,通过动态改变UniformGrid ...

  2. WPF 4 DataGrid 控件(进阶篇二)

    原文:WPF 4 DataGrid 控件(进阶篇二)      上一篇<WPF 4 DataGrid 控件(进阶篇一)>中我们通过DataGridTemplateColumn 类自定义编辑 ...

  3. MVVM模式和在WPF中的实现(二)数据绑定

    MVVM模式解析和在WPF中的实现(二) 数据绑定 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在WPF中 ...

  4. 自定义WPF ListBox的选中项样式

    首先介绍一种简单地方法:就是通过自定义SystemColors类的参数来自定义WPF ListBox选择颜色的,SystemColors的HighlightBrushKey和HighlightText ...

  5. Android高手进阶教程(二十八)之---Android ViewPager控件的使用(基于ViewPager的横向相册)!!!

      分类: Android高手进阶 Android基础教程 2012-09-14 18:10 29759人阅读 评论(35) 收藏 举报 android相册layoutobjectclassloade ...

  6. Wireshark入门与进阶系列(二)

    摘自http://blog.csdn.net/howeverpf/article/details/40743705 Wireshark入门与进阶系列(二) “君子生非异也,善假于物也”---荀子 本文 ...

  7. WPF ListBox数据绑定

    本文来源 http://wshoufeng1989.blog.163.com/blog/static/202047033201282911633670/  风随影动的博客 使用数据库AllData , ...

  8. WPF的消息机制(二)- WPF内部的5个窗口之隐藏消息窗口

    目录 WPF的消息机制(一)-让应用程序动起来 WPF的消息机制(二)-WPF内部的5个窗口 (1)隐藏消息窗口 (2)处理激活和关闭的消息的窗口和系统资源通知窗口 (3)用于用户交互的可见窗口 (4 ...

  9. SpringBoot进阶教程(二十九)整合Redis 发布订阅

    SUBSCRIBE, UNSUBSCRIBE 和 PUBLISH 实现了 发布/订阅消息范例,发送者 (publishers) 不用编程就可以向特定的接受者发送消息 (subscribers). Ra ...

随机推荐

  1. 7-性能测试i报告

    性能测试报告概述 1.测试报告是指把测试的过程和结果写成文档:对发现的问题和缺陷进行分析:为纠正软件的存在的质量问题提供依据: 为软件验收和交付打下基础 2.性能测试报告属于软件测试报告的一种,主要针 ...

  2. 【UI测试】--快捷键组合

  3. js--延时消失的菜单--(笔记)

    html:有4个li,li下分别有一个span <script>   window.onload=function(){    var aLi=document.getElementsBy ...

  4. create a plugin for PowerShell ISE

    可参考:Creating Add-ons, Plugins, and Tools for the PowerShell ISE http://www.leeholmes.com/blog/2013/0 ...

  5. [C#.Net]判断文件是否被占用的两种方法

    今天开发产线测试Tool时发现日志文件会几率性的被占用,上网浏览找到最简单的代码(API或者FileStream),在这里抛砖引玉下. 第一种方法:API using System.IO; using ...

  6. c#的装箱和拆箱及值类型和引用类型

    装箱:它允许根据值类型创建一个对象,然后使用对这新对象的一个引用. int i = 5; object o = i; int j = (int)o; 装箱:运行时将在堆上创建一个包含值5的对象(它是一 ...

  7. 在运行bat文件时,报错发生系统错误123,文件名,目录名或卷标语法不正确

    报错:发生系统错误123,文件名,目录名或卷标语法不正确 这个错误就相当于你在dos命令行中输入一个命令,报错“不是内部或外部命令,也不是可运行的程序”.此时你可以在系统环境变量中检查是否配置了这个命 ...

  8. C语言的问题,头文件:keil也许有漏洞

    2018-06-15   16:52:03 ------------------------------------------------------------------------------ ...

  9. i2c触摸屏驱动文件的实现

    转自:http://blog.chinaunix.net/uid-29507718-id-4314013.html Linux下I2C接口触摸屏驱动分析  分类: LINUX linux下触摸屏驱动的 ...

  10. 【王者荣耀之IT大神版】铭文说明

    铭文共分五级: 一级:仅有老师提供的笔记 二级:添加了自己的听课笔记 三级:添加问题+解决方案(常遇到的问题以及自己实践上遇到的问题,排位赛遇到的遗忘点) 四级:熟记铭文与并添加联想学过的知识 五级: ...