需求描述
某个ListView占据整个窗口,当窗口的宽度发生改变时,某一列中显示的、某一行的字符数目,能跟随窗口宽度变化而增减。
下面是我做完的效果:(只展示窗口的一部分)
此时是窗口缩放的极限,不能再小了。
拖动窗口变大后,可以看到字符数目也变多了。
设计思路
首先,因为需要列出多行,选择使用ListView。使用固定宽度的单列(GridViewColumn),并将其宽度设为窗口实际宽度,可以实现占满窗口的效果。每当窗口的尺寸发生变化时,通过监听,可以及时重新绘制ListView。
至于刻度尺,主要是线段的组合。这里我自己写了一个Ruler控件,并增加一个RowBaseCnt属性,用这个属性控制刻度的数目。每次属性值变化时,刻度尺需要重新绘制。
最后,RowBaseCnt的计算用的是总宽度,扣除两侧元件的固定宽度,然后除以单个字符宽度计算而成。如果实现的效果有偏差,可以手动加一个倍数或者调边距。
实现
出于保密原因,这里不会放出完整代码。不完整的部分基本都可以自行补全或自行搜索。实在不懂请在搜索无果后,关注+私信。如果您的提问太简单,恕不回复。
固定宽度的ListView列
参考下面文章,可以直接copy。
https://blog.csdn.net/pxy7896/article/details/113174144
监听窗口尺寸变化
public MainWindow(){
InitializeComponent();
...
this.SizeChanged += new SizeChangedEventHandler(MainWindow_Resize);
}
private void MainWindow_Resize(object sender, SizeChangedEventArgs e){
...
}
刻度尺控件增加一个RowBaseCnt属性
Ruler是之前写过的一个自定义控件,代码就不贴了,xaml的结构大概是:
<UserControl>
<Grid x:Name="x" HorizontalAlignment="Left">
</Grid>
</UserControl>
后台用x.Children.Add(line)的方式绘制。主要是注意循环的边界,控制线条长度等,不再贴代码。需要的私信我留邮箱。
public partial class RowRuler : Ruler {
public static readonly DependencyProperty RowBaseCntProperty =
DependencyProperty.Register(
"RowBaseCnt",
typeof(int),
typeof(RowRuler),
new FrameworkPropertyMetadata(int.MinValue, new PropertyChangedCallback(OnRowBaseCntChanged))
);
private static void OnRowBaseCntChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) {
RowRuler rr = sender as RowRuler;
if (rr != null) {
rr.OnValueChanged(args);
}
}
protected void OnValueChanged(DependencyPropertyChangedEventArgs args) {
this.RowBaseCnt = (int)args.NewValue;
// 这里表示每次修改RowBaseCnt时都重新绘制RowRuler
draw();
}
public int RowBaseCnt
{
get { return (int)GetValue(RowBaseCntProperty); }
set { SetValue(RowBaseCntProperty, value); }
}
public void draw(){
// 这里写具体的绘制代码
}
}
字符宽度计算
public static double MeasureTextWidth(string text, double fontSize, string fontFamily)
{
FormattedText formattedText = new FormattedText(
text,
System.Globalization.CultureInfo.InvariantCulture,
FlowDirection.LeftToRight,
new Typeface(fontFamily.ToString()),
fontSize,
Brushes.Black
);
return formattedText.WidthIncludingTrailingWhitespace;
}
这里为了方便,我直接用了"Courier New"。