WPF/C#:让绘制的图形可以被选中并将信息显示在ListBox中
实现的效果

如果你对此感兴趣,可以接着往下阅读。
实现过程
绘制矩形
比如说我想绘制一个3行4列的表格:
private void Button_Click_DrawRect(object sender, RoutedEventArgs e)
{
int Row = 3;
int Col = 4;
for(int i = 0; i < Row; i++)
{
for(int j = 0; j< Col; j++)
{
// 添加矩形
System.Windows.Shapes.Rectangle rectangle = new System.Windows.Shapes.Rectangle
{
Width = 50,
Height = 50,
Stroke = System.Windows.Media.Brushes.Blue,
// 设置填充颜色为透明色
Fill = System.Windows.Media.Brushes.Transparent,
StrokeThickness = 1
};
Canvas.SetLeft(rectangle, 80 + 50 * j);
Canvas.SetTop(rectangle, 50 + 50 * i);
myCanvas1.Children.Add(rectangle);
}
}
实现的效果:

现在又想画4行3列的表格了,只需修改这里:
int Row = 4;
int Col = 3;
实现的效果:

为每个单元格添加信息
绘制了单元格之后,我们想要在单元格中添加它所在的行与列的信息。
在绘制矩形后面添加:
// 在矩形内部添加文字
TextBlock textBlock = new TextBlock
{
Text = i + "-" + j,
Foreground = System.Windows.Media.Brushes.Black,
FontSize = 12
};
Canvas.SetLeft(textBlock, 80 + 50 * j + 10);
Canvas.SetTop(textBlock, 50 + 50 * i + 10);
myCanvas1.Children.Add(textBlock);
现在实现的效果如下所示:

让每个单元格可以被选中与取消选中
我们设定鼠标左键点击表示选中,鼠标右键点击表示取消选中,选中之后,单元格边框会变红,取消选中后又恢复原来的颜色。
为每个单元格添加鼠标点击事件处理程序:
// 添加鼠标事件处理器,左键点击表示选中
rectangle.MouseLeftButtonDown += Rectangle_MouseLeftButtonDown;
// 添加鼠标事件处理器,右键点击表示取消选中
rectangle.MouseRightButtonDown += Rectangle_MouseRightButtonDown;
鼠标点击事件处理程序:
// 鼠标事件处理程序,左键点击表示选中
private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
System.Windows.Shapes.Rectangle? rectangle = sender as System.Windows.Shapes.Rectangle;
if (rectangle != null)
{
// 改变矩形的颜色以表示它被选中
rectangle.Stroke = System.Windows.Media.Brushes.Red;
}
}
// 鼠标事件处理器,右键点击表示选中
private void Rectangle_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
System.Windows.Shapes.Rectangle? rectangle = sender as System.Windows.Shapes.Rectangle;
if (rectangle != null)
{
// 改变矩形的颜色以表示它被取消选中
rectangle.Stroke = System.Windows.Media.Brushes.Blue;
}
}
现在查看实现的效果:

将每个单元格与其中的信息对应起来
在这里可以发现每个单元格与其中的信息是一一对应的关系,我们就可以采用字典这种数据结构。
Dictionary<System.Windows.Shapes.Rectangle, string> rectangleText = new Dictionary<System.Windows.Shapes.Rectangle, string>();
// 将单元格与对应的信息存入字典
rectangleText[rectangle] = textBlock.Text;
这样就实现了每个单元格与其中信息的一一对应。
ListBox的使用
首先设计两个类。
public class SelectedRect
{
public string? Name { get; set; }
}
表示选中的单元格,只有一个属性就是它所存储的信息。
public class SelectedRects : ObservableCollection<SelectedRect>
{
}
表示选中的多个单元格,继承自ObservableCollection<SelectedRect>。
ObservableCollection<T>是.NET框架中的一个类,它表示一个动态数据集合,当添加、删除项或者刷新整个列表时,它会提供通知。这对于数据绑定非常有用,因为当集合改变时,UI可以自动更新以反映这些更改。
SelectedRects selectedRects;
public Drawing()
{
InitializeComponent();
this.selectedRects = new SelectedRects();
DataContext = selectedRects;
}
在WPF(Windows Presentation Foundation)中,DataContext是一个非常重要的概念,它是数据绑定的基础。
DataContext是定义在FrameworkElement类中的一个属性,几乎所有的WPF控件都继承自FrameworkElement,因此几乎所有的WPF控件都有DataContext属性。
DataContext属性通常被设置为一个对象,这个对象包含了绑定到界面元素的数据。当你在XAML中创建数据绑定时,绑定表达式会查找DataContext中的属性。
需要注意的是,DataContext是可以继承的,如果一个元素的DataContext没有被显式设置,它将使用其父元素的DataContext。这使得你可以在窗口级别设置DataContext,然后在窗口的所有子元素中使用数据绑定。
在这里我们就是这样设置了窗口的DataContext属性为selectedRects。
现在我们修改点击事件处理程序:
private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
System.Windows.Shapes.Rectangle? rectangle = sender as System.Windows.Shapes.Rectangle;
if (rectangle != null)
{
// 改变矩形的颜色以表示它被选中
rectangle.Stroke = System.Windows.Media.Brushes.Red;
string text = rectangleText[rectangle];
SelectedRect selectedRect = new SelectedRect();
selectedRect.Name = text;
selectedRects.Add(selectedRect);
}
}
private void Rectangle_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
System.Windows.Shapes.Rectangle? rectangle = sender as System.Windows.Shapes.Rectangle;
if (rectangle != null)
{
// 改变矩形的颜色以表示它被取消选中
rectangle.Stroke = System.Windows.Media.Brushes.Blue;
string text = rectangleText[rectangle];
var selectedRect = selectedRects.Where(x => x.Name == text).FirstOrDefault();
if (selectedRect != null)
{
selectedRects.Remove(selectedRect);
}
}
}
在ListBox设置数据绑定:
<ListBox Grid.Column="1" SelectedIndex="0" Margin="10,0,10,0"
ItemsSource="{Binding}">
</ListBox>
现在来看看效果:

我们会发现在ListBox中只会显示类名,并不会显示类中的信息。
这是为什么呢?
因为我们只设置了数据绑定,ListBox知道它的数据来自哪里了,但是我们没有设置数据模板,ListBox不知道该按怎样的方式显示数据。
数据模板的使用
现在我们就来设置一下数据模板,先来介绍一下数据模板。
在WPF(Windows Presentation Foundation)中,数据模板(DataTemplate)是一种定义数据视觉表示的方式。它允许你自定义如何显示绑定到控件的数据。
数据模板非常强大,它可以包含任何类型的元素,并可以使用复杂的绑定和样式。通过使用数据模板,你可以创建丰富和个性化的UI,而无需在代码中手动创建和管理元素。
现在开始尝试去使用数据模板吧。
在xaml中添加:
<Window.Resources>
<DataTemplate x:Key="MyTemplate">
<TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>
</Window.Resources>
<Window.Resources>:这是一个资源字典,它包含了在整个窗口中都可以使用的资源。在这个例子中,它包含了一个数据模板。
<DataTemplate x:Key="MyTemplate">:这定义了一个数据模板,并给它指定了一个键"MyTemplate"。这个键可以用来在其他地方引用这个模板。
<TextBlock Text="{Binding Path=Name}"/>:这是数据模板的内容。它是一个TextBlock,其Text属性绑定到数据对象的Name属性。{Binding Path=Name}是一个绑定表达式,它告诉WPF查找数据对象中名为Name的属性,并将其值绑定到TextBlock的Text属性。
让ListBox使用这个数据模板:
<ListBox Grid.Column="1" SelectedIndex="0" Margin="10,0,10,0"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource MyTemplate}">
</ListBox>
现在再来看一下效果:

发现可以正常显示数据了,但是还有一个问题,就是会重复添加,最后解决这个问题就好了!
修改鼠标左键点击事件处理程序:
// 鼠标事件处理器,左键点击表示选中
private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
System.Windows.Shapes.Rectangle? rectangle = sender as System.Windows.Shapes.Rectangle;
if (rectangle != null)
{
// 改变矩形的颜色以表示它被选中
rectangle.Stroke = System.Windows.Media.Brushes.Red;
string text = rectangleText[rectangle];
if (selectedRects.Where(x => x.Name == text).Any())
{
}
else
{
SelectedRect selectedRect = new SelectedRect();
selectedRect.Name = text;
selectedRects.Add(selectedRect);
}
}
}
现在再来看看最后的效果:

全部代码
xaml:
<Window x:Class=""
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local=""
xmlns:hc="https://handyorg.github.io/handycontrol"
mc:Ignorable="d"
Title="Drawing" Height="450" Width="800">
<Window.Resources>
<DataTemplate x:Key="MyTemplate">
<TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>
</Window.Resources>
<StackPanel>
<hc:Row Margin="0,20,0,0">
<hc:Col Span="8">
<Label Content="画矩形"></Label>
</hc:Col>
<hc:Col Span="8">
<Button Style="{StaticResource ButtonPrimary}" Content="开始"
Click="Button_Click_DrawRect"/>
</hc:Col>
<hc:Col Span="8">
<Button Style="{StaticResource ButtonPrimary}" Content="清空"
Click="Button_Click_Clear"/>
</hc:Col>
</hc:Row>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Canvas Grid.Column="0" Background="Azure" x:Name="myCanvas1" Height="400">
<!-- 在这里添加你的元素 -->
</Canvas>
<ListBox Grid.Column="1" SelectedIndex="0" Margin="10,0,10,0"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource MyTemplate}">
</ListBox>
</Grid>
</StackPanel>
</Window>
cs:
namespace xxx
{
/// <summary>
/// Drawing.xaml 的交互逻辑
/// </summary>
public partial class Drawing : System.Windows.Window
{
Dictionary<System.Windows.Shapes.Rectangle, string> rectangleText = new Dictionary<System.Windows.Shapes.Rectangle, string>();
SelectedRects selectedRects;
public Drawing()
{
InitializeComponent();
this.selectedRects = new SelectedRects();
DataContext = selectedRects;
}
private void Button_Click_DrawRect(object sender, RoutedEventArgs e)
{
int Row = 4;
int Col = 3;
for(int i = 0; i < Row; i++)
{
for(int j = 0; j< Col; j++)
{
// 添加矩形
System.Windows.Shapes.Rectangle rectangle = new System.Windows.Shapes.Rectangle
{
Width = 50,
Height = 50,
Stroke = System.Windows.Media.Brushes.Blue,
// 设置填充颜色为透明色
Fill = System.Windows.Media.Brushes.Transparent,
StrokeThickness = 1
};
// 添加鼠标事件处理器,左键点击表示选中
rectangle.MouseLeftButtonDown += Rectangle_MouseLeftButtonDown;
// 添加鼠标事件处理器,右键点击表示取消选中
rectangle.MouseRightButtonDown += Rectangle_MouseRightButtonDown;
Canvas.SetLeft(rectangle, 80 + 50 * j);
Canvas.SetTop(rectangle, 50 + 50 * i);
myCanvas1.Children.Add(rectangle);
// 在矩形内部添加文字
TextBlock textBlock = new TextBlock
{
Text = i + "-" + j,
Foreground = System.Windows.Media.Brushes.Black,
FontSize = 12
};
Canvas.SetLeft(textBlock, 80 + 50 * j + 10);
Canvas.SetTop(textBlock, 50 + 50 * i + 10);
myCanvas1.Children.Add(textBlock);
// 将单元格与对应的信息存入字典
rectangleText[rectangle] = textBlock.Text;
}
}
}
private void Button_Click_Clear(object sender, RoutedEventArgs e)
{
myCanvas1.Children.Clear();
}
// 鼠标事件处理器,左键点击表示选中
private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
System.Windows.Shapes.Rectangle? rectangle = sender as System.Windows.Shapes.Rectangle;
if (rectangle != null)
{
// 改变矩形的颜色以表示它被选中
rectangle.Stroke = System.Windows.Media.Brushes.Red;
string text = rectangleText[rectangle];
if (selectedRects.Where(x => x.Name == text).Any())
{
}
else
{
SelectedRect selectedRect = new SelectedRect();
selectedRect.Name = text;
selectedRects.Add(selectedRect);
}
}
}
// 鼠标事件处理器,右键点击表示选中
private void Rectangle_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
System.Windows.Shapes.Rectangle? rectangle = sender as System.Windows.Shapes.Rectangle;
if (rectangle != null)
{
// 改变矩形的颜色以表示它被取消选中
rectangle.Stroke = System.Windows.Media.Brushes.Blue;
string text = rectangleText[rectangle];
var selectedRect = selectedRects.Where(x => x.Name == text).FirstOrDefault();
if (selectedRect != null)
{
selectedRects.Remove(selectedRect);
}
}
}
}
}
总结
本文通过一个小示例,跟大家介绍了如何在WPF上绘制矩形,并在其中添加文本,同时也介绍了ListBox的使用,通过数据绑定与数据模板显示我们选中的单元格内的文本信息。希望对与我一样正在学习WPF或者对WPF感兴趣的同学有所帮助。
WPF/C#:让绘制的图形可以被选中并将信息显示在ListBox中的更多相关文章
- WPF 使用 Direct2D1 画图 绘制基本图形
本文来告诉大家如何在 Direct2D1 绘制基本图形,包括线段.矩形.椭圆 本文是一个系列 WPF 使用 Direct2D1 画图入门 WPF 使用 Direct2D1 画图 绘制基本图形 本文的组 ...
- 2018-8-10-WPF-使用-Direct2D1-画图-绘制基本图形
title author date CreateTime categories WPF 使用 Direct2D1 画图 绘制基本图形 lindexi 2018-08-10 19:16:53 +0800 ...
- 2019-10-23-C#-从零开始写-SharpDx-应用-绘制基础图形
title author date CreateTime categories C# 从零开始写 SharpDx 应用 绘制基础图形 lindexi 2019-10-23 21:16:35 +0800 ...
- 学习笔记:HTML5 Canvas绘制简单图形
HTML5 Canvas绘制简单图形 1.添加Canvas标签,添加id供js操作. <canvas id="mycanvas" height="700" ...
- css绘制特殊图形,meida查询,display inline-box间隙问题以及calc()函数
本文同时发表于本人个人网站 www.yaoxiaowen.com 距离上一篇文章已经一个月了,相比于写代码,发现写文章的确是更需要坚持的事情.言归正传,梳理一下这一个月来,在写ife任务时,有必要记录 ...
- 摘记 史上最强大的40多个纯CSS绘制的图形(一)
今天在国外的网站上看到了很多看似简单却又非常强大的纯CSS绘制的图形,里面有最简单的矩形.圆形和三角形,也有各种常见的多边形,甚至是阴阳太极和网站小图标,真的非常强大,分享给大家. Square(正方 ...
- 40多个纯CSS绘制的图形
本文由码农网 – 陈少华原创,转载请看清文末的转载要求. 今天在国外的网站上看到了很多看似简单却又非常强大的纯CSS绘制的图形,里面有最简单的矩形.圆形和三角形,也有各种常见的多边形,甚至是阴阳太极和 ...
- CSS 魔法系列:纯 CSS 绘制各种图形《系列六》
我们的网页因为 CSS 而呈现千变万化的风格.这一看似简单的样式语言在使用中非常灵活,只要你发挥创意就能实现很多比人想象不到的效果.特别是随着 CSS3 的广泛使用,更多新奇的 CSS 作品涌现出来. ...
- CSS 魔法系列:纯 CSS 绘制各种图形《系列五》
我们的网页因为 CSS 而呈现千变万化的风格.这一看似简单的样式语言在使用中非常灵活,只要你发挥创意就能实现很多比人想象不到的效果.特别是随着 CSS3 的广泛使用,更多新奇的 CSS 作品涌现出来. ...
- CSS 魔法系列:纯 CSS 绘制基本图形(圆、椭圆等)
我们的网页因为 CSS 而呈现千变万化的风格.这一看似简单的样式语言在使用中非常灵活,只要你发挥创意就能实现很多比人想象不到的效果.特别是随着 CSS3 的广泛使用,更多新奇的 CSS 作品涌现出来. ...
随机推荐
- ACS 构词法 + 44个后缀 记忆方法
抖音号:九词君-不用语法学好英语
- 关于使用Kotlin开发SpringBoot项目使用@Transactional和@Autowired的报错问题
原文地址: 关于使用Kotlin开发SpringBoot项目使用@Transactional和@Autowired的报错问题 - Stars-One的杂货小窝 问题描述 最近在开发一个订单模块,需要出 ...
- "高绩效"指南
前言 最近被问到一个问题,在工作中,如何拿高绩效.或者换一种表达方式,如何成为老板的"嫡系". 在这里我想简单谈一谈我的想法,可能不准确,各位看官,当饭后茶语罢了. 为了更加有说服 ...
- day04-原生的API&注解方式
原生的API&注解方式 1.MyBatis原生的API调用 1.1原生API快速入门 需求:在前面的项目基础上,使用MyBatis原生的API完成,即直接通过SqlSession接口的方法来完 ...
- 【个人笔记】2023年搭建基于webpack5与typescript的react项目
写在前面 由于我在另外的一些文章所讨论或分析的内容可能基于一个已经初始化好的项目,为了避免每一个文章都重复的描述如何搭建项目,我在本文会统一记录下来,今后相关的文章直接引用文本,方便读者阅读.此文主要 ...
- 记一次 .NET某施工建模软件 卡死分析
一:背景 1. 讲故事 前几天有位朋友在微信上找到我,说他的软件卡死了,分析了下也不知道是咋回事,让我帮忙看一下,很多朋友都知道,我分析dump是免费的,当然也不是所有的dump我都能搞定,也只能尽自 ...
- 初探修模的三维模型OBJ格式轻量化压缩的遇到常见问题与处理方法
初探修模的三维模型OBJ格式轻量化压缩的遇到常见问题与处理方法 在对经过修模的三维模型进行OBJ格式轻量化压缩处理的过程中,可能会遇到一些常见问题.以下是一些常见问题以及相应的处理方法: 1.顶点丢失 ...
- 【LeetCode刷题】69. x 的平方根
69.x的平方根(点击跳转LeetCode) 实现 int sqrt(int x) 函数. 计算并返回 x 的平方根,其中 x 是非负整数. 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去 ...
- 记录--两行CSS让页面提升了近7倍渲染性能!
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 对于前端人员来讲,最令人头疼的应该就是页面性能了,当用户在访问一个页面时,总是希望它能够快速呈现在眼前并且是可交互状态.如果页面加载 ...
- KingbaseES V8R6运维案例之---sys_waldump解析wal日志
案例说明: wal日志文件记录了,事务操作的redo日志信息,由于wal日志文件是二进制文件,无法直接读取其文件内容.sys_waldump 可以解决这个问题,通过sys_waldump来解析wal ...