1.开发背景
一个开诊所的中医朋友,希望我能给他开发一个记录病人姓名和处方的Android手机app,以便查询病人每次就诊信息,比如上一次的处方,以前他要找个病人上一次的就诊处方,几乎要翻遍一叠厚厚的处方纸张才能找到(他的门诊量还是很大的),非常麻烦。于是利用周末的两天时间开发了这款DoctorNote软件,软件截图如下:


 
 
 
 
 


DoctorNote开发过程用了很Android各个方面的知识点,比如ActionBar的使用、自定义ActionBar样式、SQLite的使用、AsyncTask的使用,SearchView的使用和SearchActivity的编写,以及AlertDialog的创建等。现总结如下:

2.项目的创建

项目的开发IDE是Eclipse,File->new->Android Application Project,项目的目录结构如下 图:

3.创建MainActivity
该类继承ListActivity实现OnItemLongClickListener接口,是程序的主界面,主要按姓名展示处方记录,单击可查看修改信息,长按可删除该记录,代码如下:

package com.foxhu.app.doctornote.ui;

import com.foxhu.app.doctornote.R;
import com.foxhu.app.doctornote.db.NoteDB; import android.os.AsyncTask;
import android.os.Bundle;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.app.SearchManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.database.Cursor;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.SimpleCursorAdapter;
import android.widget.Toast;
/**
* DoctorNote
* @author Foxhu
* @version 1.0
*
*/
public class MainActivity extends ListActivity implements OnItemLongClickListener{
public final static String EXTRA_NOTEID = "com.foxhu.app.doctornote.NOTEID";
private final static int ACTIVITY_CREATE = 0;//设置activity返回码
private final static int ACTIVITY_MODI = 1;//设置activity返回码
private Context mContext; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
setContentView(R.layout.activity_main);
new LoadAsyncTask().execute();
getListView().setOnItemLongClickListener(this);
} //android.os.AsyncTask<Params, Progress, Result>
private class LoadAsyncTask extends AsyncTask<Void,Void,Cursor>{ @Override
protected Cursor doInBackground(Void... arg0) {
Cursor cursor = NoteDB.getInstance(getApplicationContext()).getAllNote();
return cursor;
} @Override
protected void onPostExecute(Cursor result) {
super.onPostExecute(result);
//构造方法
//public SimpleCursorAdapter (Context context, int layout, Cursor c, String[] from, int[] to, int flags)
String[] from = new String[]{NoteDB.COLUMN_NAME};
int[] to = new int[]{android.R.id.text1};
SimpleCursorAdapter records = new SimpleCursorAdapter(mContext,android.R.layout.simple_list_item_1,result,from,to,0);
setListAdapter(records);
} } /**
* 处理单击事件,单击条目打开编辑窗口
*/
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Intent intent = new Intent(this,ModiNoteActivity.class);
intent.putExtra(EXTRA_NOTEID, id);//传递记录的id
this.startActivityForResult(intent, ACTIVITY_MODI); } @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
//设置查询
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) menu.findItem(R.id.search).getActionView();
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
//searchView.setSubmitButtonEnabled(true);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case R.id.action_edit:
Intent intent = new Intent(mContext, EditNoteActivity.class);
//startActivity(intent);
this.startActivityForResult(intent, ACTIVITY_CREATE);
break;
default:
break;
}
return false;
} @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
//重新加载数据
new LoadAsyncTask().execute();
} @Override
protected void onRestart() {
super.onRestart();
new LoadAsyncTask().execute();
} @Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2,
final long id) {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext)
.setTitle(R.string.delete_title)
.setMessage(R.string.delete_body)
.setNegativeButton(R.string.delete_cancel, null)
.setPositiveButton(R.string.delete_ok, new OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
if (NoteDB.getInstance(getApplicationContext()).deleteNote(id)> 0) {
new LoadAsyncTask().execute();
Toast.makeText(mContext, R.string.delete_success,
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(mContext, R.string.delete_fail,
Toast.LENGTH_SHORT).show();
}
} }); builder.create().show(); // TODO Auto-generated method stub
return false;
} }

对应的页面布局文件activity_main.xml如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" > <ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" >
</ListView> </RelativeLayout>

(1)onCreate()事件解析
setContentView(R.layout.activity_main);设置布局文件;

new LoadAsyncTask().execute();执行异步任务从SQLite数据库加载全部医生处方数据;

getListView().setOnItemLongClickListener(this);给listview控件条目设置长按监听单击事件;


(2)private class LoadAsyncTask extends AsyncTask<Void,Void,Cursor>

内部类LoadAsyncTask继承AsyncTask类,我们来看一下AsyncTask这个类,这个类的定义一般带有三个泛型参数AsyncTask<Params, Progress, Result>,并且带有4步方法,分别为onPreExecute, doInBackground, onProgressUpdate 和 onPostExecute.一般我们需要后台执行获取数据的任务放在doInBackground()方法,执行结果数据展示部分放在onPostExecute(),该方法的参数即是doInBackground()返回的数据,下面详细介绍下AsyncTask的4步方法:

①.onPreExecute(),在任务执行之前,在UI线程上调用,这步通常用来设置任务,比如在用户界面上显示进度条;

②.doInBackground(Params...),在 onPreExecute()方法执行后立即在后台线程执行,这一步通常用来执行需要花费较长时间的后台计算,异步任务的参数传递给该方法,计算的结果必须在这一步返回,并传递给onPostExecute(Result),这一步也可使用 publishProgress(Progress...)方法来产生一个或多个单位的进度,这些值是发布在在UI线程上 onProgressUpdate(Progress...) 方法中的.

③.onProgressUpdate(Progress...),在 publishProgress(Progress...)方法后在UI线程上调用,它的执行时序是不确定的,这个方法通常用来在用户界面上展示进度,而后台计算仍在执行,例如,它可以用来动态的显示进步条或者在文本框中显示记录.

④.onPostExecute(Result),在后台计算完成后在UI线程上调用,后台计算的执行结果传递该方法作为参数.


(3)ActionBar的创建

ActionBar是3.0以后出来的设计规范,支持Android 3.0+,android:minSdkVersion="11",如果想在Android 2.1上实现ActionBar需要V7兼容包,我们定义Activity的时候一般这样public class MainActivity extends ActionBarActivity ,Activity要继承ActionBarActivity,为简单起见,本软件采用android:minSdkVersion="11"。

①.实现ActionBar关键是菜单文件的创建,下面是DoctorNote的主界面菜单文件main.xml:

<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/search"
android:title="@string/search_title"
android:icon="@drawable/ic_search"
android:showAsAction="collapseActionView|ifRoom"
android:actionViewClass="android.widget.SearchView" /> <item
android:id="@+id/action_edit"
android:icon="@drawable/ic_edit"
android:showAsAction="ifRoom"
android:title="@string/action_edit"/> </menu>

其中第一个item用来定义搜索按钮,第二菜单用于定义编辑按钮,关键我们要注意android:showAsAction属性的应用,
ifRoom:如果有ActionBar有空间就显示该菜单项;

withText:如果没有设定android:icon图标,那么菜单项以文字形式展示,可以与其他关键字联合使用比如ifRoom|withText;

never:不出现在ActionBar中,按设置键可弹出;

always:不管有没有空间,总是出现在ActionBar,通常不建议使用该项,会导致多个item重叠;

collapseActionView:与之相关的动作条目(如在android:actionViewClass中声明的视图类)是可折叠的,比如搜索控件SearchView;

②.在CeateOptionsMenu(Menu menu)方法加载菜单,实现actionbar效果

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
//设置查询
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) menu.findItem(R.id.search).getActionView();
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
//searchView.setSubmitButtonEnabled(true);
return true;
}

③.对ActionBar上的按钮添加响应事件

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case R.id.action_edit:
Intent intent = new Intent(mContext, EditNoteActivity.class);
//startActivity(intent);
this.startActivityForResult(intent, ACTIVITY_CREATE);
break;
default:
break;
}
return false;
}

如果选中编辑(新建)菜单则通过intent打开EditNoteActivity.class

(4)SearchView的创建,一般分为5步

①编写菜单文件,res/menu/main.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/search"
android:title="@string/search_title"
android:icon="@drawable/ic_search"
android:showAsAction="collapseActionView|ifRoom"
android:actionViewClass="android.widget.SearchView" /> <item
android:id="@+id/action_edit"
android:icon="@drawable/ic_edit"
android:showAsAction="ifRoom"
android:title="@string/action_edit"/> </menu>

②编写搜索配置文件res/xml/searchable.xml

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/app_name"
android:hint="@string/search_hint"
android:imeOptions="actionSearch"/>

其中android:imeOptions="actionSearch"属性用来设置软键盘是搜索按钮而不是回车
③在onCreateOptionsMenu(Menu menu)方法中对SearchView通过调用setSearchableInfo(getComponentName())方法加载搜索配置信息,当SearchView和搜索配置文件正确关联后,当用户提交查询后SearchView就会通过ACTION_SEARCH intent 开启一个 activity来执行搜索任务

④修改AndroidManifest.xml配置文件,添加

<!-- Searchable -->
<activity
android:name="com.foxhu.app.doctornote.ui.SearchableActivity"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
<!-- Points to searchable activity so the whole app can invoke search. -->
<meta-data
android:name="android.app.default_searchable"
android:value="com.foxhu.app.doctornote.ui.SearchableActivity"/>

注意属性android:launchMode="singleTop",singleTop模式将SearchableActivity设为单例模式,用户可以执行多次搜索而无需创建新的Activity实例
⑤创建可搜索的Activity-SearchableActivity,SearchableActivity代码如下:

package com.foxhu.app.doctornote.ui;

import com.foxhu.app.doctornote.db.NoteDB;
import android.app.ListActivity;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
/**
* DoctorNote
* @author Foxhu
* @version 1.0
*
*/
public class SearchableActivity extends ListActivity {
private Context mContext;
//private NoteDB mNoteDB; @Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
Intent intent = new Intent(this,ModiNoteActivity.class);
intent.putExtra(MainActivity.EXTRA_NOTEID, id);//传递记录的id
this.startActivity(intent);
} @Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
mContext = this;
//mNoteDB = new NoteDB(mContext, NoteDB.DATABASE_NAME, null, NoteDB.VERSION);
getActionBar().setDisplayHomeAsUpEnabled(true);//设置返回按钮
handleIntent(getIntent());
} private void handleIntent(Intent intent) {
// TODO Auto-generated method stub
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
//use the query to search your data somehow
fillList(query);
}
} private void fillList(String query) {
// TODO Auto-generated method stub
Cursor result = NoteDB.getInstance(getApplicationContext()).queryNoteByName(query);
String[] from = new String[]{NoteDB.COLUMN_NAME};
int[] to = new int[]{android.R.id.text1};
SimpleCursorAdapter records = new SimpleCursorAdapter(mContext,android.R.layout.simple_list_item_1,result,from,to,0);
setListAdapter(records);
} @Override
protected void onNewIntent(Intent intent) {
// TODO Auto-generated method stub
super.onNewIntent(intent);
handleIntent(intent);
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case android.R.id.home:
finish();
break;
default:
break;
}
return super.onOptionsItemSelected(item);
} }

在onCreate()事件中,通过handleIntent(getIntent())检查ACTION_SEARCH intent来处理查询, 通过String query = intent.getStringExtra(SearchManager.QUERY)来获取查询关键词,然后通过fillList(query)来装载查询结果;

4.创建EditNoteActivity,该类主要用来新建处方

package com.foxhu.app.doctornote.ui;

import com.foxhu.app.doctornote.R;
import com.foxhu.app.doctornote.db.NoteDB; import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.EditText;
import android.widget.Toast;
/**
* DoctorNote
* @author Foxhu
* @version 1.0
*
*/
public class EditNoteActivity extends Activity {
private Context mContext;
private EditText mNameText;
private EditText mPrescriptionText; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
setContentView(R.layout.activity_edit_note);
mNameText = (EditText) this.findViewById(R.id.notename);
mPrescriptionText = (EditText) this.findViewById(R.id.noteprescription);
getActionBar().setDisplayHomeAsUpEnabled(true);//设置返回按钮
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.edit_note, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case R.id.action_save:
String name = mNameText.getText().toString();
String prescription = mPrescriptionText.getText().toString();
if (name.isEmpty()){
Toast.makeText(mContext, R.string.name_empty,Toast.LENGTH_SHORT).show();
}else{
NoteDB.getInstance(getApplicationContext()).insertNote(name, prescription);
this.finish();
}
break;
case android.R.id.home:
finish();
break;
default:
break;
}
return false;
} }

5.创建ModiNoteActivity,该类主要用来修改处方

package com.foxhu.app.doctornote.ui;

import com.foxhu.app.doctornote.R;
import com.foxhu.app.doctornote.db.NoteDB;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.EditText;
import android.widget.Toast;
/**
* DoctorNote
* @author Foxhu
* @version 1.0
*
*/
public class ModiNoteActivity extends Activity {
private Context mContext;
//private NoteDB mNoteDB;
private EditText mNameText;
private EditText mPrescriptionText;
private long noteId; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
setContentView(R.layout.activity_modi_note);
//mNoteDB = new NoteDB(mContext, NoteDB.DATABASE_NAME, null, NoteDB.VERSION);
Intent intent = getIntent();
noteId = intent.getLongExtra(MainActivity.EXTRA_NOTEID, 0);
Cursor cursor = NoteDB.getInstance(getApplicationContext()).queryNoteById(noteId);//根据接收的id查询记录详细信息
mNameText = (EditText) this.findViewById(R.id.modi_notename);
mPrescriptionText = (EditText) this.findViewById(R.id.modi_noteprescription); mNameText.setText(cursor.getString(cursor.getColumnIndexOrThrow(NoteDB.COLUMN_NAME)));
mPrescriptionText.setText(cursor.getString(cursor.getColumnIndexOrThrow(NoteDB.COLUMN_PRESCRIPTION)));
getActionBar().setDisplayHomeAsUpEnabled(true);//设置返回按钮 } @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.modi_note, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case R.id.action_modi:
String name = mNameText.getText().toString();
String prescription = mPrescriptionText.getText().toString();
if (name.isEmpty()){
Toast.makeText(mContext, R.string.name_empty,Toast.LENGTH_SHORT).show();
}else{
NoteDB.getInstance(getApplicationContext()).updateNote(noteId, name, prescription);
this.finish();
}
break;
case android.R.id.home:
finish();
break;
default:
break;
}
return false;
} }

5.数据库操作类NoteDB

该类继承SQLiteOpenHelper,由于多个Activity都要操作数据库,所以写了一个public static NoteDB getInstance(Context context)单例模式创建数据库操作类NoteDB对象,调用方法为NoteDB.getInstance(getApplicationContext()),代码如下

package com.foxhu.app.doctornote.db;

import java.util.Calendar;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteStatement;
/**
* DoctorNote
* @author Foxhu
* @version 1.0
*
*/
public class NoteDB extends SQLiteOpenHelper {
public static NoteDB mInstance = null;
public static final int VERSION = 1;
public static final String DATABASE_NAME = "DoctorNote"; private static final String TABLE_NOTE_NAME = "Note";
private static final String COLUMN_ID = "_id";
public static final String COLUMN_NAME = "name";
public static final String COLUMN_PRESCRIPTION = "prescription";
private static final String COLUMN_CREATETIME = "createtime"; private static final String DATABASE_NOTE_CREATE = "create table Note(_id integer primary key autoincrement, "
+ "name text not null,"
+ "prescription text not null,"
+ "createtime text not null" + ");"; public NoteDB(Context context, String name, CursorFactory factory, int version) {
super(context, name, factory, version);
} //自定义构造函数,只需要传递Activity对象给它即可
public NoteDB(Context context) {
this(context, DATABASE_NAME, null, VERSION);
}
/**
* 单例模式
*/
public static NoteDB getInstance(Context context) {
if (mInstance == null) {
mInstance = new NoteDB(context);
}
return mInstance;
} @Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DATABASE_NOTE_CREATE);
} @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub }
/**
* 获取全部数据
* @param db
* @return
*/
public Cursor getAllNote(){
return this.getReadableDatabase().query(TABLE_NOTE_NAME, new String[] {COLUMN_ID,COLUMN_NAME,COLUMN_PRESCRIPTION,COLUMN_CREATETIME}, null, null, null, null, "_id desc"); } /**
* 插入数据
* @param name
* @param prescription
* @return
*/
public long insertNote(String name,String prescription){
ContentValues values = new ContentValues();
Calendar calendar = Calendar.getInstance();
String created = calendar.get(Calendar.YEAR) + "年" + calendar.get(Calendar.MONTH) + "月" + calendar.get(Calendar.DAY_OF_MONTH) + "日";
values.put(COLUMN_NAME, name);
values.put(COLUMN_PRESCRIPTION, prescription);
values.put(COLUMN_CREATETIME, created);
return this.getWritableDatabase().insert(TABLE_NOTE_NAME, null, values);
} /**
* 根据id删除数据
* @param id
* @return
*/
public int deleteNote(long id){
return this.getWritableDatabase().delete(TABLE_NOTE_NAME, "_id=?", new String[] { String.valueOf(id) });
} /**
* 根据id更新数据
* @param id
* @param name
* @param prescription
* @return
*/
public int updateNote(long id,String name,String prescription){
ContentValues values = new ContentValues();
values.put(COLUMN_NAME, name);
values.put(COLUMN_PRESCRIPTION, prescription);
return this.getWritableDatabase().update(TABLE_NOTE_NAME, values, "_id=?", new String[] { String.valueOf(id) });
} /**
* 根据姓名查询数据
* @param name
* @return
*/
public Cursor queryNoteByName(String name){
return this.getReadableDatabase().query(TABLE_NOTE_NAME, null, "name like ?", new String[] {"%"+name+"%"}, null, null, "_id desc");
} /**
* 根据id查询详细信息
* @param id
* @return
*/
public Cursor queryNoteById(long id){
Cursor mcursor = this.getReadableDatabase().query(TABLE_NOTE_NAME, null, "_id=?", new String[] { String.valueOf(id) }, null, null, null,"1");
if (mcursor != null && mcursor.getCount() !=0){
mcursor.moveToFirst();
return mcursor;
}else{
return null;
}
}
/**
* 获取note表全部记录数
* @return
*/
public long getNoteCount(){
SQLiteStatement statement = this.getReadableDatabase().compileStatement("select count(*) from " + TABLE_NOTE_NAME);
return statement.simpleQueryForLong();
} /**
* 根据姓名查询记录数
* @param name
* @return
*/
public long getNoteCountByName(String name) {
SQLiteStatement statement = getReadableDatabase().compileStatement(
"select count(*) from " + TABLE_NOTE_NAME + " where name=" + name);
return statement.simpleQueryForLong();
}
}

github源码:
https://github.com/puma007/DoctorNote

DoctorNote医生处方笔记开发记录的更多相关文章

  1. JFinal使用笔记3-注册和登录功能开发记录

    首页 开源项目 问答 代码 博客 翻译 资讯 移动开发 招聘 城市圈 当前访客身份:游客 [ 登录 | 加入开源中国 ]   当前访客身份: 游客 [ 登录 | 加入开源中国 ] 软件   土龙 关注 ...

  2. CozyRSS开发记录22-界面退化

    CozyRSS开发记录22-界面退化 1.问题1-HtmlTextBlock 找的这个HtmlTextBlock有很严重的bug,有时候显示不完全,有时候直接就崩了.然后看了下代码,完全是学生仔水平写 ...

  3. CozyRSS开发记录21-默认RSS源列表

    CozyRSS开发记录21-默认RSS源列表 1.默认列表 在第一次使用CozyRSS的情况下,我们让它内置五个RSS源吧: 2.响应RSS源的更新 先不处理RSS源列表项的点击,响应下下拉菜单里的更 ...

  4. CozyRSS开发记录20-CanResizeWithGrip

    CozyRSS开发记录20-CanResizeWithGrip 1.窗口样式 首先,WindowStyle有四种: 然后,对于窗口缩放的ResizeMode,也有四种,CanResize和CanRes ...

  5. CozyRSS开发记录19-窗口标题栏交互

    CozyRSS开发记录19-窗口标题栏交互 1.谈谈对mvvm解耦的看法 在使用mvvm时,如何操作窗口,这是一个问题.这个问题的关键点是:mvvm是把view和viewmodel解耦了的,很多写法一 ...

  6. CozyRSS开发记录18-番外之Atom1.0的支持

    CozyRSS开发记录18-番外之Atom1.0的支持 1.对CozyRSS.Syndication批判一番 由于我工作的主要开发语言是c++,所以会看到我的c#代码写得非常朴素,很多语法糖都没有用上 ...

  7. CozyRSS开发记录17-Html2Xaml

    CozyRSS开发记录17-Html2Xaml 1.RssContentView还需要优化 上回做了RssContentView的显示,但是对于rss返回的描述(摘要),连换行的没有,更别说里面还有h ...

  8. CozyRSS开发记录16-RssContentView显示

    CozyRSS开发记录16-RssContentView显示 1.RssContentView的布局和绑定 继续参照原型图来写xaml: 然后在RSSContentFrameViewModel里提供绑 ...

  9. CozyRSS开发记录15-获取和显示RSS内容

    CozyRSS开发记录15-获取和显示RSS内容 1.内容列表 我们先给RSSContentFrame增加一个ViewModel,里面和RSS源列表一样,提供一个ObservableCollectio ...

随机推荐

  1. Google考虑抛弃Cookies机制

    根据华尔街日报的报道,Google 正在考虑抛弃古老的浏览器 cookies 来追踪用户信息的机制.作为替代,Google 将开发一种「个人匿名标识机制」.Google 早前已经计划在 IE 和 iP ...

  2. python:UnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xef in position xxx: ordinal not in range(128)

    执行sql_cmd = "select * from item_base where item_id in " + item_ids_str时报错 solve: import sy ...

  3. 查看linux系统的版本

    1. 查看内核版本命令: 1) [root@SOR_SYS ~]# cat /proc/version Linux version 2.6.18-238.el5 (mockbuild@x86-012. ...

  4. linux hosts一个诡异问题

    最近部署环境时遇到一个古怪问题. 背景环境: tomcat服务器 :  192.168.13.78 简称t 依赖服务器 :  192.168.12.159 简称s 二者关系 :t服务器的tomcat应 ...

  5. 进程间通信(IPC) 简介

    IPC是进程间通信的简称.传统上该术语描述的是运行在某个操作系统之上的不同进程间消息传递的不同方式. 我们讨论分为四个领域: 消息传递(管道,FIFO,消息队列(system v消息队列,posix消 ...

  6. background image position问题

    在CSS中,背景图片的定位方法有3种: 1)关键字:background-position: top left; 2)像素:background-position: 0px 0px; 3)百分比:ba ...

  7. socket编程在windows和linux下的区别

    如无其它说明,本文所指Linux均表示2.6内核Linux,GCC编译器,Windows均表示Windows XP系统,Visual Studio 2005 sp1编译环境. 下面大概分几个方面进行罗 ...

  8. Android 完全退出程序,以及再按一次返回键退出程序

    再按一次返回键退出最终完整方案: boolean isExit; @Override    protected void onCreate(Bundle savedInstanceState) {   ...

  9. TigerLeapMC V1.3 for Windows(支持DLNA)

    TigerLeapMC V1.3 2014-04-10: 1.更新tlplayer TigerLeapMC是基于tlplayer作为播放器的集成DLNA,(DMS,DMR,DMP)等,支持各种网络播放 ...

  10. git push origin master、git pull出现如下错误

    git push origin master出现如下错误: Counting objects: , done. Writing objects: % (/), bytes, done. Total ( ...