开包即食的教程带你浅尝最新开源的C# Web引擎 Blazor

在今年年初,恰逢新春佳节临近的时候. 微软给全球的C#开发者们,着实的送上了一分惊喜. 微软正式开源Blazor ,将.NET带回到浏览器.

这个小惊喜,迅速的在dotnet开发者中间传开了. 而就在昨天(2018年3月22日) Blazor发布了它的第一次Release. Blazor到底是个什么样的东西呢?我们是否真的可以携着C#语言进入前端的市场中? 不如现在就跟我一起体验dotnet blazor吧.

首先

获取最新版的dotnet core 并安装Blazor模板:

  • 安装 最新的.Net Core(版本需要高于2.1.101)
  • 对于简单的尝试来说,VS code 已经足够. 所以笔者并没有亲自安装Visual Studio.

使用命令行初始化项目:

dotnet new -i Microsoft.AspNetCore.Blazor.Templates
dotnet new blazor -o BlazorApp1 cd BlazorApp1 dotnet run

 

  • 如果你需要使用Visual Studio,
    • 安装最新的Visual Studio 2017.
    • 安装 ASP.NET Core Blazor Language Services extension
    • 在Visual Studio中创建新的测试项目:
    • 选择 File -> New Project -> Web -> ASP.NET Core Web Application
    • 确定在Target Framework里选择了 .NET Core and ASP.NET Core 2.0.
    • 选择 Blazor 模板

分享图片

 

敌后根据地? 如何在前端渲染cshtml

当我们运行起项目之后,就可以看到如下提示

分享图片

这个时候我们在浏览器里打开监听的端口 http://localhost:17477. 就可以看到我们这个项目的网页了.

这个简单的示例项目带了3个页面

 

 

分享图片

 第一个页面比较简单,但先别急,让我们打开浏览器工具. 先看看页面在加载页面过程中都加载了什么

分享图片

在初次打开页面的时候,我们看到的是这样一个Loading..的页面.  这个页面的代码是这样的.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>BlazorDemo</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/site.css" rel="stylesheet" />
</head>
<body>
    <app>Loading...</app>

    <script src="css/bootstrap/bootstrap-native.min.js"></script>
    <script src="_framework/blazor.js" main="BlazorDemo.dll" entrypoint="BlazorDemo.Program::Main" references="Microsoft.AspNetCore.Blazor.Browser.dll,Microsoft.AspNetCore.Blazor.dll,Microsoft.Extensions.DependencyInjection.Abstractions.dll,Microsoft.Extensions.DependencyInjection.dll,mscorlib.dll,netstandard.dll,System.Core.dll,System.Diagnostics.StackTrace.dll,System.dll,System.Globalization.Extensions.dll,System.Net.Http.dll,System.Runtime.Serialization.Primitives.dll,System.Security.Cryptography.Algorithms.dll" linker-enabled="true"></script></body>
</html>

可以看到这个页面加载了两个js,第一个是bootstrap的,第二个叫做blazor.js. 只不过这个js有非常多的参数,有 main,entrypoint,和 references. 看看References里写的是不是很熟悉? 一看就是.net的dll.

blazor.js 加载了mono.js,mono.js 加载了mono.wasm. 这个是个什么文件?

分享图片

wasm代表的就是Web Assembly,简单地说它就是编译好的二进制文件,可以由浏览器直接运行,源语言可以是C/C++或者任何可以编译到Web Assembly的文件,而这里我们加载的就是mono 编译好的Web Assembly文件,它被加载之后,相当于浏览器中启动了一个mono 运行环境.

随后的两个js 是笔者chrome浏览器插入的js,在这里不要被他们干扰了. 那么mono 运行时加载完成之后. 就需要加载dotnet 的Dll了,首先是入口库,接着就是需要的引用库

分享图片

好家伙 1.9MB. 当所有的Dll被下载完毕之后,这个时候我们的浏览器就可以运行我们这个dotnet的网页了. 于是就回到了我们最开始看到的那个应用程序.

所以 总结一下 blazor.js 调用mono.js,mono.js加载mono.wsam,然后根据写在script标签里的内容继续的加载dotnet的库文件. 如果浏览器不支持wsam,就会尝试使用asm.js加载mono.asm.js

柳暗花明又一村,Blazor的模板究竟是怎样的.

我们已经知道,经过前面的步骤,浏览器里已经运行了一个.Net 运行时了. 而且加载了项目必须的dll. 那么这样一个简单的程序,它的代码究竟是怎么样的呢? 

打开项目代码,映入眼帘的是一个标准的.net Project

分享图片

_ViewImports.cshtml包含了项目一些其他页面中最常使用的namespace

?
1
2
3
4
5
6
7
@ using System.Net.Http
@ using Microsoft.AspNetCore.Blazor
@ using Microsoft.AspNetCore.Blazor.Components
@ using Microsoft.AspNetCore.Blazor.Layouts
@ using Microsoft.AspNetCore.Blazor.Routing
@ using BlazorDemo
@ using BlazorDemo.Shared

 

Program.cs是程序的入口点

using Microsoft.AspNetCore.Blazor.Browser.Rendering;
using Microsoft.AspNetCore.Blazor.Browser.Services;
using System;

namespace BlazorDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            var serviceProvider = new BrowserServiceProvider(configure =>
            {
                // Add any custom services here
            });

            new BrowserRenderer(serviceProvider).AddComponent<App>("app");
        }
    }
}

在入口点中,我们注册了一个浏览器渲染服务 BrowserRender,让他渲染App

App.cshmtl是这样的

<Router AppAssembly=typeof(Program).Assembly />

这里的Router对应的是Microsoft.AspNetCore.Blazor.Routing.Router. 当给它一个AppAssembly时,他就会自动的把当前的Url 和 AppAssembly的其他Pages对应起来.

所以 当我们在浏览器里输入 /Counter时,他就会加载Pages/Couter.cshtml.

Shared文件夹里分别是布局文件,导航栏,还有一个我们自定义的控件 SurveyPrompt. 

熟悉Razor引擎的小伙伴们一定很轻车熟路了. 那么当我们打开网站时,默认显示给我们的 就是Index,这个时候我们会加载Pages/Index.cshtml

Index.cshtml的代码是这个样子的

@page "/"

<h1>Hello,world!</h1>

Welcome to your new app.

<SurveyPrompt Title="How is Blazor working for you?" />

@page 可以告诉Router,当前页面注册到 "/"

除了显示hello world以外,我们在这里还看到了刚刚说到的第三方控件. SurveyPrompt. 果然不简单嘛,一个看似简单的页面,居然还告诉了我们如何使用自定义控件.

从声明上看,我们知道 SunveyPrompt是一个控件,并且有一个属性Title. 现在我们打开它的代码

<div class="alert alert-survey" role="alert">
    <span class="glyphicon glyphicon-ok-circle" aria-hidden="true"></span>
    <strong>@Title</strong>

    Please take our
    <a target="_blank" class="alert-link" href="https://go.microsoft.com/fwlink/?linkid=870381">
        brief survey
    </a>
    and tell us what you think.
</div>

@functions
{
    // This is to demonstrate how a parent component can supply parameters
    public string Title { get; set; }
}

我们可以看到代码分为两部分,@functions上面是类似html的东西,下面是类似C#的东西. 熟悉React或者Vue的伙伴们恐怕不会对这种混写感到陌生. 这个就是Blazor的语法. Html部分很像使Razor的模板方式. 而最后整个页面都会被编译成一个类,这个类派生自 Component. 如果你编译过项目,你会在Debug下面的Shared目录找到一个叫SurveyPrompt.g.cs的东西

#pragma checksum "/Users/pzhi/SCM/gitHub/zhipu123/BlazorDemo/Shared/SurveyPrompt.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "a2a2ea88635b799343bc6d9647bbb818c8a20c9d"
// <auto-generated/>
#pragma warning disable 1591
namespace BlazorDemo.Shared
{
    #line hidden
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Net.Http;
    using Microsoft.AspNetCore.Blazor;
    using Microsoft.AspNetCore.Blazor.Components;
    using Microsoft.AspNetCore.Blazor.Layouts;
    using Microsoft.AspNetCore.Blazor.Routing;
    using BlazorDemo;
    using BlazorDemo.Shared;
    public class SurveyPrompt : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
    {
        #pragma warning disable 1998
        protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
        {
            base.BuildRenderTree(builder);
            builder.OpenElement(0,"div");
            builder.AddAttribute(1,"class","alert alert-survey");
            builder.AddAttribute(2,"role","alert");
            builder.AddContent(3,"\n    ");
            builder.OpenElement(4,"span");
            builder.AddAttribute(5,"glyphicon glyphicon-ok-circle");
            builder.AddAttribute(6,"aria-hidden","true");
            builder.CloseElement();
            builder.AddContent(7,"\n    ");
            builder.OpenElement(8,"strong");
            builder.AddContent(9,Title);
            builder.CloseElement();
            builder.AddContent(10,"\n\n    Please take our\n    ");
            builder.OpenElement(11,"a");
            builder.AddAttribute(12,"target","_blank");
            builder.AddAttribute(13,"alert-link");
            builder.AddAttribute(14,"href","https://go.microsoft.com/fwlink/?linkid=870381");
            builder.AddContent(15,"\n        brief survey\n    ");
            builder.CloseElement();
            builder.AddContent(16,"\n    and tell us what you think.\n");
            builder.CloseElement();
            builder.AddContent(17,"\n\n");
        }
        #pragma warning restore 1998
        
    // This is to demonstrate how a parent component can supply parameters
    public string Title { get; set; }
    }
}
#pragma warning restore 1591

我们发现@functions里面的内容 会作为这个类的成员变量和 成员方法,而上面的内容则被编译到了BuildRenderTree方法中.

那么到了这里我们大概知道了这个简单的HomePage都有什么玄机了. 我们也大概知道了Blazor的语法,也知道其实我们所有的页面最终都会是一个Componet.

那么什么是Componet呢? 在这里并不想过多的去笔墨介绍这个概念. 如果你是一个Vue或者React的开发,你应该对这个模块化开发不陌生. 一个Componet,就是满足一定的功能,有自己的属性,状态. 可以展示特定数据的元素.

就如同我们这里的SurveyPrompt,接受一个Title属性,并且负责把他展示成这样子

分享图片

 数据驱动? Blazor的刷新和绑定机制初探

现在我们知道了一个简单的页面是如何渲染出来的. 那么让我们打开Counter这个配置来看一看. 数据是如何交互的

我们第二个page张这样子

分享图片

有一个button,大声的叫我们点它. 当我们点击的时候. 上面的current count 变成了 1

分享图片

 

这一切是怎么发生的呢? 以下是Counter.cshtml的代码

@page "/counter"
<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button @onclick(IncrementCount)>Click me</button>

@functions {
    int currentCount = 0;

    void IncrementCount()
    {
        currentCount++;
    }
}

 我们看到 这个页面非常简单,我们定义了一个CurrentCount的Field,然后在IncreaseCount方法里给它加一. 一个叫Click me的button标签里 有一个@onclick方法,将IncreaseCount作为参数

Counter.cshtml编译后的代码张这样

 

#pragma checksum "/Users/pzhi/SCM/gitHub/zhipu123/BlazorDemo/Pages/Counter.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "05ad2dd449cbc9f09f8b759e1f06e7eb5e9583b4"
// <auto-generated/>
#pragma warning disable 1591
namespace BlazorDemo.Pages
{
    #line hidden
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Net.Http;
    using Microsoft.AspNetCore.Blazor;
    using Microsoft.AspNetCore.Blazor.Components;
    using Microsoft.AspNetCore.Blazor.Layouts;
    using Microsoft.AspNetCore.Blazor.Routing;
    using BlazorDemo;
    using BlazorDemo.Shared;
    [Microsoft.AspNetCore.Blazor.Layouts.LayoutAttribute(typeof(MainLayout))]
    [Microsoft.AspNetCore.Blazor.Components.RouteAttribute("/counter")]
    public class Counter : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
    {
        #pragma warning disable 1998
        protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
        {
            base.BuildRenderTree(builder);
            builder.OpenElement(0,"h1");
            builder.AddContent(1,"Counter");
            builder.CloseElement();
            builder.AddContent(2,"\n\n");
            builder.OpenElement(3,"p");
            builder.AddContent(4,"Current count: ");
            builder.AddContent(5,currentCount);
            builder.CloseElement();
            builder.AddContent(6,"\n\n");
            builder.OpenElement(7,"button");
            builder.AddAttribute(8,onclick(IncrementCount));
            builder.AddContent(9,"Click me");
            builder.CloseElement();
            builder.AddContent(10,"\n\n");
        }
        #pragma warning restore 1998
        
    int currentCount = 0;

    void IncrementCount()
    {
        currentCount++;
    }
    }
}
#pragma warning restore 1591

 

我们看到 @onclick其实在这里就是执行了一个Component的一个方法onclick,顾名思义,当这个Component被点击的时候就被调用. 我们的IncreaseCount被作为参数传给了它,可见onclick会在被点击的时候执行IncreaseCount.

那么问题来了,当我们执行了IncreaseCount方法时,页面怎么会知道要不要刷新? 是刷新整个页面还是刷新所有?

熟悉WPF的同学可能知道,在WPF中如果我们需要让一个ViewModel可以被监听变化,他就需要实现INotifyChanged事件. 那么同样道理,我们的这个IncreaseCount可能也是类似的吗?

然而基于编译后的代码我们可以发现 CurrentCount作为我们Counter这个类的Field,并没有任何机会高速Page自己变化了. 而且这个Field非常普通,也不是什么WPF中的DP,所以到目前为止变化是怎么通知的.并没有一个合理的解释. 后面的时间里我会尝试阅读Blazor的代码搞清楚这件事情. 

第一个问题画个问号,那么第二个问题呢? 

打开浏览器工具,定位到button,再次点击button观察dom的反应.

分享图片

我们看到 在点击Button的时候,button上面的<p>标签闪动了,说明它被刷新了,而其他标签并没有. 所以局部刷新的功能是有的. 效率问题不用担心了. 

编辑Click me,把他的内容变成 "点击我",再次点击按钮,我们看到还是只有p变,而且button也没有变回原来的内容

分享图片

 

 所以我们知道,这个局部刷新不是简单的拿Dom作比较,肯定是有Virtual Dom的机制在里面.

 

 星星之火,可燎原?

在简单的尝试了Blazor之后,还是很兴奋的. 可以看到Blazor是一个初具规模的产品. 我们C#开发可以用Blazor在今后写前端渲染的网页了! 

我很期望这样一个产品能够持续的演进下去.

就目前版本看(0.1.0),Blazor尚不能应用到产品中. 主要还是有以下的原因

  •  打包大小太大,1.8M的大小对于网站简直是致命的.
  •  产品还不成熟,现在Component还只能支持简单的事件,笔者测试的时候只有onclick,onchange. 
  •  兼容性差,使用了WebAssembly,就注定了两年前的浏览器必定不能支持.

当然我们还是不能否认,Blazor为如何让更多语言进入前端世界打开了一扇新的大门. 也许未来JavaScript将不仅仅是前端唯一可以使用的利器. 我们会看到C/C++,Python,Java写的前端渲染页面也不一定呢.

当然在后端语言打入前端世界的道路上,WebAssembly也未必是唯一的路劲,比如Scala.js就完全使用了js重写了Scala的库函数,类似的还有Kotlin.js. 可以看到虽然JavaScript已经非常Fancy了,但是后端程序员们进军前端的热情可谓从未停歇过啊.

祝dotnet的应用越来越广,祝广大后端程序员们新年成就慢慢,加薪升职.

部分 FAQ(翻译自Blazor官方)

Q:Is this Silverlight all over again? 这又是一个Silverlight吗? 

No,Blazor is a .NET web framework based on HTML and CSS that runs in the browser using open web standards. It requires no plugin and works on mobile devices and older browsers.

 

当然不是了,Blazor完全是基于Css 和 Html展现的,它的运行不需要任何插件.

 

Q:What features will Blazor support?Blazor都会支持什么功能?

Blazor会支持现在主流单页面Web Application所应具有的功能:

  • A component model for building composable UI 一个面向组件化UI构建而设计的控件模型
  • Routing 路由
  • Layouts 布局
  • Forms and validation 表单验证
  • Dependency injection 依赖注入 
  • JavaScript interop 与JavaScript的互操作
  • Live reloading in the browser during development 开发过程中浏览器的热重载
  • Server-side rendering 后端渲染(前后端均可渲染页面)
  • Full .NET debugging both in browsers and in the IDE 在浏览器和IDE中都可以获得全面的.Net 调试支持
  • Rich IntelliSense and tooling 丰富的代码提示和辅助工具
  • Ability to run on older (non-WebAssembly) browsers via asm.js 在老旧浏览器上能通过 asm.js加载网页
  • Publishing and app size trimming 进一步缩减发布网站时的大包大小

Q: Can I access the DOM from a Blazor app? 我可以在Blazor中操作DOM吗

You can access the DOM through JavaScript interop from .NET code. However,Blazor is a component based framework that minimizes the need to access the DOM directly.

你可以使用JavaScript互操作层操纵DOM. 但是请注意,Blazor是一个模块化渲染的框架,他的目的就是尽可能减少直接操纵DOM

 

时间:2019-09-30 00:39:15 阅读(14)
© 2017 版权所有 鲁ICP备17052893号

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读6.2k次,点赞2次,收藏3次。C#数学运算表达式解释器测试文件内容:a=2+3*2;b=2*(2+3);浏览按钮事件处理程序: private void button_browse_Click(object sender, EventArgs e) { OpenFileDialog fbd = new OpenFileDialog(); fbd.T_c# 表达式分析器
文章浏览阅读5.2k次,点赞6次,收藏7次。程序要做到用户配置的灵活性,就需要添加配置管理功能,这里使用.NET的应用程序配置文件app.config来保存配置信息,.NET Framework提供了对配置文件读写的良好支持。要实现配置文件的读取功能,需要引用System.Configuration命名空间。提供源码下载,有源有真相。_引用封送类的字段,访问上面的成员可能导致运行时异常
文章浏览阅读9k次。错误信息检测到 ContextSwitchDeadlock Message: CLR 无法从 COM 上下文 0x622b440 转换为 COM 上下文 0x622b5b0,这种状态已持续 60 秒。拥有目标上下文/单元的线程很有可能执行的是非泵式等待或者在不发送 Windows 消息的情况下处理一个运行时间非常长的操作。这种情况通常会影响到性能,甚至可能导致应用程序不响应或者使用的内存随时间不断_contextswitchdeadlock
文章浏览阅读2w次,点赞10次,收藏9次。我发生错误时的环境:Windows 7,Framework 4、0,Microsoft Office 2007,VS2010,c# WinForm;部分代码: string strConn = "Provider=Microsoft.Ace.OleDb.12.0;Persist Security Info=False;" + "data source=" + _c# oledb 操作必须使用一个可更新的查询
文章浏览阅读9.8k次。C# 二进制字节流查找函数IndexOf /// /// 报告指定的 System.Byte[] 在此实例中的第一个匹配项的索引。 /// /// 被执行查找的 System.Byte[]。 /// 要查找的 System.Byte[]。 /// 如果找到该字节数组,则为 searchBytes 的索_c#byte[]查找
文章浏览阅读2.5w次,点赞3次,收藏9次。c#DataGridView数据绑定示例 格式化单元格的内容在使用DataGridView显示数据库中的数据时,我们需要对某列的数据显示格式进行格式化。这里使用实时构建的数据,如下图:在显示时对第三列的数据进行格式化,如下图:测试数据构建及数据绑定: private void Form1_Load(object sender, EventArgs e) { _c#datatable列格式化
文章浏览阅读2.8w次,点赞3次,收藏4次。完整错误信息错误 1 命名空间“System”中不存在类型或命名空间名称“Linq”。是否缺少程序集引用? F:CsProjectsCSharp实现SPY++CSharp实现SPY++Form1.cs 6 14 CSharp实现SPY++错误原因开始的时候创建项目选择的Framework版本是4.0,但后来为了项目的平台适应性,将Framework的版本改为了2.0,重新编译_命名空间system中不存在类型或命名空间名称
文章浏览阅读1.9w次。一、通过配置文件实现以管理员身份运行程序Vista 和 Windows 7 操作系统为了加强安全,增加了 UAC(用户账户控制) 的机制,如果 UAC 被打开,用户即使是以管理员权限登录,其应用程序默认情况下也无法对系统目录,系统注册表等可能影响系统运行的设置进行写操作。这个机制大大增强了系统的安全性,但对应用程序开发者来说,我们不能强迫用户去关闭UAC,但有时我们开发的应用程序又需要_c# 默认程序以管理身份运行。
文章浏览阅读5.2k次。在使用C#操作IIS创建应用程序池出现异常:无效索引(Exception from HRESULT:0x80070585)相关代码:public static string CreateAppPool(string appPoolName, string frameworkVersion, string managedPipelineMode) {_create website 无效索引。 (0x80070585)
文章浏览阅读9.5k次,点赞3次,收藏4次。C#二进制字节数组操作函数 截取字节数组SubByte /// /// 截取字节数组 /// /// 要截取的字节数组 /// 开始截取位置的索引 /// 要截取的字节长度 /// 截取后的字节数组 public byte[] SubByte(byte[] srcByt_c#字节数组截取
文章浏览阅读2.4w次,点赞5次,收藏16次。C#是微软公司发布的一种面向对象的、运行于.NET Framework之上的高级程序设计语言。并定于在微软职业开发者论坛(PDC)上登台亮相。C#是微软公司研究员Anders Hejlsberg的最新成果。C#看起来与Java有着惊人的相似;它包括了诸如单一继承、接口、与Java几乎同样的语法和编译成中间代码再运行的过程。但是C#与Java有着明显的不同,它借鉴了Delphi的一个特点,与COM(_c#读文件
文章浏览阅读4.8w次,点赞12次,收藏44次。C#创建Excel文件,这里实际上是从资源中提取一个事先创建好的Excel文件,文件提取成功后,使用OleDb方法连接Excel,向Excel文件中写入数据。创建解决方案菜单》新建》项目》Windows窗体应用程序:添加相关组件:添加两个DataGridView,一个TextBox,两个按钮 ,如下图:添加Excel资源:先在文件夹中新建一个Excel文件,在Sheet1表的第一行设置列名:双击“_c#保存到excel
文章浏览阅读2.8k次。windows 7和vista提高的系统的安全性,同时需要明确指定“以管理员身份运行”才可赋予被运行软件比较高级的权限,比如访问注册表等。否则,当以普通身份运行的程序需要访问较高级的系统资源时,将会抛出异常。如何让程序在启动时,自动要求“管理员”权限了,我们只需要修改app.manifest文件中的配置项即可。app.manifest文件默认是不存在的,我们可以通过以下操作来自_vb.net 程式以管理员运行
文章浏览阅读6.1k次,点赞4次,收藏7次。窗口风格(Window style)WS_BORDER 有边框窗口 WS_CAPTION 必须和WS_BORDER风格配合,但不能与WS_DLGFRAME风格一起使用。指示窗口包含标题要部分。 WS_CHILD 说明窗口为子窗口,不能应用于弹出式窗口风格(WS_POPUP)。 WS_CHILDWINDOW 同WS_CHILD。 WS_CLIPCHILDREN 绘制父窗口时_net(c#):ws_caption | ws_border
文章浏览阅读1.8w次,点赞3次,收藏9次。C#修改文件或文件夹的权限,为指定用户、用户组添加完全控制权限 //给Excel文件添加"Everyone,Users"用户组的完全控制权限 FileInfo fi = new FileInfo(excelPath); System.Security.AccessControl.FileSecurity fileSecurity_c# 判断 文件夹 是否 users 用户组 写入 权限
文章浏览阅读9.3k次。C# 模拟PrintScreen 和 Alt+PrintScreen截取屏幕图片keybd_event API函数功能:该函数合成一次击键事件。系统可使用这种合成的击键事件来产生WM_KEYUP或WM_KEYDOWN消息,键盘驱动程序的中断处理程序调用keybd_event函数。在Windows NT中该函数己被使用SendInput来替代它。函数原型;VOID keybd_event..._如何编程调用 printscreen
文章浏览阅读1w次。这本来是在VS2005下创建的一下项目,后来改用VS2010的开发环境,.NET Framework的版本还是使用2.0,但每次生成之后都会在解决方案的同级目录下产生一个名称乱码的文件夹,解决了那个问题之后,由于这个Windows窗体应用程序添加一个安装项目,项目生成时出现以下错误:错误 1 验证时出错。HRESULT = '8000000A' F:CsProjects屏幕截图2005屏幕截_error1an error occurred while validating. hresult = '8000000a
文章浏览阅读7.3k次。上一篇:C#软件开发实例.私人订制自己的屏幕截图工具(六)添加配置管理功能由于截图时可能需要精确截取某一部分,所以需要放大镜的功能,这样截取的时候才更容易定位截图的位置。添加PictureBox,name属性设置为“pictureBox_zoom”;在“Form1_Load”事件处理函数中添加以下代码://设置放大镜的大小 this.pictureBox_zoom.Widt_c#实现放大镜效果
文章浏览阅读4.5k次。C# 绘制箭头的方法,仿微信截图的箭头效果见下图,实际上还是有区别的,箭头的起点处微信的是圆端,而我实现的是尖端。说说我的实现吧,实现方法其实是划线,线的两端都要设置端点样式。看代码:Point _StarPoint = new Point(0, 0);Point _EndPoint = new Point(300, 300);System.Drawing.Drawing2..._adjustablearrowcap
文章浏览阅读1.3w次,点赞3次,收藏4次。在实现“C#软件开发实例.私人订制自己的屏幕截图工具(六)添加配置管理功能”功能时,遇到警告:由于“Screenshot.Form1.ZoomBoxHeight”是引用封送类的字段,访问上面的成员可能导致运行时异常解决方案:对字段对待封装:在需要封装的字段上单击鼠标右键,重构》封装字段:输入属性名:使用默认设置,单击应用_由于引入封装类的字段