Commit fe860d03 SK

添加项目文件。

1 个父辈 168c8f99
正在显示 47 个修改的文件 包含 5480 行增加0 行删除
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\OpenCvSharp3-AnyCPU.4.0.0.20181129\build\OpenCvSharp3-AnyCPU.props" Condition="Exists('..\packages\OpenCvSharp3-AnyCPU.4.0.0.20181129\build\OpenCvSharp3-AnyCPU.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{529F3829-BD91-42A7-95AF-9DEA2DC409CB}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>AOI</RootNamespace>
<AssemblyName>AOI</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="OpenCvSharp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp3-AnyCPU.4.0.0.20181129\lib\net40\OpenCvSharp.dll</HintPath>
</Reference>
<Reference Include="OpenCvSharp.Blob, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp3-AnyCPU.4.0.0.20181129\lib\net40\OpenCvSharp.Blob.dll</HintPath>
</Reference>
<Reference Include="OpenCvSharp.Extensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp3-AnyCPU.4.0.0.20181129\lib\net40\OpenCvSharp.Extensions.dll</HintPath>
</Reference>
<Reference Include="OpenCvSharp.UserInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp3-AnyCPU.4.0.0.20181129\lib\net40\OpenCvSharp.UserInterface.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="AoiProject.cs" />
<Compile Include="util\Base64Util.cs" />
<Compile Include="util\ImageUtil.cs" />
<Compile Include="AoiMethod.cs" />
<Compile Include="blob\AoiBlobMethod.cs" />
<Compile Include="mark\AoiMarkMethod.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ResultBean.cs" />
<Compile Include="rgb\AoiMethodRgb.cs" />
<Compile Include="util\JsonUtil.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\OpenCvSharp3-AnyCPU.4.0.0.20181129\build\OpenCvSharp3-AnyCPU.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\OpenCvSharp3-AnyCPU.4.0.0.20181129\build\OpenCvSharp3-AnyCPU.props'))" />
</Target>
</Project>
\ No newline at end of file
using OpenCvSharp;
using OpenCvSharp.Extensions;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AOI
{
public abstract class AoiMethod
{
/// <summary>
/// 兴趣区域路径
/// </summary>
public GraphicsPath RoiPath;
public abstract ResultBean Check(Image standardImage, Image imageToCheck);
/// <summary>
/// 获取单通道的掩模图片
/// </summary>
/// <param name="img"></param>
/// <param name="path"></param>
/// <returns></returns>
public Image GetRoiMask(Image img, GraphicsPath path)
{
if (path != null)
{
var bounds = path.GetBounds();
if (bounds.Width > 0 && bounds.Height > 0)
{
Bitmap mask = new Bitmap(img.Width, img.Height);
using (Graphics g = Graphics.FromImage(mask))
{
var br = new TextureBrush(img);
g.FillPath(br, path);
}
return mask;
}
}
return null;
}
public Image GetRoiImage(Image image, GraphicsPath path, bool needCut)
{
Image maskImg = GetRoiMask(image, path);
if (maskImg != null)
{
var bounds = path.GetBounds();
int resultWidth = (int)bounds.Width;
int resultHeight = (int)bounds.Height;
var srcLocation = bounds.Location;
if (!needCut)
{
//获取带原图位置的大图
resultWidth = image.Width;
resultHeight = image.Height;
srcLocation = PointF.Empty;
}
Bitmap result = new Bitmap(resultWidth, resultHeight);
var dstRect = new RectangleF(0, 0, resultWidth, resultHeight);
var srcRect = new RectangleF(srcLocation.X, srcLocation.Y, resultWidth, resultHeight);
using (Graphics g = Graphics.FromImage(result))
{
g.DrawImage(maskImg, dstRect, srcRect, GraphicsUnit.Pixel);
}
return result;
}
return null;
}
public Image GetRoiImage(Image image, bool needCut)
{
return GetRoiImage(image, RoiPath, needCut);
}
}
}
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
namespace AOI
{
public class AoiProject
{
public AoiProject(Image theImage)
{
this.standardImage = theImage;
}
/// <summary>
/// 标准的Image
/// </summary>
private Image standardImage { get; set; }
/// <summary>
/// 所有的AOI方法
/// </summary>
public Dictionary<string, AoiMethod> methodMap = new Dictionary<string, AoiMethod>();
public List<ResultBean> CheckAll(Image image)
{
//如果设置了校准方法,先校准图片
var markMethodMap = methodMap.Where(kv=>kv.Value is AoiMarkMethod);
foreach (var item in markMethodMap)
{
ResultBean resultBean = item.Value.Check(standardImage, image);
if (resultBean.result)
{
//校准成功
image = resultBean.currentRoiImage;
}
}
List<ResultBean> resultBeans = new List<ResultBean>();
foreach(var item in methodMap)
{
AoiMethod method = item.Value;
if(method is AoiMarkMethod)
{
//校准图片的,忽略
}
else
{
ResultBean resultBean = method.Check(standardImage, image);
resultBean.labelKey = item.Key;
resultBeans.Add(resultBean);
}
}
return resultBeans;
}
public void Save(string filePath)
{
Dictionary<string, string> projectMap = new Dictionary<string, string>();
string base64ImgStr = Base64Util.ToBase64(this.standardImage);
projectMap.Add("base64Img", base64ImgStr);
string methodMapJson = JsonUtil.SerializeObject(this.methodMap);
projectMap.Add("methodMap", methodMapJson);
JsonUtil.SerializeObjectToFile(projectMap,filePath,false);
}
public void Load(string filePath)
{
Dictionary<string, string> projectMap = JsonUtil.DeserializeJsonToObjectFromFile<Dictionary<string, string>>(filePath);
string base64Img = projectMap["base64Img"];
this.standardImage = Base64Util.ToImage(base64Img);
string methodMapJson = projectMap["methodMap"];
this.methodMap = JsonUtil.DeserializeJsonToObject<Dictionary<string, AoiMethod>>(methodMapJson);
}
}
}
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("AOI")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AOI")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("529f3829-bd91-42a7-95af-9dea2dc409cb")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AOI
{
public class ResultBean
{
/// <summary>
/// AOI标识
/// </summary>
public string labelKey;
/// <summary>
/// AOI检测结果,true表示OK, false表示NG
/// </summary>
public bool result = false;
public Image standardRoiImage;
public Image currentRoiImage;
}
}
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
using OpenCvSharp.Blob;
using OpenCvSharp.XFeatures2D;
namespace AOI
{
/// <summary>
/// 斑点分析
/// </summary>
public class AoiBlobMethod : AoiMethod
{
/// <summary>
/// 二值化时的阈值, 小于0表示自动计算阈值,绝对值为用户设定的阈值,大于0表示按用户设置的阈值进行二值化
/// </summary>
public int thresh = -1;
/// <summary>
/// 统计Blob时,使用黑色的或白色的进行统计
/// </summary>
public bool whiteOnBlack = false;
/// <summary>
/// 过滤Blob时的最少像素数
/// </summary>
public int minArea = 0;
/// <summary>
/// 过滤Blob时的最多像素数,小于0表示不限制
/// </summary>
public int maxArea = -1;
/// <summary>
/// 经过过滤后的Blob的 最小数量
/// </summary>
public int minNum = 0;
/// <summary>
/// 经过过滤后的Blob的 最大数量, 小于0表示不限制
/// </summary>
public int maxNum = -1;
public override ResultBean Check(Image standardImage, Image imageToCheck)
{
ResultBean resultBean = new ResultBean();
bool needCut = true;
Image standardRoiImg = GetRoiImage(standardImage, needCut);
resultBean.standardRoiImage = standardRoiImg;
Image currentRoiImg = GetRoiImage(imageToCheck, needCut);
resultBean.currentRoiImage = currentRoiImg;
int num = GetBlobNum(currentRoiImg, out Image dstImg, out List<CvBlob> blobList);
bool result = false;
if (num > minNum)
{
if(maxNum <= 0)
{
result = true;
}
else if(num < maxNum)
{
result = true;
}
}
resultBean.result = result;
return resultBean;
}
/// <summary>
/// 对源图像进行二值化,找出所有Blob后,根据minArea和maxArea过滤Blob后的数量
/// </summary>
/// <param name="srcImg">原始图片</param>
/// <param name="dstImg">二值化后的图片</param>
/// <param name="blobList">所有的Blob</param>
/// <returns>过滤后的Blob数量</returns>
public int GetBlobNum(Image srcImg, out Image dstImg, out List<CvBlob> blobList)
{
Mat srcMat = ImageUtil.ToMat(srcImg);
Mat threshMat = new Mat();
Cv2.CvtColor(srcMat, threshMat, ColorConversionCodes.RGB2GRAY);
ThresholdTypes threshType = ThresholdTypes.Binary;
if (whiteOnBlack)
{
threshType = ThresholdTypes.BinaryInv;
}
if (thresh < 0)
{
threshType = threshType | ThresholdTypes.Otsu;
}
Cv2.Threshold(threshMat, threshMat, thresh, 255, threshType);
CvBlobs blobs = new CvBlobs();
blobs.Label(threshMat);
blobList = blobs.Values.ToList();
dstImg = ImageUtil.ToImage(threshMat);
List<CvBlob> resultBlobs = blobList.Where(b => {
if (b.Area > minArea)
{
if (maxArea <= 0 )
{
return true;
}
else if (b.Area < maxArea)
{
return true;
}
}
return false;
}).ToList();
return resultBlobs.Count;
}
}
}
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
using OpenCvSharp.XFeatures2D;
namespace AOI
{
/// <summary>
/// 从搜索区域中查找Mark区域,对图片进行校准
/// </summary>
public class AoiMarkMethod : AoiMethod
{
/// <summary>
/// 搜索区域路径
/// </summary>
public GraphicsPath SearchPath;
public override ResultBean Check(Image standardImage, Image imageToCheck)
{
ResultBean resultBean = new ResultBean();
resultBean.standardRoiImage = standardImage;
bool needCut = false;
//标准图中的Mart区域
Image markImage = GetRoiImage(standardImage, RoiPath, needCut);
//搜索区域
Image searchImage = GetRoiImage(imageToCheck, SearchPath, needCut);
if (markImage != null && searchImage != null)
{
var affine = GetAffineMat(markImage, searchImage);
if(affine != null)
{
var matToCheck = ImageUtil.ToMat(imageToCheck);
var fixedMat = FixImage(affine, matToCheck);
resultBean.result = true;
resultBean.currentRoiImage = ImageUtil.ToImage(fixedMat);
}
}
return resultBean;
}
/// <summary>
/// 校准图片
/// </summary>
/// <param name="affineMat"></param>
/// <param name="srcMat"></param>
/// <returns></returns>
private Mat FixImage(Mat affineMat, Mat srcMat)
{
Mat resultMat = new Mat();
Cv2.WarpAffine(srcMat, resultMat, affineMat, srcMat.Size());
return resultMat;
}
/// <summary>
/// 获取映射距阵
/// </summary>
/// <param name="markImage"></param>
/// <param name="srcImage"></param>
/// <returns></returns>
private Mat GetAffineMat(Image markImage, Image srcImage)
{
Mat markMat = ImageUtil.ToMat(new Bitmap(markImage));
Mat originalMat = ImageUtil.ToMat(new Bitmap(srcImage));
Mat srcMat = new Mat();
//灰度图转换
Cv2.CvtColor(markMat, markMat, ColorConversionCodes.RGB2GRAY);
Cv2.CvtColor(originalMat, srcMat, ColorConversionCodes.RGB2GRAY);
//提取特征点
SIFT sift = SIFT.Create(200);
KeyPoint[] markKeyPoints, srcKeyPoints;
MatOfFloat roiDescriptors = new MatOfFloat();
MatOfFloat srcDescriptors = new MatOfFloat();
sift.DetectAndCompute(markMat, null, out markKeyPoints, roiDescriptors);
sift.DetectAndCompute(srcMat, null, out srcKeyPoints, srcDescriptors);
var flannMatcher = new FlannBasedMatcher();
DMatch[] matchePoints = flannMatcher.Match(srcDescriptors, roiDescriptors);
//提取强特征点
double minMatch = 1;
double maxMatch = 0;
for (int i = 0; i < matchePoints.Length; i++)
{
double distance = matchePoints[i].Distance;
//匹配值最大最小值获取
if (distance < minMatch)
{
minMatch = distance;
}
if (distance > maxMatch)
{
maxMatch = distance;
}
}
List<DMatch> goodMatchePoints = new List<DMatch>();
for (int i = 0; i < matchePoints.Length; i++)
{
if (matchePoints[i].Distance < minMatch + (maxMatch - minMatch) / 4)
{
goodMatchePoints.Add(matchePoints[i]);
}
}
//获取排在前N个的最优匹配特征点
int num = goodMatchePoints.Count;
if (num >= 3)
{
num = 3;
}
else
{
//不匹配
return null;
}
List<Point2f> markPoints = new List<Point2f>();
List<Point2f> srcPoints = new List<Point2f>();
goodMatchePoints.Sort((left, right) =>
{
if (left.Distance > right.Distance)
return 1;
else if (left.Distance == right.Distance)
return 0;
else
return -1;
});
//Mat matchMat = new Mat();
//Cv2.DrawMatches(srcMat, srcKeyPoints, markMat, roiKeyPoints, goodMatchePoints.Take(num), matchMat);
//Cv2.ImShow("Match", matchMat);
for (int i = 0; i < num; i++)
{
srcPoints.Add(srcKeyPoints[goodMatchePoints[i].QueryIdx].Pt);
markPoints.Add(markKeyPoints[goodMatchePoints[i].TrainIdx].Pt);
}
//获取图像1到图像2的投影映射矩阵 尺寸为3*3
Mat affineMat = Cv2.GetAffineTransform(srcPoints, markPoints);
return affineMat;
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net45" />
<package id="OpenCvSharp3-AnyCPU" version="4.0.0.20181129" targetFramework="net45" />
</packages>
\ No newline at end of file
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AOI.rgb
{
/// <summary>
/// 颜色抽取
/// </summary>
public class AoiMethodRgb : AoiMethod
{
public int minR = 1;
public int maxR = 1;
public int minG = 1;
public int maxG = 255;
public int minB = 255;
public int maxB = 255;
/// <summary>
/// 抽取出的像素最小占比
/// </summary>
public float minRate = 0;
/// <summary>
/// 抽取出的像素最大占比
/// </summary>
public float maxRate = 100;
public override ResultBean Check(Image standardImage, Image imageToCheck)
{
ResultBean resultBean = new ResultBean();
bool needCut = true;
Image standardRoiImg = GetRoiImage(standardImage, needCut);
resultBean.standardRoiImage = standardRoiImg;
Image currentRoiImg = GetRoiImage(imageToCheck, needCut);
resultBean.currentRoiImage = currentRoiImg;
float rate = GetRate(currentRoiImg, out Image dstImg);
bool result = false;
if(rate >= minRate && rate <= maxRate)
{
result = true;
}
resultBean.result = result;
return resultBean;
}
public float GetRate(Image img, out Image dstImg)
{
float percent = 0;
dstImg = null;
bool needCut = true;
Image currentRoiImg = GetRoiImage(img, needCut);
if (currentRoiImg != null)
{
Mat originalRoiMat = ImageUtil.ToMat(currentRoiImg);
Mat roiMat = new Mat();
Cv2.CvtColor(originalRoiMat, roiMat, ColorConversionCodes.BGRA2BGR);
Mat dst = new Mat();
//如果不是矩形可能会把透明像素也计算进去,所以这里最小从1开始
int lowR = minR > 0 ? minR : 1;
int lowG = minG > 0 ? minG : 1;
int lowB = minB > 0 ? minB : 1;
Scalar minScalar = Scalar.FromRgb(lowR, lowG, lowB);
Scalar maxScalar = Scalar.FromRgb(maxR, maxG, maxB);
Cv2.InRange(roiMat, minScalar, maxScalar, dst);
int count = Cv2.CountNonZero(dst);
originalRoiMat.CopyTo(dst, dst);
dstImg = ImageUtil.ToImage(dst);
//计算总像素
minScalar = Scalar.FromRgb(1, 1, 1);
maxScalar = Scalar.FromRgb(255, 255, 255);
Cv2.InRange(roiMat, minScalar, maxScalar, dst);
int totalCount = Cv2.CountNonZero(dst);
percent = count * 100.0f / totalCount;
}
return percent;
}
}
}
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
namespace AOI
{
public class Base64Util
{
/// <summary>
/// 将图片数据转换为Base64字符串
/// </summary>
public static string ToBase64(Image img)
{
if (img == null)
{
return "";
}
BinaryFormatter binFormatter = new BinaryFormatter();
MemoryStream memStream = new MemoryStream();
binFormatter.Serialize(memStream, img);
byte[] bytes = memStream.GetBuffer();
string base64 = Convert.ToBase64String(bytes);
return base64;
}
/// <summary>
/// 将Base64字符串转换为图片
/// </summary>
public static Image ToImage(string base64)
{
if (base64 == null || base64 == "")
{
return null;
}
byte[] bytes = Convert.FromBase64String(base64);
MemoryStream memStream = new MemoryStream(bytes);
BinaryFormatter binFormatter = new BinaryFormatter();
Image img = (Image)binFormatter.Deserialize(memStream);
return img;
}
}
}

using OpenCvSharp;
using OpenCvSharp.Blob;
using OpenCvSharp.Extensions;
using OpenCvSharp.XFeatures2D;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace AOI
{
public class ImageUtil
{
public static Mat ToMat(Image image)
{
return BitmapConverter.ToMat(new Bitmap(image));
}
public static Image ToImage(Mat mat)
{
return BitmapConverter.ToBitmap(mat);
}
}
}
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AOI
{
public class JsonUtil
{
/// <summary>
/// 将对象序列化为JSON格式
/// </summary>
/// <param name="o">对象</param>
/// <returns>json字符串</returns>
public static string SerializeObject(object o)
{
string json = JsonConvert.SerializeObject(o);
return json;
}
/// <summary>
/// 将对象序列化为JSON格式
/// </summary>
/// <param name="o">对象</param>
/// <returns>json字符串</returns>
public static bool SerializeObjectToFile(object o, string filePath, bool backUp)
{
try
{
string json = JsonConvert.SerializeObject(o);
if (File.Exists(filePath))
{
if (backUp)
{
//String Path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
string backUpPath = filePath + "." + DateTime.Now.ToString("yyyyMMddHHmmssfff");
File.Copy(filePath, backUpPath);
}
File.Delete(filePath);
}
File.WriteAllText(filePath, json);
return true;
}
catch (Exception ex)
{
//LogUtil.error("保存文件到[" + filePath + "]失败:" + ex.Message);
}
return false;
}
/// <summary>
/// 解析JSON字符串生成对象实体
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="json">json字符串(eg.{"ID":"112","Name":"石子儿"})</param>
/// <returns>对象实体</returns>
public static T DeserializeJsonToObject<T>(string json) where T : class
{
JsonSerializer serializer = new JsonSerializer();
StringReader sr = new StringReader(json);
object o = serializer.Deserialize(new JsonTextReader(sr), typeof(T));
T t = o as T;
return t;
}
/// <summary>
/// 解析文件到生成对象实体
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="json">json字符串(eg.{"ID":"112","Name":"石子儿"})</param>
/// <returns>对象实体</returns>
public static T DeserializeJsonToObjectFromFile<T>(string filePath) where T : class
{
if (!File.Exists(filePath))
{
//LogUtil.error("加载:文件[" + filePath + "]不存在");
return null;
}
string jsonTxt = File.ReadAllText(filePath);
JsonSerializer serializer = new JsonSerializer();
StringReader sr = new StringReader(jsonTxt);
object o = serializer.Deserialize(new JsonTextReader(sr), typeof(T));
T t = o as T;
return t;
}
/// <summary>
/// 解析JSON数组生成对象实体集合
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="json">json数组字符串(eg.[{"ID":"112","Name":"石子儿"}])</param>
/// <returns>对象实体集合</returns>
public static List<T> DeserializeJsonToList<T>(string json) where T : class
{
JsonSerializer serializer = new JsonSerializer();
StringReader sr = new StringReader(json);
object o = serializer.Deserialize(new JsonTextReader(sr), typeof(List<T>));
List<T> list = o as List<T>;
return list;
}
/// <summary>
/// 解析文件
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="json">json数组字符串(eg.[{"ID":"112","Name":"石子儿"}])</param>
/// <returns>对象实体集合</returns>
public static List<T> DeserializeJsonToListFromFile<T>(string filePath) where T : class
{
if (!File.Exists(filePath))
{
//LogUtil.error("加载:文件[" + filePath + "]不存在");
return new List<T>();
}
string jsonTxt = File.ReadAllText(filePath);
JsonSerializer serializer = new JsonSerializer();
StringReader sr = new StringReader(jsonTxt);
object o = serializer.Deserialize(new JsonTextReader(sr), typeof(List<T>));
List<T> list = o as List<T>;
return list;
}
/// <summary>
/// 反序列化JSON到给定的匿名对象.
/// </summary>
/// <typeparam name="T">匿名对象类型</typeparam>
/// <param name="json">json字符串</param>
/// <param name="anonymousTypeObject">匿名对象</param>
/// <returns>匿名对象</returns>
public static T DeserializeAnonymousType<T>(string json, T anonymousTypeObject)
{
T t = JsonConvert.DeserializeAnonymousType(json, anonymousTypeObject);
return t;
}
}
}

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27703.2035
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AccAOI", "AccAOI\AccAOI.csproj", "{81D116DC-69C9-4B3B-AB7B-E324AF18CA3E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageBox", "ImageBox\ImageBox.csproj", "{DB03ED04-5E06-4FEB-B891-0633448F24EC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AOI", "AOI\AOI.csproj", "{529F3829-BD91-42A7-95AF-9DEA2DC409CB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{81D116DC-69C9-4B3B-AB7B-E324AF18CA3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{81D116DC-69C9-4B3B-AB7B-E324AF18CA3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{81D116DC-69C9-4B3B-AB7B-E324AF18CA3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81D116DC-69C9-4B3B-AB7B-E324AF18CA3E}.Release|Any CPU.Build.0 = Release|Any CPU
{DB03ED04-5E06-4FEB-B891-0633448F24EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DB03ED04-5E06-4FEB-B891-0633448F24EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB03ED04-5E06-4FEB-B891-0633448F24EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB03ED04-5E06-4FEB-B891-0633448F24EC}.Release|Any CPU.Build.0 = Release|Any CPU
{529F3829-BD91-42A7-95AF-9DEA2DC409CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{529F3829-BD91-42A7-95AF-9DEA2DC409CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{529F3829-BD91-42A7-95AF-9DEA2DC409CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{529F3829-BD91-42A7-95AF-9DEA2DC409CB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9483E9C2-E09B-497C-A69A-A8DFF75803C7}
EndGlobalSection
EndGlobal
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{81D116DC-69C9-4B3B-AB7B-E324AF18CA3E}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>AccAOI</RootNamespace>
<AssemblyName>AccAOI</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Form1.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<Compile Include="imageBoxEx\DragHandle.cs" />
<Compile Include="imageBoxEx\DragHandleAnchor.cs" />
<Compile Include="imageBoxEx\DragHandleCollection.cs" />
<Compile Include="imageBoxEx\ImageBoxEx.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AOI\AOI.csproj">
<Project>{529f3829-bd91-42a7-95af-9dea2dc409cb}</Project>
<Name>AOI</Name>
</ProjectReference>
<ProjectReference Include="..\ImageBox\ImageBox.csproj">
<Project>{db03ed04-5e06-4feb-b891-0633448f24ec}</Project>
<Name>ImageBox</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
\ No newline at end of file
namespace AccAOI
{
partial class Form1
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.buttonOpen = new System.Windows.Forms.Button();
this.panel1 = new System.Windows.Forms.Panel();
this.imageBox = new ImageBoxEx();
this.R = new System.Windows.Forms.Label();
this.maxR = new System.Windows.Forms.NumericUpDown();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.minR = new System.Windows.Forms.NumericUpDown();
this.minG = new System.Windows.Forms.NumericUpDown();
this.maxG = new System.Windows.Forms.NumericUpDown();
this.minB = new System.Windows.Forms.NumericUpDown();
this.maxB = new System.Windows.Forms.NumericUpDown();
this.imageBoxEx1 = new ImageBoxEx();
this.labelCount = new System.Windows.Forms.Label();
this.panel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.maxR)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.minR)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.minG)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.maxG)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.minB)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.maxB)).BeginInit();
this.SuspendLayout();
//
// buttonOpen
//
this.buttonOpen.Location = new System.Drawing.Point(12, 12);
this.buttonOpen.Name = "buttonOpen";
this.buttonOpen.Size = new System.Drawing.Size(75, 23);
this.buttonOpen.TabIndex = 1;
this.buttonOpen.Text = "打开";
this.buttonOpen.UseVisualStyleBackColor = true;
this.buttonOpen.Click += new System.EventHandler(this.buttonOpen_Click);
//
// panel1
//
this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panel1.Controls.Add(this.imageBox);
this.panel1.Location = new System.Drawing.Point(12, 50);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(457, 388);
this.panel1.TabIndex = 3;
//
// imageBox
//
this.imageBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.imageBox.DragHandleSize = 9;
this.imageBox.Location = new System.Drawing.Point(0, 0);
this.imageBox.Name = "imageBox";
this.imageBox.SelectionColor = System.Drawing.Color.Empty;
this.imageBox.SelectionMode = Cyotek.Windows.Forms.ImageBoxSelectionMode.Rectangle;
this.imageBox.ShowPixelGrid = true;
this.imageBox.Size = new System.Drawing.Size(457, 388);
this.imageBox.TabIndex = 2;
this.imageBox.Text = "imageBoxEx1";
this.imageBox.Selected += new System.EventHandler<System.EventArgs>(this.imageBox_Selected);
this.imageBox.SelectionRegionChanged += new System.EventHandler(this.imageBox_SelectionRegionChanged);
//
// R
//
this.R.AutoSize = true;
this.R.Location = new System.Drawing.Point(503, 219);
this.R.Name = "R";
this.R.Size = new System.Drawing.Size(11, 12);
this.R.TabIndex = 7;
this.R.Text = "R";
//
// maxR
//
this.maxR.Location = new System.Drawing.Point(614, 215);
this.maxR.Maximum = new decimal(new int[] {
255,
0,
0,
0});
this.maxR.Name = "maxR";
this.maxR.Size = new System.Drawing.Size(52, 21);
this.maxR.TabIndex = 9;
this.maxR.Value = new decimal(new int[] {
255,
0,
0,
0});
this.maxR.ValueChanged += new System.EventHandler(this.maxR_ValueChanged);
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(503, 267);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(11, 12);
this.label1.TabIndex = 10;
this.label1.Text = "G";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(503, 313);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(11, 12);
this.label2.TabIndex = 13;
this.label2.Text = "B";
//
// minR
//
this.minR.Location = new System.Drawing.Point(529, 215);
this.minR.Maximum = new decimal(new int[] {
255,
0,
0,
0});
this.minR.Name = "minR";
this.minR.Size = new System.Drawing.Size(52, 21);
this.minR.TabIndex = 16;
this.minR.ValueChanged += new System.EventHandler(this.minR_ValueChanged);
//
// minG
//
this.minG.Location = new System.Drawing.Point(529, 265);
this.minG.Maximum = new decimal(new int[] {
255,
0,
0,
0});
this.minG.Name = "minG";
this.minG.Size = new System.Drawing.Size(52, 21);
this.minG.TabIndex = 18;
this.minG.ValueChanged += new System.EventHandler(this.minG_ValueChanged);
//
// maxG
//
this.maxG.Location = new System.Drawing.Point(614, 265);
this.maxG.Maximum = new decimal(new int[] {
255,
0,
0,
0});
this.maxG.Name = "maxG";
this.maxG.Size = new System.Drawing.Size(52, 21);
this.maxG.TabIndex = 17;
this.maxG.Value = new decimal(new int[] {
255,
0,
0,
0});
this.maxG.ValueChanged += new System.EventHandler(this.maxG_ValueChanged);
//
// minB
//
this.minB.Location = new System.Drawing.Point(529, 311);
this.minB.Maximum = new decimal(new int[] {
255,
0,
0,
0});
this.minB.Name = "minB";
this.minB.Size = new System.Drawing.Size(52, 21);
this.minB.TabIndex = 20;
this.minB.ValueChanged += new System.EventHandler(this.minB_ValueChanged);
//
// maxB
//
this.maxB.Location = new System.Drawing.Point(614, 311);
this.maxB.Maximum = new decimal(new int[] {
255,
0,
0,
0});
this.maxB.Name = "maxB";
this.maxB.Size = new System.Drawing.Size(52, 21);
this.maxB.TabIndex = 19;
this.maxB.Value = new decimal(new int[] {
255,
0,
0,
0});
this.maxB.ValueChanged += new System.EventHandler(this.maxB_ValueChanged);
//
// imageBoxEx1
//
this.imageBoxEx1.DragHandleSize = 9;
this.imageBoxEx1.Location = new System.Drawing.Point(475, 50);
this.imageBoxEx1.Name = "imageBoxEx1";
this.imageBoxEx1.Size = new System.Drawing.Size(230, 159);
this.imageBoxEx1.TabIndex = 21;
//
// labelCount
//
this.labelCount.AutoSize = true;
this.labelCount.Location = new System.Drawing.Point(540, 376);
this.labelCount.Name = "labelCount";
this.labelCount.Size = new System.Drawing.Size(11, 12);
this.labelCount.TabIndex = 22;
this.labelCount.Text = "0";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(717, 450);
this.Controls.Add(this.labelCount);
this.Controls.Add(this.imageBoxEx1);
this.Controls.Add(this.minB);
this.Controls.Add(this.maxB);
this.Controls.Add(this.minG);
this.Controls.Add(this.maxG);
this.Controls.Add(this.minR);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.maxR);
this.Controls.Add(this.R);
this.Controls.Add(this.panel1);
this.Controls.Add(this.buttonOpen);
this.Name = "Form1";
this.Text = "Form1";
this.panel1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.maxR)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.minR)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.minG)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.maxG)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.minB)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.maxB)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button buttonOpen;
private ImageBoxEx imageBox;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Label R;
private System.Windows.Forms.NumericUpDown maxR;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.NumericUpDown minR;
private System.Windows.Forms.NumericUpDown minG;
private System.Windows.Forms.NumericUpDown maxG;
private System.Windows.Forms.NumericUpDown minB;
private System.Windows.Forms.NumericUpDown maxB;
private ImageBoxEx imageBoxEx1;
private System.Windows.Forms.Label labelCount;
}
}
using Cyotek.Windows.Forms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AccAOI
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private Image originalImage;
private void buttonOpen_Click(object sender, EventArgs e)
{
using (FileDialog dialog = new OpenFileDialog())
{
dialog.Filter = "All Supported Images (*.bmp;*.dib;*.rle;*.gif;*.jpg;*.png)|*.bmp;*.dib;*.rle;*.gif;*.jpg;*.png|Bitmaps (*.bmp;*.dib;*.rle)|*.bmp;*.dib;*.rle|Graphics Interchange Format (*.gif)|*.gif|Joint Photographic Experts (*.jpg)|*.jpg|Portable Network Graphics (*.png)|*.png|All Files (*.*)|*.*";
dialog.DefaultExt = "png";
if (dialog.ShowDialog(this) == DialogResult.OK)
{
try
{
originalImage = Image.FromFile(dialog.FileName);
imageBox.Image = originalImage;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
private void imageBox_Selected(object sender, EventArgs e)
{
//Image selectImage = imageBox.GetSelectedImage();
//RectangleF region = imageBox.SelectionRegion;
//Image threshImage = ImageUtil.Merge(originalImage, selectImage, region);
//imageBox.Image = threshImage;
}
private void imageBox_SelectionRegionChanged(object sender, EventArgs e)
{
//Image selectImage = imageBox.GetSelectedImage();
//if (selectImage != null)
//{
Matrix translateMatrix = new Matrix();
translateMatrix.Translate(100, 0);
RectangleF region = imageBox.SelectionRegion;
GraphicsPath path = new GraphicsPath();
path.AddEllipse(region);
Image threshImage = CutImage(imageBox.Image, path);
cutImage = threshImage;
imageBoxEx1.Image = threshImage;
}
private Image CutImage(Image src, GraphicsPath path)
{
var bounds = path.GetBounds();
Bitmap b = new Bitmap(src.Width, src.Height);
using (Graphics g = Graphics.FromImage(b))
{
var br = new TextureBrush(src);
g.FillPath(br, path);
}
if(bounds.Width > 0 && bounds.Height > 0)
{
Bitmap result = new Bitmap((int)bounds.Width, (int)bounds.Height);
var srcRect = bounds;
var dstRect = new RectangleF(0, 0, bounds.Width, bounds.Height);
bounds.Location = System.Drawing.Point.Empty;
using (Graphics g = Graphics.FromImage(result))
{
bounds.Location = System.Drawing.Point.Empty;
g.DrawImage(b, dstRect, srcRect, GraphicsUnit.Pixel);
}
return result;
}
return null;
}
Image cutImage;
private void InRangeImage()
{
//Mat src = BitmapConverter.ToMat(new Bitmap(cutImage));
//Cv2.CvtColor(src, src, ColorConversionCodes.BGRA2BGR);
//Mat dst = new Mat();
//Scalar minScalar = Scalar.FromRgb((int)minR.Value, (int)minG.Value, (int)minB.Value);
//Scalar maxScalar = Scalar.FromRgb((int)maxR.Value, (int)maxG.Value, (int)maxB.Value);
//Cv2.InRange(src, minScalar, maxScalar, dst);
//int count = Cv2.CountNonZero(dst);
//labelCount.Text = count + "";
//src.CopyTo(dst, dst);
//imageBoxEx1.Image = BitmapConverter.ToBitmap(dst);
}
private void minR_ValueChanged(object sender, EventArgs e)
{
InRangeImage();
}
private void maxR_ValueChanged(object sender, EventArgs e)
{
InRangeImage();
}
private void minG_ValueChanged(object sender, EventArgs e)
{
InRangeImage();
}
private void maxG_ValueChanged(object sender, EventArgs e)
{
InRangeImage();
}
private void minB_ValueChanged(object sender, EventArgs e)
{
InRangeImage();
}
private void maxB_ValueChanged(object sender, EventArgs e)
{
InRangeImage();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AccAOI
{
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("AccAOI")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AccAOI")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("81d116dc-69c9-4b3b-ab7b-e324af18ca3e")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
// 方法是按如下所示使用“*”: :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: 4.0.30319.42000
//
// 对此文件的更改可能导致不正确的行为,如果
// 重新生成代码,则所做更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace AccAOI.Properties
{
/// <summary>
/// 强类型资源类,用于查找本地化字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// 返回此类使用的缓存 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AccAOI.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 覆盖当前线程的 CurrentUICulture 属性
/// 使用此强类型的资源类的资源查找。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
\ No newline at end of file
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace AccAOI.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
using System.Drawing;
namespace AccAOI
{
// Cyotek ImageBox
// Copyright (c) 2010-2014 Cyotek.
// http://cyotek.com
// http://cyotek.com/blog/tag/imagebox
// Licensed under the MIT License. See imagebox-license.txt for the full text.
// If you use this control in your applications, attribution, donations or contributions are welcome.
internal class DragHandle
{
#region Public Constructors
public DragHandle(DragHandleAnchor anchor)
: this()
{
this.Anchor = anchor;
}
#endregion
#region Protected Constructors
protected DragHandle()
{
this.Enabled = true;
this.Visible = true;
}
#endregion
#region Public Properties
public DragHandleAnchor Anchor { get; protected set; }
public Rectangle Bounds { get; set; }
public bool Enabled { get; set; }
public bool Visible { get; set; }
#endregion
}
}
namespace AccAOI
{
// Cyotek ImageBox
// Copyright (c) 2010-2014 Cyotek.
// http://cyotek.com
// http://cyotek.com/blog/tag/imagebox
// Licensed under the MIT License. See imagebox-license.txt for the full text.
// If you use this control in your applications, attribution, donations or contributions are welcome.
internal enum DragHandleAnchor
{
None,
TopLeft,
TopCenter,
TopRight,
MiddleLeft,
MiddleCenter,
MiddleRight,
BottomLeft,
BottomCenter,
BottomRight
}
}
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
namespace AccAOI
{
// Cyotek ImageBox
// Copyright (c) 2010-2014 Cyotek.
// http://cyotek.com
// http://cyotek.com/blog/tag/imagebox
// Licensed under the MIT License. See imagebox-license.txt for the full text.
// If you use this control in your applications, attribution, donations or contributions are welcome.
internal class DragHandleCollection : IEnumerable<DragHandle>
{
#region Instance Fields
private readonly IDictionary<DragHandleAnchor, DragHandle> _items;
#endregion
#region Public Constructors
public DragHandleCollection()
{
_items = new Dictionary<DragHandleAnchor, DragHandle>();
_items.Add(DragHandleAnchor.TopLeft, new DragHandle(DragHandleAnchor.TopLeft));
_items.Add(DragHandleAnchor.TopCenter, new DragHandle(DragHandleAnchor.TopCenter));
_items.Add(DragHandleAnchor.TopRight, new DragHandle(DragHandleAnchor.TopRight));
_items.Add(DragHandleAnchor.MiddleLeft, new DragHandle(DragHandleAnchor.MiddleLeft));
_items.Add(DragHandleAnchor.MiddleRight, new DragHandle(DragHandleAnchor.MiddleRight));
_items.Add(DragHandleAnchor.BottomLeft, new DragHandle(DragHandleAnchor.BottomLeft));
_items.Add(DragHandleAnchor.BottomCenter, new DragHandle(DragHandleAnchor.BottomCenter));
_items.Add(DragHandleAnchor.BottomRight, new DragHandle(DragHandleAnchor.BottomRight));
_items.Add(DragHandleAnchor.MiddleCenter, new DragHandle(DragHandleAnchor.MiddleCenter));
}
#endregion
#region Public Properties
public int Count
{
get { return _items.Count; }
}
public DragHandle this[DragHandleAnchor index]
{
get { return _items[index]; }
}
#endregion
#region Public Members
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
/// </returns>
public IEnumerator<DragHandle> GetEnumerator()
{
return _items.Values.GetEnumerator();
}
public DragHandleAnchor HitTest(Point point)
{
DragHandleAnchor result;
result = DragHandleAnchor.None;
foreach (DragHandle handle in this)
{
if (handle.Visible && handle.Bounds.Contains(point))
{
result = handle.Anchor;
break;
}
}
return result;
}
#endregion
#region IEnumerable<DragHandle> Members
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
/// </returns>
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}
}
using Cyotek.Windows.Forms;
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace AccAOI
{
// Cyotek ImageBox
// Copyright (c) 2010-2014 Cyotek.
// http://cyotek.com
// http://cyotek.com/blog/tag/imagebox
// Licensed under the MIT License. See imagebox-license.txt for the full text.
// If you use this control in your applications, attribution, donations or contributions are welcome.
internal class ImageBoxEx : ImageBox
{
#region Instance Fields
private readonly DragHandleCollection _dragHandles;
private int _dragHandleSize;
private Size _minimumSelectionSize;
#endregion
#region Public Constructors
public ImageBoxEx()
{
_dragHandles = new DragHandleCollection();
this.DragHandleSize = 9;
this.MinimumSelectionSize = Size.Empty;
this.PositionDragHandles();
}
#endregion
#region Events
/// <summary>
/// Occurs when the DragHandleSize property value changes
/// </summary>
[Category("Property Changed")]
public event EventHandler DragHandleSizeChanged;
/// <summary>
/// Occurs when the MinimumSelectionSize property value changes
/// </summary>
[Category("Property Changed")]
public event EventHandler MinimumSelectionSizeChanged;
[Category("Action")]
public event EventHandler SelectionMoved;
[Category("Action")]
public event CancelEventHandler SelectionMoving;
[Category("Action")]
public event EventHandler SelectionResized;
[Category("Action")]
public event CancelEventHandler SelectionResizing;
#endregion
#region Overridden Methods
/// <summary>
/// Raises the <see cref="System.Windows.Forms.Control.MouseDown" /> event.
/// </summary>
/// <param name="e">
/// A <see cref="T:System.Windows.Forms.MouseEventArgs" /> that contains the event data.
/// </param>
protected override void OnMouseDown(MouseEventArgs e)
{
Point imagePoint;
imagePoint = this.PointToImage(e.Location);
if (e.Button == MouseButtons.Left && (this.SelectionRegion.Contains(imagePoint) || this.HitTest(e.Location) != DragHandleAnchor.None))
{
this.DragOrigin = e.Location;
this.DragOriginOffset = new Point(imagePoint.X - (int)this.SelectionRegion.X, imagePoint.Y - (int)this.SelectionRegion.Y);
}
else
{
this.DragOriginOffset = Point.Empty;
this.DragOrigin = Point.Empty;
}
base.OnMouseDown(e);
}
/// <summary>
/// Raises the <see cref="System.Windows.Forms.Control.MouseMove" /> event.
/// </summary>
/// <param name="e">
/// A <see cref="T:System.Windows.Forms.MouseEventArgs" /> that contains the event data.
/// </param>
protected override void OnMouseMove(MouseEventArgs e)
{
// start either a move or a resize operation
if (!this.IsSelecting && !this.IsMoving && !this.IsResizing && e.Button == MouseButtons.Left && !this.DragOrigin.IsEmpty && this.IsOutsideDragZone(e.Location))
{
DragHandleAnchor anchor;
anchor = this.HitTest(this.DragOrigin);
if (anchor == DragHandleAnchor.None)
{
// move
this.StartMove();
}
else if (this.DragHandles[anchor].Enabled && this.DragHandles[anchor].Visible)
{
// resize
this.StartResize(anchor);
}
}
// set the cursor
this.SetCursor(e.Location);
// perform operations
this.ProcessSelectionMove(e.Location);
this.ProcessSelectionResize(e.Location);
base.OnMouseMove(e);
}
/// <summary>
/// Raises the <see cref="System.Windows.Forms.Control.MouseUp" /> event.
/// </summary>
/// <param name="e">
/// A <see cref="T:System.Windows.Forms.MouseEventArgs" /> that contains the event data.
/// </param>
protected override void OnMouseUp(MouseEventArgs e)
{
if (this.IsMoving)
{
this.CompleteMove();
}
else if (this.IsResizing)
{
this.CompleteResize();
}
base.OnMouseUp(e);
}
/// <summary>
/// Raises the <see cref="System.Windows.Forms.Control.Paint" /> event.
/// </summary>
/// <param name="e">
/// A <see cref="T:System.Windows.Forms.PaintEventArgs" /> that contains the event data.
/// </param>
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (this.AllowPainting && !this.SelectionRegion.IsEmpty)
{
foreach (DragHandle handle in this.DragHandles)
{
if (handle.Visible)
{
this.DrawDragHandle(e.Graphics, handle);
}
}
}
}
/// <summary>
/// Raises the <see cref="System.Windows.Forms.Control.Resize" /> event.
/// </summary>
/// <param name="e">
/// An <see cref="T:System.EventArgs" /> that contains the event data.
/// </param>
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
this.PositionDragHandles();
}
/// <summary>
/// Raises the <see cref="System.Windows.Forms.ScrollableControl.Scroll" /> event.
/// </summary>
/// <param name="se">
/// A <see cref="T:System.Windows.Forms.ScrollEventArgs" /> that contains the event data.
/// </param>
protected override void OnScroll(ScrollEventArgs se)
{
base.OnScroll(se);
this.PositionDragHandles();
}
/// <summary>
/// Raises the <see cref="ImageBox.Selecting" /> event.
/// </summary>
/// <param name="e">
/// The <see cref="System.EventArgs" /> instance containing the event data.
/// </param>
protected override void OnSelecting(ImageBoxCancelEventArgs e)
{
e.Cancel = this.IsMoving || this.IsResizing || this.SelectionRegion.Contains(this.PointToImage(e.Location)) || this.HitTest(e.Location) != DragHandleAnchor.None;
base.OnSelecting(e);
}
/// <summary>
/// Raises the <see cref="ImageBox.SelectionRegionChanged" /> event.
/// </summary>
/// <param name="e">
/// The <see cref="System.EventArgs" /> instance containing the event data.
/// </param>
protected override void OnSelectionRegionChanged(EventArgs e)
{
base.OnSelectionRegionChanged(e);
this.PositionDragHandles();
}
/// <summary>
/// Raises the <see cref="ImageBox.ZoomChanged" /> event.
/// </summary>
/// <param name="e">
/// The <see cref="System.EventArgs" /> instance containing the event data.
/// </param>
protected override void OnZoomChanged(EventArgs e)
{
base.OnZoomChanged(e);
this.PositionDragHandles();
}
/// <summary>
/// Processes a dialog key.
/// </summary>
/// <returns>
/// true if the key was processed by the control; otherwise, false.
/// </returns>
/// <param name="keyData">One of the <see cref="T:System.Windows.Forms.Keys"/> values that represents the key to process. </param>
protected override bool ProcessDialogKey(Keys keyData)
{
bool result;
if (keyData == Keys.Escape && (this.IsResizing || this.IsMoving))
{
if (this.IsResizing)
{
this.CancelResize();
}
else
{
this.CancelMove();
}
result = true;
}
else
{
result = base.ProcessDialogKey(keyData);
}
return result;
}
#endregion
#region Public Properties
[Category("Appearance")]
[DefaultValue(8)]
public virtual int DragHandleSize
{
get { return _dragHandleSize; }
set
{
if (this.DragHandleSize != value)
{
_dragHandleSize = value;
this.OnDragHandleSizeChanged(EventArgs.Empty);
}
}
}
[Browsable(false)]
public DragHandleCollection DragHandles
{
get { return _dragHandles; }
}
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool IsMoving { get; protected set; }
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool IsResizing { get; protected set; }
[Category("Behavior")]
[DefaultValue(typeof(Size), "0, 0")]
public virtual Size MinimumSelectionSize
{
get { return _minimumSelectionSize; }
set
{
if (this.MinimumSelectionSize != value)
{
_minimumSelectionSize = value;
this.OnMinimumSelectionSizeChanged(EventArgs.Empty);
}
}
}
[Browsable(false)]
public RectangleF PreviousSelectionRegion { get; protected set; }
#endregion
#region Protected Properties
protected Point DragOrigin { get; set; }
protected Point DragOriginOffset { get; set; }
protected DragHandleAnchor ResizeAnchor { get; set; }
#endregion
#region Public Members
public void CancelResize()
{
this.SelectionRegion = this.PreviousSelectionRegion;
this.CompleteResize();
}
public void StartMove()
{
CancelEventArgs e;
if (this.IsMoving || this.IsResizing)
{
throw new InvalidOperationException("A move or resize action is currently being performed.");
}
e = new CancelEventArgs();
this.OnSelectionMoving(e);
if (!e.Cancel)
{
this.PreviousSelectionRegion = this.SelectionRegion;
this.IsMoving = true;
}
}
#endregion
#region Protected Members
protected virtual void DrawDragHandle(Graphics graphics, DragHandle handle)
{
int left;
int top;
int width;
int height;
Pen outerPen;
Brush innerBrush;
left = handle.Bounds.Left;
top = handle.Bounds.Top;
width = handle.Bounds.Width;
height = handle.Bounds.Height;
if (handle.Enabled)
{
outerPen = SystemPens.WindowFrame;
innerBrush = SystemBrushes.Window;
}
else
{
outerPen = SystemPens.ControlDark;
innerBrush = SystemBrushes.Control;
}
graphics.FillRectangle(innerBrush, left + 1, top + 1, width - 2, height - 2);
graphics.DrawLine(outerPen, left + 1, top, left + width - 2, top);
graphics.DrawLine(outerPen, left, top + 1, left, top + height - 2);
graphics.DrawLine(outerPen, left + 1, top + height - 1, left + width - 2, top + height - 1);
graphics.DrawLine(outerPen, left + width - 1, top + 1, left + width - 1, top + height - 2);
}
/// <summary>
/// Raises the <see cref="DragHandleSizeChanged" /> event.
/// </summary>
/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
protected virtual void OnDragHandleSizeChanged(EventArgs e)
{
EventHandler handler;
this.PositionDragHandles();
this.Invalidate();
handler = this.DragHandleSizeChanged;
if (handler != null)
{
handler(this, e);
}
}
/// <summary>
/// Raises the <see cref="MinimumSelectionSizeChanged" /> event.
/// </summary>
/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
protected virtual void OnMinimumSelectionSizeChanged(EventArgs e)
{
EventHandler handler;
handler = this.MinimumSelectionSizeChanged;
if (handler != null)
{
handler(this, e);
}
}
/// <summary>
/// Raises the <see cref="SelectionMoved" /> event.
/// </summary>
/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
protected virtual void OnSelectionMoved(EventArgs e)
{
EventHandler handler;
handler = this.SelectionMoved;
if (handler != null)
{
handler(this, e);
}
}
/// <summary>
/// Raises the <see cref="SelectionMoving" /> event.
/// </summary>
/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
protected virtual void OnSelectionMoving(CancelEventArgs e)
{
CancelEventHandler handler;
handler = this.SelectionMoving;
if (handler != null)
{
handler(this, e);
}
}
/// <summary>
/// Raises the <see cref="SelectionResized" /> event.
/// </summary>
/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
protected virtual void OnSelectionResized(EventArgs e)
{
EventHandler handler;
handler = this.SelectionResized;
if (handler != null)
{
handler(this, e);
}
}
/// <summary>
/// Raises the <see cref="SelectionResizing" /> event.
/// </summary>
/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
protected virtual void OnSelectionResizing(CancelEventArgs e)
{
CancelEventHandler handler;
handler = this.SelectionResizing;
if (handler != null)
{
handler(this, e);
}
}
#endregion
#region Private Members
private void CancelMove()
{
this.SelectionRegion = this.PreviousSelectionRegion;
this.CompleteMove();
}
private void CompleteMove()
{
this.ResetDrag();
this.OnSelectionMoved(EventArgs.Empty);
}
private void CompleteResize()
{
this.ResetDrag();
this.OnSelectionResized(EventArgs.Empty);
}
private DragHandleAnchor HitTest(Point cursorPosition)
{
return this.DragHandles.HitTest(cursorPosition);
}
private bool IsOutsideDragZone(Point location)
{
Rectangle dragZone;
int dragWidth;
int dragHeight;
dragWidth = SystemInformation.DragSize.Width;
dragHeight = SystemInformation.DragSize.Height;
dragZone = new Rectangle(this.DragOrigin.X - (dragWidth / 2), this.DragOrigin.Y - (dragHeight / 2), dragWidth, dragHeight);
return !dragZone.Contains(location);
}
private void PositionDragHandles()
{
if (this.DragHandles != null && this.DragHandleSize > 0)
{
if (this.SelectionRegion.IsEmpty)
{
foreach (DragHandle handle in this.DragHandles)
{
handle.Bounds = Rectangle.Empty;
}
}
else
{
int left;
int top;
int right;
int bottom;
int halfWidth;
int halfHeight;
int halfDragHandleSize;
Rectangle viewport;
int offsetX;
int offsetY;
viewport = this.GetImageViewPort();
offsetX = viewport.Left + this.Padding.Left + this.AutoScrollPosition.X;
offsetY = viewport.Top + this.Padding.Top + this.AutoScrollPosition.Y;
halfDragHandleSize = this.DragHandleSize / 2;
left = Convert.ToInt32((this.SelectionRegion.Left * this.ZoomFactor) + offsetX);
top = Convert.ToInt32((this.SelectionRegion.Top * this.ZoomFactor) + offsetY);
right = left + Convert.ToInt32(this.SelectionRegion.Width * this.ZoomFactor);
bottom = top + Convert.ToInt32(this.SelectionRegion.Height * this.ZoomFactor);
halfWidth = Convert.ToInt32(this.SelectionRegion.Width * this.ZoomFactor) / 2;
halfHeight = Convert.ToInt32(this.SelectionRegion.Height * this.ZoomFactor) / 2;
this.DragHandles[DragHandleAnchor.TopLeft].Bounds = new Rectangle(left - this.DragHandleSize, top - this.DragHandleSize, this.DragHandleSize, this.DragHandleSize);
this.DragHandles[DragHandleAnchor.TopCenter].Bounds = new Rectangle(left + halfWidth - halfDragHandleSize, top - this.DragHandleSize, this.DragHandleSize, this.DragHandleSize);
this.DragHandles[DragHandleAnchor.TopRight].Bounds = new Rectangle(right, top - this.DragHandleSize, this.DragHandleSize, this.DragHandleSize);
this.DragHandles[DragHandleAnchor.MiddleLeft].Bounds = new Rectangle(left - this.DragHandleSize, top + halfHeight - halfDragHandleSize, this.DragHandleSize, this.DragHandleSize);
this.DragHandles[DragHandleAnchor.MiddleRight].Bounds = new Rectangle(right, top + halfHeight - halfDragHandleSize, this.DragHandleSize, this.DragHandleSize);
this.DragHandles[DragHandleAnchor.BottomLeft].Bounds = new Rectangle(left - this.DragHandleSize, bottom, this.DragHandleSize, this.DragHandleSize);
this.DragHandles[DragHandleAnchor.BottomCenter].Bounds = new Rectangle(left + halfWidth - halfDragHandleSize, bottom, this.DragHandleSize, this.DragHandleSize);
this.DragHandles[DragHandleAnchor.BottomRight].Bounds = new Rectangle(right, bottom, this.DragHandleSize, this.DragHandleSize);
this.DragHandles[DragHandleAnchor.MiddleCenter].Bounds = new Rectangle(left + halfWidth - halfDragHandleSize, top + halfHeight - halfDragHandleSize, this.DragHandleSize, this.DragHandleSize);
}
}
}
private void ProcessSelectionMove(Point cursorPosition)
{
if (this.IsMoving)
{
int x;
int y;
Point imagePoint;
imagePoint = this.PointToImage(cursorPosition, true);
x = Math.Max(0, imagePoint.X - this.DragOriginOffset.X);
if (x + this.SelectionRegion.Width >= this.ViewSize.Width)
{
x = this.ViewSize.Width - (int)this.SelectionRegion.Width;
}
y = Math.Max(0, imagePoint.Y - this.DragOriginOffset.Y);
if (y + this.SelectionRegion.Height >= this.ViewSize.Height)
{
y = this.ViewSize.Height - (int)this.SelectionRegion.Height;
}
this.SelectionRegion = new RectangleF(x, y, this.SelectionRegion.Width, this.SelectionRegion.Height);
}
}
private void ProcessSelectionResize(Point cursorPosition)
{
if (this.IsResizing)
{
Point imagePosition;
float left;
float top;
float right;
float bottom;
bool resizingTopEdge;
bool resizingBottomEdge;
bool resizingLeftEdge;
bool resizingRightEdge;
imagePosition = this.PointToImage(cursorPosition, true);
// get the current selection
left = this.SelectionRegion.Left;
top = this.SelectionRegion.Top;
right = this.SelectionRegion.Right;
bottom = this.SelectionRegion.Bottom;
// decide which edges we're resizing
resizingTopEdge = this.ResizeAnchor >= DragHandleAnchor.TopLeft && this.ResizeAnchor <= DragHandleAnchor.TopRight;
resizingBottomEdge = this.ResizeAnchor >= DragHandleAnchor.BottomLeft && this.ResizeAnchor <= DragHandleAnchor.BottomRight;
resizingLeftEdge = this.ResizeAnchor == DragHandleAnchor.TopLeft || this.ResizeAnchor == DragHandleAnchor.MiddleLeft || this.ResizeAnchor == DragHandleAnchor.BottomLeft;
resizingRightEdge = this.ResizeAnchor == DragHandleAnchor.TopRight || this.ResizeAnchor == DragHandleAnchor.MiddleRight || this.ResizeAnchor == DragHandleAnchor.BottomRight;
// and resize!
if (resizingTopEdge)
{
top = imagePosition.Y;
if (bottom - top < this.MinimumSelectionSize.Height)
{
top = bottom - this.MinimumSelectionSize.Height;
}
}
else if (resizingBottomEdge)
{
bottom = imagePosition.Y;
if (bottom - top < this.MinimumSelectionSize.Height)
{
bottom = top + this.MinimumSelectionSize.Height;
}
}
if (resizingLeftEdge)
{
left = imagePosition.X;
if (right - left < this.MinimumSelectionSize.Width)
{
left = right - this.MinimumSelectionSize.Width;
}
}
else if (resizingRightEdge)
{
right = imagePosition.X;
if (right - left < this.MinimumSelectionSize.Width)
{
right = left + this.MinimumSelectionSize.Width;
}
}
this.SelectionRegion = new RectangleF(left, top, right - left, bottom - top);
}
}
private void ResetDrag()
{
this.IsResizing = false;
this.IsMoving = false;
this.DragOrigin = Point.Empty;
this.DragOriginOffset = Point.Empty;
}
private void SetCursor(Point point)
{
Cursor cursor;
if (this.IsSelecting)
{
cursor = Cursors.Default;
}
else
{
DragHandleAnchor handleAnchor;
handleAnchor = this.IsResizing ? this.ResizeAnchor : this.HitTest(point);
if (handleAnchor != DragHandleAnchor.None && this.DragHandles[handleAnchor].Enabled)
{
switch (handleAnchor)
{
case DragHandleAnchor.TopLeft:
case DragHandleAnchor.BottomRight:
cursor = Cursors.SizeNWSE;
break;
case DragHandleAnchor.TopCenter:
case DragHandleAnchor.BottomCenter:
cursor = Cursors.SizeNS;
break;
case DragHandleAnchor.TopRight:
case DragHandleAnchor.BottomLeft:
cursor = Cursors.SizeNESW;
break;
case DragHandleAnchor.MiddleLeft:
case DragHandleAnchor.MiddleRight:
cursor = Cursors.SizeWE;
break;
case DragHandleAnchor.MiddleCenter:
cursor = Cursors.Cross;
break;
default:
throw new ArgumentOutOfRangeException();
}
}
else if (this.IsMoving || this.SelectionRegion.Contains(this.PointToImage(point)))
{
cursor = Cursors.SizeAll;
}
else
{
cursor = Cursors.Default;
}
}
this.Cursor = cursor;
}
private void StartResize(DragHandleAnchor anchor)
{
CancelEventArgs e;
if (this.IsMoving || this.IsResizing)
{
throw new InvalidOperationException("A move or resize action is currently being performed.");
}
e = new CancelEventArgs();
this.OnSelectionResizing(e);
if (!e.Cancel)
{
this.ResizeAnchor = anchor;
this.PreviousSelectionRegion = this.SelectionRegion;
this.IsResizing = true;
}
}
#endregion
}
}
此文件类型无法预览
此文件的差异太大,无法显示。
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{DB03ED04-5E06-4FEB-B891-0633448F24EC}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ImageBox</RootNamespace>
<AssemblyName>ImageBox</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ImageBox.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="ImageBox\ImageBoxActionSources.cs" />
<Compile Include="ImageBox\ImageBoxBorderStyle.cs" />
<Compile Include="ImageBox\ImageBoxCancelEventArgs.cs" />
<Compile Include="ImageBox\ImageBoxGridDisplayMode.cs" />
<Compile Include="ImageBox\ImageBoxGridScale.cs" />
<Compile Include="ImageBox\ImageBoxNativeMethods.cs" />
<Compile Include="ImageBox\ImageBoxSelectionMode.cs" />
<Compile Include="ImageBox\ImageBoxSizeMode.cs" />
<Compile Include="ImageBox\ImageBoxZoomActions.cs" />
<Compile Include="ImageBox\ImageBoxZoomEventArgs.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ImageBox\ScrollControl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="ImageBox\ScrollProperties.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="ImageBox\VirtualScrollableControl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="ImageBox\ZoomLevelCollection.cs" />
<Compile Include="ImageBox\ZoomLevelCollectionConverter.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="ImageBox.bmp" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
\ No newline at end of file
using System;
namespace Cyotek.Windows.Forms
{
// Cyotek ImageBox
// Copyright (c) 2010-2014 Cyotek.
// http://cyotek.com
// http://cyotek.com/blog/tag/imagebox
// Licensed under the MIT License. See imagebox-license.txt for the full text.
// If you use this control in your applications, attribution, donations or contributions are welcome.
/// <summary>
/// Specifies the source of an action being performed.
/// </summary>
[Flags]
public enum ImageBoxActionSources
{
/// <summary>
/// Unknown source.
/// </summary>
Unknown = 0,
/// <summary>
/// A user initialized the action.
/// </summary>
User = 1
}
}
namespace Cyotek.Windows.Forms
{
// Cyotek ImageBox
// Copyright (c) 2010-2014 Cyotek.
// http://cyotek.com
// http://cyotek.com/blog/tag/imagebox
// Licensed under the MIT License. See imagebox-license.txt for the full text.
// If you use this control in your applications, attribution, donations or contributions are welcome.
/// <summary>
/// Specifies the border styles of an image
/// </summary>
public enum ImageBoxBorderStyle
{
/// <summary>
/// No border.
/// </summary>
None,
/// <summary>
/// A fixed, single-line border.
/// </summary>
FixedSingle,
/// <summary>
/// A fixed, single-line border with a solid drop shadow.
/// </summary>
FixedSingleDropShadow,
/// <summary>
/// A fixed, single-line border with a soft outer glow.
/// </summary>
FixedSingleGlowShadow
}
}
using System.ComponentModel;
using System.Drawing;
namespace Cyotek.Windows.Forms
{
// Cyotek ImageBox
// Copyright (c) 2010-2014 Cyotek.
// http://cyotek.com
// http://cyotek.com/blog/tag/imagebox
// Licensed under the MIT License. See imagebox-license.txt for the full text.
// If you use this control in your applications, attribution, donations or contributions are welcome.
/// <summary>
/// Provides data for a cancelable event.
/// </summary>
public class ImageBoxCancelEventArgs : CancelEventArgs
{
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ImageBoxCancelEventArgs"/> class.
/// </summary>
/// <param name="location">The location of the action being performed.</param>
public ImageBoxCancelEventArgs(Point location)
: this()
{
this.Location = location;
}
#endregion
#region Protected Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ImageBoxCancelEventArgs"/> class.
/// </summary>
protected ImageBoxCancelEventArgs()
{ }
#endregion
#region Public Properties
/// <summary>
/// Gets or sets the location of the action being performed.
/// </summary>
/// <value>The location of the action being performed.</value>
public Point Location { get; protected set; }
#endregion
}
}
namespace Cyotek.Windows.Forms
{
// Cyotek ImageBox
// Copyright (c) 2010-2014 Cyotek.
// http://cyotek.com
// http://cyotek.com/blog/tag/imagebox
// Licensed under the MIT License. See imagebox-license.txt for the full text.
// If you use this control in your applications, attribution, donations or contributions are welcome.
/// <summary>
/// Specifies the display styles for the background texture grid
/// </summary>
public enum ImageBoxGridDisplayMode
{
/// <summary>
/// No background.
/// </summary>
None,
/// <summary>
/// Background is displayed in the control's client area.
/// </summary>
Client,
/// <summary>
/// Background is displayed only in the image region.
/// </summary>
Image
}
}
namespace Cyotek.Windows.Forms
{
// Cyotek ImageBox
// Copyright (c) 2010-2014 Cyotek.
// http://cyotek.com
// http://cyotek.com/blog/tag/imagebox
// Licensed under the MIT License. See imagebox-license.txt for the full text.
// If you use this control in your applications, attribution, donations or contributions are welcome.
/// <summary>
/// Specifies the size of the background texture grid.
/// </summary>
public enum ImageBoxGridScale
{
/// <summary>
/// Displays a solid color
/// </summary>
None,
/// <summary>
/// Half of the default size.
/// </summary>
Tiny,
/// <summary>
/// Default size.
/// </summary>
Small,
/// <summary>
/// 50% increase of default size.
/// </summary>
Medium,
/// <summary>
/// 100% increase of default size.
/// </summary>
Large
}
}
using System;
using System.Runtime.InteropServices;
// ReSharper disable NotAccessedField.Global
// ReSharper disable InconsistentNaming
// ReSharper disable FieldCanBeMadeReadOnly.Global
namespace Cyotek.Windows.Forms
{
// Cyotek ImageBox
// Copyright (c) 2010-2014 Cyotek.
// http://cyotek.com
// http://cyotek.com/blog/tag/imagebox
// Licensed under the MIT License. See imagebox-license.txt for the full text.
// If you use this control in your applications, attribution, donations or contributions are welcome.
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable PartialTypeWithSinglePart
internal partial class NativeMethods // partial for when linking this file into other assemblies
// ReSharper restore PartialTypeWithSinglePart
// ReSharper restore ClassNeverInstantiated.Global
{
#region Enums
[Flags]
public enum SIF
{
SIF_RANGE = 0x0001,
SIF_PAGE = 0x0002,
SIF_POS = 0x0004,
SIF_DISABLENOSCROLL = 0x0008,
SIF_TRACKPOS = 0x0010,
SIF_ALL = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS
}
#endregion
#region Constants
public const int GWL_STYLE = (-16);
public const int SB_BOTH = 3;
public const int SB_BOTTOM = 7;
public const int SB_CTL = 2;
public const int SB_ENDSCROLL = 8;
public const int SB_HORZ = 0;
public const int SB_LEFT = 6;
public const int SB_LINEDOWN = 1;
public const int SB_LINELEFT = 0;
public const int SB_LINERIGHT = 1;
public const int SB_LINEUP = 0;
public const int SB_PAGEDOWN = 3;
public const int SB_PAGELEFT = 2;
public const int SB_PAGERIGHT = 3;
public const int SB_PAGEUP = 2;
public const int SB_RIGHT = 7;
public const int SB_THUMBPOSITION = 4;
public const int SB_THUMBTRACK = 5;
public const int SB_TOP = 6;
public const int SB_VERT = 1;
public const int WM_HSCROLL = 0x00000114;
public const int WM_VSCROLL = 0x00000115;
public const int WS_BORDER = 0x00800000;
public const int WS_EX_CLIENTEDGE = 0x200;
public const int WS_HSCROLL = 0x00100000;
public const int WS_VSCROLL = 0x00200000;
#endregion
#region Private Constructors
private NativeMethods()
{ }
#endregion
#region Class Members
[DllImport("user32.dll", SetLastError = true)]
public static extern int GetScrollInfo(IntPtr hwnd, int bar, [MarshalAs(UnmanagedType.LPStruct)] SCROLLINFO scrollInfo);
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32.dll")]
public static extern int SetScrollInfo(IntPtr hwnd, int bar, [MarshalAs(UnmanagedType.LPStruct)] SCROLLINFO scrollInfo, bool redraw);
[DllImport("user32.dll")]
public static extern int SetWindowLong(IntPtr hwnd, int index, UInt32 newLong);
#endregion
#region Nested Types
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class SCROLLINFO
{
public int cbSize;
public SIF fMask;
public int nMin;
public int nMax;
public int nPage;
public int nPos;
public int nTrackPos;
public SCROLLINFO()
{
cbSize = Marshal.SizeOf(this);
nPage = 0;
nMin = 0;
nMax = 0;
nPos = 0;
nTrackPos = 0;
fMask = 0;
}
}
#endregion
}
// ReSharper restore NotAccessedField.Global
// ReSharper restore FieldCanBeMadeReadOnly.Global
// ReSharper restore InconsistentNaming
}
namespace Cyotek.Windows.Forms
{
// Cyotek ImageBox
// Copyright (c) 2010-2014 Cyotek.
// http://cyotek.com
// http://cyotek.com/blog/tag/imagebox
// Licensed under the MIT License. See imagebox-license.txt for the full text.
// If you use this control in your applications, attribution, donations or contributions are welcome.
/// <summary>
/// Specifies the selection mode.
/// </summary>
public enum ImageBoxSelectionMode
{
/// <summary>
/// No selection.
/// </summary>
None,
/// <summary>
/// Rectangle selection.
/// </summary>
Rectangle,
/// <summary>
/// Zoom selection.
/// </summary>
Zoom
}
}
namespace Cyotek.Windows.Forms
{
// Cyotek ImageBox
// Copyright (c) 2010-2014 Cyotek.
// http://cyotek.com
// http://cyotek.com/blog/tag/imagebox
// Licensed under the MIT License. See imagebox-license.txt for the full text.
// If you use this control in your applications, attribution, donations or contributions are welcome.
/// <summary>
/// Determines the sizing mode of an image hosted in an <see cref="ImageBox" /> control.
/// </summary>
public enum ImageBoxSizeMode
{
/// <summary>
/// The image is disiplayed according to current zoom and scroll properties.
/// </summary>
Normal,
/// <summary>
/// The image is stretched to fill the client area of the control.
/// </summary>
Stretch,
/// <summary>
/// The image is stretched to fill as much of the client area of the control as possible, whilst retaining the same aspect ratio for the width and height.
/// </summary>
Fit
}
}
using System;
namespace Cyotek.Windows.Forms
{
// Cyotek ImageBox
// Copyright (c) 2010-2014 Cyotek.
// http://cyotek.com
// http://cyotek.com/blog/tag/imagebox
// Licensed under the MIT License. See imagebox-license.txt for the full text.
// If you use this control in your applications, attribution, donations or contributions are welcome.
/// <summary>
/// Describes the zoom action occuring
/// </summary>
[Flags]
public enum ImageBoxZoomActions
{
/// <summary>
/// No action.
/// </summary>
None = 0,
/// <summary>
/// The control is increasing the zoom.
/// </summary>
ZoomIn = 1,
/// <summary>
/// The control is decreasing the zoom.
/// </summary>
ZoomOut = 2,
/// <summary>
/// The control zoom was reset.
/// </summary>
ActualSize = 4
}
}
using System;
namespace Cyotek.Windows.Forms
{
// Cyotek ImageBox
// Copyright (c) 2010-2014 Cyotek.
// http://cyotek.com
// http://cyotek.com/blog/tag/imagebox
// Licensed under the MIT License. See imagebox-license.txt for the full text.
// If you use this control in your applications, attribution, donations or contributions are welcome.
/// <summary>
/// Contains event data for the <see cref="ImageBox.ZoomChanged"/> event.
/// </summary>
public class ImageBoxZoomEventArgs : EventArgs
{
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ImageBoxZoomEventArgs"/> class.
/// </summary>
/// <param name="actions">The zoom operation being performed.</param>
/// <param name="source">The source of the operation.</param>
/// <param name="oldZoom">The old zoom level.</param>
/// <param name="newZoom">The new zoom level.</param>
public ImageBoxZoomEventArgs(ImageBoxZoomActions actions, ImageBoxActionSources source, int oldZoom, int newZoom)
: this()
{
this.Actions = actions;
this.Source = source;
this.OldZoom = oldZoom;
this.NewZoom = newZoom;
}
#endregion
#region Protected Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ImageBoxZoomEventArgs"/> class.
/// </summary>
protected ImageBoxZoomEventArgs()
{ }
#endregion
#region Public Properties
/// <summary>
/// Gets or sets the actions that occured.
/// </summary>
/// <value>The zoom operation.</value>
public ImageBoxZoomActions Actions { get; protected set; }
/// <summary>
/// Gets or sets the new zoom level.
/// </summary>
/// <value>The new zoom level.</value>
public int NewZoom { get; protected set; }
/// <summary>
/// Gets or sets the old zoom level.
/// </summary>
/// <value>The old zoom level.</value>
public int OldZoom { get; protected set; }
/// <summary>
/// Gets or sets the source of the operation..
/// </summary>
/// <value>The source.</value>
public ImageBoxActionSources Source { get; protected set; }
#endregion
}
}
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
#if USEWIN32PINVOKELIB
using Cyotek.Win32;
#endif
// Original ScrollControl code by Scott Crawford (http://sukiware.com/)
namespace Cyotek.Windows.Forms
{
/// <summary>
/// Defines a base class for controls that support scrolling behavior.
/// </summary>
[ToolboxItem(false)]
public partial class ScrollControl : Control
{
#region Instance Fields
private bool _alwaysShowHScroll;
private bool _alwaysShowVScroll;
private BorderStyle _borderStyle;
private Size _pageSize;
private Size _scrollSize;
private Size _stepSize;
#endregion
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ScrollControl" /> class.
/// </summary>
public ScrollControl()
{
// ReSharper disable DoNotCallOverridableMethodsInConstructor
this.BorderStyle = BorderStyle.Fixed3D;
this.ScrollSize = Size.Empty;
this.PageSize = Size.Empty;
this.StepSize = new Size(10, 10);
this.HorizontalScroll = new HScrollProperties(this);
this.VerticalScroll = new VScrollProperties(this);
// ReSharper restore DoNotCallOverridableMethodsInConstructor
}
#endregion
#region Events
/// <summary>
/// Occurs when the BorderStyle property value changes
/// </summary>
[Category("Property Changed")]
public event EventHandler BorderStyleChanged;
/// <summary>
/// Occurs when the mouse wheel moves while the control has focus.
/// </summary>
[Browsable(true)]
[EditorBrowsable(EditorBrowsableState.Always)]
[Category("Mouse")]
public new event MouseEventHandler MouseWheel;
/// <summary>
/// Occurs when the PageSize property value changes
/// </summary>
[Category("Property Changed")]
public event EventHandler PageSizeChanged;
/// <summary>
/// Occurs when the user or code scrolls through the client area.
/// </summary>
[Category("Action")]
public event ScrollEventHandler Scroll;
/// <summary>
/// Occurs when the ScrollSize property value changes
/// </summary>
[Category("Property Changed")]
public event EventHandler ScrollSizeChanged;
/// <summary>
/// Occurs when the StepSize property value changes
/// </summary>
[Category("Property Changed")]
public event EventHandler StepSizeChanged;
#endregion
#region Overridden Properties
/// <summary>
/// Gets the required creation parameters when the control handle is created.
/// </summary>
/// <value>The create params.</value>
/// <returns>
/// A <see cref="T:System.Windows.Forms.CreateParams" /> that contains the required creation parameters when the handle to the control is created.
/// </returns>
protected override CreateParams CreateParams
{
get
{
CreateParams createParams;
createParams = base.CreateParams;
switch (_borderStyle)
{
case BorderStyle.FixedSingle:
createParams.Style |= NativeMethods.WS_BORDER;
break;
case BorderStyle.Fixed3D:
createParams.ExStyle |= NativeMethods.WS_EX_CLIENTEDGE;
break;
}
return createParams;
}
}
#endregion
#region Overridden Methods
/// <summary>
/// Raises the <see cref="System.Windows.Forms.Control.EnabledChanged" /> event.
/// </summary>
/// <param name="e">
/// An <see cref="T:System.EventArgs" /> that contains the event data.
/// </param>
protected override void OnEnabledChanged(EventArgs e)
{
base.OnEnabledChanged(e);
this.UpdateScrollbars();
}
/// <summary>
/// Raises the <see cref="System.Windows.Forms.Control.MouseDown" /> event.
/// </summary>
/// <param name="e">
/// A <see cref="T:System.Windows.Forms.MouseEventArgs" /> that contains the event data.
/// </param>
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (!this.Focused)
{
this.Focus();
}
}
/// <summary>
/// Raises the <see cref="System.Windows.Forms.Control.MouseWheel" /> event.
/// </summary>
/// <param name="e">
/// A <see cref="T:System.Windows.Forms.MouseEventArgs" /> that contains the event data.
/// </param>
protected override void OnMouseWheel(MouseEventArgs e)
{
MouseEventHandler handler;
if (this.WheelScrollsControl)
{
int x;
int y;
int delta;
x = this.HorizontalScroll.Value;
y = this.VerticalScroll.Value;
// TODO: Find if we are hovering over a horizontal scrollbar and scroll that instead of the default vertical.
if (this.VerticalScroll.Visible && this.VerticalScroll.Enabled)
{
if (ModifierKeys == Keys.Control)
{
delta = this.VerticalScroll.LargeChange;
}
else
{
delta = SystemInformation.MouseWheelScrollLines * this.VerticalScroll.SmallChange;
}
y += (e.Delta > 0) ? -delta : delta;
}
else if (this.HorizontalScroll.Visible && this.HorizontalScroll.Enabled)
{
if (ModifierKeys == Keys.Control)
{
delta = this.HorizontalScroll.LargeChange;
}
else
{
delta = SystemInformation.MouseWheelScrollLines * this.HorizontalScroll.SmallChange;
}
x += (e.Delta > 0) ? -delta : delta;
}
this.ScrollTo(x, y);
}
handler = this.MouseWheel;
if (handler != null)
{
handler(this, e);
}
base.OnMouseWheel(e);
}
/// <summary>
/// Processes Windows messages.
/// </summary>
/// <param name="msg">
/// The Windows <see cref="T:System.Windows.Forms.Message" /> to process.
/// </param>
[DebuggerStepThrough]
protected override void WndProc(ref Message msg)
{
switch (msg.Msg)
{
case NativeMethods.WM_HSCROLL:
case NativeMethods.WM_VSCROLL:
this.WmScroll(ref msg);
break;
default:
base.WndProc(ref msg);
break;
}
}
#endregion
#region Public Properties
/// <summary>
/// Gets or sets a value indicating whether the horizontal scrollbar should always be displayed, even when not required.
/// </summary>
/// <value>
/// <c>true</c> if the horizontal scrollbar should always be displayed; otherwise, <c>false</c>.
/// </value>
[Category("Layout")]
[DefaultValue(false)]
public bool AlwaysShowHScroll
{
get { return _alwaysShowHScroll; }
set
{
if (_alwaysShowHScroll != value)
{
_alwaysShowHScroll = value;
if (value)
{
NativeMethods.SCROLLINFO scrollInfo;
scrollInfo = new NativeMethods.SCROLLINFO();
scrollInfo.fMask = NativeMethods.SIF.SIF_RANGE | NativeMethods.SIF.SIF_DISABLENOSCROLL;
scrollInfo.nMin = 0;
scrollInfo.nMax = 0;
scrollInfo.nPage = 1;
this.SetScrollInfo(ScrollOrientation.HorizontalScroll, scrollInfo, false);
this.Invalidate();
}
else
{
this.UpdateHorizontalScrollbar();
}
}
}
}
/// <summary>
/// Gets or sets a value indicating whether the vertical scrollbar should always be displayed, even when not required.
/// </summary>
/// <value>
/// <c>true</c> if the vertical scrollbar should always be displayed; otherwise, <c>false</c>.
/// </value>
[Category("Layout")]
[DefaultValue(false)]
public bool AlwaysShowVScroll
{
get { return _alwaysShowVScroll; }
set
{
bool shown = VScroll;
_alwaysShowVScroll = value;
if (_alwaysShowVScroll != shown)
{
if (_alwaysShowVScroll)
{
NativeMethods.SCROLLINFO scrollInfo;
scrollInfo = new NativeMethods.SCROLLINFO();
scrollInfo.fMask = NativeMethods.SIF.SIF_RANGE | NativeMethods.SIF.SIF_DISABLENOSCROLL;
scrollInfo.nMin = 0;
scrollInfo.nMax = 0;
scrollInfo.nPage = 1;
this.SetScrollInfo(ScrollOrientation.VerticalScroll, scrollInfo, false);
this.Invalidate();
}
else
{
this.UpdateVerticalScrollbar();
}
}
}
}
/// <summary>
/// Gets or sets the border style.
/// </summary>
/// <value>The border style.</value>
[Category("Appearance")]
[DefaultValue(typeof(BorderStyle), "Fixed3D")]
public virtual BorderStyle BorderStyle
{
get { return _borderStyle; }
set
{
if (this.BorderStyle != value)
{
_borderStyle = value;
this.OnBorderStyleChanged(EventArgs.Empty);
}
}
}
/// <summary>
/// Gets the horizontal scrollbar properties.
/// </summary>
/// <value>The horizontal scrollbar properties.</value>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
public HScrollProperties HorizontalScroll { get; protected set; }
/// <summary>
/// Gets or sets the size of the scroll pages.
/// </summary>
/// <value>The size of the page.</value>
/// <exception cref="System.ArgumentOutOfRangeException"></exception>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public virtual Size PageSize
{
get { return _pageSize; }
set
{
if (value.Width < 0)
{
throw new ArgumentOutOfRangeException("value", "Width must be a positive integer.");
}
if (value.Height < 0)
{
throw new ArgumentOutOfRangeException("value", "Height must be a positive integer.");
}
if (this.PageSize != value)
{
_pageSize = value;
this.OnPageSizeChanged(EventArgs.Empty);
}
}
}
/// <summary>
/// Gets or sets the size of the scroll area.
/// </summary>
/// <value>The size of the scroll.</value>
/// <exception cref="System.ArgumentOutOfRangeException"></exception>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public virtual Size ScrollSize
{
get { return _scrollSize; }
set
{
if (value.Width < 0)
{
throw new ArgumentOutOfRangeException("value", "Width must be a positive integer.");
}
if (value.Height < 0)
{
throw new ArgumentOutOfRangeException("value", "Height must be a positive integer.");
}
if (this.ScrollSize != value)
{
_scrollSize = value;
this.OnScrollSizeChanged(EventArgs.Empty);
}
}
}
/// <summary>
/// Gets or sets the size of scrollbar stepping.
/// </summary>
/// <value>The size of the step.</value>
/// <exception cref="System.ArgumentOutOfRangeException"></exception>
[Category("Layout")]
[DefaultValue(typeof(Size), "10, 10")]
public virtual Size StepSize
{
get { return _stepSize; }
set
{
if (value.Width < 0)
{
throw new ArgumentOutOfRangeException("value", "Width must be a positive integer.");
}
if (value.Height < 0)
{
throw new ArgumentOutOfRangeException("value", "Height must be a positive integer.");
}
if (this.StepSize != value)
{
_stepSize = value;
this.OnStepSizeChanged(EventArgs.Empty);
}
}
}
/// <summary>
/// Gets the vertical scrollbar properties.
/// </summary>
/// <value>The vertical scrollbar properties.</value>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
public VScrollProperties VerticalScroll { get; protected set; }
#endregion
#region Protected Properties
/// <summary>
/// Gets or sets a value indicating whether the horizontal scrollbar is displayed
/// </summary>
/// <value>
/// <c>true</c> if the horizontal scrollbar is displayed; otherwise, <c>false</c>.
/// </value>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
protected bool HScroll
{
get { return (NativeMethods.GetWindowLong(this.Handle, NativeMethods.GWL_STYLE) & NativeMethods.WS_HSCROLL) == NativeMethods.WS_HSCROLL; }
set
{
uint longValue = NativeMethods.GetWindowLong(this.Handle, NativeMethods.GWL_STYLE);
if (value)
{
longValue |= NativeMethods.WS_HSCROLL;
}
else
{
unchecked
{
longValue &= (uint)~NativeMethods.WS_HSCROLL;
}
}
NativeMethods.SetWindowLong(this.Handle, NativeMethods.GWL_STYLE, longValue);
}
}
/// <summary>
/// Gets or sets a value indicating whether the vertical scrollbar is displayed
/// </summary>
/// <value>
/// <c>true</c> if the vertical scrollbar is displayed; otherwise, <c>false</c>.
/// </value>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
protected bool VScroll
{
get { return (NativeMethods.GetWindowLong(this.Handle, NativeMethods.GWL_STYLE) & NativeMethods.WS_VSCROLL) == NativeMethods.WS_VSCROLL; }
set
{
uint longValue = NativeMethods.GetWindowLong(this.Handle, NativeMethods.GWL_STYLE);
if (value)
{
longValue |= NativeMethods.WS_VSCROLL;
}
else
{
unchecked
{
longValue &= (uint)~NativeMethods.WS_VSCROLL;
}
}
NativeMethods.SetWindowLong(this.Handle, NativeMethods.GWL_STYLE, longValue);
}
}
/// <summary>
/// Gets or sets a value indicating whether the control is scrolled when the mouse wheel is spun
/// </summary>
/// <value>
/// <c>true</c> if the mouse wheel scrolls the control; otherwise, <c>false</c>.
/// </value>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
protected bool WheelScrollsControl { get; set; }
#endregion
#region Public Members
/// <summary>
/// Scrolls both scrollbars to the given values
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
public void ScrollTo(int x, int y)
{
this.ScrollTo(ScrollOrientation.HorizontalScroll, x);
this.ScrollTo(ScrollOrientation.VerticalScroll, y);
}
#endregion
#region Protected Members
/// <summary>
/// Gets the type of scrollbar event.
/// </summary>
/// <param name="wParam">The wparam value from a window proc.</param>
/// <returns></returns>
/// <exception cref="System.ArgumentException"></exception>
protected ScrollEventType GetEventType(IntPtr wParam)
{
switch (wParam.ToInt32() & 0xFFFF)
{
case NativeMethods.SB_BOTTOM:
return ScrollEventType.Last;
case NativeMethods.SB_ENDSCROLL:
return ScrollEventType.EndScroll;
case NativeMethods.SB_LINEDOWN:
return ScrollEventType.SmallIncrement;
case NativeMethods.SB_LINEUP:
return ScrollEventType.SmallDecrement;
case NativeMethods.SB_PAGEDOWN:
return ScrollEventType.LargeIncrement;
case NativeMethods.SB_PAGEUP:
return ScrollEventType.LargeDecrement;
case NativeMethods.SB_THUMBPOSITION:
return ScrollEventType.ThumbPosition;
case NativeMethods.SB_THUMBTRACK:
return ScrollEventType.ThumbTrack;
case NativeMethods.SB_TOP:
return ScrollEventType.First;
default:
throw new ArgumentException(string.Format("{0} isn't a valid scroll event type.", wParam), "wparam");
}
}
/// <summary>
/// Raises the <see cref="BorderStyleChanged" /> event.
/// </summary>
/// <param name="e">
/// The <see cref="EventArgs" /> instance containing the event data.
/// </param>
protected virtual void OnBorderStyleChanged(EventArgs e)
{
EventHandler handler;
base.UpdateStyles();
handler = this.BorderStyleChanged;
if (handler != null)
{
handler(this, e);
}
}
/// <summary>
/// Raises the <see cref="PageSizeChanged" /> event.
/// </summary>
/// <param name="e">
/// The <see cref="EventArgs" /> instance containing the event data.
/// </param>
protected virtual void OnPageSizeChanged(EventArgs e)
{
EventHandler handler;
this.UpdateScrollbars();
handler = this.PageSizeChanged;
if (handler != null)
{
handler(this, e);
}
}
/// <summary>
/// Raises the <see cref="Scroll" /> event.
/// </summary>
/// <param name="e">
/// The <see cref="ScrollEventArgs" /> instance containing the event data.
/// </param>
protected virtual void OnScroll(ScrollEventArgs e)
{
ScrollEventHandler handler;
this.UpdateHorizontalScroll();
this.UpdateVerticalScroll();
handler = this.Scroll;
if (handler != null)
{
handler(this, e);
}
}
/// <summary>
/// Raises the <see cref="ScrollSizeChanged" /> event.
/// </summary>
/// <param name="e">
/// The <see cref="EventArgs" /> instance containing the event data.
/// </param>
protected virtual void OnScrollSizeChanged(EventArgs e)
{
EventHandler handler;
this.UpdateScrollbars();
handler = this.ScrollSizeChanged;
if (handler != null)
{
handler(this, e);
}
}
/// <summary>
/// Raises the <see cref="StepSizeChanged" /> event.
/// </summary>
/// <param name="e">
/// The <see cref="EventArgs" /> instance containing the event data.
/// </param>
protected virtual void OnStepSizeChanged(EventArgs e)
{
EventHandler handler;
handler = this.StepSizeChanged;
if (handler != null)
{
handler(this, e);
}
}
/// <summary>
/// Set the given scrollbar's tracking position to the specified value
/// </summary>
/// <param name="scrollbar">The scrollbar.</param>
/// <param name="value">The value.</param>
protected virtual void ScrollTo(ScrollOrientation scrollbar, int value)
{
NativeMethods.SCROLLINFO oldInfo;
oldInfo = this.GetScrollInfo(scrollbar);
if (value > ((oldInfo.nMax - oldInfo.nMin) + 1) - oldInfo.nPage)
{
value = ((oldInfo.nMax - oldInfo.nMin) + 1) - oldInfo.nPage;
}
if (value < oldInfo.nMin)
{
value = oldInfo.nMin;
}
if (oldInfo.nPos != value)
{
NativeMethods.SCROLLINFO scrollInfo;
scrollInfo = new NativeMethods.SCROLLINFO();
scrollInfo.fMask = NativeMethods.SIF.SIF_POS;
scrollInfo.nPos = value;
this.SetScrollInfo(scrollbar, scrollInfo, true);
this.OnScroll(new ScrollEventArgs(ScrollEventType.ThumbPosition, oldInfo.nPos, value, scrollbar));
}
}
/// <summary>
/// Updates the properties of the horizontal scrollbar.
/// </summary>
protected virtual void UpdateHorizontalScroll()
{
NativeMethods.SCROLLINFO scrollInfo;
scrollInfo = this.GetScrollInfo(ScrollOrientation.HorizontalScroll);
this.HorizontalScroll.Enabled = this.Enabled;
this.HorizontalScroll.LargeChange = scrollInfo.nPage;
this.HorizontalScroll.Maximum = scrollInfo.nMax;
this.HorizontalScroll.Minimum = scrollInfo.nMin;
this.HorizontalScroll.SmallChange = this.StepSize.Width;
this.HorizontalScroll.Value = scrollInfo.nPos;
this.HorizontalScroll.Visible = true;
}
/// <summary>
/// Updates the horizontal scrollbar.
/// </summary>
protected virtual void UpdateHorizontalScrollbar()
{
NativeMethods.SCROLLINFO scrollInfo;
int scrollWidth;
int pageWidth;
scrollWidth = this.ScrollSize.Width - 1;
pageWidth = this.PageSize.Width;
if (scrollWidth < 1)
{
scrollWidth = 0;
pageWidth = 1;
}
scrollInfo = new NativeMethods.SCROLLINFO();
scrollInfo.fMask = NativeMethods.SIF.SIF_PAGE | NativeMethods.SIF.SIF_RANGE;
if (this.AlwaysShowHScroll || !this.Enabled)
{
scrollInfo.fMask |= NativeMethods.SIF.SIF_DISABLENOSCROLL;
}
scrollInfo.nMin = 0;
scrollInfo.nMax = scrollWidth;
scrollInfo.nPage = pageWidth;
this.SetScrollInfo(ScrollOrientation.HorizontalScroll, scrollInfo, true);
}
/// <summary>
/// Updates the scrollbars.
/// </summary>
protected void UpdateScrollbars()
{
this.UpdateHorizontalScrollbar();
this.UpdateVerticalScrollbar();
}
/// <summary>
/// Updates the properties of the vertical scrollbar.
/// </summary>
protected virtual void UpdateVerticalScroll()
{
NativeMethods.SCROLLINFO scrollInfo;
scrollInfo = this.GetScrollInfo(ScrollOrientation.VerticalScroll);
this.VerticalScroll.Enabled = this.Enabled;
this.VerticalScroll.LargeChange = scrollInfo.nPage;
this.VerticalScroll.Maximum = scrollInfo.nMax;
this.VerticalScroll.Minimum = scrollInfo.nMin;
this.VerticalScroll.SmallChange = this.StepSize.Height;
this.VerticalScroll.Value = scrollInfo.nPos;
this.VerticalScroll.Visible = true;
}
/// <summary>
/// Updates the vertical scrollbar.
/// </summary>
protected virtual void UpdateVerticalScrollbar()
{
NativeMethods.SCROLLINFO scrollInfo;
int scrollHeight;
int pageHeight;
scrollHeight = this.ScrollSize.Height - 1;
pageHeight = this.PageSize.Height;
if (scrollHeight < 1)
{
scrollHeight = 0;
pageHeight = 1;
}
scrollInfo = new NativeMethods.SCROLLINFO();
scrollInfo.fMask = NativeMethods.SIF.SIF_PAGE | NativeMethods.SIF.SIF_RANGE;
if (AlwaysShowVScroll)
{
scrollInfo.fMask |= NativeMethods.SIF.SIF_DISABLENOSCROLL;
}
scrollInfo.nMin = 0;
scrollInfo.nMax = scrollHeight;
scrollInfo.nPage = pageHeight;
this.SetScrollInfo(ScrollOrientation.VerticalScroll, scrollInfo, true);
}
/// <summary>
/// Processes the WM_HSCROLL and WM_VSCROLL Windows messages.
/// </summary>
/// <param name="msg">
/// The Windows <see cref="T:System.Windows.Forms.Message" /> to process.
/// </param>
protected virtual void WmScroll(ref Message msg)
{
ScrollOrientation scrollbar;
int oldValue;
int newValue;
ScrollEventType eventType;
eventType = this.GetEventType(msg.WParam);
scrollbar = msg.Msg == NativeMethods.WM_HSCROLL ? ScrollOrientation.HorizontalScroll : ScrollOrientation.VerticalScroll;
if (eventType != ScrollEventType.EndScroll)
{
int step;
NativeMethods.SCROLLINFO scrollInfo;
step = scrollbar == ScrollOrientation.HorizontalScroll ? this.StepSize.Width : this.StepSize.Height;
scrollInfo = this.GetScrollInfo(scrollbar);
scrollInfo.fMask = NativeMethods.SIF.SIF_POS;
oldValue = scrollInfo.nPos;
switch (eventType)
{
case ScrollEventType.ThumbPosition:
case ScrollEventType.ThumbTrack:
scrollInfo.nPos = scrollInfo.nTrackPos;
break;
case ScrollEventType.SmallDecrement:
scrollInfo.nPos = oldValue - step;
break;
case ScrollEventType.SmallIncrement:
scrollInfo.nPos = oldValue + step;
break;
case ScrollEventType.LargeDecrement:
scrollInfo.nPos = oldValue - scrollInfo.nPage;
break;
case ScrollEventType.LargeIncrement:
scrollInfo.nPos = oldValue + scrollInfo.nPage;
break;
case ScrollEventType.First:
scrollInfo.nPos = scrollInfo.nMin;
break;
case ScrollEventType.Last:
scrollInfo.nPos = scrollInfo.nMax;
break;
default:
Debug.Assert(false, string.Format("Unknown scroll event type {0}", eventType));
break;
}
if (scrollInfo.nPos > ((scrollInfo.nMax - scrollInfo.nMin) + 1) - scrollInfo.nPage)
{
scrollInfo.nPos = ((scrollInfo.nMax - scrollInfo.nMin) + 1) - scrollInfo.nPage;
}
if (scrollInfo.nPos < scrollInfo.nMin)
{
scrollInfo.nPos = scrollInfo.nMin;
}
newValue = scrollInfo.nPos;
this.SetScrollInfo(scrollbar, scrollInfo, true);
}
else
{
oldValue = 0;
newValue = 0;
}
this.OnScroll(new ScrollEventArgs(eventType, oldValue, newValue, scrollbar));
}
#endregion
#region Private Members
/// <summary>
/// Gets scrollbar properties
/// </summary>
/// <param name="scrollbar">The bar.</param>
/// <returns></returns>
private NativeMethods.SCROLLINFO GetScrollInfo(ScrollOrientation scrollbar)
{
NativeMethods.SCROLLINFO info;
info = new NativeMethods.SCROLLINFO();
info.fMask = NativeMethods.SIF.SIF_ALL;
NativeMethods.GetScrollInfo(this.Handle, (int)scrollbar, info);
return info;
}
/// <summary>
/// Sets scrollbar properties.
/// </summary>
/// <param name="scrollbar">The scrollbar.</param>
/// <param name="scrollInfo">The scrollbar properties.</param>
/// <param name="refresh">
/// if set to <c>true</c> the scrollbar will be repainted.
/// </param>
/// <returns></returns>
// ReSharper disable UnusedMethodReturnValue.Local
private int SetScrollInfo(ScrollOrientation scrollbar, NativeMethods.SCROLLINFO scrollInfo, bool refresh) // ReSharper restore UnusedMethodReturnValue.Local
{
return NativeMethods.SetScrollInfo(this.Handle, (int)scrollbar, scrollInfo, refresh);
}
#endregion
}
}
using System.ComponentModel;
// Original ScrollControl code by Scott Crawford (http://sukiware.com/)
namespace Cyotek.Windows.Forms
{
partial class ScrollControl
{
#region Nested Types
/// <summary>
/// Provides basic properties for the horizontal scroll bar in a <see cref="ScrollControl"/>.
/// </summary>
public class HScrollProperties : ScrollProperties
{
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ScrollProperties" /> class.
/// </summary>
/// <param name="container">The <see cref="ScrollControl" /> whose scrolling properties this object describes.</param>
public HScrollProperties(ScrollControl container)
: base(container)
{ }
#endregion
}
/// <summary>
/// Encapsulates properties related to scrolling.
/// </summary>
public abstract class ScrollProperties
{
#region Instance Fields
private readonly ScrollControl _container;
#endregion
#region Protected Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ScrollProperties"/> class.
/// </summary>
/// <param name="container">The <see cref="ScrollControl"/> whose scrolling properties this object describes.</param>
protected ScrollProperties(ScrollControl container)
{
//System.Windows.Forms.ScrollProperties
_container = container;
}
#endregion
#region Public Properties
/// <summary>
/// Gets or sets whether the scroll bar can be used on the container.
/// </summary>
/// <value><c>true</c> if the scroll bar can be used; otherwise, <c>false</c>.</value>
[DefaultValue(true)]
public bool Enabled { get; set; }
/// <summary>
/// Gets or sets the distance to move a scroll bar in response to a large scroll command.
/// </summary>
/// <value>An <see cref="int"/> describing how far, in pixels, to move the scroll bar in response to a large change.</value>
[DefaultValue(10)]
public int LargeChange { get; set; }
/// <summary>
/// Gets or sets the upper limit of the scrollable range.
/// </summary>
/// <value>An <see cref="int"/> representing the maximum range of the scroll bar.</value>
[DefaultValue(100)]
public int Maximum { get; set; }
/// <summary>
/// Gets or sets the lower limit of the scrollable range.
/// </summary>
/// <value>An <see cref="int"/> representing the lower range of the scroll bar.</value>
[DefaultValue(0)]
public int Minimum { get; set; }
/// <summary>
/// Gets the control to which this scroll information applies.
/// </summary>
/// <value>A <see cref="ScrollControl"/>.</value>
public ScrollControl ParentControl
{
get { return _container; }
}
/// <summary>
/// Gets or sets the distance to move a scroll bar in response to a small scroll command.
/// </summary>
/// <value>An <see cref="int"/> representing how far, in pixels, to move the scroll bar.</value>
[DefaultValue(1)]
public int SmallChange { get; set; }
/// <summary>
/// Gets or sets a numeric value that represents the current position of the scroll bar box.
/// </summary>
/// <value>An <see cref="int"/> representing the position of the scroll bar box, in pixels. </value>
[Bindable(true)]
[DefaultValue(0)]
public int Value { get; set; }
/// <summary>
/// Gets or sets whether the scroll bar can be seen by the user.
/// </summary>
/// <value><c>true</c> if it can be seen; otherwise, <c>false</c>.</value>
[DefaultValue(false)]
public bool Visible { get; set; }
#endregion
}
/// <summary>
/// Provides basic properties for the vertical scroll bar in a <see cref="ScrollControl"/>.
/// </summary>
public class VScrollProperties : ScrollProperties
{
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ScrollProperties" /> class.
/// </summary>
/// <param name="container">The <see cref="ScrollControl" /> whose scrolling properties this object describes.</param>
public VScrollProperties(ScrollControl container)
: base(container)
{ }
#endregion
}
#endregion
}
}
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
// Original VirtualScrollableControl code by Scott Crawford (http://sukiware.com/)
namespace Cyotek.Windows.Forms
{
/// <summary>
/// Defines a base class for controls that support auto-scrolling behavior.
/// </summary>
[ToolboxItem(false)]
public class VirtualScrollableControl : ScrollControl
{
#region Instance Fields
private bool _autoScroll;
private Size _autoScrollMargin;
private Size _autoScrollMinSize;
private Point _autoScrollPosition;
#endregion
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="VirtualScrollableControl" /> class.
/// </summary>
public VirtualScrollableControl()
{
this.AutoScrollMargin = Size.Empty;
this.AutoScrollMinSize = Size.Empty;
this.AutoScrollPosition = Point.Empty;
this.AutoScroll = true;
base.SetStyle(ControlStyles.ContainerControl, true);
}
#endregion
#region Events
/// <summary>
/// Occurs when the AutoScroll property value changes
/// </summary>
[Category("Property Changed")]
public event EventHandler AutoScrollChanged;
/// <summary>
/// Occurs when the AutoScrollMargin property value changes
/// </summary>
[Category("Property Changed")]
public event EventHandler AutoScrollMarginChanged;
/// <summary>
/// Occurs when the AutoScrollMinSize property value changes
/// </summary>
[Category("Property Changed")]
public event EventHandler AutoScrollMinSizeChanged;
/// <summary>
/// Occurs when the AutoScrollPosition property value changes
/// </summary>
[Category("Property Changed")]
public event EventHandler AutoScrollPositionChanged;
#endregion
#region Overridden Methods
/// <summary>
/// Raises the <see cref="System.Windows.Forms.Control.Resize" /> event.
/// </summary>
/// <param name="e">
/// An <see cref="T:System.EventArgs" /> that contains the event data.
/// </param>
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
this.AdjustScrollbars();
if (this.AutoScroll && !this.AutoScrollPosition.IsEmpty)
{
int xOffset;
int yOffset;
Rectangle scrollArea;
scrollArea = this.ScrollArea;
xOffset = scrollArea.Right - this.DisplayRectangle.Right;
yOffset = scrollArea.Bottom - this.DisplayRectangle.Bottom;
if (this.AutoScrollPosition.Y < 0 && yOffset < 0)
{
yOffset = Math.Max(yOffset, this.AutoScrollPosition.Y);
}
else
{
yOffset = 0;
}
if (this.AutoScrollPosition.X < 0 && xOffset < 0)
{
xOffset = Math.Max(xOffset, this.AutoScrollPosition.X);
}
else
{
xOffset = 0;
}
this.ScrollByOffset(new Size(xOffset, yOffset));
}
}
/// <summary>
/// Raises the <see cref="ScrollControl.Scroll" /> event.
/// </summary>
/// <param name="e">
/// The <see cref="ScrollEventArgs" /> instance containing the event data.
/// </param>
protected override void OnScroll(ScrollEventArgs e)
{
if (e.Type != ScrollEventType.EndScroll)
{
switch (e.ScrollOrientation)
{
case ScrollOrientation.HorizontalScroll:
this.ScrollByOffset(new Size(e.NewValue + this.AutoScrollPosition.X, 0));
break;
case ScrollOrientation.VerticalScroll:
this.ScrollByOffset(new Size(0, e.NewValue + this.AutoScrollPosition.Y));
break;
}
}
base.OnScroll(e);
}
/// <summary>
/// Raises the <see cref="System.Windows.Forms.Control.VisibleChanged" /> event.
/// </summary>
/// <param name="e">
/// An <see cref="T:System.EventArgs" /> that contains the event data.
/// </param>
protected override void OnVisibleChanged(EventArgs e)
{
if (base.Visible)
{
base.PerformLayout();
}
base.OnVisibleChanged(e);
}
#endregion
#region Public Properties
/// <summary>
/// Gets or sets a value indicating whether the container enables the user to scroll to any controls placed outside of its visible boundaries.
/// </summary>
/// <value>
/// <c>true</c> if the container enables auto-scrolling; otherwise, <c>false</c>.
/// </value>
[Category("Layout")]
[DefaultValue(true)]
public virtual bool AutoScroll
{
get { return _autoScroll; }
set
{
if (this.AutoScroll != value)
{
_autoScroll = value;
this.OnAutoScrollChanged(EventArgs.Empty);
}
}
}
/// <summary>
/// Gets or sets the size of the auto-scroll margin.
/// </summary>
/// <value>
/// A <see cref="T:System.Drawing.Size" /> that represents the height and width of the auto-scroll margin in pixels.
/// </value>
/// <exception cref="System.ArgumentOutOfRangeException"></exception>
[Category("Layout")]
[DefaultValue(typeof(Size), "0, 0")]
public virtual Size AutoScrollMargin
{
get { return _autoScrollMargin; }
set
{
if (value.Width < 0)
{
throw new ArgumentOutOfRangeException("value", "Width must be a positive integer.");
}
else if (value.Height < 0)
{
throw new ArgumentOutOfRangeException("value", "Height must be a positive integer.");
}
if (this.AutoScrollMargin != value)
{
_autoScrollMargin = value;
this.OnAutoScrollMarginChanged(EventArgs.Empty);
}
}
}
/// <summary>
/// Gets or sets the minimum size of the auto-scroll.
/// </summary>
/// <value>
/// A <see cref="T:System.Drawing.Size" /> that determines the minimum size of the virtual area through which the user can scroll.
/// </value>
[Category("Layout")]
[DefaultValue(typeof(Size), "0, 0")]
public virtual Size AutoScrollMinSize
{
get { return _autoScrollMinSize; }
set
{
if (this.AutoScrollMinSize != value)
{
_autoScrollMinSize = value;
this.OnAutoScrollMinSizeChanged(EventArgs.Empty);
}
}
}
/// <summary>
/// Gets or sets the location of the auto-scroll position.
/// </summary>
/// <value>
/// A <see cref="T:System.Drawing.Point" /> that represents the auto-scroll position in pixels.
/// </value>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public virtual Point AutoScrollPosition
{
get { return _autoScrollPosition; }
set
{
Point translated;
translated = this.AdjustPositionToSize(new Point(-value.X, -value.Y));
if (this.AutoScrollPosition != translated)
{
this.ScrollByOffset(new Size(_autoScrollPosition.X - translated.X, _autoScrollPosition.Y - translated.Y));
_autoScrollPosition = translated;
this.OnAutoScrollPositionChanged(EventArgs.Empty);
}
}
}
#endregion
#region Protected Properties
/// <summary>
/// Total area of all visible controls which are scrolled with this container
/// </summary>
protected Rectangle ScrollArea
{
get
{
Rectangle area;
area = Rectangle.Empty;
foreach (Control child in Controls)
{
if (child.Visible)
{
area = Rectangle.Union(child.Bounds, area);
}
}
return Rectangle.Union(area, new Rectangle(_autoScrollPosition, _autoScrollMinSize));
}
}
/// <summary>
/// Gets the view port rectangle.
/// </summary>
/// <value>The view port rectangle.</value>
protected Rectangle ViewPortRectangle
{
get { return new Rectangle(-_autoScrollPosition.X, -_autoScrollPosition.Y, this.DisplayRectangle.Width, this.DisplayRectangle.Height); }
}
#endregion
#region Public Members
/// <summary>
/// Scrolls the specified child control into view on an auto-scroll enabled control.
/// </summary>
/// <param name="activeControl">The child control to scroll into view.</param>
public void ScrollControlIntoView(Control activeControl)
{
if (activeControl.Visible && AutoScroll && (HorizontalScroll.Visible || VerticalScroll.Visible))
{
Point position;
position = this.AdjustPositionToSize(new Point(this.AutoScrollPosition.X + activeControl.Left, this.AutoScrollPosition.Y + activeControl.Top));
if (position.X != this.AutoScrollPosition.X || position.Y != this.AutoScrollPosition.Y)
{
this.ScrollByOffset(new Size(this.AutoScrollPosition.X - position.X, this.AutoScrollPosition.Y - position.Y));
}
}
}
#endregion
#region Protected Members
/// <summary>
/// Adjusts the given Point according to the scroll size
/// </summary>
/// <param name="position">The position.</param>
/// <returns></returns>
protected Point AdjustPositionToSize(Point position)
{
int x;
int y;
x = position.X;
y = position.Y;
if (x < -(this.AutoScrollMinSize.Width - this.ClientRectangle.Width))
{
x = -(this.AutoScrollMinSize.Width - this.ClientRectangle.Width);
}
if (y < -(this.AutoScrollMinSize.Height - this.ClientRectangle.Height))
{
y = -(this.AutoScrollMinSize.Height - base.ClientRectangle.Height);
}
if (x > 0)
{
x = 0;
}
if (y > 0)
{
y = 0;
}
return new Point(x, y);
}
/// <summary>
/// Raises the <see cref="AutoScrollChanged" /> event.
/// </summary>
/// <param name="e">
/// The <see cref="EventArgs" /> instance containing the event data.
/// </param>
protected virtual void OnAutoScrollChanged(EventArgs e)
{
EventHandler handler;
handler = this.AutoScrollChanged;
if (handler != null)
{
handler(this, e);
}
}
/// <summary>
/// Raises the <see cref="AutoScrollMarginChanged" /> event.
/// </summary>
/// <param name="e">
/// The <see cref="EventArgs" /> instance containing the event data.
/// </param>
protected virtual void OnAutoScrollMarginChanged(EventArgs e)
{
EventHandler handler;
handler = this.AutoScrollMarginChanged;
if (handler != null)
{
handler(this, e);
}
}
/// <summary>
/// Raises the <see cref="AutoScrollMinSizeChanged" /> event.
/// </summary>
/// <param name="e">
/// The <see cref="EventArgs" /> instance containing the event data.
/// </param>
protected virtual void OnAutoScrollMinSizeChanged(EventArgs e)
{
EventHandler handler;
this.AutoScrollPosition = this.AdjustPositionToSize(this.AutoScrollPosition);
this.AdjustScrollbars();
handler = this.AutoScrollMinSizeChanged;
if (handler != null)
{
handler(this, e);
}
}
/// <summary>
/// Raises the <see cref="AutoScrollPositionChanged" /> event.
/// </summary>
/// <param name="e">
/// The <see cref="EventArgs" /> instance containing the event data.
/// </param>
protected virtual void OnAutoScrollPositionChanged(EventArgs e)
{
EventHandler handler;
handler = this.AutoScrollPositionChanged;
if (handler != null)
{
handler(this, e);
}
}
#endregion
#region Private Members
/// <summary>
/// Adjusts the scrollbars.
/// </summary>
private void AdjustScrollbars()
{
Rectangle clientRectangle;
Size scrollSize;
Size pageSize;
int horzAddition;
int vertAddition;
bool horizontalScrollVisible;
bool verticalScrollVisible;
clientRectangle = this.ClientRectangle;
scrollSize = new Size();
pageSize = new Size();
horzAddition = 0;
vertAddition = 0;
horizontalScrollVisible = false;
verticalScrollVisible = false;
if (this.AutoScroll && (this.AutoScrollMinSize.Height > clientRectangle.Height || this.AutoScrollMinSize.Width > clientRectangle.Width))
{
int i;
for (i = 0; i < 2; i++)
{
if (this.AutoScrollMinSize.Width > (clientRectangle.Width - vertAddition))
{
horizontalScrollVisible = true;
horzAddition = SystemInformation.VerticalScrollBarWidth;
}
if (this.AutoScrollMinSize.Height > (clientRectangle.Height - horzAddition))
{
verticalScrollVisible = true;
vertAddition = SystemInformation.HorizontalScrollBarHeight;
}
}
}
if (verticalScrollVisible)
{
scrollSize.Height = this.AutoScrollMinSize.Height;
if (clientRectangle.Height > horzAddition)
{
pageSize.Height = clientRectangle.Height - horzAddition;
}
}
if (horizontalScrollVisible)
{
scrollSize.Width = this.AutoScrollMinSize.Width;
if (clientRectangle.Width > vertAddition)
{
pageSize.Width = clientRectangle.Width - vertAddition;
}
}
this.ScrollSize = scrollSize;
this.PageSize = pageSize;
}
/// <summary>
/// Scrolls child controls by the given offset
/// </summary>
/// <param name="offset">The offset.</param>
private void ScrollByOffset(Size offset)
{
if (!offset.IsEmpty)
{
this.SuspendLayout();
foreach (Control child in Controls)
{
child.Location -= offset;
}
_autoScrollPosition = new Point(_autoScrollPosition.X - offset.Width, _autoScrollPosition.Y - offset.Height);
this.ScrollTo(-_autoScrollPosition.X, -_autoScrollPosition.Y);
this.ResumeLayout();
this.Invalidate();
}
}
#endregion
};
} ;
using System;
using System.Collections;
using System.Collections.Generic;
namespace Cyotek.Windows.Forms
{
/// <summary>
/// Represents available levels of zoom in an <see cref="ImageBox"/> control
/// </summary>
public class ZoomLevelCollection : IList<int>
{
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ZoomLevelCollection"/> class.
/// </summary>
public ZoomLevelCollection()
{
this.List = new SortedList<int, int>();
}
/// <summary>
/// Initializes a new instance of the <see cref="ZoomLevelCollection"/> class.
/// </summary>
/// <param name="collection">The default values to populate the collection with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the <c>collection</c> parameter is null</exception>
public ZoomLevelCollection(IEnumerable<int> collection)
: this()
{
if (collection == null)
{
throw new ArgumentNullException("collection");
}
this.AddRange(collection);
}
#endregion
#region Class Properties
/// <summary>
/// Returns the default zoom levels
/// </summary>
public static ZoomLevelCollection Default
{
get
{
return new ZoomLevelCollection(new[]
{
7, 10, 15, 20, 25, 30, 50, 70, 100, 150, 200, 300, 400, 500, 600, 700, 800, 1200, 1600
});
}
}
#endregion
#region Public Properties
/// <summary>
/// Gets the number of elements contained in the <see cref="ZoomLevelCollection" />.
/// </summary>
/// <returns>
/// The number of elements contained in the <see cref="ZoomLevelCollection" />.
/// </returns>
public int Count
{
get { return this.List.Count; }
}
/// <summary>
/// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only.
/// </summary>
/// <value><c>true</c> if this instance is read only; otherwise, <c>false</c>.</value>
/// <returns>true if the <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only; otherwise, false.
/// </returns>
public bool IsReadOnly
{
get { return false; }
}
/// <summary>
/// Gets or sets the zoom level at the specified index.
/// </summary>
/// <param name="index">The index.</param>
public int this[int index]
{
get { return this.List.Values[index]; }
set
{
this.List.RemoveAt(index);
this.Add(value);
}
}
#endregion
#region Protected Properties
/// <summary>
/// Gets or sets the backing list.
/// </summary>
protected SortedList<int, int> List { get; set; }
#endregion
#region Public Members
/// <summary>
/// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1" />.
/// </summary>
/// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1" />.</param>
public void Add(int item)
{
this.List.Add(item, item);
}
/// <summary>
/// Adds a range of items to the <see cref="ZoomLevelCollection"/>.
/// </summary>
/// <param name="collection">The items to add to the collection.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the <c>collection</c> parameter is null.</exception>
public void AddRange(IEnumerable<int> collection)
{
if (collection == null)
{
throw new ArgumentNullException("collection");
}
foreach (int value in collection)
{
this.Add(value);
}
}
/// <summary>
/// Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1" />.
/// </summary>
public void Clear()
{
this.List.Clear();
}
/// <summary>
/// Determines whether the <see cref="T:System.Collections.Generic.ICollection`1" /> contains a specific value.
/// </summary>
/// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1" />.</param>
/// <returns>true if <paramref name="item" /> is found in the <see cref="T:System.Collections.Generic.ICollection`1" />; otherwise, false.</returns>
public bool Contains(int item)
{
return this.List.ContainsKey(item);
}
/// <summary>
/// Copies a range of elements this collection into a destination <see cref="Array"/>.
/// </summary>
/// <param name="array">The <see cref="Array"/> that receives the data.</param>
/// <param name="arrayIndex">A 64-bit integer that represents the index in the <see cref="Array"/> at which storing begins.</param>
public void CopyTo(int[] array, int arrayIndex)
{
for (int i = 0; i < this.Count; i++)
{
array[arrayIndex + i] = this.List.Values[i];
}
}
/// <summary>
/// Finds the index of a zoom level matching or nearest to the specified value.
/// </summary>
/// <param name="zoomLevel">The zoom level.</param>
public int FindNearest(int zoomLevel)
{
int nearestValue = this.List.Values[0];
int nearestDifference = Math.Abs(nearestValue - zoomLevel);
for (int i = 1; i < this.Count; i++)
{
int value = this.List.Values[i];
int difference = Math.Abs(value - zoomLevel);
if (difference < nearestDifference)
{
nearestValue = value;
nearestDifference = difference;
}
}
return nearestValue;
}
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>A <see cref="T:System.Collections.Generic.IEnumerator`1" /> that can be used to iterate through the collection.</returns>
public IEnumerator<int> GetEnumerator()
{
return this.List.Values.GetEnumerator();
}
/// <summary>
/// Determines the index of a specific item in the <see cref="T:System.Collections.Generic.IList`1" />.
/// </summary>
/// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.IList`1" />.</param>
/// <returns>The index of <paramref name="item" /> if found in the list; otherwise, -1.</returns>
public int IndexOf(int item)
{
return this.List.IndexOfKey(item);
}
/// <summary>
/// Not implemented.
/// </summary>
/// <param name="index">The index.</param>
/// <param name="item">The item.</param>
/// <exception cref="System.NotImplementedException">Not implemented</exception>
public void Insert(int index, int item)
{
throw new NotImplementedException();
}
/// <summary>
/// Returns the next increased zoom level for the given current zoom.
/// </summary>
/// <param name="zoomLevel">The current zoom level.</param>
/// <returns>The next matching increased zoom level for the given current zoom if applicable, otherwise the nearest zoom.</returns>
public int NextZoom(int zoomLevel)
{
int index;
index = this.IndexOf(this.FindNearest(zoomLevel));
if (index < this.Count - 1)
{
index++;
}
return this[index];
}
/// <summary>
/// Returns the next decreased zoom level for the given current zoom.
/// </summary>
/// <param name="zoomLevel">The current zoom level.</param>
/// <returns>The next matching decreased zoom level for the given current zoom if applicable, otherwise the nearest zoom.</returns>
public int PreviousZoom(int zoomLevel)
{
int index;
index = this.IndexOf(this.FindNearest(zoomLevel));
if (index > 0)
{
index--;
}
return this[index];
}
/// <summary>
/// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1" />.
/// </summary>
/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1" />.</param>
/// <returns>true if <paramref name="item" /> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1" />; otherwise, false. This method also returns false if <paramref name="item" /> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1" />.</returns>
public bool Remove(int item)
{
return this.List.Remove(item);
}
/// <summary>
/// Removes the element at the specified index of the <see cref="ZoomLevelCollection"/>.
/// </summary>
/// <param name="index">The zero-based index of the element to remove.</param>
public void RemoveAt(int index)
{
this.List.RemoveAt(index);
}
/// <summary>
/// Copies the elements of the <see cref="ZoomLevelCollection"/> to a new array.
/// </summary>
/// <returns>An array containing copies of the elements of the <see cref="ZoomLevelCollection"/>.</returns>
public int[] ToArray()
{
int[] results;
results = new int[this.Count];
this.CopyTo(results, 0);
return results;
}
#endregion
#region IList<int> Members
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>An <see cref="ZoomLevelCollection" /> object that can be used to iterate through the collection.</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
namespace Cyotek.Windows.Forms
{
public class ZoomLevelCollectionConverter
: TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return destinationType == typeof(InstanceDescriptor) || base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
string data;
ZoomLevelCollection result;
data = value as string;
if (!string.IsNullOrEmpty(data))
{
char separator;
string[] items;
TypeConverter converter;
if (culture == null)
culture = CultureInfo.CurrentCulture;
result = new ZoomLevelCollection();
separator = culture.TextInfo.ListSeparator[0];
items = data.Split(separator);
converter = TypeDescriptor.GetConverter(typeof(int));
foreach (string item in items)
result.Add((int)converter.ConvertFromString(context, culture, item));
}
else
result = null;
return result;
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
object result;
if (destinationType == null)
throw new ArgumentNullException("destinationType");
if (value is ZoomLevelCollection)
{
if (destinationType == typeof(string))
{
ZoomLevelCollection collection;
StringBuilder data;
string separator;
TypeConverter converter;
collection = (ZoomLevelCollection)value;
if (culture == null)
culture = CultureInfo.CurrentCulture;
separator = culture.TextInfo.ListSeparator + " ";
converter = TypeDescriptor.GetConverter(typeof(int));
data = new StringBuilder();
foreach (int item in collection)
{
if (data.Length != 0)
data.Append(separator);
data.Append(converter.ConvertToString(context, culture, item));
}
result = data.ToString();
}
else if (destinationType == typeof(InstanceDescriptor))
{
ZoomLevelCollection collection;
ConstructorInfo constructor;
collection = (ZoomLevelCollection)value;
constructor = typeof(ZoomLevelCollection).GetConstructor(new Type[] { typeof(IList<int>) });
result = new InstanceDescriptor(constructor, new object[] { collection.ToArray() });
}
else
result = null;
}
else
result = null;
if (result == null)
result = base.ConvertTo(context, culture, value, destinationType);
return result;
}
}
}
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("ImageBox")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ImageBox")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("db03ed04-5e06-4feb-b891-0633448f24ec")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!