顯示具有 Silverlight 標籤的文章。 顯示所有文章
顯示具有 Silverlight 標籤的文章。 顯示所有文章

2011年1月26日

A Distributable (.exe) Silverlight OOB Application

Silverlight 的 Out of Browser 可以很方便讓你由網站,直接將程式安裝到桌面上;但是,若想把 Silverlight 包裝成可安裝的套裝軟體,反而變得比較麻煩。

下面這篇文章可以告訴你如何處理:

A Distributable (.exe) Silverlight OOB Application
How to distribute a Silverlight OOB Application?

2010年10月20日

Design-Time Attributes for Components and Behaviors

使用 Expression Blend 設計 Silverlight 介面時,若希望設計人員能更清楚 Property 的含意,可以透過 Design-Time Attributes 來協助。

以下列出可能會使用到的項目:


可以在 class 上加入 Description, 來說明物件的功用 (上圖)
    [Description("可點選物件 - 可以設定為正確或錯誤點選")]
    public class ClickItemProcess : QuestionGroupBase<panel>
    {
       //..
    }


Description 也可以使用在 property 上, 並能以 Category 來分類 (上圖)
        [Category("遊戲功能"), Description("若此物件為錯誤答案,點選後所顯示的動畫(Storyboard)")]
        public string WrongAnswerAnimation
        {
            get { return (string)GetValue(WrongAnswerAnimationProperty); }
            set { SetValue(WrongAnswerAnimationProperty, value); }
        }

如果 property 不希望出現在 Expression Blend 的面板上, 可以將 Browsable 設為 false
        Result m_Result = Result.NoAnswer;
         [Browsable(false)]
        public Result Result
        {
            get { return m_Result; }
            set { m_Result = value; }
        }


如果 properties 屬於 state, element 或 storyboard, 並希望直接出現下拉選單,則可以用 CustomPropertyValueEditorAttribute 來設定。CustomPropertyValueEditor.StateName, CustomPropertyValueEditor.Element, CustomPropertyValueEditor.Storyboard 分別對應這三種不同類型的物件。

        [CustomPropertyValueEditorAttribute(CustomPropertyValueEditor.Storyboard)] 
        public Storyboard RightAnswerAnimation
        {
            get { return (Storyboard)GetValue(RightAnswerAnimationProperty); }
            set { SetValue(RightAnswerAnimationProperty, value); }
        }

另外,對於 TriggerAction, 可以利用 DefaultTriggerAttribute 預設 event。以及利用 TypeConstraintAttribute 來限制 TargetedTriggerAction 與 EventTriggerBase 的 AssociatedObject 型態。

    [DefaultTrigger(typeof(UIElement), typeof(EventTrigger), "MouseLeftButtonDown")]
    [DefaultTrigger(typeof(ButtonBase), typeof(EventTrigger), "Click")]
    public class WaveAction : TriggerAction<UIElement> { }

[reference]
MSDN: Design-Time Attributes for Components
State, Element, and Storyboard Pickers
Silverlight Hover Behavior

2010年10月12日

Free Silverlight Hosting

在部落格上探討 Silverlight 的技術與應用,如果不能顯示範例執行的樣貌,是一件令人苦惱的事情。當然,可以花錢用虛擬主機解決,只是還沒有收到 Google AdSense 的支票,卻要先支出,也太吃虧了。

先前微軟提供了 Microsoft Silverlight Streaming by Windows Live 免費的 hosting 服務,2010 已由 Azure 取代,也有 Introductory Special 免費方案 (Limited Amount at No Charge),但是台灣地區卻遲遲未上線。想亂編一個美國的地址去註冊,因為要輸入信用卡號,覺得不妥而作罷。

好在發現可以利用 Google App Engine application 來解決,雖然要多繞一圈,但還算值得,而且第二個 ap 之後,也會方便許多。步驟如下:

  1. 建立 Python 開發環境,並安裝 Google App Engine 上傳檔案的工具
  2. 利用 Google App Engine 建立帳號並新增 Application
  3. 撰寫 app.yaml 來設定上傳的檔案,而 .py (以 Python為例) 可以是一個空檔案
  4. 利用 appcfg.py 上傳 app.yaml, silverlight.js, .xap 至 Server
  5. 在部落格的網頁中,加入呼叫 .xap 的語法

app.yaml 範例:

application: dysonliu
version: 1
runtime: python
api_version: 1

handlers:

- url: /Silverlight3D.xap
static_files: Silverlight3D.xap
upload: Silverlight3D.xap
mime_type: application/x-silverlight-app

- url: /Silverlight.js
static_files: Silverlight.js
upload: Silverlight.js

- url: .*
script: Silverlight3D.py


插入部落格 HTML 的語法,可以由 Silverlight 的專案抄過來,然後把 Silverlight.js 與 .xap 的位置改掉,並加入寬度與高度的設定。

[reference]
Google 應用服務引擎 - 入門指南
How to embed a silverlight control on a Google Sites webpage?

2010年9月28日

Jigsaw Puzzle by Silverlight

我打算使用 Silverlight 來寫拼圖遊戲,並以網友自己的照片,來做為圖案。為了要完成這項工作,需要將複雜的過程,分成幾個步驟,並找到對應的解決方法。
  1. 首先,我們可以想像將照片切分成大小相同的矩形。
  2. 接著將矩形的四個邊,轉換成拼圖所特有的曲線。
  3. 由於曲線的兩端固定在矩形的頂點上,利用亂數改變曲線的線條,便可以產生每個形狀都有些微差異的拼塊了。

執行上列的步驟,我們需要了解 Path 的語法,以及切割照片的方法。

Cubic Bezier Curve

利用 Cubic Beizer Curver 可以很容易設計出我們所要的曲線。上面的解說圖,說明 Cubic Bezier Curve 的語法,如果是直接寫在 xaml 上,結果如下:
<Path Data="Mx1,y1 Cx2,y2 x3,y3 x4,y4 C....", ..>

如果用程式來產生,程式碼如下:
            Path path = new Path();
            PathGeometry pathGeometry = new PathGeometry(); 

            path.Data = pathGeometry; 
            pathGeometry.Figures = new PathFigureCollection(); 

            PathFigure figur = new PathFigure(); 
            pathGeometry.Figures.Add(figur); 
            figur.StartPoint = new Point(x1, y1);

            BezierSegment seg1 = new BezierSegment();
            seg1.Point1 = new Point(x2, y2);
            seg1.Point2 = new Point(x3, y3);
            seg1.Point3 = new Point(x4, y4);
            figur.Segments.Add(seg1); 
            :            
            :            
            path.Stroke = new SolidColorBrush(Colors.Blue);
            path.StrokeThickness = 3.0;
            this.LayoutRoot.Children.Add(path);


Piece Sharp

接下來,可以利用 Expression Blend 設計一段邊線的模板 (PathNodes),並調整數值,使左右能夠對稱,並利用旋轉、鏡射,產出完整的拼塊圖案。
        
Point[] PathNodes = new Point[]
        {
            new Point( 33,8),  // C1-1
            new Point(69,9),   // C1-2
            new Point(77,-8),   // C1-3

            new Point( 85,-23),  // C2-1
            new Point(54,-39),   // C2-2 
            new Point(65,-58),   // C2-3

            new Point( 77,-76),          // C3-1
            new Point(200-77,-76),    // C3-2
            new Point(200-65,-58),   // C3-3

            new Point(200-54,-39),   // C4-1
            new Point(200-85,-23),   // C4-2
            new Point(200-77,-8),     // C4-3

            new Point(200-69,9),  // C5-1 
            new Point(200-33,8),  // C5-2
            new Point(200,0)        // C5-3
        };

        private enum EdgeOrientation
        {
            Horizontal = 0,
            Vertical = 1
        }

       private PathGeometry CreateJigsawPuzzlePathGrometry(Point startPoint, Size pieceSize, EdgeOrientation orientation)
        {            
            PathGeometry pathGeometry = new PathGeometry();
            pathGeometry.Figures = new PathFigureCollection();

            PathFigure figur = new PathFigure();
            figur.StartPoint = startPoint;
            pathGeometry.Figures.Add(figur);

            Point lastPoint = startPoint;

            for (int edge = 0; edge < 4; edge++)
            {
                TransformGroup group = new TransformGroup();
                double scaleX = (edge % 2 == 0) ? pieceSize.Width / 200 : pieceSize.Height / 200;
                double scaleY = (edge % 2 == 0) ? pieceSize.Height / 200 : pieceSize.Width / 200;
                scaleY = (edge % 2 == (int)orientation) ? -scaleY : scaleY;

                ScaleTransform st = new ScaleTransform() { ScaleX = scaleX, ScaleY = scaleY };
                group.Children.Add(st);

                TranslateTransform tt = new TranslateTransform() { X = lastPoint.X, Y = lastPoint.Y };
                group.Children.Add(tt);

                RotateTransform rt = new RotateTransform() { Angle = edge * 90, CenterX = lastPoint.X, CenterY = lastPoint.Y };
                group.Children.Add(rt);

                for (int i = 0; i < PathNodes.Length / 3; i++)
                {
                    BezierSegment seg = new BezierSegment();
                    seg.Point1 = group.Transform(PathNodes[i * 3]);
                    seg.Point2 = group.Transform(PathNodes[i * 3 + 1]);
                    seg.Point3 = group.Transform(PathNodes[i * 3 + 2]);

                    figur.Segments.Add(seg);
                    lastPoint = seg.Point3;
                }
            }
            return pathGeometry;
        }


CreateJigsawPuzzlePathGrometry 有三個參數:
startPoint - 我們將一張圖,以矩形劃分,每個矩形的左上角,距離圖片左上角的位置,即是每一片小拼塊開始進行切割的 startPoint
pieceSize - 指劃分圖片矩形大小
orientation - 由於鄰近的小拼塊,凹凸位置剛好相反,orientation 應交互變換



Clip Image

我們利用上列方法所產生的 PathGrometry 來進行圖片切割的工作,並讓切割後的圖案成為獨立的 element,並有一致的原始點位置,方便使用者移動與操作。
Silverlight 並沒有 sprite 的功能,ImageBrush.ImageSource 也沒辦法設定位移與範圍,所以我利用了 WriteableBitmap 來達成這項工作。

   
        private Canvas CreatePiece(BitmapImage bitmap, Point startPoint, Size pieceSize, EdgeOrientation orientation)
        {
            Image imageTemp = new Image();
            imageTemp.Source = bitmap;
            imageTemp.Clip = CreateJigsawPuzzlePathGrometry(startPoint, pieceSize, orientation);

            Size panelSize = new Size(pieceSize.Width * 2, pieceSize.Height * 2);
            WriteableBitmap wb = new WriteableBitmap((int)panelSize.Width, (int)panelSize.Height);
            TranslateTransform translate = new TranslateTransform() { X = -startPoint.X + pieceSize.Width / 2, Y = -startPoint.Y + pieceSize.Height / 2 };
            wb.Render(imageTemp, translate);
            wb.Invalidate();

            Image image = new Image();
            image.Source = wb;
            Canvas.SetLeft(image, -pieceSize.Width / 2);
            Canvas.SetTop(image, -pieceSize.Height / 2);

            Canvas canvas = new Canvas();
            canvas.Children.Add(image);

            Path path = new Path() { StrokeThickness = 2, Stroke = new SolidColorBrush(Colors.Black) };
            path.Data = CreateJigsawPuzzlePathGrometry(startPoint, pieceSize, orientation);
            Canvas.SetLeft(path, -startPoint.X);
            Canvas.SetTop(path, -startPoint.Y);
            canvas.Children.Add(path);
            
            return canvas;
        }
     


不過,後續的事情還很多,只是技術上困難的部分大概都搞定了。切割時,還要考慮最外圍邊緣必須改為直線,而操作介面則是另一項複雜的學問,但我就不再談下去了。

2010年9月16日

Embed HTML in Silverlight 的問題

將 silverlight 設定為 windowless 雖然可以順利以 floating 方式顯示 HTML 區塊,卻會造成中文輸入法失效的問題。由於公司入選台灣微軟BizsparkCamp 雲端/ Silverlight創新徵選會,很榮幸能就此問題向章立民老師請教。
章老師提到,使用 windowless 不是一個恰當的做法,可能衍生的不只是中文輸入的問題,應避免使用。文件內容以資料庫或 xml 存放,並依照 HTML 或 Silverlight 的不同,來採取最恰當的顯示方法,才是最佳的處理方式。
章老師的答案,讓我覺得寫程式真的偷懶不得!!
前一篇 Embed HTML in Silverlight

2010年5月19日

Embed HTML in Silverlight

最近處理 Silverlight 顯示 HTML 視窗的問題,
看到一篇文章,測試了五種不同的方法,
分別如下:
  1. WebBrowser - 可以顯示, 但限定在 Out of Browser 的模式
  2. RichTextBox - 無法顯示 HTML
  3. HTML Host Control - 即在 Silverlight 上, 疊一個 position:absolute 的區塊或 ifarem
  4. Liquid RichTextBox - 勉強可以, 有些 HTML 的語法無法呈現, 對中文的支援更糟
  5. HtmlTextBox - 同樣是勉強可用

原始文章位置:http://www.cnblogs.com/Robin2005/archive/2010/05/18/1737887.html
其中 HTML Host Control 應該是相容性最不受限的方法,
但嚴格來說,這不能算是 Silverlight 所提供的功能。

下列class,可以輸入InnerHtml,來顯示 HTML 的內容
但記得在包含 Silverlight 的網頁上,加入 id 為 winContent 的 div
並將 Silverlight 物件設為 windowless。
    public partial class HtmlHostControl : UserControl
    {
        public string InnerHtml
        {
            get { return m_InnerHtml; }
            set
            {
                m_InnerHtml = value;
                if (m_DivIFrameHost != null)
                    m_DivIFrameHost.SetProperty("innerHTML", value);
            }
        }

        public HtmlHostControl()
        {
            InitializeComponent();
            SizeChanged += new SizeChangedEventHandler(HtmlHostControl_SizeChanged);
            CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
        }

        void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            ResetHtmlHostPosition();
        }

        void HtmlHostControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            ResetHtmlHostPosition();
        }

        HtmlElement m_DivIFrameHost = null;
        string m_InnerHtml = "";

        public void Show()
        {
            if (m_DivIFrameHost == null)
            {
                HtmlDocument doc = HtmlPage.Document;
                m_DivIFrameHost = doc.GetElementById("winContent"); 
                m_DivIFrameHost.SetStyleAttribute("visibility", "visible");

                m_DivIFrameHost.SetProperty("innerHTML", "Hello");
            }

            ResetHtmlHostPosition();
        }

        private void ResetHtmlHostPosition()
        {
            if (m_DivIFrameHost != null)
            {
                GeneralTransform generalTransform = HtmlHostPanel.TransformToVisual(Application.Current.RootVisual);

                Point pos1 = generalTransform.Transform(new Point(0, 0));
                Point pos2 = generalTransform.Transform(new Point(HtmlHostPanel.ActualWidth, HtmlHostPanel.ActualHeight));

                m_DivIFrameHost.SetStyleAttribute("left", pos1.X.ToString() + "px");
                m_DivIFrameHost.SetStyleAttribute("top", pos1.Y.ToString() + "px");
                m_DivIFrameHost.SetStyleAttribute("width", (pos2.X - pos1.X).ToString() + "px");
                m_DivIFrameHost.SetStyleAttribute("height", (pos2.Y - pos1.Y).ToString() + "px");
            }
        }

        public void ReleaseAll()
        {
            CompositionTarget.Rendering -= CompositionTarget_Rendering;
            if (m_DivIFrameHost != null)
                m_DivIFrameHost.SetStyleAttribute("visibility", "hidden");
        }
    }

2009年11月19日

Silverlight 4


"你認為該有的,過去卻沒有的,現在都有了, 列印, 滑鼠右鍵, WebCam,
拖曳檔案, 驗證與安全性, RichtextBox, 剪貼簿, 輸入法支援..."
以上是由董大偉部落格所擷取的一段話。

Silverlight 的版本更新真的有夠快,
年中才剛由 2.0 改為 3.0,看來最近又要再改了。

[Reference]
Silverlight 4 beta 登場 : 此時無聲勝有聲, 一切盡在不言中...

2009年11月14日

Bing Maps Silverlight Control SDK


先是 Bing, 現在又有 Bing Maps,
實在很難對 Microsoft 這個龍頭批評什麼!

Bing Maps 看起來離 Google Maps 還有一段不小的距離,
也還沒有中文化,不知道台灣會不會有人想去用他的SDK?
總之, 只是看到消息, 順手記錄下來罷了!

[Reference]
Bing Maps Silverlight Control SDK

2009年11月11日

Silverlight Unloaded Event & ZIndex


Silverlight 有一個問題,就是沒有提供 Unloaded Event,
如果你設計了一個 UserControl 並在 Loaded 中加入了 event
那麼這個 UserControl 若移出 Parent 後再加入,
就會再呼叫一次 Loaded,而 event 便再增加一次。

因此,圖形物件的 layer 在進行變更時,
要記得利用 Canvas.SetZIndex 來處理,
而不要用 Panel.Children.Remove() 及 Panel.Children.Add().

2009年11月2日

Rich Internet Application Market Share


因為訂閱了 Google Blog 有關 Silverlight 的快訊,
收到了 Kimo Chung's AS3 Playground: Why Silverlight? um, I don't know.
這篇文章,
也因此發現了有關 RIA 市場占有率的現況,
提供大家分享。

Silverlight 全世界的安裝比例,大約為 29%,
台灣的安裝比列則是41%。



[Reference]
Rich Internet Application Statistics
Rich Internet Application Market Share

2009年10月29日

Silverlight Game Loop

撰寫遊戲程式,經常需要利用 main loop 處理一些工作。
以下是 Silverlight 使用 loop 的方法。
public Page()
{    
    InitializeComponent();
    CompositionTarget.Rendering += new EventHandler(SnowFlakeTimer);
} 

private void SnowFlakeTimer(object sender, EventArgs e)
{
    // do your task    
}

[Reference]
Silverlight Tip of the Day #50 – Main Game Loop Revisited!

Getting Query String Values in Silverlight

Silverlight 可以直接取得網址後面的參數,
方法如下:
string val = System.Windows.Browser.HtmlPage.Document.QueryString["foo"];

[Reference]
Getting Query String Values in Silverlight

2009年10月28日

Silverlight TextBox 斷行處理

下列的範例,可以將 TextBlock.Text 所取得的字串, 拆解成字串陣列。

string text = TheTextBox.Text;
text = text.Replace(Environment.NewLine, "\r");
string[] texts = text.Split(new char[] { '\r'  });

2009年10月25日

Silverlight String to Path

由於 Silverlight 並沒有中文字型,所以要顯示中文字便比較麻煩。 如果文字的內容是固定,可以用圖形或將文字轉成 path 的方式處理, 若文字是變動性的,甚至是由 user 來輸入, 就必須建立 WCF 由 server 端來處理了。 以下是 Server 端, 將 string 轉成 path 並傳回的方法:
public string GetFont
  (string str, string fontFamily, int nSize)
{
   Typeface typeface = 
       new Typeface(new FontFamily(fontFamily),
       FontStyles.Normal, FontWeights.Normal, 
       FontStretches.Normal);

   FormattedText text = new FormattedText(str,
       new System.Globalization.CultureInfo("zh-tw"),
       FlowDirection.LeftToRight, typeface, nSize,
       Brushes.Black);

   Geometry geo = text.BuildGeometry(new Point(0, 0));
      
   PathGeometry path = geo.GetFlattenedPathGeometry();
   string data = path.ToString();

   string xamlTriangle = "<Path xmlns='http://schemas.microsoft.com/" + 
          "winfx/2006/xaml/presentation' " +
     "xmlns:x='http://schemas.microsoft.com/" +
          "winfx/2006/xaml' " +
     "Data='" + data + "' Fill='LightBlue' " + 
     "Stretch='Fill'/>";

   return xamlTriangle;
}
而 Client 的程式如下:
void client_StringToPathCompleted(object sender,
 DoWorkCompletedEventArgs e)
{

 Path newPath = (Path)
  System.Windows.Markup.XamlReader.Load(e.Result);
 this.LayoutRoot.Children.Add(newPath);

}
[Reference]
以 WPF + AJAX 在執行期間將文字轉成 Path
In SL3.0, can you not just use XamlReader.Load ?

Silverlight Color Picker and HSV RGB Convert

Silverlight 沒有 Color Dialog, 所以必需自己處理。
我找到 TeamLive Blog 有關 color picker 的文章,
覺得超棒,而且含了 XAML 語法。
可惜文章中,沒有 source code,
其中需要應用到 HSV 與 RGV 的相互轉換,
我把相關的參考資料列在下方。

[Reference]
TeamLive Blog - Silverlight Color Picker
RGB 與 HSV 相互轉換的方法

2009年9月3日

TransformToVisual

使用 UIElement.TransformToVisual 時,常常會把角色給搞混,為了一勞永逸,乾脆好好記錄下來,並用圖形來表示。
以下是將 EllipseObject 由 OriginalCanvas 轉換到 TargetCanvas,並保持不動的程式碼。
Point PointOfOriginal = 
  new Point(Canvas.GetLeft(EllipseObject), 
            Canvas.GetTop(EllipseObject));

GeneralTransform generalTransform = 
  OriginalCanvas.TransformToVisual(TargetCanvas);

OriginalCanvas.Children.Remove(EllipseObject);

Point PointOfTarget = 
  generalTransform.Transform(PointOfOriginal);

Canvas.SetLeft(EllipseObject, PointOfTarget.X);
Canvas.SetTop(EllipseObject, PointOfTarget.Y);

TargetCanvas.Children.Add(EllipseObject);

2009年8月20日

Silverlight MediaElement

在 Silverlight 中,播放 video 與 audio 的方法是透過 MediaElement,以下分別就 video 與 audio 各蒐集了一個範例。
[Reference]
Video - Using the Media Element control in Silverlight 2: http://www.c-sharpcorner.com/UploadFile/mamta_m/111292008005520AM/1.aspx

2009年8月17日

Silverlight 3.0

關於 Silverlight 3.0 所增加的新功能,簡單以條列方式記錄:

影像部分增加
Smooth Stream, Full Screen HD Playback, Content Protection 等
圖形部分增加
3D Projection, Pixel Shader Effects, Bitmap API
通訊部分增加
.NET RIA Services (但是彈性比 Web Service 小)
控制部分增加
Mouse Wheel, Multi Touch (Windows 7)

2009年7月9日

Read File in WebService

最近在開發 Silverlight Application 時,
為了讓程式保持在最短小的狀態,
需要透過 WebService 下傳 Xap 檔案。
在設計的過程中,
必須解決 WebService 讀取相對目錄下的檔案問題,
以下是相對目錄的取得方式:

string path =
  System.Web.Hosting.HostingEnvironment.MapPath
               ("~/ClientBin/PhotoViewer.xap");           
  FileStream fileStream = 
     File.Open(path, FileMode.Open, 
               FileAccess.Read, FileShare.Read);

Deploying Vue & .NET with Google OAuth on GCP Cloud Run

Deploying Vue & .NET with Google OAuth on GCP Cloud Run Deploying Vue & .NET with Google OAuth on GCP Cloud Run...