[转载]实现checkbox的全选/全不选/点选/行内点选(原生JS版和jQ版)

mikel阅读(878)

[转载]实现checkbox的全选/全不选/点选/行内点选(原生JS版和jQ版) – Mr.Think的博客@MrThink.net… – 博客园.

日常项目中, 对于列表类文章或数据, 大概都会用到checkbox的全选或全不选的功能, 以前的项目中也写过checkbox的选择js, 但都没有整理过. 正好前几天一个兄弟遇到了这个问题, 索性, 我花了点时间, 用原生JS与jQuery分别写了一个版本, 考虑到使用时灵活性问题, 未封装, 需要的童鞋使用时自行改下相关参数.
实现checkbox的全选/全不选/点选/行内点选
功能介绍点此查看DEMO
1. 全选/全不选 选框一体实现, 即列表中选框的状态与全选/全不选框前的选框状态一致;
2. 自动更改 全选/全不选 选框的状态, 即列表中选框都选中时, 全选/全不选 选框也选中, 反之亦然;
3. 列表行内点击也可选中行内的checkbox, 并与1,2中的功能联动.
另,本文重在写全选, 鼠标划入划出背景变色为简易实现, 更加完善的请参考: http://mrthink.net/javascript-tagnames-highlight/.
原生JS版本核心代码

var js_chk = document.forms[js].chk_can;
var jsitems = document.forms[js].jsitems;
var jsrows = document.getElementById(js).getElementsByTagName(dd);

//判断选中个数与实际选框个数实现全选/全不选框的状态
var chk_canle = function(){
var checkedLen = 0;
//计算列表中选中状态的选框个数
for (var m = 0; m < jsitems.length; m++) {
if (jsitems[m].checked) {
checkedLen += 1;
}
}
//判断选中个数与实际个数是否相同,以确定全选/全不选状态
for (var m = 0; m < js_chk.length; m++) {
js_chk[m].checked = (jsitems.length == checkedLen);
}
}

//全选与全不选一体实现
for (var i = 0; i < js_chk.length; i++) {
js_chk[i].onclick = function(){
//列表中选框与全选选框统一状态
for (var m = 0; m < jsitems.length; m++) {
jsitems[m].checked = this.checked;
}
//全选选框统一状态
for (var m = 0; m < js_chk.length; m++) {
js_chk[m].checked = this.checked;
}
}
}

//列表中选框点击
for (var i = 0; i < jsitems.length; i++) {
jsitems[i].onclick = function(e){
//阻止冒泡,避免行点击事件中,直接选择选框无效
e && e.stopPropagation ? e.stopPropagation() : window.event.cancelBubble=true;
chk_canle();
}
}

//行内点击
for (var i = 0; i < jsrows.length; i++) {
jsrows[i].onclick = function(){
//行内点击时,行内的选框状态为原状态取反
this.getElementsByTagName(input)[0].checked = !this.getElementsByTagName(input)[0].checked;
chk_canle();
}
}

jQ版本核心代码

var _jq_chk = $(#jq>dl>dt>label>:checkbox);
var _jqitems = $(:checkbox[name=jqitems]);
var _rows = $(#jq>dl>dd);

//全选与全不选一体实现
_jq_chk.click(function(){
//列表中选框和全选选框统一状态
_jqitems.add(_jq_chk).attr(checked, this.checked);
});

//选框的点击事件
_jqitems.click(function(e){
//阻止冒泡,避免行点击事件中,直接选择选框无效
e.stopPropagation();
//判断选中个数与实际个数是否相同,以确定全选/全不选状态
_jq_chk.attr(checked, _jqitems.size() == _jqitems.filter(:checked).size());
});

//点选行时选中行内的checkbox
_rows.bind({
mouseenter: function(){
$
(this).addClass(hover);
},
mouseleave: function(){
$
(this).removeClass(hover);
},
//点选
click: function(){
//行内点击时,行内的选框状态为原状态取反
$
(this).find(:checkbox).attr(checked, !$(this).find(:checkbox).get(0).checked)
//判断选中个数与实际个数是否相同,以确定全选/全不选状态
_jq_chk.attr(checked, _jqitems.size() == _jqitems.filter(:checked).size());
}
});

[转载]Android 2.3 SDK 配置方法

mikel阅读(756)

[转载]Android 2.3 SDK 配置方法 – 青竹少年 – 博客园.

安装Android 2.3有两种方法:1.从官方直接下载Android 2.3 SDK。 2.从SDK 2.2更新到2.3。

在这,我就不说第一种了,没什么可说的。我就说说第二种吧。

我是在Windows下的Android-sdk-windows里更新的,并没有去Eclipse更新,我就给大家说说我更新的步骤吧:

第一步:打开你的Android SDK and AVD Manager,先别急着下载什么的,因为你现在什么也下载不了,因为你必须先在Setting里面的Misc下面勾上Force https://……sources to be fetched using http://….这一项。看下面的截图:

第二步:现在你可以点击Available packages选项了。然后,把那些需要更新的东东都打上对勾,再点击Install Selected按钮。然后,按照它的指示进行操作就行了,挺简单的。下面是截图:

第三步:当你上面的工作做完后,你会发现在你的C:\android-sdk-windows\tools目录下并没有adb.exe这个可执 行文件。并且当你打开Eclipse时,有关Android的插件会报错。这时你就应该这样做:首先,改一下你的环境变量,把原来的 C:\android-sdk-windows\tools改成C:\android-sdk-windows\platform-tools。其次,把 C:\android-sdk-windows\platform-tools目录下的 adb.exe,AdbWinApi.dll,AdbWinUsbApi.dll 这三个文件拷到你C:\android-sdk-windows\tools目录下,然后把其它文件都拷贝到C:\android-sdk- windows\platforms\android-9\tools目录下,这时你就有疑问了,在C:\android-sdk-windows \platforms\android-9 这个目录下并没有tools文件夹,这时就需要你建一个新的文件夹,把它们放到里面。到这,大部分工作已经完成,现在你可以重启你Eclipse了,不过 它会提示你更新Android插件,这时,你按照提示做就OK了。

下面是我成功安装后,Android 2.3的界面:

看上去也没太大的变化啊!不过图标变的好看多了。好吧,写到这,也就写完了,如果大家有什么问题,可以问我,我会尽量回答的。

[转载]IPC框架分析 Binder,Service,Service manager

mikel阅读(947)

[转载]IPC框架分析 Binder,Service,Service manager – 手中无模式 心中有模式 – 博客园.

我首先从宏观的角度观察Binder,Service,Service Manager,并阐述各自的概念。从Linux的概念空间中,Android的设计Activity托管在不同的的进程,Service也都是托管在不 同的进程,不同进程间的Activity,Service之间要交换数据属于IPC。Binder就是为了Activity通讯而设计的一个轻量级的 IPC框架。

在代码分析中,我发现Android中只是把Binder理解成进程间通讯的实现,有点狭隘,而是应该站在公共对象请求代理这个高度来理解 Binder,Service的概念,这样我们就会看到不一样的格局,从这个高度来理解设计意图,我们才会对Android中的一些天才想法感到惊奇。从 Android的外特性概念空间中,我们看不到进程的概念,而是Activity,Service,AIDL,INTENT。一般的如果我作为设计者,在 我们的根深蒂固的想法中,这些都是如下的C/S架构,客户端和服务端直接通过Binder交互数据,打开Binder写入数据,通过Binder读取数 据,通讯就可以完成了。

该注意到Android的概念中,Binder是一个很低层的概念,上面一层根本都看不到Binder,而是Activity跟一个Service的对象直接通过方法调用,获取服务。

这个就是Android提供给我们的外特性:在Android中,要完成某个操作,所需要做的就是请求某个有能力的服务对象去完成动作,而无需知道 这个通讯是怎样工作的,以及服务在哪里。所以Andoid的IPC在本质上属于对象请求代理架构,Android的设计者用CORBA的概念将自己包装了 一下,实现了一个微型的轻量级CORBA架构,这就是Andoid的IPC设计的意图所在,它并不是仅仅解决通讯,而是给出了一个架构,一种设计理念,这 就是Android的闪光的地方。Android的Binder更多考虑了数据交换的便捷,并且只是解决本机的进程间的通讯,所以不像CORBA那样复 杂,所以叫做轻量级。

所以要理解Android的IPC架构,就需要了解CORBA的架构。而CORBA的架构在本质上可以使用下面图来表示:

在服务端,多了一个代理器,更为抽象一点我们可以下图来表示。

分析和CORBA的大体理论架构,我给出下面的Android的对象代理结构。

在结构图中,我们可以较为清楚的把握Android的IPC包含了如下的概念:

•设备上下文什(ContextObject)
设备上下文包含关于客服端,环境或者请求中没有作为参数传递个操作的上下文信息,应用程序开发者用ContextObject接口上定义的操作来创建和操作上下文。

• Android代理:这个是指代理对象
• Binder Linux内核提供的Binder通讯机制

Android的外特性空间是不需要知道服务在那里,只要通过代理对象完成请求,但是我们要探究Android是如何实现这个架构,首先要问的是在 Client端要完成云服务端的通讯,首先应该知道服务在哪里?我们首先来看看Service Manger管理了那些数据。Service Manager提供了add service,check service两个重要的方法,并且维护了一个服务列表记录登记的服务名称和句柄。

Service manager service使用0来标识自己。并且在初始化的时候,通过binder设备使用BINDER_SET_CONTEXT_MGR ioctl将自己变成了CONTEXT_MGR。Svclist中存储了服务的名字和Handle,这个Handle作为Client端发起请求时的目标 地址。服务通过add_service方法将自己的名字和Binder标识handle登记在svclist中。而服务请求者,通过 check_service方法,通过服务名字在service list中获取到service 相关联的Binder的标识handle,通过这个Handle作为请求包的目标地址发起请求。

我们理解了Service Manager的工作就是登记功能,现在再回到IPC上,客服端如何建立连接的?我们首先回到通讯的本质:IPC。从一般的概念来讲,Android设计 者在Linux内核中设计了一个叫做Binder的设备文件,专门用来进行Android的数据交换。所有从数据流来看Java对象从Java的VM空间 进入到C++空间进行了一次转换,并利用C++空间的函数将转换过的对象通过driver\binder设备传递到服务进程,从而完成进程间的IPC。这 个过程可以用下图来表示

这里数据流有几层转换过程。

(1) 从JVM空间传到c++空间,这个是靠JNI使用ENV来完成对象的映射过程。

(2) 从c++空间传入内核Binder设备,使用ProcessState类完成工作。

(3) Service从内核中Binder设备读取数据。

Android设计者需要利用面向对象的技术设计一个框架来屏蔽掉这个过程。要让上层概念空间中没有这些细节。Android设计者是怎样做的呢?我们通过c++空间代码分析,看到有如下空间概念包装(ProcessState@(ProcessState.cpp)

在ProcessState类中包含了通讯细节,利用open_binder打开Linux设备dev\binder,通过ioctrl建立的基本的通讯 框架。利用上层传递下来的servicehandle来确定请求发送到那个Service。通过分析我终于明白了Bnbinder,BpBinder的命 名含义,Bn-代表Native,而Bp代表Proxy。一旦理解到这个层次,ProcessState就容易弄明白了。

下面我们看JVM概念空间中对这些概念的包装。为了通篇理解设备上下文,我们需要将Android VM概念空间中的设备上下文和C++空间总的设备上下文连接起来进行研究。

为了在上层使用统一的接口,在JVM层面有两个东西。在Android中,为了简化管理框架,引入了ServiceManger这个服务。所有的服 务都是从ServiceManager开始的,只用通过Service Manager获取到某个特定的服务标识构建代理IBinder。在Android的设计中利用Service Manager是默认的Handle为0,只要设置请求包的目标句柄为0,就是发给Service Manager这个Service的。在做服务请求时,Android建立一个新的Service Manager Proxy。Service Manager Proxy使用ContexObject作为Binder和Service Manager Service(服务端)进行通讯。

我们看到Android代码一般的获取Service建立本地代理的用法如下:

IXXX  mIxxx=IXXXInterface.Stub.asInterface(ServiceManager.getService(“xxx”));

例如:使用输入法服务:

IInputMethodManager mImm=

IInputMethodManager.Stub.asInterface(ServiceManager.getService(“input_method”));
这些服务代理获取过程分解如下:

(1) 通过调用GetContextObject调用获取设备上下对象。注意在AndroidJVM概念空间的ContextObject只是 与Service Manger Service通讯的代理Binder有对应关系。这个跟c++概念空间的GetContextObject意义是不一样的。

注意看看关键的代码

BinderInternal.getContextObject()    @BinderInteral.java
NATIVE JNI:getContextObject()   @android_util_Binder.cpp

Android_util_getConextObject            @android_util_Binder.cpp
ProcessState::self()->getCotextObject(0)  @processState.cpp
getStrongProxyForHandle(0)  @
NEW BpBinder(0)

注意ProcessState::self()->getCotextObject(0) @processtate.cpp,就是该函数在进程空间建立
了ProcessState对象,打开了Binder设备dev\binder,并且传递了参数0,这个0代表了与Service Manager这个服务绑定。

(2) 通过调用ServiceManager.asInterface(ContextObject)建立一个代理ServiceManger。

mRemote= ContextObject(Binder)

这样就建立起来ServiceManagerProxy通讯框架。

(3)客户端通过调用ServiceManager的getService的方法建立一个相关的代理Binder。

ServiceMangerProxy.remote.transact(GET_SERVICE)

IBinder=ret.ReadStrongBinder() -》这个就是JVM空间的代理Binder

JNI Navite: android_os_Parcel_readStrongBinder()    @android_util_binder.cpp

Parcel->readStrongBinder()  @pacel.cpp

unflatten_binder  @pacel.cpp

getStrongProxyForHandle(flat_handle)

NEW BpBinder(flat_handle)-》这个就是底层c++空间新建的代理Binder。

整个建立过程可以使用如下的示意图来表示:


Activity为了建立一个IPC,需要建立两个连接:访问Servicemanager Service的连接,IXXX具体XXX Service的代理对象与XXXService的连接。这两个连接对应c++空间ProcessState中BpBinder。对IXXX的操作最后就 是对BpBinder的操作。由于我们在写一个Service时,在一个Package中写了Service Native部分和Service Proxy部分,而Native和Proxy都实现相同的接口:IXXX Interface,但是一个在服务端,一个在客服端。客户端调用的方式是使用remote->transact方法向Service发出请求,而 在服务端的OnTransact中则是处理这些请求。所以在Android Client空间就看到这个效果:只需要调用代理对象方法就达到了对远程服务的调用目的,实际上这个调用路径好长好长。

我们其实还一部分没有研究,就是同一个进程之间的对象传递与远程传递是区别的。同一个进程间专递服务地和对象,就没有代理BpBinder产生,而只是对 象的直接应用了。应用程序并不知道数据是在同一进程间传递还是不同进程间传递,这个只有内核中的Binder知道,所以内核Binder驱动可以将 Binder对象数据类型从BINDER_TYPE_BINDER修改为BINDER_TYPE_HANDLE或者 BINDER_TYPE_WEAK_HANDLE作为引用传递。

[转载]谈.net开发人员应该熟悉的开发模式

mikel阅读(888)

[转载]谈.net开发人员应该熟悉的开发模式 – 无疆_炎戎 – 博客园.

我们总会有这样一个经验:一个系统最不容易也最不应该变化的部分是领域逻辑,最容易变化也最应该变化的是数据的呈现方式。

在java的各种应用中可以说是到处可见mvc,j2ee贯穿mvc的概念,Android的开发方式也是类mvc的,mvc结构对于做过java 应用的人而言简直就是司空见惯。而在.net这边,由于之前微软为大家提供的各种winform、ASP.NET项目典范(比如那个petshop series)将“三层”概念很好的灌输到了.net程序员的大脑中,许多.net开发者凡是做个东西都要搬出自己最拿手的IModel、IDAL这样的 神器。

其实mvc与所谓的“三层架构”是两个层次上的东西,前者是一种结构模式,而后者则是分层的角度去说。

一件很奇怪的事情,许多人知道“三层”却不知道mvc,其实这要归结与.net的早期开发技术ASP.NET和winform这些page controller的典范让许多人对三层夸夸其谈却对mvc视而不见甚至一无所知。什么是page controller模式呢?搞.net的大多都用过winform和webform,这种xxxform用起来很直观,我们想要做一个程序,ok,最简 单的方式就是拖拖拽拽几个控件,然后在一个叫code behind的东西里写这些UI事件的处理逻辑,加一大堆变量用于记录数据和状态,这样一个程序就能出炉。这种开发方式对于一些小软件系统的开发其实效率 还是蛮高的,后来人们看到其弊端—一旦修改UI,事件处理就要跟着变,但是业务还是那个业务,凭什么要修改非UI的代码?于是有人提出“三层”,最朴 素的理解就是将原本那堆事件处理里的code分成业务代码和数据库访问代码并转移到其它类中,做多了就把那坨UI叫做UI,那坨业务代码叫做BLL,那坨 DAO叫做DAL。也就是这种架构:

image

而对于j2ee的开发者来说熟悉的是下图。

image

(说明:这两幅图copy自是daxnet文)

MVC是什么

MVC是一个很经典的结构,并且其又其思想衍生出很多变种比如MVP,MVVP。传统的MVC结构之一是这样的(拿主动型mvc来说):

image

比如web开发(比如ASP.NET mvc或者是java的web开发方式),view就是纯web页面或者webservice,当提交一个表单/调用webservice或者ajax后 会将数据提交给controller(当然期间可能会经过各种filterchain、listener这样的东西)controller调用相应的业务 模块来处理这个请求,最终结果会更新View的显示。

MVP

对于非天然mvc的框架

对于asp.net/winform而言,虽然可以通过改造让其支持mvc结构的开发(比如通过定制IHttpModule、 IHttpHandler云云),但是在企业看来这些都算是邪门武功(因为这样会丧失xxxform在开发上的很多特性比如快速开发)。大多数使用的是 mvp模式。什么是mvp呢?其实mvp是mvc的一个变种。因为用winform或者webform的话form始终是个阻碍mvc开发的问题。那么 好,我们仍然使用designer和codebehind,其实一个架构设计的好坏是取决于人而不是具体的技术的,只要我们OO一时强page controller一样好用。

image

在MVP模式中我们需要自己定制各个View(web页面或者窗体)对应的IView和IPresenter、IModel。IView要对 IPresenter暴露操作UI、数据绑定的接口,IPresenter对IView要暴露当UI事件触发需要调用的接口,IPresenter根据 IView传递过来的请求调用业务接口并根据结果操作UI。举个简单的例子,一个计算“x+y=?”的程序。如果我们这样定义IPresenter和 IView

public interface IPresenter
{
IView View { get; set; }
void CalculateResult();
}

public interface IView
{
IPresenter Presenter { get; set; }
void ShowResult(string result);
int ValueOne { get; }
int ValueTwo { get; }
}

IPresenter的实现如下(这里从简把IModel去掉了)

Presenter

namespace ClientLibrary
{
public class Presenter : IPresenter
{
private IView _view;
public IView View
{
get
{
return _view;
}
set
{
_view
= value;
_view.Presenter
= this;
}
}

private static readonly string RESULT_FORMATTER = {0}+{1},the result is {2};
public void CalculateResult()
{
if (_view != null)
{
var result
= string.Format(RESULT_FORMATTER, _view.ValueOne, _view.ValueTwo, _view.ValueOne + _view.ValueTwo);
_view.ShowResult(result);
this.A = 123;
}
}
private int _a;
public int A
{
set
{
A
= value;
}
}
}
}

View的实现如下(那silverlight为例,换成别的也行)

MainPage

namespace Debug
{
public partial class MainPage : UserControl, IView
{
public MainPage()
{
InitializeComponent();
}

private IPresenter _presenter;

private void btn_Click(object sender, RoutedEventArgs e)
{
if (_presenter != null)
{
_presenter.CalculateResult();
}
#region hidden
/*int total = 0;
try
{
total = int.Parse(tb1.Text) + int.Parse(tb2.Text);
MessageBox.Show(“计算结果:” + total.ToString());
}
catch (Exception ex)
{
MessageBox.Show(“出错啦” + ex.ToString());
}
finally
{
tb1.Text = string.Empty;
tb2.Text = string.Empty;
}
*/
#endregion

}

public IPresenter Presenter
{
get
{
return _presenter;
}
set
{
_presenter
= value;
}
}

public void ShowResult(string result)
{
MessageBox.Show(result);
}

public int ValueOne
{
get { return int.Parse(tb1.Text); }
}

public int ValueTwo
{
get { return int.Parse(tb2.Text); }
}
}
}

一个很简单的东西,看上去写成的要多些那么一坨东西,但是好处是显而易见的,就是更换view非常方便,根本不用去改你的IPresenter、Presenter和业务。一切都是接口调用而不依赖具体实现,这就是好处。

你必须要懂的MVVM

对于.NET平台的开发人员,托微软的福分我们拥有一种更为强大的模型—MVVM。这应该算是做WPF/Silverlight应用的人必懂的 一种结构,WPF/silverlight天生支持数据绑定和命令绑定(不过sl在命令绑定上还比较弱),这就为我们使用MVVM创造了可能。

View是什么呢,纯的View只有xaml或者附带必要的只与View本身相关逻辑代码。ViewModel,你可以把它理解为View具体呈现 内容所依赖数据的一个抽象,在MVVM中View与ViewModel总会有一种绑定关系,一旦ViewModel中被绑定的数据发生改变View上的数 据就会跟着变,相反也有可能,比如你的账号密码框内容发生变化,关联的ViewModel中的数据就会被框架自动通知到。

在wpf/silverlight中,绑定是通过xaml语法来完成(虽然你可以选择用C#来写但不符合mvvm的宗旨),并且绑定双方的通知机制 是有框架来完成,也就是说一个会xaml和blend的美工只需事先和coder商量下“咱们的xx和xx是在哪个ViewModel上叫XXX的属性的 XXX属性……”问题之后就可以各干各的了。那么ViewModel怎么写,咋view中又怎么绑定到viewmodel呢?首先我们谈 ViewModel。

说道ViewModel你需要知道依赖属性和依赖对象的概念,这是wpf/silverlight的基础所以不多说。有两种方式写 ViewModel。第一种是自己去实现INotifyPropertyChanged接口,并在属性变化时去调用 NotifyPropertyChanged事件。

为了方便我们定义一个ViewModelBase的抽象基类,然后让其他ViewModel继承这个基类。

ViewModelBase

public abstract class ViewModelBase : System.ComponentModel.INotifyPropertyChanged, IDisposable
{
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
var arg
= new System.ComponentModel.PropertyChangedEventArgs(propertyName);
PropertyChanged(
this, arg);
}
}
public virtual void Dispose()
{

}
}

DemoViewModel
public class DemoViewModel : ViewModelBase     {         #region fields         private string _propertyA;         #endregion         #region presentation properties         public string PropertyA         {             get             {                 return _propertyA;             }             set             {                 if (_propertyA != value)                 {                     _propertyA = value;                     base.OnPropertyChanged("PropertyA");                 }             }         }         #endregion     }
 

第二种是利用DependencyObject和DependencyProperty。

PeopleItemViewModel

public class PeopleItemViewModel : DependencyObject, IPeopleItemViewModel
{
public PeopleItemViewModel()
{

}
public static readonly DependencyProperty SimpleUserDataProperty = DependencyProperty.Register(SimpleUserData, typeof(SimpleUserData), typeof(PeopleItemViewModel));
public static readonly DependencyProperty RelativeSimpleUserDataProperty = DependencyProperty.Register(RelativeSimpleUserData, typeof(ObservableCollection<SimpleUserData>), typeof(PeopleItemViewModel));
public static readonly DependencyProperty AllSimpleUserDataProperty = DependencyProperty.Register(AllSimpleUserData, typeof(ObservableCollection<SimpleUserData>), typeof(PeopleItemViewModel));

public SimpleUserData SimpleUserData
{
get
{
return (SimpleUserData)base.GetValue(SimpleUserDataProperty);
}
set
{
if (!base.CheckAccess())
{
Dispatcher.Invoke(
new Action(
()
=>
{
SimpleUserData
= value;
}));
}
else
base.SetValue(SimpleUserDataProperty, value);
}
}
public ObservableCollection<SimpleUserData> RelativeSimpleUserData
{
get
{
return (ObservableCollection<SimpleUserData>)base.GetValue(RelativeSimpleUserDataProperty);
}
set
{
if (!base.CheckAccess())
{
Dispatcher.Invoke(
new Action(
()
=>
{
RelativeSimpleUserData
= value;
}));
}
else
{
base.SetValue(RelativeSimpleUserDataProperty, value);
var collectionView
= CollectionViewSource.GetDefaultView(value);
collectionView.SortDescriptions.Add(
new SortDescription(Distance, ListSortDirection.Ascending));
}
}
}
public ObservableCollection<SimpleUserData> AllSimpleUserData
{
get
{
return (ObservableCollection<SimpleUserData>)base.GetValue(AllSimpleUserDataProperty);
}
set
{
if (!base.CheckAccess())
{
Dispatcher.Invoke(
new Action(
()
=>
{
AllSimpleUserData
= value;
}));
}
else
{
base.SetValue(AllSimpleUserDataProperty, value);
var collectionView
= CollectionViewSource.GetDefaultView(value);
collectionView.SortDescriptions.Add(
new SortDescription(Distance, ListSortDirection.Ascending));
}
}
}
}

在View中绑定ViewModel。

为了方便,我们可以在app.xaml中将需要的viewmode放到全局资源字典中。

image

然后再我们的vs视图设计器Properties(中文版显示的是“属性”)页上选择为绑定源设置绑定目标(包括source和path等)以及必要的值转换器等等即可。

image image image

(PS:虽然vs很强大,但个人还是建议熟悉xaml的绑定语法,想当初用vs2008搞wpf的时候貌似还没有这么方便的设计器。。。)

[转载]dedecms5.6内容页面调用当前文章的相关文章解决办法

mikel阅读(981)

[转载]dedecms5.6内容页面调用当前文章的相关文章解决办法 – 北方的雪 – 博客园.

在使用dedecms5.6时发现如果在内容页面调用相关文章,简单的使用dedecms arclist不能够实现,但是arclist有一个字段keyword,如果把当前文章的keyword调用出来,就能够得到当前相关文章的列表.我的 做法是对keyword附一个固定的值

复制代码

  1. {dede:arclist keyword=’relation’ row=’5′}
  2. <li><a href=”[field:arcurl/]”>[field:title/]</a></li>
  3. {/dede:arclist}

如果是在终端页面调用相关文章,就将keyword的值固定,其他的参数也都是可以用的,默认的keyword值是当前页面得关键字,有兴趣的可以去我网站看看 游戏联盟114 可以对比下面相关文章的关键字和当前页面得关键字

具体的实现方式是:
1.修改include/arc.archives.class.php找到MakeOneTag($this->dtp, $this, ‘N’,$reltag);将其替换为

复制代码

  1. $reltag = explode(‘,’,$this->Fields[‘keywords’]);
  2. $reltag = $reltag[0];
  3. MakeOneTag($this->dtp, $this, ‘N’,$reltag);

2.修改include/下的channelunit.func.php找到函数MakeOneTag函数 MakeOneTag(&$dtp, &$refObj, $parfield=’Y’)在函数的最后加上一个参数

复制代码

  1. MakeOneTag(&$dtp, &$refObj, $parfield=’Y’,$reltag)

仔细看下有什么区别吧
在函数中找到

复制代码

  1. if(in_array($tagname,$alltags))
  2. {
  3. $filename = DEDEINC.’/taglib/’.$tagname.’.lib.php’;
  4. include_once($filename);
  5. $funcname = ‘lib_’.$tagname;
  6. $dtp->Assign($tagid,$funcname($ctag,$refObj));
  7. }

将其修改为

复制代码

  1. if(in_array($tagname,$alltags))
  2. {
  3. $filename = DEDEINC.’/taglib/’.$tagname.’.lib.php’;
  4. include_once($filename);
  5. $funcname = ‘lib_’.$tagname;
  6. if($tagname == ‘arclist’){
  7. foreach($ctag->CAttribute->Items as $key => $val){
  8. if($key == ‘keyword’){
  9. if($val==’Relation’){
  10. $ctag->CAttribute->Items[$key]=$reltag;
  11. }
  12. }
  13. }
  14. }
  15. $dtp->Assign($tagid,$funcname($ctag,$refObj));
  16. }

呵呵,去生成静态吧,不要忘记了 keyword=’relation’  relation 不要变哦,变了可就调不出来了

[转载]GSM蜂窝基站定位基本原理浅析

mikel阅读(1089)

[转载]GSM蜂窝基站定位基本原理浅析 – Mobile On Line 镜像站点 – 博客园.

位置服务已经成为越来越热的一门技术,也将成为以后所有移动设备(智能手机、掌上电脑等)的标配。随着人们对BLS(Based Location Serices,基于位置的服务)需求的飞速增长,无线定位技术也越来越得到重视。GSM蜂窝基站定位,以其定位速度快、成本低(不需要移动终端上添加额外的硬件)、耗电少、室内可用等优势,作为一种轻量级的定位方法,也越来越常用。本文简单介绍一下各种基于GSM蜂窝基站的定位方法及基本原理,给开发人员作为参考。我将尽量尝试用开发人员熟悉的方式来描述问题。

预备知识:GSM蜂窝网络基础结构

我 们知道,GSM网络的基础结构是由一系列的蜂窝基站构成的,这些蜂窝基站把整个通信区域划分成如图所示的一个个蜂窝小区(当然实际上,一个基站往往不并不 只是对应一个小区,但是这个与我们讨论的主题关系不大,我们不做深究)。这些小区小则几十米,大则几千米。如下图所示,我们用移动设备在GSM网络中通 信,实际上就是通过某一个蜂窝基站接入GSM网络,然后通过GSM网络进行数据(语音数据、文本数据、多媒体数据等)传输的。也就是说我们在GSM中通信 时,总是需要和某一个蜂窝基站连接的,或者说是处于某一个蜂窝小区中的。那么GSM定位,就是借助这些蜂窝基站进行定位。

2009698297_thumb1

1.COO(Cell of Origin)定位

COO 定位是一种单基站定位,即根据设备当前连接的蜂窝基站的位置来确定设备的位置。那么很显然,定位的精度就取决于蜂窝小区的半径。在基站密集的城市中心地 区,通常会采用多层小区,小区划分的很小,这时定位精度可以达到50M以内;而在其他地区,可能基站分布相对分散,小区半径较大,可能达到几千米,也就意 味着定位精度只能粗略到几千米。目前Google地图移动版中,通过蜂窝基站确定“我的位置”,基本上用的就是这种方法。

从原理上我们 可以看出,COO定位其精度是不太确定的。但是这却是GSM网络中的移动设备最快捷、最方便的定位方法,因为GSM网络端以及设备端都不需要任何的额外硬 件投入。只要运营商支持,GSM网络中的设备都可以以编程方式获取到当前基站的一个唯一代码,我们可以称之为基站ID,或CellID。在一般的设备中, 可能都存在一个类似如下的GetCurrentCellID()方法的接口来提供当前GSM蜂窝基站ID:

CellID = GetCurrentCellID();

通过这个接口获取到CellID后,我们还需要根据这个CellID查出该蜂窝基站所在的具体地理坐标。这时,我们可能就需要调用一些包含 [CellID,地理坐标]对应关系的外部数据以确定相应的地理坐标。这个外部数据,通常可以由一些第三方Web服务来提供。这些Web服务的接口可能类 似于如下形式:

Position=GetPosition(CellID);

当然,再次说明,上面的GetCurrentCellID方法、GetPosition方法都是我虚构的,只是为了说明逻辑关系,并不一定实际存在。关于COO方法在Windows Mobile环境下的具体编程方法,请参考《为Windows Mobile设备创建位置感知的应用程序》。

2.七号信令定位

该技术以信令监测为基础,能够对移动通信网中特定的信令过程,如漫游、切换以及与电路相关的信令过程进行过滤和分析,并将监测结果提供给业务中心, 以实现对特定用户的个性化服务。该项技术通过对信令进行实时监测,可定位到一个小区,也可定位到地区。故适用对定位精确度要求不高的业务,如漫游用户问候 服务,远程设计服务、平安报信和货物跟踪等。目前,国内各省和地区移动公司的短信欢迎系统采用的就是此种技术。

7.TOA/TDOA定位

TOA(Time of Arrival,到达时间)、TDOA(Time Difference of Arrival,到达时间差)都是基于电波传播时间的定位方法。同时也都是三基站定位方法,二者的定位都需要同时有三个位置已知的基站合作才能进行。

TOA_DTOA_thumb6

如上图所示,TOA/DTOA定位方法都是通过三对[Positioni,Ti](i=1,2,3)来确定设备的位置Location。二者的不同只是GetLocation()函数的具体算法上的不同。

TOA电波到达时间定位基本原理是得到Ti(i=1,2,3)后,由Ti*c得到设备到基站i之间的距离Ri,然后根据几何只是建立方程组并求解,从而求得Location值。如下图所示。

TOA_thumb1

由于图中距离的计算完全依赖于时间,因此TOA算法对系统的时间同步要求很高,任何很小的时间误差都会被放大很多倍,同时由于多径效应的影响又会带来很大的误差,因而单纯的TOA在实际中应用很少。

DTOA电波到达时间差定位是对TOA定位的改进,与TOA的不同之处在于,得到Ti后不是立即用Ti去求距离Ri,而是先对T1,T2,T3两两求差,然后通过一些巧妙的数学算法建立方程组并求解,从而得到Location值。如下图所示。

DTOA_thumb

DTOA由于其中巧妙设计的求差过程会抵消其中很大一部分的时间误差和多径效应带来的误差,因而可以大大提高定位的精确度。

由于DTOA对网络要求相对较低,并且精度较高,因而目前已经成为研究的热点。

4.AOA定位

AOA(Angle of Arrival,到达角度)定位是一种两基站定位方法,基于信号的入射角度进行定位。

AOA_thumb

如上图所示,知道了基站1到设备之间连线与基准方向的夹角α1,就可以画出一条射线L1;同样知道了知道了基站2到设备之间连线与基准方向的夹角α2,就可以画出一条射线L2。那么L1月L2的交点就是设备的位置。这就是AOA定位的基本数学原理。用函数调用表达如下。

Location=GetLocation([Pisition1,α1],[Position2,α2]);

AOA定位通过两直线相交确定位置,不可能有多个交点,避免了定位的模糊性。但是为了测量电磁波的入射角度,接收机必须配备方向性强的天线阵列。

5.基于场强的定位

该方法是通过测出接收到的信号场强和已知的信道衰落模型及发射信号的场强值估计收发信短的距离,根据多个三个距离值就可以得到设备的位置。从数学模型上看,和TOA算法类似,只是获取距离的方式不同。场强算法虽然简单,但是由于多径效应的影响,定位精度较差。

6.混合定位

混合定位就是同时使用两种以上的定位方法来进行定位。通过各种定位方法之间结合使用,互补短长,以达到更高的定位精度。

A-GPS定位(辅助GPS定位)就是一种混合定位,是GPS定位技术与GSM网络的结合。A-GPS具有很高的定位精度,目前正被越来越广泛的使用。

GPS定位作为一种传统的定位方法,仍是目前应用最广泛、定位精度最高的定位技术。但是相对而言,GPS定位成本高(需要终端配备GPS硬件)、定 位慢(GPS硬件初始化通常需要3~5分钟甚至10分钟以上的时间)、耗电多(需要额外硬件自然耗电多),因此在一些定位精度要求不高,但是定位速度要求 较高的场景下,并不是特别适合;同时因为GPS卫星信号穿透能力弱,因此在室内无法使用(关于GPS的定位原理可参考GPS定位基本原理浅析)。相比之下,GSM蜂窝基站定位快速、省电、低成本、应用范围限制小,因此在一些精度要求不高的轻型场景下,也大有用武之地。关于在Windows Mobile环境下GPS定位和GSM蜂窝基站定位的相关开发技术,可参考为Windows Mobile设备创建位置感知的应用程序

[转载]web开发Javascript点点小技巧

mikel阅读(1044)

[转载]【web开发】Javascript点点小技巧 – 275095923 – 博客园.

1、特性检测而非浏览器检测

因为某某特性某浏览器不支持,我们经常的做法是在代码中直接先做浏览器判断如:

1 if(Broswer.isFirfox){
2 //do something
3 }

其实这样做是不科学的,因为很可以其它浏览器上可以支持你要用的特性,所以,比较好的做法为是直接做特性判断。

如:

1 if(window.localStorage){
2 //使用本地存储功能
3 }

2、使用方括号来访问属性或方法

这一点到不是强制的,只不过如果使用方括号来访问可以享受一些动态特性带来的好处,而且命名方面有少了许多限制。

如:

1 for(var i=0;i<9;i++){
2 obj["method"+i]();
3 }

3、表单的那些事

这里主要提两个很有用的属性,可以让你操作表单方便不少。

1、form有一个elements属性。作用呢就是可以得到一个表单下的所有表单元素,这样在批量处理表单元素时就很有用,如:表单元素的序列化,或者验证之类的很有帮助。

2、对于第一个表单元素也有一个类似属性为form.这样可以很轻松得到一个表单元素属于哪个表单。
4、a元素onclick的那些事。

1 <a href="cool.html" onclick = "doSomething()">做点什么吧</a>

点击这样一个链接时会有两种情况发生,1、如果dosomthing返回true,那么浏览器就会发生跳转到cool.html,相返如果返回false的话,就会忽略href。因此借住这个特性,我们可以写这样的代码。

1 function doSomething(){
2 return confirm("您确认要离开吗");
3 }

有没有发现比起下面这样的代码爽了很多。

1 function doSomething(){
2 var ret = confirm("确认要离开吗?");
3 if(ret){
4 window.loaction.href = "cool.html";
5 }
6 }

5、类型转换时不一样的做法。

怎样把字符串转换成数字呢?我知道parseInt(“123”,10),除此之外还有什么好办法没,看下面的。

1 var num1 = "123";
2 num1 = num1*1;
3 var num2 = "123";
4 num2 = +num2;

这两种方法是不是很不错。

还是很简洁吧。祝学习愉快!

1 var a = 1;
2 a = !!a;

那转换为bool类型有没有什么好办法呢?有啊!

[转载]ASP.Net MVC探索之路 Model的比较验证

mikel阅读(1125)

[转载]ASP.Net MVC探索之路 – Model的比较验证 – Catcher In The Rye – 博客园.

WebForm有一个比较验证服务器控件CompareValidator ,可以比较两个控件的值大小或一个控件与某一个具体值的大小。可以进行string,int,double,DateTime,decimal这些数据类 型的==、!=、>、<、>=、<=比较。在ASP.NET MVC 2.0中,我们已经可以使用基于DataAnnotations的校验方式,对Model的值进行空校验(Required)、范围校验(Range)、 字符串长度校验(StringLengthAttribute)等。在ASP.NET MVC 3中,我们还可以使用CompareAttribute进行简单的相等(==)校验,但仅此而已,其他校验就没有了。
这里我们定义一个类似WebForms验证服务器控件CompareValidator的Attribule。

首先定义一个枚举表示我们要比较的数据类型:

public enum ValidationDataType : byte
{
String,Integer,Double,Date,Currency
/*Decimal*/
}

再定义一个枚举表示比较方式:

public enum ValidationCompareOperator : byte
{
Equal, NotEqual,GreaterThan,GreaterThanEqual,LessThan,LessThanEqual
}

然后当然就是主角CompareAttribute:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public class CompareAttribute : ValidationAttribute
{
public string SourceProperty { get; private set; }
public string OriginalProperty { get; private set; }
public ValidationCompareOperator Operator { get; private set; }
public ValidationDataType Type{ get; private set; }

private const string _defaultErrorMessage = ‘{0}’ 与 ‘{1}’ 进行 {2} 比较失败;

public CompareAttribute(string sourceProperty, string originalProperty
, ValidationCompareOperator op, ValidationDataType type)
:
base(_defaultErrorMessage)
{
SourceProperty
= sourceProperty;
OriginalProperty
= originalProperty;
Operator
= op;
Type
= type;
}

public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
SourceProperty, OriginalProperty, Operator.ToString());
}

public override bool IsValid(object value)
{
PropertyDescriptorCollection properties
= TypeDescriptor.GetProperties(value);
object sourceProperty = properties.Find(SourceProperty, true /* ignoreCase */)
.GetValue(value);
object originalProperty = properties.Find(OriginalProperty, true /* ignoreCase */)
.GetValue(value);

return compare(sourceProperty,originalProperty);
}

private bool compare(object sourceProperty, object originalProperty)
{
int num = 0;
switch (this.Type)
{
case ValidationDataType.String:
num
= string.Compare((string)sourceProperty
, (
string)originalProperty, false, CultureInfo.CurrentCulture);
break;

case ValidationDataType.Integer:
num
= ((int)sourceProperty).CompareTo(originalProperty);
break;

case ValidationDataType.Double:
num
= ((double)sourceProperty).CompareTo(originalProperty);
break;

case ValidationDataType.Date:
num
= ((DateTime)sourceProperty).CompareTo(originalProperty);
break;

case ValidationDataType.Currency:
num
= ((decimal)sourceProperty).CompareTo(originalProperty);
break;
}
switch (this.Operator)
{
case ValidationCompareOperator.Equal:
return (num == 0);

case ValidationCompareOperator.NotEqual:
return (num != 0);

case ValidationCompareOperator.GreaterThan:
return (num > 0);

case ValidationCompareOperator.GreaterThanEqual:
return (num >= 0);

case ValidationCompareOperator.LessThan:
return (num < 0);

case ValidationCompareOperator.LessThanEqual:
return (num <= 0);
}
return true;

}
}

在Model中就可以这样使用了,以下校验两次输入的密码是否一致:

[Compare(PasswordConfirm, Password, ValidationCompareOperator.Equal
,ValidationDataType.String, ErrorMessage
= 请确认两次输入的密码一致)]
public class UserInputEdit
{
[DisplayName(
登录密码)]
public string Password { get; set; }

[DisplayName(确认密码)]
public string PasswordConfirm { get; set; }
}

如果果要Model中有两个时间,开始时间和结束时间,要求结束时间必须大于开始时间:

[Compare(TimeEnd, TimeStart, ValidationCompareOperator.GreaterThan
, ValidationDataType.Date, ErrorMessage
= 结束时间必须大于开始时间)]
public class UserInputEdit
{
[DisplayName(
开始时间)]
public DateTime TimeStart { get; set; }

[DisplayName(结束时间)]
public DateTime TimeEnd { get; set; }
}

ASP.NET MVC 3也有一个CompareAttribute,但它只能进行Equals比较。同样的比较两次密码是否一致,以上代码可以写成这样:
public class UserInputEdit
{
[DisplayName(
登录密码)]
public string Password { get; set; }

[DisplayName(确认密码)]
[Compare(
Password, ErrorMessage = 请确认两次输入的密码一致)]
public string PasswordConfirm { get; set; }
}

在 我们自定义的CompareAttribute中,必须将Attribute应用于class上。如果您想像ASP.NET MVC 3中,将标记写在属性,很遗憾不行。因为ValidationResult IsValid(…)的方法在.Net 4.0才有,MVC 3也才有相应的支持。当然也可以修改我们自定义的CompareAttribute,但请注意以下代码我没测试过:

代码

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field
, AllowMultiple
= true)]
public class CompareAttribute : ValidationAttribute
{
public string OriginalProperty { get; private set; }
public ValidationCompareOperator Operator { get; private set; }
public ValidationDataType Type{ get; private set; }

private const string _defaultErrorMessage = ‘{0}’ 与 ‘{1}’ 进行 {2} 比较失败;

public CompareAttribute(string originalProperty
, ValidationCompareOperator op, ValidationDataType type)
:
base(_defaultErrorMessage)
{
OriginalProperty
= originalProperty;
Operator
= op;
Type
= type;
}

public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
name, OriginalProperty, Operator.ToString());
}

protected override ValidationResult IsValid(object value
, ValidationContext validationContext)
{
PropertyInfo originalProperty
= validationContext.ObjectType
.GetProperty(
this.OriginalProperty);
object originalValue = originalProperty.GetValue(validationContext.ObjectInstance, null);

if(!compare(value, originalValue))
return new ValidationResult(this.FormatErrorMessage(validationContext
.DisplayName));

return null;
}

private bool compare(object sourceProperty, object originalProperty)
{
int num = 0;
switch (this.Type)
{
case ValidationDataType.String:
num
= string.Compare((string)sourceProperty
, (
string)originalProperty, false, CultureInfo.CurrentCulture);
break;

case ValidationDataType.Integer:
num
= ((int)sourceProperty).CompareTo(originalProperty);
break;

case ValidationDataType.Double:
num
= ((double)sourceProperty).CompareTo(originalProperty);
break;

case ValidationDataType.Date:
num
= ((DateTime)sourceProperty).CompareTo(originalProperty);
break;

case ValidationDataType.Currency:
num
= ((decimal)sourceProperty).CompareTo(originalProperty);
break;
}
switch (this.Operator)
{
case ValidationCompareOperator.Equal:
return (num == 0);

case ValidationCompareOperator.NotEqual:
return (num != 0);

case ValidationCompareOperator.GreaterThan:
return (num > 0);

case ValidationCompareOperator.GreaterThanEqual:
return (num >= 0);

case ValidationCompareOperator.LessThan:
return (num < 0);

case ValidationCompareOperator.LessThanEqual:
return (num <= 0);
}
return true;

}
}

[转载]深入ASP.NET MVC3 Razor你准备好了吗?

mikel阅读(1122)

[转载]深入Razor,你准备好了吗?(兼谈我的学习方法和定位) – 撞破南墙 – 博客园.

目录

1 学习方法论

1下定义-针对不同的定义做不同的学习

2如何学习

3 知其所以然的学习

3MVC中页面引擎的入口

4我的定位

(主观的看法很多,说的不好不对的地方请多多指教)

1学习方法

给你要做的事下个定义

我的博士导师跟我说: 如果给问题下准了定义,那么问题就算解决了60%了。

来自《想外行一样思考,想内行一样实践》的一句话。

现在的问题便是你是如何看待razor,准备学习到什么样的程度?

先说说程度问题:

1了解阶段。

看看介绍(如news里面的文章)。知道有这么回事。

2 会用阶段。

那么仅仅是去看一些走马观花式的介绍性文章(比如我那个系列),基本就够你吹吹牛说你会用了。你也可以用在自己的小项目里。这时候你仅需要把所有的公开的API和属性,还有函数名弄懂是怎么回事就OK了。

3掌握应用阶段。

应用阶段不只要知道他是如何使用,更需要知道他的里面的代码是怎么跑的?

1知道里面的架构,知道他是怎么运作的(以便分析性能等)。

2知道他的使用范围和局限性,扩展性等。

我也说的不好,总结得不好,因为我正在这个阶段探索和努力。

4吸收为己用

1 或许是他的实现某个功能的一种机制。如mvvm都有的消息机制。

2 或许是其中的一些较好的写法和做法。比如我从OXITE(link)中学到了使用扩展方法来使得代码优雅,细粒度保持重用性,更好的泛型封装CURD等等。

3 或许是其中一些设计思想。比如一些设计模式,如何对一个大的架构进行解剖和隔离,我在这方面还没上路。

大家互相交流,我也是新手。

2读者类型和我自己的定位

好吧。我的朋友你是如何看待RAZOR的?

类型A:“无所不能”的技术至上的功能派:

如果你只是停留在第一第二阶段,不管你是否自己察觉。但对希望能够进入三,四层感觉,又不知道该如何下手。好吧,交个朋友!希望你能follow我的文章,让我们一起来经历一次这样的体验,真的很棒!

类型B:进阶型:

像我一样是一个脱离了功能派的有点自知之明了。但是又一直在想如何突破天花板,成为小牛。一直徘徊着的家伙们,这里有个同类。我觉得读代码的能力非常重要,对一个框架的深入探究和掌握也是一种非常好的锻炼。so follow me。

类型C:小牛大牛

没什么好说的,欢迎牛牛来指点!

3RAZOR是什么?

如你所知RAZOR是一个“剃须刀”,我这里是指MVC3 自带的页面引擎view  engine ,是指这一套类库。

4说了这么多,我们该如何学习呢?

具体的学法参考圣殿骑士的对框架的研究:

1,首先看框架的相关介绍,了解相关的背景、功能、架构图以及其他一些相关信息——认识了解。

2,根据介绍查看并调试框架所提供的实例——熟悉功能。

3,自己写一些相关的项目,主要是熟悉该框架,如果说要急于做项目,后面就可以把框架引入到项目当中——具体使用。

4,根据该框架提供的详细单元测试研究其源码,这也是我最喜欢研究这些开源框架的原因——原理剖析。

5,通过上面的步骤认真分析其原理及细节——准备重现。

6,自己也根据之前的思路重复开发这个框架,最好能用TDD——框架复原捷径。

更多的如何阅读代码,看这里

5 我自己的总结是这样。

1 是什么。

看介绍性的文章对其有一个基本的了解,知道他是干什么的。看其背景看其产生的原因,往往他产生的原因就是他的最初的核心功能也是最需要学习的。

2 使用它。使用该框架,看官方示例和一些入门系列,和文档来入门。如我们之前的一系列文章。

3了解全貌。有源码就看源码,知道其框架,分几部分,如何实现其核心功能,拆分各部分。心里有数。

4各个击破。拆成各部分后,一个模块一个模块的看。具体可以看接口,看基础类等,看其测试代码了解其要实现的功能。

5吸收。到了这个阶段,从整体到细节一切已经了然于胸,即使一些无聊的派生类等分支也有自信迅速看懂.我也没有什么经验。有的人把别人的框架里面的某些机 制变成自己永久代码类库的一部分( 我在积累),有的人以自己重新实现,甚至推出更优的同类的东西。这个看个人了吧。

下载MVC3的源码吧!不过。。。你真的准备好了吗?

http://aspnet.codeplex.com/wikipage?title=MVC&referringTitle=Home

3知其所以然的学习

既然说了这么多废话了,那就多说几句题外话吧。在开始找到MVC3中RAZOR页面引擎的入口前,我想先问一下看官,服务器接收到一个URL请求是如何处理又是在哪里返回给服务器的呢?

昨天看到 invoy给我留言,引起了我的思考。。。越反思,越冒汗。。最近在看的CLR VIA C#(LINK) 也说到了对代码的控制,失控是一件非常恐怖的事,如果你不知道你的代码干了什么,你将随着框架而摇摆,你懂的!

while(time++ &&  life– >0  ){
累;
}
die();

这里贴个图

2010112203014846

图片来自 HttpApplication处理管道

建议阅读:

Web开发学习心得5——Asp.net的设计思想 这篇写的通俗的,

———————–时光荏苒,转眼间你就懂得了一个URL如何传到了HttpApplication—————–

3MVC中页面引擎的入口

现在让我们进入MVC3中的源码,去解决我们第一个疑惑MVC3中是如何调用RAZOR这个页面引擎的。

STEP1

(参考重典大哥的文章http://www.cnblogs.com/chsword/archive/2010/07/10/1774937.html

我们找到几个关键的接口。通常从接口开始是个不错的选择。

IView :用于呈现

public interface IView {
void Render(ViewContext viewContext, TextWriter writer);
}

IViewEngine :用于找到页面

public interface IViewEngine {
ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache);
ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache);
void ReleaseView(ControllerContext controllerContext, IView view);
}

利用reflector工具顺藤摸瓜:

image

添加到类图

image

这下你应该清楚了

image

这下类的继承关系就很清楚了。也一目了然RAZOR和WEBFORM viewengine的关系。

STEP2

不去纠缠于细节,跳出来立马思考.我们虽然知道了他们继承于什么,

RAZOR在MVC3中的关系与位置立马清晰了,但是还是不知道到底是在哪里呈现。这时候有两个容易的思路。

第一个:是重典有提到过的一个

 ViewEngines.Engines.Clear();
 ViewEngines.Engines.Add(new WebPageEngine());

第二个:MVC在Controller 和 view 之间交互的时候。

我是想到了第一个,因为当时由他的文章启发去寻找,结果多费了些功夫。

如果你从第二个思路出发应该会更快。在这个地方我也花费了一点时间。

——时钟滴答—–

我发现了

public abstract class ActionResult {

public abstract void ExecuteResult(ControllerContext context);

}

image

现在整个思路终于串起来了。

public override void ExecuteResult(ControllerContext context) {
if (context == null) {
throw new ArgumentNullException(“context”);
}
if (String.IsNullOrEmpty(ViewName)) {
ViewName = context.RouteData.GetRequiredString(“action”);
}

ViewEngineResult result = null;

if (View == null) {
//1为 content 找到 页面并返回 ViewEngineResult
result = FindView(context);
View = result.View;
}

TextWriter writer = context.HttpContext.Response.Output;
//把所有的需要传递到view的东西都在这里
ViewContext viewContext = new ViewContext(context, View, ViewData, TempData, writer);
//在这里渲染页面
View.Render(viewContext, writer);

if (result != null) {
//发布结果
result.ViewEngine.ReleaseView(context, View);
}
}

1ActionResult 接收ControllerContext  并执行2和3

2IviewEngine负责找到页面

3 IVIEW 对应页面负责render呈现。

在这里就告一段落吧。一般都这里,我都是忍不住喜欢到处逛逛里面是

实现的,和更多的细节。

hi 我的朋友,你是否的朋友是否有所收获?

4我的定位

老赵 说:

希望可以给初学者以合适引导。坚定的北大青鸟反对者,强烈愤慨恶劣的培训机构对于处于懵懂期的初学者以误导,强烈抵制各种虚假广告给业界带来的不良影响,强烈建议有理想有抱负的从业青年放弃北大青鸟,不要做冤大头。

刘伟鹏 说:

知其所以然的学习。

好吧。我还是引用我之前写的一段话,表明我的立场。

[转载]GPS定位基本原理浅析

mikel阅读(1000)

[转载]GPS定位基本原理浅析 – Mobile On Line 镜像站点 – 博客园.

位置服务已经成为越来越热的一门技术,也将成为以后所有移动设备(智能手机、掌上电脑等)的标配。而定位导航技术中,目前精度最高、应用最广泛的,自然非GPS莫属了。网络上介绍GPS原理的专业资料很多,而本文试图从编程人员的角度出发,以一种程序员易于理解的方式来简单介绍一下GPS定位的基本原理,希望对做GPS开发的朋友有所启发。当然,本文并没有涉及具体的开发方面的技术。

一、GPS定位数学模型

之所以先介绍数学模型,是因为我认为这个数学模型可能是程序员比较关心的问题。当然事先声明,这个模型只是我根据一些GPS资料总专为程序员总结出来的一个简化模型,细节方面可能并不符合实际,想了解具体细节请参考专业的GPS讲解资料。

GPS定位,实际上就是通过四颗已知位置的卫星来确定GPS接收器的位置。

GPS_thumb22

如上图所示,图中的GPS接收器为当前要确定位置的设备,卫星1、2、3、4为本次定位要用到的四颗卫星:

  • Position1、Position2、Position3、Position4分别为四颗卫星的当前位置(空间坐标),已知
  • d1、d2、d3、d4分别为四颗卫星到要定位的GPS接收器的距离,已知
  • Location 为要定位的卫星接收器的位置,待求

那么定位的过程,简单来讲就是通过一个函数GetLocation(),从已知的[Position1,d1]、[Position2,d2]、[Position3,d3]、[Position4,d4]四对数据中求出Location的值。用程序员熟悉的函数调用来表示就是:

Location=GetLocation([Position1,d1],[Position2,d2],[Position3,d3],[Position4,d4]);

一看到这个函数调用,程序员们就该来劲了:这些参数从哪里来?这个函数又是如何执行?由谁来执行的呢?立体几何还没有忘干净的可能还要问:为什么必须要4对参数呢?那下面我们就来一起探究一下。

1.Position1、Position2、Position3、Position4这些位置信息从哪里来?

实际上,运行于宇宙空间的GPS卫星,每一个都在时刻不停地通过卫星信号向全世界广播自己的当前位置坐标信息。任何一个GPS接收器都可以通过天线很轻松地接收到这些信息,并且能够读懂这些信息(这其实也是每一个GPS芯片的核心功能之一)。这就是这些位置信息的来源。

2.d1、d2、d3、d4这些距离信息从哪里来?

我们已经知道每一个GPS卫星都在不辞辛劳地广播自己的位置,那么在发送位置信息的同时,也会附加上该数据包发出时的时间戳。GPS接收器收到数据包后,用当前时间(当前时间当然只能由GPS接收器自己来确定了)减去时间戳上的时间,就是数据包在空中传输所用的时间了。

知道了数据包在空中的传输时间,那么乘上他的传输速度,就是数据包在空中传输的距离,也就是该卫星到GPS接收器的距离了。数据包是通过无线电波传送的,那么理想速度就是光速c,把传播时间记为Ti的话,用公式表示就是:

di=c*Ti(i=1,2,3,4);

这就是di(i=1,2,3,4)的来源了。

3.GetLocation()函数是如何执行的?

这个函数是我为了说明问题而虚构的,事实上未必存在,但是一定存在这样类似的运算逻辑。这些运算逻辑可以由软件来实现,但是事实上可能大都是由硬件芯片来完成的(这可能也是每一个GPS芯片的核心功能之一)。

4.为什么要必须要四对参数?

根据立体几何知识,三维空间中,三对[Positioni,di]这样的数据就可以确定一个点了(实际上可能是两个,但我们可以通过逻辑判断舍去一 个),为什么这里需要四对呢?理想情况下,的确三对就够了,也就是说理想情况下只需要三颗卫星就可以实现GPS定位。但是事实上,必须要四颗。

因为根据上面的公式,di是通过c*Ti计算出来的,而我们知道c值是很大的(理想速度即光速),那么对于时间Ti而言,一个极小的误差都会被放大 很多倍从而导致整个结果无效。也就是说,在GPS定位中,对时间的精度要求是极高的。GPS卫星上是用銫原子钟来计时的,但是我们不可能为每一个GPS接 收器也配一个銫原子钟,因为一个銫原子钟的价格可能已经超过了这个GPS设备再加上使用GPS的这辆名贵汽车的价格。

同时,由于速度c也会受到空中电离层的影响,因此也会有误差;再者,GPS卫星广播的自己的位置也可能会有误差。其他等等一些因素也会影响数据的精确度。

总之,数据是存在误差的。这些误差可能导致定位精确度降低,也可能直接导致定位无效。GetLocation(函数)中多用了一组数据,正是为了来校正误差。至于具体的细节,我们就不用关心了,我们只要知道,多用一组数据,就可以通过一些巧妙的算法,消除或减小误差,保证定位有效。这就是GetLocation()函数必须用四组数据的原因,也就是为什么必须有四颗卫星才能定位的原因。

5.GetLocation()函数返回的位置信息怎样被GPS设备识别呢?

前面说在进行位置计算时都是用的空间坐标形式表示,但是对GPS设备及应用程序而言,通常需要用的是一个[经度,纬度,高度]这样的位置信息。那么 我们可以想象,在GetLocation()函数返回位置结果前,可能会进行一个从空间坐标形式到经纬度形式的转换,我们不妨假设存在一个 Convert(经纬度,空间坐标)这样的函数来进行这个转换。

6.单点定位与差分定位

实际上上面所说的只是定位原理中的其中一种,称为单点定位,或绝对定位。就是通过唯一的一个GPS接收器来确定位置。

GPS_thumb11

目前定位精度最高的是差分定位,或称相对定位。就是通过增加一个参考GPS接收器来提高定位精度。

GPS_thumb1

上面我们已经围绕一个虚拟的GetLocation()函数基本搞清楚了GPS定位的基本数学模型,对于编程而言,知道这些就足够了(其实不知道也不影响编程)。如果好奇心还没满足的话,我们继续了解一些GPS相关的背景知识。

二、GPS卫星是哪里来的?

(废话,当然是人发射的!地球人发射的!)

GPS(Global Position System,全球定位系统),全称为NAVSTAR GPS(NAVigation Satellite Timing And Ranging Global Position System,导航星测时与测距全球定位系统)。GPS是一个由美国国防部开发的空基全天侯导航系统,它用以满足军方在地面或近地空间内获取在一个通用参 照系中的位置、速度和时间信息的要求。

1.GPS发展历程

  • 1957年10月第一颗人造地球卫星SputnikⅠ发射成功,空基导航定位由此开始
  • 1958年开始设计NNSS-TRANSIT,即子午卫星系统;
    1964年该系统正式运行;
    1967年该系统解密以供民用。
  • 1973年,美国国防部批准研制GPS;
    1991年海湾战争中,GPS首次大规模用于实战;
    1994年,GPS全部建成投入使用;
    2000年,克林顿宣布,GPS取消实施SA(对民用GPS精度的一种人为限制策略)。

2.美国政府的的GPS策略

  • 两种GPS服务:
    SPS–标准定位服务,民用,精度约为100M;
    PPS–精密定位服务,军用和得到特许的民间用户使用,精度高达10M.
  • 两种限制民用定位精度的措施(保障国家利益不受侵害):
    SA–选择可用性,认为降低普通用户的测量精度,限制水平定位精度100M,垂直157M(已于2005年5月1日取消);
    AS–反电子欺骗。

3.其他卫星导航系统

  • GLONASS(全球轨道导航卫星系统),前苏联
  • Galileo-ENSS(欧洲导航卫星系统,即伽利略计划),欧盟
  • 北斗导航系统,中国

三、GPS系统的构成

GPS系统=空间部分+控制部分+用户部分

GPS_thumb23

1.空间部分

GPS空间部分主要由24颗GPS卫星构成,其中21颗工作卫星,3颗备用卫星。24颗卫星运行在6个轨道平面上,运行周期为12个小时。保证在任一时刻、任一地点高度角15度以上都能够观测到4颗以上的卫星。

主要作用:发送用于导航定位的卫星信号。

构成:24颗卫星=21颗工作卫星+3颗备用卫星

GPS_thumb1

2.控制部分

GPS控制部分由1个主控站,5个检测站和3个注入站组成。

组成:GPS控制部分=主控站(1个)+监测站(5个)+注入站(3个)

作用:监测和控制卫星运行,编算卫星星历(导航电文),保持系统时间。

  • 主控站:从各个监控站收集卫星数据,计算出卫星的星历和时钟修正参数等,并通过注入站注入卫星;向卫星发布指令,控制卫星,当卫星出现故障时,调度备用卫星。
  • 监控站:接收卫星信号,检测卫星运行状态,收集天气数据,并将这些信息传送给主控站。
  • 注入站:将主控站计算的卫星星历及时钟修正参数等注入卫星。

GPS_thumb3

分布情况:

  • 主控站:位于美国科罗拉多州(Calorado)的法尔孔(Falcon)空军基地。
  • 注入站:阿松森群岛(Ascendion),大西洋;迭戈加西亚(Diego Garcia),印度洋;卡瓦加兰(Kwajalein),东太平洋。
  • 监控站:1个与主控站在一起;3个与注入站在一起;另外一个在夏威夷(Hawaii),西太平洋。

GPS_thumb2

3.用户部分

GPS用户设备部分包含GPS接收器及相关设备。GPS接收器主要由GPS芯片构成。

如车载、船载GPS导航仪,内置GPS功能的移动设备,GPS测绘设备等都属于GPS用户设备。

组成:主要为GPS接收器

作用:接收、跟踪、变换和测量GPS信号的设备,GPS系统的消费者。

GPS定位是目前最为精确、应用最为广泛的定位导航技术,以后将会成为每一个移动设备的标配之一。现在的中高端只能手机,有相当一部分已经配备了 GPS硬件。那么针对GPS定位的开发技术也将成为一项主流常规技术。本文目的在于让准备进行GPS定位开发的编程人员对于GPS有一个大致的了解,这对 于编程可能没有什么直接的帮助,但是我想了解一下GPS的大致工作原理,在编程过程中就能够对GPS设备的工作特性有一个感性的认识,这对于开发还是有很 大间接好处的。想了解关于GPS定位的具体开发技术,请参考《为Windows Mobile设备创建位置感知的应用程序》