星期三, 12月 21, 2011

UserControl 傳值

之前有人問說,如果兩個 UserControl 在同一個page,要怎麼互相把值丟來丟去,這問題好像有學 .net 的人都會碰到,Bibby 的想法很簡單,只要雙方的可以知道彼此,那想怎樣就可以怎樣了,接下來寫個簡單的範例,加上點小技巧,希望大家可以了解

先來個圖例

image

再看結果

image

實戰演練:

先新增這兩個interface


    /// <summary>
    /// 讓Page實作,讓Page有Container的功能
    /// </summary>
    public interface IContainer
    {
        object GetObj(string key);
        void AddObj(string key,object o);
    }


    /// <summary>
    /// 讓顯示的uc2來實作,這樣就會有接值得功能
    /// </summary>
    public interface ICommand
    {
        void ToDo(object obj);
    }

Default.cs(Page)


    public partial class _Default : System.Web.UI.Page, IContainer
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            //把uc加進去,讓其他頁面可以取得想要的uc
            dic.Add("uc1", Uc11);
            dic.Add("uc2", Uc21);
        }

        //這裡把uc都加入,以後要找uc就來這找就行了
        Dictionary<string, object> dic = new Dictionary<string, object>();
        public object GetObj(string key)
        {
            if (dic.ContainsKey(key))
                return dic[key];
            return null;
        }

        public void AddObj(string key, object obj)
        {
            dic[key] = obj;
        }
    }

Uc1.cs

    public partial class Uc1 : System.Web.UI.UserControl
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            btn.Click += new EventHandler(btn_Click);
        }

        void btn_Click(object sender, EventArgs e)
        {
            //確認Page是否實作IContainer
            var container = Page as IContainer;
            if (Page == null)
                return;

            //確認uc2是否有時做ICommand
            var uc2 = container.GetObj("uc2");
            var command = uc2 as ICommand;
            if (command == null)
                return;

            command.ToDo(DateTime.Now);

            //((Page as IContainer).GetObj("uc2") as ICommand).ToDo(DateTime.Now);
        }
    }

Uc2.cs

    public partial class Uc2 : System.Web.UI.UserControl, ICommand
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        public void ToDo(object obj)
        {
            lit.Text = obj.ToString();
        }
    }

Code 的部份大概就是這樣子了,分兩點來解釋:

第一,讓 Page 實作 Icontainer 這 interface 就是要讓 Page 變成一個 Container 讓大家可以想要什麼東西就從 Page 這邊拿,我們可以經由 Page 來取得想要 uc,取得後轉型成想要的型態,傳統的方式用 FindControl 來找尋,缺點是相依性很重,很容易調一下版面或移一下 uc 就讓頁面死掉,這種作法是在 Page 裡面把 uc 一個一個加入 Container,如果之後頁面很複雜,我們沒辦法在 Page 知道哪些 uc 要加入,我們也可以在 uc 的 Init 事件加進去,反正我們最終的目的就是要把 Page 當作一個 Container,如何取得 uc 的方式統一管理

第二,uc2 有實作 Icommand 這 interface,其實如果沒有實作也行,只要把 object t轉成 uc2 的型別就可以了,但是在考慮相依性的問題,我們不希望 uc1 知道 uc2 是誰,實作 ICommand 就是要相依反轉降低耦合,讓 uc1 不知道 uc2,如果以後 uc2 改了,uc1 就不用動了

Source Code
http://dl.dropbox.com/u/19052216/WebShare/ObserverUC.zip

有問題一起討論吧!!

星期五, 11月 25, 2011

簡單的Text Templating

最近在處理範本的問題,Bibby 習慣慣把範本寫成一個一個的text檔,然後再寫一個Parser去解析,最後用自己寫好的 class 處理,今天看到一個蠻不錯的 extention,可以很快速的解處理這個問題,在這裡分享給大家

我們先開啟 console application 再開啟NuGet

clip_image001

下載GazorGenerator

clip_image002

安裝完直接在目錄下會多個 SampleTemplate.cshtml 檔案,這是範本測試檔,我們直接在 Program.cs 加入下列這段code 就可以跑了

            var template = new SampleTemplate()
{
Message = "Bibby",
};
Console.WriteLine(template.TransformText());
Console.ReadLine();

我們可以看到畫面是

clip_image001[4]

這樣程式就寫完了,夠快吧! 不過我們一定會想,為啥會這樣就寫完了,我們看剛剛那個 SampleTemplate.cshtml 還有 SampleTemplate.generated.cs 就大概就明瞭了

SampleTemplate.cshtml

@* Generator: Template *@

@functions {
public string Message { get; set; }
}

Hello @Message!
SampleTemplate.generated.cs

#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.239
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace RazorTemplateTest
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "1.2.0.0")]
public partial class SampleTemplate : RazorGenerator.Templating.RazorTemplateBase
{
#line hidden

#line 3 "..\..\SampleTemplate.cshtml"

public string Message { get; set; }

#line default
#line hidden

public override void Execute()
{


WriteLiteral("\r\n\r\n");


WriteLiteral("\r\n\r\nHello ");



#line 7 "..\..\SampleTemplate.cshtml"
Write(Message);


#line default
#line hidden
WriteLiteral("!\r\n");


}
}
}
#pragma warning restore 1591

SampleTemplate.generated.cs是自動產生出來的,裡面程式都實作完了,所以畫面就會是你想要的結果了,那要怎麼設定才有自動產生的功能呢?我們看一下 SampleTemplate.cshtml 的Properties

clip_image001[6]

就是在 Custom Tool 上面加入RazorGenerator,加入後在 cshtml 有任何改變 generated.cs 就會自動再產生一次,設定很簡單,接下來我們就按圖施工新增一個 MailTemplate.cshtml 來試著完成一個需求

MailTemplate.cshtml

@* Generator : Template TypeVisibility : Internal *@
@functions {
public dynamic Model { get; set; }
}
Hi! @Model.Name

非常感謝您申請 @Model.Domain
以下是 @Model.Name 的登入情報。請妥善保管。
(此郵件由自動送信程序發送。)

郵件地址: @Model.Email
密碼 : @Model.Password
登入URL : http://@Model.Domain

-----------------------------
@Model.Domain, inc. http://@Model.Domain

然後在 MailTemplate.cshtml 的 Properties 加入 RazorGenerator 就行了,最後在 Program.cs 上加入

            var mailTemplate = new MailTemplate()
{
Model = new {
Name="Bibby",
Password="1234",
Domain = "Bibby.be",
Email="admin@bibby.be",
}
};
Console.WriteLine(mailTemplate.TransformText());

結果:

clip_image001[8]

這樣就完成我們當初的需求了,收工!不過這方式是有缺點啦,因為要改 cshtml 的時候 generated.cs 會重新產生,這樣對於沒有 visual studio 或是不是 developer 是有問題的,如果有這種需求那要參考我好朋友 Wade的文章 用Razor語法寫範本-RazorEngine組件介紹 這種方式,這樣就可以用程式動態去處理,試試看吧!有問題再一起討論吧!

參考:
http://razorgenerator.codeplex.com/

http://haacked.com/archive/2011/08/01/text-templating-using-razor-the-easy-way.aspx

星期日, 11月 20, 2011

Config the Elmah with Sqlite

之前Bibby都把elmah放在mssql裡面,可是遇到一個問題,如果專案沒有mssql的時候,就得改成xml的方式來做,改成xml來做其實也沒有啥不好,只是龜毛的我不喜歡xml那樣,一天一個xml的,看起來有點礙眼,之前閱讀到elmah的文件,有看過是支援sqlite的,所以乾脆以後都把elmah功能寫到sqlite裡面好了,這樣就不同的專案就可以用相同的解決方法處理了
不過在套sqlite的時候,其實不是這麼順利,官方文件(wiki)沒有寫的很清楚,花了一會才用成功,在這裡紀錄一下,以後大家參考就不用浪費時間再跟我做一樣的事情了,接下來就看圖說故事..

clip_image001

先在Reference上面按右鍵選擇NuGet

clip_image002

用搜尋的方式,先把System.Data.SQLite裝上

clip_image003

再裝上ELMAH,這樣元件都裝好了,NuGet真的超級方便..讚..

接下來我們開始設定web.config檔,我們先看一下官方的設定檔好了(這設定檔我的官方網站在鬼打牆,一直找不到)

<!--
Use to log errors to SQLite using ASP.NET 2.0.
Set value of connectionStringName attribute to
the name of the connection string settings to
use from the <connectionStrings> section.
<errorLog type="Elmah.SQLiteErrorLog, Elmah" connectionStringName="..." />
The format of the connection string should be as follows:
<connectionStrings>
<add name="..." connectionString="data source=[path to the database file]" />
</connectionStrings>
Replace the content of the brackets with a file name, for example:
data source=C:\Elmah.db
If the database file doesn't exist it is created automatically.
To specify a path relative to and below the application root,
start with the root operator (~) followed by a forward slash (/),
as it is common in ASP.NET applications. For example:
data source=~/App_Data/Error.db
-->

上面的設定檔很清楚,所以我們修改web.config就行了

  <connectionStrings>
  <add name="elmah" connectionString="data source=~/App_Data/elmah.db" />
</connectionStrings>
<elmah>
  <errorLog type="Elmah.SQLiteErrorLog, Elmah" connectionStringName="elmah" />
</elmah>

把上面這段加在web.config裡面,這樣就可以使用了,第一次的時候elmah會很貼心的幫你產生出sqlite.db的,這時你就可以用資料庫工具看到資料已經寫入了sqlite
clip_image001[4]

測試一下頁面也沒問題..

clip_image002[4]

這樣就完成我們的需求了,有問題再討論吧!

參考:
http://code.google.com/p/elmah/w/list

星期四, 11月 17, 2011

mvc3 自動加的 client 驗證

日前在處理mvc3 client的驗證問題,發現到如果在型別是int或是decimal等都會自動幫你加入驗證,這一點對Bibby我是蠻困擾的,Bibby驗證都是自己加的,自己來才是王道!下列就是mvc3"假伯"幫我們加的東西..

自動幫妳加入錯誤訊息
The field Money must be a number.

產生的html code

<label for="Money">Money</label>:
<input class="input-validation-error text-box single-line" data-val="true"
data-val-number="The field Money must be a number."
id="Money" name="Money" type="text" value="" />
<span class="field-validation-error" data-valmsg-for="Money" data-valmsg-replace="true">
A value is required.</span>

接下來就是尋找如何解決這ox的問題,找了一下發現原來是ClientDataTypeModelValidatorProvider幫我們加上去的,我們看一下source code

/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* This software is subject to the Microsoft Public License (Ms-PL).
* A copy of the license can be found in the license.htm file included
* in this distribution.
*
* You must not remove this notice, or any other, from this software.
*
* ***************************************************************************/

namespace System.Web.Mvc{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web.Mvc.Resources;

public class ClientDataTypeModelValidatorProvider : ModelValidatorProvider {

private static readonly HashSet<Type> _numericTypes = new HashSet<Type>(new Type[] {
typeof(byte), typeof(sbyte),
typeof(short), typeof(ushort),
typeof(int), typeof(uint),
typeof(long), typeof(ulong),
typeof(float), typeof(double), typeof(decimal)
});

public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context) {
if (metadata == null) {
throw new ArgumentNullException("metadata");
}
if (context == null) {
throw new ArgumentNullException("context");
}

return GetValidatorsImpl(metadata, context);
}

private static IEnumerable<ModelValidator> GetValidatorsImpl(ModelMetadata metadata, ControllerContext context) {
Type type = metadata.ModelType;
if (IsNumericType(type)) {
yield return new NumericModelValidator(metadata, context);
}
}

private static bool IsNumericType(Type type) {
Type underlyingType = Nullable.GetUnderlyingType(type); // strip off the Nullable<>
return _numericTypes.Contains(underlyingType ?? type);
}

internal sealed class NumericModelValidator : ModelValidator {
public NumericModelValidator(ModelMetadata metadata, ControllerContext controllerContext)
: base(metadata, controllerContext) {
}

public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() {
ModelClientValidationRule rule = new ModelClientValidationRule() {
ValidationType = "number",
ErrorMessage = MakeErrorString(Metadata.GetDisplayName())
};

return new ModelClientValidationRule[] { rule };
}

private static string MakeErrorString(string displayName) {
// use CurrentCulture since this message is intended for the site visitor
return String.Format(CultureInfo.CurrentCulture, MvcResources.ClientDataTypeModelValidatorProvider_FieldMustBeNumeric, displayName);
}

public override IEnumerable<ModelValidationResult> Validate(object container) {
// this is not a server-side validator
return Enumerable.Empty<ModelValidationResult>();
}
}

}
}

上面的code很清楚,在"那些"型別,都會幫你加上驗證,所以知道"人是誰殺的"那就閹掉他吧XD..解決方法請在Global.asax裡面加入下段的code

            var cdProvider = ModelValidatorProviders.Providers
.SingleOrDefault(p => p.GetType().Equals(typeof(ClientDataTypeModelValidatorProvider)));
if (cdProvider != null)
{
ModelValidatorProviders.Providers.Remove(cdProvider);
ModelValidatorProviders.Providers.Add(new CustomClientDataTypeModelValidatorProvider());
}

用借屍還魂的方式,再新增一個去代替內建的就可以了

    public class CustomClientDataTypeModelValidatorProvider : ModelValidatorProvider
{
public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context)
{
return Enumerable.Empty<ModelValidator>();
}
}

就可以解決了,有問題在一起討論吧!

參考:
http://forums.asp.net/t/1512140.aspx/2/10

星期五, 10月 21, 2011

寫支 console application 來更新 svn 的版本號

簡介

之前有過一篇文章"用 Subversion 來自動更新網站版本和更新時間",用來更新網站的版本和更新時間,不過這個方法不算是很好的方法,有兩點原因,一、個是當我要更新版本號的時候,要去修改 web.config的內容,這點對於版本控管的概念來說是不對的,因為修改原因不是因為 web.config 修改而是你需要版本更新而去改,二、是這部份需要靠記憶來記住這件事,如果忘記就不會更新內容,所以花了一點時間想了一個我覺得更好的方法,在這裡來分享個各位

說明

想法大概是這樣,Bibby 在佈署網站的時候,都會習慣把網站用 Publish 的方式先丟到一個資料夾裡面,然後再去對那資料夾做一些佈署前該做的事,例如測試資料夾要砍掉,Html的layout砍掉等等,所以目標就是寫一隻 console application 來對那個資料夾做事,用程式來代替手工完成佈署前需要做的部份,不過這次範例先 foucs 在更新 svn 的版本號這個動作

步驟

1.在佈署的網站的 web.config 加入下列的設定檔,加入是為了讓 console 來讀取

<appSettings>
<add key="svnPath" value="D:\Projects\URNTW" />
<add key="svnRevision" value="1" />
<add key="svnDate" value="2011/09/07 03:15:45" />
</appSettings>


2.要安裝 TortoiseSVN ,要用到 TortoiseSVN 的 SubWCRev.exe

3.新增一個 console application 來處理這件事

namespace TempConsole
{
class Program
{
static void Main(string[] args)
{
//塞入要處理的path
Helper.BaseFolderPath = args[0];

//更新版svn本資訊
Console.WriteLine("---------更新版svn本資訊-----------");
SvnUtility su = new SvnUtility();
su.ToUpdateSVNVersionAndDate();
Console.WriteLine("---------完成-----------");

Console.Read();
}
}

class Helper
{
static string _BaseFolderPath;
public static string BaseFolderPath
{
get
{
if (string.IsNullOrEmpty(_BaseFolderPath))
throw new Exception("BaseFolderPath不許為空值");
return _BaseFolderPath;
}
set
{
_BaseFolderPath = value;
}
}
}

class SvnUtility
{
/// <summary>
/// 更新版svn本資訊
/// </summary>
/// <param name="folderPath"></param>
public void ToUpdateSVNVersionAndDate()
{
var wu = new WebConfigUtility();

string sourceFolderPath = wu.GetWebConfigSettingValue("svnPath");
string svnFile = string.Format(@"{0}\{1}.txt"
, Helper.BaseFolderPath, Guid.NewGuid().ToString("N"));
using (var stream = File.Create(svnFile))
using (StreamWriter sw = new StreamWriter(stream))
{
//參考http://bluecat.csie.net/2010/07/13/5105/
sw.WriteLine("$WCREV$");
sw.WriteLine("$WCDATE$");
}

string consoleArgs = string.Format(@"{0} {1} {1}", sourceFolderPath, svnFile);
CallConsoleWordApp(@"SubWCRev.exe", consoleArgs, () =>
{
var svnInfo = File.ReadAllLines(svnFile);
File.Delete(svnFile);

wu.SetWebConfigSettingValue("svnRevision", svnInfo[0]);
wu.SetWebConfigSettingValue("svnDate", svnInfo[1]);
Console.WriteLine(string.Concat("處理", string.Concat(Helper.BaseFolderPath, @"\Web.config")));
});
}

/// <summary>
/// 呼叫 產生 Word 的程式
/// </summary>
/// <param name="appPath">被呼叫的程式路徑</param>
/// <param name="parameter">參數,c:/test.exe aa bb cc</param>
void CallConsoleWordApp(string appPath, string parameter, Action fun)
{
const int wait = 3000;

//BMK 呼叫 產生Word 的程式
var startInfo = new ProcessStartInfo(appPath, parameter)
{
WindowStyle = ProcessWindowStyle.Hidden
};

var process = new Process
{
StartInfo = startInfo
};
process.Start();
process.WaitForExit(wait);//程式等三秒沒執行就跳出
bool IsGet = true;
while (IsGet)
{
if (process.HasExited)
{
fun.Invoke();
IsGet = false;
}
}

}
}

class WebConfigUtility
{
readonly string configFile;
public WebConfigUtility()
{
this.configFile = string.Concat(Helper.BaseFolderPath, @"\Web.config");
}

public void SetWebConfigSettingValue(string key, string value)
{
var root = XElement.Load(configFile);
var settings = root.Element("appSettings").Elements("add");

try
{
settings.First(a => a.Attribute("key").Value == key)
.Attribute("value").Value = value;
root.Save(configFile);
}
catch
{
throw new Exception("沒有這個item");
}
}

public string GetWebConfigSettingValue(string key)
{
var root = XElement.Load(configFile);
var settings = root.Element("appSettings").Elements("add");

try
{
return settings.First(a => a.Attribute("key").Value == key)
.Attribute("value").Value;
}
catch
{
throw new Exception("沒有這個item");
}
}
}
}

4.下載 Open++ 這軟體來呼叫 console application

先大概簡介一下,這個程式是用來修改滑鼠右鍵 menu 的,Bibby會用這隻程式是因為有三個原因,一、很直覺,有簡潔易懂的界面可以用,二、可以分組,這功能很重要幫助分類,三、免費又免安裝,基於這三點,不用怎麼可以,Bibby知道也可以去編輯 regedit 檔案來達成這個效果,不過基於懶又不想研究太深入的關係,就拿人家寫好的軟體來用就對了!接下來就是簡單的使用流程,看圖說故事摟..

開起解壓縮後的資料夾,執行程式

clip_image001

新增按鈕,選擇 Command

clip_image002

1.新增Command的名稱
2.這個Command的位置
3.執行程式會帶入的參數名稱,這很重要,因為我們就是要對這個資料夾來處理
4.這個Command的內容只出現單一資料夾的狀態下

clip_image003

1.增加按鈕
2.增加分割線,這是為了要分組用的

image

1.新增好內容後,要來安裝這個程式,這樣滑鼠右鍵才會出現,如果有一天您不想要這個程式,只要用uninstall這個內容就可以了

clip_image005

1.在資料夾上點滑鼠右鍵,就可以看到 TempConsole 這個我們剛剛新增的 Command 了

clip_image006

結果

我們就可以在web.config裡面看到修改了

clip_image007

總結

這個作法比之前的作法好很多,在進階一點,我們可以把佈署前想要做的事情都放在這支 console application 來處理,例如:刪除一些不要的檔案,加密一些設定檔,壓縮整個要佈署的資料夾等等,這些內容實作都不難,寫好了就可以用很久很久,身為程式設計師的我們,就是要想些有的沒有的來讓世界變得更好,如果大家對於此作法有任何的意見,留言一起討論吧!

參考
http://bluecat.csie.net/2010/07/13/5105/
http://dengdun.webs.com/

星期三, 5月 18, 2011

Silverlight 的初始值

最近在學習 Silverlight,這裡紀錄一下在寫 Silverlight 時,會常常用到的技巧。我們初始程式時,經常都會給程式初始值,那 Silverlight 要如何給初始值呢?有兩種方法,一是用 QueryString,這方式在寫網頁的時候一定常用,二是可以設定放置在 Silverlight 的 Html 的參數,有點模糊吧!我們直接看code..

第一種方法 QueryString

http://localhost:2418/?qs1=123&qs2=456&qs3=789

xaml

<StackPanel x:Name="LayoutRoot" Background="White">
<TextBlock x:Name="tbInitValue" TextWrapping="Wrap" Text="InitValue:" Foreground="Red"/>
<StackPanel x:Name="stInitValue" HorizontalAlignment="Left" Margin="8,0,0,0" />
<TextBlock x:Name="tbQueryString" TextWrapping="Wrap" Text="QueryString:" Foreground="Red"/>
<StackPanel x:Name="stQueryString" HorizontalAlignment="Left" Margin="8,0,0,0"/>
</StackPanel>

.cs

public partial class InitValue : UserControl
{
public InitValue()
{
InitializeComponent();

//QueryString
var qs = HtmlPage.Document.QueryString;
foreach (var key in qs.Keys)
{
TextBlock tb = new TextBlock();
tb.Text = string.Format("{0}:{1}", key, qs[key]);
stQueryString.Children.Add(tb);
}

}
}

第二種方法 InitParams

.App.xaml.cs

private void Application_Startup(object sender, StartupEventArgs e)
{
var obj = new InitValue.InitValue();
this.RootVisual = obj;
//InitParams
foreach (var key in e.InitParams.Keys)
{
TextBlock tb = new TextBlock();
tb.Text = string.Format("{0}:{1}",key, e.InitParams[key]);
obj.stInitValue.Children.Add(tb);
}
}

.html

<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
<param name="source" value="/ClientBin/SilverlightApplication1.xap">
<param name="onError" value="onSilverlightError">
<param name="onError" value="onSilverlightError">
<param name="background" value="silver">
<param name="minRuntimeVersion" value="3.0.40818.0">
<param name="autoUpgrade" value="true">
<param name="enableHtmlAccess" value="true">

<param name="initParams" value="initp1=a987,initp2=b654,initp3=c321">

<param name="windowless" value="false">
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&amp;v=3.0.40818.0" style="text-decoration: none;">
<img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none;">
</a>
</object>

結果:

image

這裡做個簡單的說明,用 InitParams 的時候需要在 App.xmal.cs 裡面處理,在用 QueryString 需要在 xmal.cs 裡面處理,這兩個的差別要注意一下,有問題再一起討論吧!!

參考:
http://www.switchonthecode.com/tutorials/silverlight-2-using-initparams

星期五, 5月 06, 2011

(敗家文)Synology DS410 + WD2TB x3 合體

上個月月底的某一天的晚上,看著 nba 精彩刺激的季後賽,忽然聽到 server 上的硬碟咖啦咖啦響,心想完蛋了,硬碟不會葛屁了吧!馬上遠端連去 server 看看,喵低,果然進不去了..案,之後拔出來用一堆有的沒有的方法(搖一搖它..摸一摸它..拜一拜插根香..還有人叫用電擊的方式XD)看會不會活起來,不過都沒有成功,唉唉唉..一整個很鬱悶..

話說遇到了還是遇到了,還是要想個辦法解決,我不要再出現硬碟掛了只能偷哭得窘境,探聽了一下搜尋的一下..就敗了下列的東西..><||..

image

很快的,早上訂貨下午箱子就會出現在你家裡(這樣消費真的有快感XD)

先看盒子照..

P1090061

脫掉衣服,感覺還蠻素雅的

P1090063

大食怪的 2TB 硬碟的近照..威..

P1090064

看一下內裝..未放硬碟..

P1090067

全部塞進去就對了,合體!!

P1090069

開始工作照..

P1090072

看一下合體起來的軟體畫面..

 image

貼完啦大概是這樣,軟體的操作界面還蠻直白的很容易懂,說明書很多很多頁很詳細,等下次用到有心得再上來報告,先把資料備份安全的部份處理好,讓硬碟死掉的惡夢在我生活中消失,這就是花錢當凱子的好處,哈,如果有人有跟我一樣的顧慮,怕哪天硬碟死了自己也會哭死的,可以考慮一下衝下去,別想太多..^___^

參考:
http://www.synology.com/cht/index.php

星期二, 2月 08, 2011

時區 (TimeZones) 的下拉選單

常在註冊一些論壇或是網站的時候,都會看到您目前屬於那一個時區的下拉式選單,如果這功能用 .net 要如何做呢?

image

在之前的方法都是寫死的,需要用就去網路查一下資料,到底有哪些時區可以選,這個東西通常都是寫好包起來,等有需要在拿出來使用,還有也要寫一下由使用者時區來顯示當地時間的 method,其實不算難寫,只是有點麻煩,不過微軟佛心來了,幫我們把這個東西整理好了,讓我們不用花心思在這個沒啥營養的東西,先看 Code 吧!

ReadOnlyCollection<TimeZoneInfo> tzi = TimeZoneInfo.GetSystemTimeZones();
DateTime dt = DateTime.Now;
foreach(var item in tzi)
{
var t = TimeZoneInfo
.ConvertTimeBySystemTimeZoneId(dt,TimeZoneInfo.Local.Id,item.Id);
var display = string.Concat(t," ==> ",item.DisplayName);
Console.WriteLine(display);
}

image

上面這段 Code Snippet 我是把當地的時間還有時區印出來,如果在 dropdownlist 需要用的話,下列這樣寫法就可以了

ReadOnlyCollection<TimeZoneInfo> tzi = TimeZoneInfo.GetSystemTimeZones();
DateTime dt = DateTime.Now;
foreach (var timeZone in tzi)
{
ddlTimeZone.Items.Add(new ListItem(timeZone.DisplayName, timeZone.Id));
}

參考:
http://msdn.microsoft.com/zh-tw/library/system.timezoneinfo.getsystemtimezones.aspx
http://www.dotnetcurry.com/ShowArticle.aspx?ID=593

星期四, 1月 27, 2011

.NET library for the Google Data API

今天在逛網路的時候,發現到 .NET library for the Google Data API 這專案,提供的 service 如下

Each of the following Google services provides a Google data API:

  • Base
  • Blogger
  • Calendar
  • Spreadsheets
  • Google Apps Provisioning
  • Code Search
  • Notebook
  • Picasa Web Albums
  • Document Feed
  • Contacts
  • You Tube
  • Google Health
  • Google Analytics
  • Google Webmaster Tools

哇,這些功能之前要使用的時候,就必須刻苦去讀 google 的 api document 然後組出 querystring 或是 javascript 的方式處理,現在有很方便的 dll 可以 reference ,當然二話不說,先把專案載下來看看..

image

專案還蠻多的,進入每個專案就可以看到各個功能的 sample code,有了 sample code 不看 document 也可以無腦使用了,不過要使用還是 線上 document 還是看一看才是真的!

現在,來試來跑一下 Calendar 專案,先設定 StartUp Project 然後按 F5 程式就出現了,依上面的內容填入帳號密碼..

SNAGHTML1f3c1e1

內容就出現啦,一整個方便,好物好物!!

goolge 服務很輕鬆的無縫整合到 .net,不過當東西越來越方便呼叫越來越簡單後,我們就是不是該想想,作為工程師的價值在哪呢?

參考:
http://code.google.com/p/google-gdata/

星期五, 1月 14, 2011

如何用 jQuery 去判斷檔案存不存在

最近好忙阿,趕羚羊的忙,Blog 草都有 180 了,心裡有個聲音,你再這樣墮落下去就去會被嫌棄的!! 所以新的年度,還是要重新開始,套一句常常聽到的話'"時間就像女人的乳溝,擠一擠還是有”,所以要寫文要寫文要寫文!!

喇賽的事情不多說了,今天要分享一下最近學到的東西,就是如何用 jQuery 去判斷檔案存不存在,這個問題對於網頁工作者非常有用,舉一個例子,例如一個購物網,一定會有產品列表頁,頁面上的產品圖片如果後台的維護人員還沒有上圖,這頁面上的產品我們會希望給它一個預設的圖,等候台上好圖後,圖片就恢復成該圖片自己的圖,像這種功能,用這方式做就很簡單輕鬆好自在!!我們直接看 code 吧!

function IsFileExist(filePath){
var bo = false;
$.ajax({
url:filePath,
type:'HEAD',
async:false,
success:function(){
bo = true;
},
error:function(){
bo = false;
}
});
return bo;
}

上面這個 filePath 是指檔案在 Server 端的路徑,還有注意我有加一個 async:false 的參數,這是說,不要執行非同步,簡單的來說就是會等結果出來才會傳回 true/false..

參考:
http://www.ambitionlab.com/how-to-check-if-a-file-exists-using-jquery-2010-01-06


2011/01/12更新
好友demo有建議,如果是的話 onerror 這個 tag 來處理掉比較好,詳情可以看他的文章..