PowerShell执行脚本策略错误
- 错误信息:PowerShell运行脚本错误——“系统上禁止运行脚本”
- 原因:默认执行策略为Restricted
- 解决:执行Set-ExecutionPolicy RemoteSigned
解:奇葩史
解:奇葩史
问题:WPF中MVVM模式下 ListView绑定ListCollectionView时,CurrentChanged无法触发
解决方案:
经历(吐槽):
解:奇葩史
行:奇葩史
最近由“中兴制裁”事件引发了许多“中国芯”的讨论,我也来蹭蹭热度,来扯一下软件开发中“重新造轮子”的问题。
在我们接触到软件行业的时候,就常常会听到有人说“不要重新造轮子”的论点,个人其实挺反对这种论点,倒不是因为他不对,而是因为他缺少场景。 —— 没有前提条件的结论,都有失偏颇。还有就是最适合的轮子才是好轮子。
最后,我们可以不重复造轮子,但我们不能不会造轮子;我们一开始可以造的没别人好,但我们不能没有自己的轮子。 —— 愿祖国越来越强大,程序员起来造世界。
持续更新中……
2017-02-26 今日发现Xamarin官方已经开始逐步提供中文文档,故将减少相关翻译。
数据访问
部署发布
疑难解答
掘:奇葩史
C#钩子程序入门
现在网络上涉及到钩子程序入门,基本都是以三个基础概念:装载钩子程序,卸载钩子程序,以及回调。但是,本文却不会以这些为出发点,前面的三个概念确实是钩子程序中的重要部分,但对于入门而言,有时是难以理解的(至少本人之前很长时间在这个上面一直是糊里糊涂的,还是后来突然有所明悟 —— 这个看个人,可能有些人一开始就明白了,就像大学里学C语言一样。)。所以本文以个人入门时,最早接触的几个概念来进行描述。
本文主要涉及三个函数/API接口:FindWindow、FindWindowEx、SendMessage。前两个是查找窗体,并返回句柄;最后一个则是消息发送。
注,进行下面内容时,可以利用SPY++工具辅助理解。
FindWindow查找最顶层的窗口句柄,即父窗口为null。并且如果有多个匹配结果,则它只返回最先查找到的结果。
用法 —— 以记事本为例:
[DllImport("user32.dll", EntryPoint = "FindWindow")]
private extern static IntPtr FindWindow(string lpClassName, string lpWindowName);
IntPtr ParenthWnd = FindWindow(null,"无标题 - 记事本"); //方法1
ParentWnd = FindWindow("Notepad", null); //方法2
参数:第一个参数为待查找的窗口类;第二个参数为窗口标题。如果查找到窗口,则返回窗口句柄,否则返回0。上述代码中的方法1和方法2在本示例中效果是一样的。
注意:在函数中的两个参数关系是同时匹配。如果你只需要匹配类或者窗体名称,则另一个参数需设置为null。
用于查找窗口中的子窗口句柄,如窗口内部的各种控件。
引入:
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
参数:第一个参数为父级窗口,第二个参数为同级窗口的前一个窗口句柄,第三个为窗口类,第四个为窗口标题。
注:如果第一个和第二个参数均设置为IntPtr.Zero,则其效果等同于FindWindow。
用于向指定的窗体句柄上发送消息,如设置文本、鼠标按下等消息。
引入:
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(IntPtr hWnd, int Msg, string wParam, string lParam);
参数:第一个参数为待发送消息的窗口句柄,第二个为待发送的消息类型,后两个为附加参数,其设置与第二个参数相关联。上述引入时,后两个参数为string类型,但其并不固定,你可以将其处理为object类型。具体内容在遇到时,在进行说明。
另有一个与SendMessage相似的函数 —— PostMessage,不过相对来说SendMessage使用的更多,因为它看起来比较负责任。从比较专业(网络协议)的方面来解释就像:PostMessage像UDP协议,TCP像TCP协议;而比较通俗的讲,以送快递为例,PostMessage是送到代理点就表示送到了,而SendMessage则表示送到家并且要明确签收才行,所以在这上面就可以看出,SendMessage更加负责任。
关于第二个参数,有很多消息类型,具体可以查看:https://msdn.microsoft.com/zh-cn/library/ms644927.aspx
或者查看:http://git.oschina.net/huaxia283611/codes/mtgvh1q4ero7uwk38c25b84 —— 注释不完整,逐步完善
本小节简要介绍如何使用上述函数。
在使用windows api的类中添加如下引用:
using System.Runtime.InteropServices;
即添加DllImport相关的引用。
使用DllImport导入相关函数,如导入FindWindow:
[DllImport("user32.dll", EntryPoint = "FindWindow")]
private extern static IntPtr FindWindow(string lpClassName, string lpWindowName);
其中导入函数修饰符使用extern static。另使用特性(Attribute)修饰 —— DllImport。第一个参数为相关的dll,此处使用user32.dll,但在某些平台上需要使用coredll.dll;第二个参数EntryPoint为相关dll中的函数签名,如果你的函数定义与其一致,则此参数可以省略,不一致则必须,如下面两句导入,均可使用 —— 不过为了维护管理方便,常常保持一致:
[DllImport("user32.dll")]
private extern static IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", EntryPoint = "FindWindow")]
private extern static IntPtr MyFindWindow(string lpClassName, string lpWindowName);
上面完成后,即可调用,方式如调用其他静态方法一样。
至此,入门内容介绍完了,其中主要包含了查找窗体后设置子窗体内容的基本操作。
以下为微软官方相关文档参考:
此处主要介绍的绑定类是System.Windows.Data.Binding
,如果涉及其他内容,将简要介绍,不会过多说明。
下面将简要介绍最基础(最常用)的三个属性:
Path —— 路径,用于索引到具体的属性,常常会省略书写,示例如下:
<TextBox Text="{Binding Path=A.B}" />
其中Path=
可以省略,因为Binding元素含有一个带参构造函数,其参数为path。另外,示例中A.B
需具体到属性,如果A
已经是需要绑定的具体属性,则可以用A
替换A.B
。即最简单的格式是:
<TextBox Text="{Binding A}" />
注:如果未指定,即表示使用默认模式,而在不同的依赖属性上,其模式是不一样的。在使用时,如果不确定其默认模式是否是自己需要的模式时,则可以手动指定。
注:当然,此处也有默认值设置,但不同的控件 属性的 默认 值也不一样,不过大部分情况下默认 值是PropertyChanged,比较特殊的有TextBox的Text属性,其默认值是LostFocus。
下面给一个最常用的绑定书写方式:
<TextBox Text="{Binding A,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" />
控件绑定,即在同一个界面中不同控件之间的数据同步处理,最常见的就是滑动条与一个文本框之间的绑定。在控件绑定中,需要指定绑定类的ElementName属性值,即当前属性绑定到哪一个控件的属性上。示例如下:
<Slider Name="slider" Maximum="100" />
<TextBox Text="{Binding ElementName=slider,Path=Value,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" />
注:在WPF开发中,我们常常是不为控件设置Name值的,而在控件绑定中,必须为源控件添加Name属性值;而有些控件可能会不含有Name属性,此时则使用
x:Name
来指定名称。
在控件绑定中有一个比较特殊的存在——模板绑定-TemplateBinding,它与Binding并不在一个继承结构上。TemplateBinding是用在控件模板定义中的,用于绑定模板对应控件中的属性,示例如下:
<TextBox x:Name="templatebinding">
<TextBox.Template>
<ControlTemplate TargetType="TextBox">
<TextBlock Text="{TemplateBinding Text}" />
</ControlTemplate>
</TextBox.Template>
</TextBox>
TemplateBinding可以简单理解为在Binding中设置了ElementName为其父级控件 —— 事实并非如此,仅作为辅助理解。TemplateBinding相对与Binding要少很多属性内容。
此处数据绑定表示在WPF中的对象绑定,即常见场景 就是把数据库 数据显示到 界面上。而在真实的项目开发中 ,常 会用到MVVM模式,数据绑定将会在那里体现出来,但MVVM模式开发则不在此节中叙述。
下面以一个最简单的示例解释数据绑定:
后台类 —— 数据源结构:
class ForDataBinding
{
public int Count { get; set; }
}
数据源初始化 —— 创建数据并将数据绑定到界面:
ForDataBinding data = new ForDataBinding();
data.Count = 10;
this.fordatabinding.DataContext = data;
界面控件设置 —— 指定控件绑定到源数据的哪个属性:
<Grid x:Name="fordatabinding">
<TextBox Text="{Binding Count}" />
</Grid>
其中设置了Grid的DataContext,即表示Grid内部数据上下文是以设置的数据源为基础,在此示例中,Text属性绑定的Count就是以ForDataBinding类对象为基础查找属性。 —— 即绑定路径是以当前位置以树形结构往下查找对应属性。
Binding除了以上内容,还有其他的属性设置,本小节将简要介绍几个较为常用的内容。
在数据绑定中,有时我们需要显示的数据与源数据不一样,如时间格式,浮点数格式,或者更复杂一些的想要一个类对象中的多个属性组合一起显示。
对于简单的数据格式化,可以通过StringFormat来处理,如时间格式化为yyyy-MM-dd
,浮点数保留两位小数等等。其代码示例如下:
后台类:
class SimpleDataConvert
{
public DateTime Date { get; set; } = DateTime.Now;
public float Price { get; set; } = 100.123456f;
}
使用:
this.simpleconvert.DataContext = new SimpleDataConvert();
界面处理:
<StackPanel x:Name="simpleconvert">
<TextBox Text="{Binding Date,StringFormat=yyyy-MM/dd}" />
<TextBlock Text="{Binding Price,StringFormat=f2}" />
</StackPanel>
上述示例结果就是将Date日期格式化为yyyy-MM/dd
;将Price保留两位小数显示。
但是有些数据显示要求无法通过StringFormat处理,则需要使用Binding的属性Converter来处理了 —— 即通过值转换器来处理。下面我们以上面用到的时间转化为例,假如我们要在前台显示yyyyMMdd
格式的日期,此时从数据源显示到界面可以正确处理,但是在界面输入,它无法正确转化为源数据,即内置的Converter不支持,此时我们就需要自己实现值转换,示例 如下:
首先定义DateConverter,实现接口IValueConverter,代码如下:
class DateConverter : IValueConverter
{
/// <summary>
/// 数据源转界面显示
/// </summary>
/// <param name="value"></param>
/// <param name="targetType"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value.GetType() == typeof(System.DateTime))
{
return ((System.DateTime)value).ToString("yyyyMMdd");
}
else
{
return value;
}
}
/// <summary>
/// 界面显示转数据源
/// </summary>
/// <param name="value"></param>
/// <param name="targetType"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType == typeof(System.DateTime) && value != null)
{
DateTime dt = DateTime.Now;
string valuestr = value.ToString();
if (DateTime.TryParse(valuestr, out dt))
{
return dt;
}
else if (valuestr.Length == 8)
{
string yearstr = valuestr.Substring(0, 4);
string monthstr = valuestr.Substring(4, 2);
string daystr = valuestr.Substring(6, 2);
if (DateTime.TryParse(string.Format("{0}-{1}-{2}", yearstr, monthstr, daystr), out dt))
{
return dt;
}
}
}
return value;
}
}
然后在Xaml文件中添加引用:
由于此处DateConvert直接定义在当前窗体类命名空间下,所以其已经默认添加了如下空间,如果定义在其他位置,则需要手动添加空间引用。
xmlns:local="clr-namespace:Binding_Demo"
资源定义,以便于在控件中引用
<Window.Resources>
<local:DateConverter x:Key="dateconvert" />
</Window.Resources>
最后,则将值转换器应用到控件上,代码如下:
<TextBox Text="{Binding Date,Converter={StaticResource dateconvert}}" />
至此,一个简单的值转换器就完成了。
在绑定中的验证主要设计四个属性:
下面我们以异常验证规则来简要介绍验证规则的使用 —— 验证处理涉及的内容有很多,单此一节无法描述完整,故仅列举最简单的使用方式:
首先是后台类的定义:
class ForExceptionValidate
{
private int max;
public int Max
{
get { return max; }
set
{
if (value > 100)
{
throw new Exception("Max不能超过100");
}
max = value;
}
}
}
this.forvalidate.DataContext = new ForExceptionValidate();
然后是界面使用:
<StackPanel x:Name="forvalidate">
<TextBox >
<TextBox.Text>
<Binding Path="Max" >
<Binding.ValidationRules>
<ExceptionValidationRule></ExceptionValidationRule>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</StackPanel>
在此 示例 中,后台类中抛出的异常,会作为界面的验证结果来处理 —— 所以此处虽然没有明确使用异常捕获,但程序并 不会崩溃。
最后,简要说下依赖属性,所有上面的绑定基础都需要靠依赖属性。所有需要绑定功能的属性都进行了对应依赖属性(System.Windows.DependencyProperty)定义。在WPF中,我们大部分时间是在用依赖属性 —— 各种绑定,而自己的定义依赖属性的情况相对较少,所以此处就不再介绍如何定义依赖属性 —— 作为入门介绍教程。
在WPF中,严格来讲,控件是继承自System.Windows.Control类的元素。但有时我们还习惯性会将面板说成面板控件、Border说成Border控件(合理的说法应该叫***元素),不过这些,我们不会在本节中进行详细讨论,本节中将主要介绍以Control为基类的控件。
WPF中控件有很多,可以大致分为以下几类:
下述继承关系并不代表直接继承,有的是子类的子类等关系
在WPF中,有许多控件,下面介绍几个最常用的控件,我们以上述所列分类分别介绍。
内容控件中,使用Content属性设置显示的内容,而Content类型是object,所以其自由度很高。
列表项控件常用于数据列表的绑定显示。
文本控件
范围控件
其他控件
关于控件的简单设置,可以见Hello,World篇中的基本属性设置内容:
WPF中的样式其实和HTML中的css样式的概念是及其相似的。它其实是为了让控件的属性设置可以统一管理。当然,它还有额外的功能,最典型的就是触发器。下面说下样式的定义和使用。
样式可以定义在许多不同的位置,它可以直接定义在对应的控件中,如下:
<Button Content="样式设置">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="Red" />
</Style>
</Button.Style>
</Button>
当然,这种用法并不建议,因为它失去了统一管理的优势,除非是控件有定制化需求,一般不会这样写。针对上面的内容,我们可以将样式抽取出来,然后将样式放置到当前窗体的样式列表中,然后在控件上使用样式,方法如下:
首先将样式定义到当前窗体的Window.Resources中
<Window.Resources>
<Style x:Key="winbtn" TargetType="Button">
<Setter Property="Background" Value="Blue" />
</Style>
</Window.Resources>
然后在相应的控件上应用样式
<Button Content="样式设置2" Style="{StaticResource winbtn}"></Button>
到这,我们就可以在当前窗体中使用统一样式了。但是如果你的应用含有多个窗体 页面时,需要统一样式,这样就不够了,所以我们需要使用资源字典来管理我们的样式,方法如下:
首先在项目上右键,点击添加-资源字典,然后再资源字典中定义样式,代码如下:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Control_Style_Template">
<Style x:Key="stylebtn" TargetType="Button">
<Setter Property="Background" Value="Yellow" />
</Style>
</ResourceDictionary>
此时,样式还未生效,我们需要将样式的资源字典加载到应用中使用,即将样式资源字典添加到App.xaml中,代码如下:
<Application.Resources>
<ResourceDictionary Source="/StyleDictionary.xaml" />
</Application.Resources>
最后,将样式应用到控件中,上面将 资源字典引用添加到App.xaml中,说明整个应用都可以使用这个资源字典,所以在窗体中使用时如下:
<Button Content="样式设置3" Style="{StaticResource stylebtn}" />
至此,样式最基本的使用方式就讲完了,下面简要描述一下样式中各个关键字的意义。
样式的基本结构:
<Style x:Key="标识" TargetType="对应的控件类型">
<Setter Property="属性名称" Value="属性值" />
</Style>
使用结构:
<控件类型 Style="{StaticResource 标识key}" />
Tips:
- 其中
x:key
是用于标识样式名称,如果将其省略,则表示此样式为默认样式,即不需要你手动为控件添加Style,默认使用此样式 —— 需要注意,保证默认样式(相同控件)最多只有一个;- 其中Value的类型是object,所以它可以采用复杂属性设置,内容见Hello,World。
- 其中样式引用使用StaticResource,还可以使用DynamicResource(相对占用资源较多)—— 它们具体的区别本节不做讨论。
触发器为我们极大的简化了界面逻辑的书写,它主要包含三大类:简单的Trigger —— 主要处理属性变化、DataTrigger —— 数据绑定变化触发、EventTrigger —— 事件触发器。其中前两个可以进一步细分 —— 单个和多个。下面简要介绍下简单的触发器和事件触发器:
简单的触发器使用Trigger和MultiTrigger来实现,它们是使用的最为频繁的触发器。其效果是当一个或多个属性发生改变时,改变 其他的一个或多个属性的值。示例如下:
示例效果:鼠标悬停,字体绿色;鼠标悬停并按下,字体白色:
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Green" />
</Trigger>
<MultiTrigger >
<MultiTrigger.Conditions>
<Condition Property="IsPressed" Value="True" />
<Condition Property="IsMouseOver" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="Margin" Value="1" />
<Setter Property="Foreground" Value="White" />
</MultiTrigger>
</Style.Triggers>
其中的MultiTrigger中的Setter设置也可以套在MultiTrigger.Setters之内,如下:
<MultiTrigger.Setters>
<Setter Property="Margin" Value="1" />
<Setter Property="Foreground" Value="White" />
</MultiTrigger.Setters>
此处使用前景色做触发示例,而未选择背景色,因为背景色的MouseOver是无效的,原因是其内部使用ButtonChrome样式,需要利用模板处理才可以正确修改。
事件触发器由具体的事件引发。其主要用于动画的处理,其他情况使用的较少。关于动画的制作本节不做描述。
WPF在界面设计中最强大的部分应该就是模板了。它可以让你将一个勾选框改成一个按钮的样子,或者将方形按钮改成圆形按钮,等等。模板的定义和使用方式基本 和样式 一样,可以在控件内定义、也可以抽取出来定义到资源字典中。
WPF中模板主要有三种类型,ControlTemplate、DataTemplate和ItemsPanelTemplate,在本文中,将只介绍控件模板ControlTemplate,熟悉了控件模板,其他的两个大概也就会用了,况且另外两个相对与控件模板使用的要少一些。
下面是控件模板最简单的使用:定义+使用
<ControlTemplate x:Key="txt" TargetType="TextBox">
<TextBlock Text="{TemplateBinding Text}"></TextBlock>
</ControlTemplate>
<TextBox Text="控件模板" Template="{StaticResource txt}" />
当然,个人并不建议上面的定义方式,上面是直接自己写控件模板,但这样就丢失了默认模板的一些特点和功能(如上面的模板就让TextBox无法显示光标,无法定位输入位置),我更建议利用IDE来自动生成模板,因为这样会带有原始的默认模板,而以此模板进行修改可以保证功能不丢失。当然,也不能过于依赖自动生成的内容,因为其内容相对冗余,自己可以进行精简。
以现有模板为基础创建新的模板步骤:
一般情况下,都是使用方法1,即样式模板一起定义。
下面代码简要展示一个TextBox添加一个内置的标签:—— 以原生模板简单修改
<ControlTemplate x:Key="TextBoxControlTemplate1" TargetType="{x:Type TextBox}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<DockPanel>
<TextBlock DockPanel.Dock="Left" Text="内置标签:"></TextBlock>
<ScrollViewer x:Name="PART_ContentHost" Focusable="False" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
</DockPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" TargetName="border" Value="#FF7EB4EA"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="BorderBrush" TargetName="border" Value="#FF569DE5"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
关于控件的模板内容其实有很多,此处不再详述。
链接标注 原文 则表示未译,其他带有中文标题的表示译文内容。
要求:能听懂英文-外国人做的视频、能看墙外的-视频在Youtube上
网站内容管理——Authoring Websites
网站定制——Customizing Websites
Orchard库使用——Using the Orchard Gallery
网站管理——Managing Websites
缘由:由于刚接触Orchard不久,之前想为网站添加百度统计,后来又改为添加Google代码跟踪管理器,都建议将相关代码添加到
<head>
标签中,但是直接在控制面板中又无法修改到<head>
标签内容,故有如下修改:
解决方案:
Orchard中默认使用的页面(母版)为文件夹\Core\Shapes\Views
中的Documnet.cshtml
文件,修改此文件<head>
标签即可。
情景2:在一般情况上面修改没有问题,但有一次我启用了导入/导出模块,它依赖Setup.Service模块,所以,Setup.Service模块启用了,这样带来的问题就是Orchard原来的母版失效了。
后经查看,发现Orchard使用此模块内的Documnet.cshtml
文件作为母版,故又需要改此模块内的母版页 —— 具体路径为“Modules\Orchard.Setup\Views
”。
另,事实上个人觉得修改主题文件比较合理,但是个人现在暂未确定下来使用什么主题(可能后期自己开发),所有暂且使用以上方法。
当然,上述内容还可以通过开发模块来设置等等,
本文只提供了一个相对简便的修改方法。