Posts Tagged .NET

Multi-touch and Ink support in Silverlight

Xem bản tiếng Việt

Silverlight is Microsoft’s ambitious dream to provide a simple-but-powerful development platform for Rich Internet Applications (RIAs). The release of Windows Phone 7 marks Microsoft’s latest effort to broaden Silverlight’s reach to the booming portable market, where the number of users increases by millions every year. As this market requires nontraditional ways to interact with the device (you don’t expect your cell phone to have mouse and full-size keyboard, do you?), Silverlight is also empowered with new support for some of the currently “hot” technologies, including Multi-touch and Ink.

Multi-touch

Multi-touch is an exciting technology that contributed to the success of the over-popular iPhone and iPad. Though the first touch-enabled (single-touch) device has appeared long ago, it is only multi-touch that truly pushes user experience to a new level by allowing them to perform complex maneuvers with more than one finger. This can create some fancy effects such as zooming and rotating photos that were previously impossible with single-touch. With more and more devices adopting to use this technology, Silverlight of course, cannot stay out of the game. Indeed, Silverlight, since version 3.0, has officially support Multi-touch.

Multi-touch is basically an input method, and the first thing we usually think about input processing is input events. In Silverlight, the main event that we need to care about is FrameReported, declared in the Touch class. Registering this event is as simple as follow:

Touch.FrameReported += new TouchFrameEventHandler(Touch_FrameReported);

Notice that unlike some common events such as Button.Click, FrameReported is a static event that doesn’t link to any specific instances of the Touch class (actually Touch is also static and therefore cannot have any instances!). When a device is touched, it raises this event repeatedly after a specific interval, the duration of which depends largely on the hardware being used. But for now we’ll skip the details, our interest here is how to handle this event, so let’s shift our focus to the event handler:

void OnTouchFrameReported(object sender, TouchFrameEventArgs e)
{
   string str = "";
   foreach (TouchPoint tp in e.GetTouchPoints(this))
   {
      str += string.Format("{0}; ", tp.Position);
   }
   MessageBox.Show(str);
}

Not surprisingly, it’s no different from that of a normal event. The above code simply collects the position of each touch point and displays them on the screen. There’s only one thing that needs a bit more explanation, that’s the second parameter of type TouchFrameEventArgs of the event handling method. This parameter contains useful members, including the two methods GetPrimaryTouchPoint() and GetTouchPoints(), whose names are already self-explanatory: GetPrimaryTouchPoint() returns the first touch point in the series (represented by an object of the TouchPoint class), while GetTouchPoints() returns a collection of all touch points. The TouchPoint class provides the following properties:

  • Position: the coordinate of the touch point. This can be relative to another UI element (if you pass that element to GetPrimaryTouchPoint() or GetTouchPoints()) or absolute (passing null).
  • Size: the size of the touch point, reflecting how strong you press your finger.
  • Action: describes the user’s activity. A Down value means the user just pressed his finger on the screens, Up means the user lifted his finger, and Move means the finger was dragged.
  • TouchDevice: the device that provides information about the touch. The DirectlyOver property of TouchDevice returns the topmost UI element at the touch point. This is mainly for compatibility with WPF.

Ink

Ink is a special type of content in the form of drawings created by an input device such as mouse or stylus (a pen-like input device). Silverlight provides one class, the InkPresenter, that facilitates the way you work with Ink. The ink itself is represented by a Stroke instance. Here’s the code to create an InkPresenter in XAML:

<Grid x:Name="grid">
   <InkPresenter x:Name="inkPresenter"
                 Background="White"/>
</Grid>

Just as with Multi-touch, to work with Ink, you will need to know about the events. A common scenario is that in the MouseLeftButtonDown event, we’ll instantiate a new Stroke object, and continue to build up this Stroke as the user drags the device (mouse or stylus…) upon the InkPresenter with the MouseMove event, and finally complete the stroke in the MouseLeftButtonUp event. This is illustrated in the code below:

private Stroke _stroke;

public MainPage()
{
   InitializeComponent();

   inkPresenter.MouseLeftButtonDown += new MouseButtonEventHandler(inkPresenter_MouseLeftButtonDown);
   inkPresenter.MouseMove += new MouseEventHandler(inkPresenter_MouseMove);
   inkPresenter.MouseLeftButtonUp += new MouseButtonEventHandler(inkPresenter_MouseLeftButtonUp);
}

private void inkPresenter_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
   inkPresenter.CaptureMouse();
   _stroke = new Stroke(e.StylusDevice.GetStylusPoints(inkPresenter));
   inkPresenter.Strokes.Add(_stroke);
}

private void inkPresenter_MouseMove(object sender, MouseEventArgs e)
{
   if (_stroke != null)
   {
      _stroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(inkPresenter));
   }
}

private void inkPresenter_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
   inkPresenter.ReleaseMouseCapture();
   _stroke = null;
}

Besides, the Stroke has many properties that allow you to format the drawing (such as changing size and color…). One great thing about Silverlight is that much of these features are accessible in both ways: declaratively (using XAML) or programmatically (using code). But this time, I’ll leave them up to you to discover.

Conclusion

Every application needs input! That’s true unless you never work on anything more complex than a Hello World program. Input can come from many sources: mouse, keyboard, multi-touch or ink… By providing support for such a broad range of input technologies, Silverlight has proven to be suitable for virtually every platform: from web to desktop to mobile computing. May it fulfill Microsoft’s dream about a world powered by Silverlight? Only time will tell but the ability to handle multi-touch and ink input natively are certainly welcome, as it not only simplifies the job of the developers, but also helps create a rich user experience that RIA once promised.

, ,

Để lại phản hồi

Kiểm soát truy cập với WCF Throttling

Dịch vụ của bạn có thể bị quá tải khi số người sử dụng tăng đột biến. Thật không may, các hệ thống phần mềm thường không thích nghi tốt trong những trường hợp như thế này. Kịch bản xấu nhất là toàn hệ thống bị crash dẫn đến việc gián đoạn dịch vụ, gây khó chịu cho cả nhà cung cấp lẫn người sử dụng! Để tránh rơi vào tình huống trên, WCF cung cấp một cơ chế cho phép kiểm soát lượng truy cập đến dịch vụ và giới hạn số kết nối tối đa. Tính năng đó gọi là Throttling.

Cấu hình WCF Throttling

Cũng như nhiều tính năng khác, Throttling cho phép bạn cấu hình bằng hai cách: khai báo trong file config hoặc bằng lập trình trong code. Ví dụ sau minh họa cách cấu hình theo kiểu khai báo sử dụng thẻ <serviceThrottling> trong phần <serviceBehaviors>

<system.serviceModel>
   <services>
      <service name="ThrottledService" behaviorConfiguration="ThrottlingDemo">
         ...
      </service>
   </services>
   <behaviors>
      <serviceBehaviors>
         <behavior name="ThrottlingDemo">
            <serviceThrottling
               maxConcurrentCalls="100"
               maxConcurrentSessions="5000"
               maxConcurrentInstances="5100" />
         </behavior>
      </serviceBehaviors>
   </behaviors>
</system.serviceModel>

Thẻ <serviceThrottling> có 3 thuộc tính quan trọng sau:

  • maxConcurrentCalls: số yêu cầu tối đa đồng thời. Thuộc tính này giới hạn tổng số yêu cầu có thể được xử lý tại một thời điểm. Trong .NET Framework 3.0, giá trị này mặc định là 16. Tuy nhiên con số này là quá thấp trong nhiều trường hợp thực tế dẫn đến việc các nhà quản trị thường xuyên phải cấu hình lại. Vì vậy WCF4 đã thay đổi giá trị mặc định này thành 16 x ProcessorCount (16 x số bộ vi xử lý trên máy).
  • maxConcurrentSessions: số kết nối có session tối đa. Giá trị mặc định là 10 (WCF3) và 100 x ProcessorCount (WCF4).
  • maxConcurrentInstances: số đối tượng InstanceContext tối đa. Con số này sẽ tương đương với tổng số session nếu InstanceContextMode là PerSession hoặc tổng số lời gọi dịch vụ đồng thời nếu InstanceContextMode là PerCall. Giá trị mặc định bằng tổng giá trị của maxConcurrentCalls và maxConcurrentSessions.

Tương tự, ta cũng có thể thực hiện cấu hình Throttling trong code. Một lưu ý nhỏ là các thiết lập bằng code sẽ ghi đè các thiết lập trong file config trong trường hợp cả hai thiết lập này cùng tồn tại. Việc cấu hình trong code được thực hiện thông qua property Behaviors của lớp ServiceDescription:

ServiceHost host = new ServiceHost(typeof(ThrottledService));
ServiceThrottlingBehavior throttlingBehavior =
   host.Description.Behaviors.Find<ServiceThrottlingBehavior>(  );
if(throttlingBehavior == null)
{
   throttlingBehavior = new ServiceThrottlingBehavior(  );
   throttlingBehavior.MaxConcurrentCalls = 100;
   throttlingBehavior.MaxConcurrentSessions = 5000;
   throttlingBehavior.MaxConcurrentInstances = 5100;
   host.Description.Behaviors.Add(throttlingBehavior);
}

host.Open(  );

Đoạn code trên kiểm tra xem đối tượng ServiceThrottlingBehavior có tồn tại hay chưa. Nếu chưa có, một đối tượng mới được tạo và thiết lập các giá trị cần thiết. Nhớ rằng bạn cần phải thực hiện cấu hình trước khi gọi phương thức Open() của ServiceHost.

Ngoài ra, nếu bạn sử dụng TCP hoặc IPC binding, bạn còn có thể chỉ định số kết nối tối đa cho từng Endpoint của binding đó với property MaxConnections của lớp NetTcpBinding hoặc NetNamedPipeBinding. Sau đây là cách cấu hình trong file config (đương nhiên là bạn cũng có thể cấu hình trong code như ở trên):

<bindings>
   <netTcpBinding>
      <binding name="TCP" maxConnections="30"/>
   </netTcpBinding>
</bindings>

Nhận xét

Throttling bảo vệ dịch vụ khỏi nguy cơ bị vắt kiệt tài nguyên vào những lúc cao điểm bằng cách ngưng xử lý các yêu cầu một khi hệ thống vượt quá mức giới hạn cho phép. Các yêu cầu này không bị từ chối mà được đưa vào hàng đợi chờ đến lượt mình được xử lý. Tuy nhiên nếu thời gian chờ quá dài thì phía client có thể sẽ gặp phải TimeoutException.

Throttling không phải là liều thuốc thần làm tăng năng suất hệ thống. Trên thực tế, Throttling chỉ có tác dụng khi sự gia tăng số lượng client là đột biến và nhất thời. Nó sẽ trở nên vô dụng nếu hệ thống bị quá tải thường xuyên và kéo dài. Trong trường hợp đó, bạn nên nghĩ đến việc nâng cấp hoặc thiết kế lại hệ thống cho phù hợp với nhu cầu sử dụng cao hơn.

,

Để lại phản hồi

Follow

Get every new post delivered to your Inbox.