어제 프로젝트 관련된 코딩을 하다가 난수를 써야 할 일이 있어서
C#의 Random Class에 관해 알아 보았다!

사실 Random Class의 사용방법은 그리 복잡하지도 어렵지도 않지만;
내가 만들고 싶은 난수가 적절히 만들어 지지 않아 몇시간을 테스트한김에
이와 관련된 포스팅을 하게 되었다;

예전 C언어나 C++의 rand() 함수를 사용할때는

int random = rand()%50;
위의 코드를 수행하게 되면 random 변수에는 에는 0부터 49까지 난수가 들어가게 된다;
rand()에sms seed 값이 있어 저렇게만 수행할 경우
만약 랜덤한 수가 1 3 6 2 6 순으로 나왔다면; 프로그램을 껏다 켜도 똑같은 패턴으로 나오게 된다;
그래서 아래의 항목을 추가하게 되면 그것을 막을 수 있었다;

srand(time(NULL)); // 시간에 따른 난수 발생, 없을경우 실행때마다 같은 난수가 발생한다.


이제 C# 의 Random Class를 보자;

사용법 정말 간단하다;

Random r  = new Random();

생성자는 오버로딩 되어있어 생성시 시드값을 정할수 있고! 정하지 않을수 있다;

정할경우 위에 말한대로 계속 똑같은 패턴의 난수가 발생하며 디폴트일 경우에는 시스템의 시간을 이용하여 
시드값을 정하기 때문에 매번 다른 패턴의 난수
가 발생한다;

제공하는 매소드를 알아보자;

r.Next() : 범위가 없는 랜덤한 값을 리턴한다
r.Next(int maxValue) : 난수의 범위의 상한을 지정
r.Next(int minValue, int maxValue) : 난수의 범위의 하한과 상한을 지정!


여기서 중요한것은 난수의 하한은 난수에 포함 되지만 상한은 포함 되지 않는다는것이다;
즉 1부터 10의 값을 난수로 얻고 싶을때 Next(1,10); 을 호출하면 10은 죽어도 안나온다는 말인다;;
10을 난수로 얻고 싶다면 Next(1,11)을 호출 해야한다;

그외에
r.NextBytes()
r.NextDouble() 
메소드가 있는데 int값만 필요해서 사용하지는 않았지만 메소드 명으로 쉽게 짐작 할수 있다;

이제 본론으로 들어가서 이렇게 간단한 Random Class의 사용방법을  포스팅을 하게 된 이유는
내가 발생하고 싶은 난수가 특정시간에 여러개의 객체를 생성할때 각각의 객체마다 다른 
난수를 가지고 있게 하고 싶었지만 Seed값을 기본적으로 시간을 사용하기 때문에 
할수가 없어서이다;

다음의 예제를 보면;

class Program
{
        static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                Item item = new Item();
            }
        }
}

class Item
{
        int num1;
        int num2;
        public Item()
        {
            Random r = new Random();
            num1 = r.Next(1, 100);
            num2 = r.Next(100, 200);
            Console.WriteLine("{0} , {1}", num1, num2);
        }
}



매우 간단한 구조이다 Main()에서는 Item 객체를 10개 만들고 
Item 객체의 생성자에서는 난수를 2개 (각각 1~99, 100~199 범위의 값) 발생시켜
출력한다;

어떤 결과가 나올까? 10개의 객체는 각각 다른 난수를 가지고 있을까?

-- 실행 결과 --

결과처럼 '아니오' 이다; 

이와 같은 발생의 이유는 기본적으로 난수발생의 시드가 시간이기 떄문이다;
위에 예제처럼 빠르게 10개의 객체를 생성할 경우 시드가 같아져 같은 결과가 나오는것이다;

어떻게 해결할까?

밑의 두가지 예제의 차이를 알게되면 쉽게 해결 가능하다;
예제1)
Random
r = new Random();
for (int i = 0; i < 10; i++)
{
     Console.WriteLine("{0}", r.Next());               
}

예제2)
for (int i = 0; i < 10; i++)
{
     Random r = new Random();
     Console.WriteLine("{0}", r.Next());
}

--결과 화면--


화면에서 보다싶이 Random 객체를 빠르게 10번 생성한 예제 2에서는  같은 번호가 나왔고
객체를 재사용한 예제1에서는 다른 결과가 나왔다;


이 차이를 이용해 위에서 실패한 Item class에 랜덤한값을 배치 할수 있는것이다;

Random 객체를 static으로 두고 하나만 계속 사용한다면 위의 예제도 우리가 원하는 난수를 갖게 될것이다;

Posted by 맨날맑음
,


프로그래밍을 하다보면 Thread로 처리해야 하는 일들이 생기게 된다..

그런데 실버라이트에서는 객체를 컨트롤 할때 주스레드(UI thread)에서
처리 하지 않게되면 Cross Thread라는 문제를 발생시키다;
예제를 보면 쉽게 이해가 갈것이다!

구현하고자하는 프로그램!

간단히 실버라이트 page에 버튼하나와 TextBlock을 배치하여 버튼클릭시 TextBlock에
지정한 문자열을 표시하도록 했다!
-- page.xaml --

<UserControl x:Class="UIThread.Page"
    xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml"
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
     <Button Height="85" HorizontalAlignment="Right" Margin="0,0,47,56" VerticalAlignment="Bottom" Width="142" Content="Make Thread" x:Name="btnThread"/>
     <TextBlock Height="82" Margin="22,22,32,0" VerticalAlignment="Top" Text="TextBlock" TextWrapping="Wrap" x:Name="txtTextBlock"/>
    </Grid>
</UserControl>



-- UI 화면 --



-- page.xaml.cs --

using System.Windows;
using System.Windows.Controls;
//Thread를 쓰기위한 using
using System.Threading;
namespace UIThread
{
    public partial class Page : UserControl
    {
        public Page()
        {
            InitializeComponent();
            btnThread.Click += new RoutedEventHandler(btnThread_Click);
        }

        void btnThread_Click(object sender, RoutedEventArgs e)
        {
            //Thread 생성
            Thread thread = new Thread(Doit);
            thread.Start("스레드 작업 잘될까?");
        }

        //Cross Thread 발생 Method
        void CrossThread(object state)
        {
            string txt = (string)state;
            txtTextBlock.Text = txt;
        }

        //Cross Thread 해결한 Method
        void Doit(object state)
        {
            string txt = (string)state;
            //Dispatcher 사용
            Dispatcher.BeginInvoke(
                delegate()
                {
                    txtTextBlock.Text = txt;
                }
                );           
        }
    }
}
비하인드 코드에서 보는 바와 같이 버튼을 클릭하게 되면 Thread를 하나 생성하고

일반적으로 생각하기 쉬운 방법인 CrossThread 메소드를 호출해 보았다!

-- 오류화면 --

결과는 TextBlock이라는 문자열에 전혀 변화가 없고 왼쪽 하단에 오류만 덩그러니 일어난다!
오류 정보를 보니 잘못된 크로스 스레드 액세스란다;
txtTextBlock.Text = txt; 구문때문에 ""스레드 작업 잘될까?""라는 구문이 출력해야 맞을텐데;;

이것은 바로 실버라이트 UI의 스레드 모델때문이다!
실버라이트 컨트롤의 제어는 해당하는 주스레드에서 행해져야 하지만;
우리가 강제로 쓰레드를 생성하여 컨트롤을 변경하려 했기 떄문이다;

그렇다면 해결방법은? C# 의 Delegate처럼 주스레드에 변경을 부탁하면 된다!

부탁하는 방법은 UserControl 클래스가 가지고있는  Dispatcher을 사용하면 된다!
Dispatcher의 멤버로는 Dispatcher.Invoke()와 Dispatcher.BeginInvoke()가 있다;
잘알다싶이 Invoke는 동기식 BefinInvoke는 비동기 방식이다!!!

그럼 이번엔  Dispatcher를 사용한 Doit 메소드를 호출하여 보자!!

-- 실행 화면 --

위와같이 아무런 오류없이 잘 되는것을 확인할수 있다!!
Posted by 맨날맑음
,

현재 실버라이트(Silverlight 2.0)에서는 더블클릭을 위한 이벤트가
지원되지 않아서 간단하게 DateTime객체를  을 이용하여 전체화면을 만들어 보았다;;

구현하고자 하는 프로그램!
Rectangle 객체를 더블클릭 하면 더블클릭 되었습니다! 라는 리스트 박스에 메세지 띄우기!!

1.우선 새프로젝트(실버라이트응용프로그램)를 만들고


2. 간단하게 page.xaml에 Rectangle로 만든 Button과 ListBox를 올려 놓는다!
     
     
     
      
         
           
              
              
           
         
      
      
     
 
--page.xaml--



3. page.xaml 비하인트 코드(page.xaml.cs)에 rectangle에 MouseLeftButtonDown이벤트를
 추가한다!

--page.xaml.cs--
public partial class Page : UserControl
{
        DateTime mouseLastClick=DateTime.Now.AddSeconds(-1);

        public Page()
        {
            InitializeComponent();
            MyButton.MouseLeftButtonDown += new MouseButtonEventHandler 
              (MyButton_MouseLeftButtonDown);
        }

        void MyButton_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if ((DateTime.Now - mouseLastClick).Milliseconds < 200)
            {
                MyListBox.Items.Add("더블클릭 되었습니다!");
                mouseLastClick = DateTime.Now.AddSeconds(-1);
            }
            else
            {
                mouseLastClick = DateTime.Now;                
            }
        }
}

코드에는 DateTime 마우스 처음 클릭시간을 저장하기 위해 DateTime변수를 클래스의 멤버변수로 선언했으며
MouseLeftButtonDown이벤트 메소드에
현재 마우스를 클릭한 시각 - 마지막으로 마우스를 클릭한 시각 =  0.2초를 넘지 않는다면 더블클릭으로 간주하여
더블클릭 돼었다고 메세지를 띄우게 하였다;

이때 DateTime.Now.AddSeconds(-1); -1을 대입해주는건 더블클릭이 된후 마우스클릭에대해 더블클릭으로
인지하는것을 막기 위한이다!
  (생각해봐라; 저게 없다면 3번 빠르게 누르면 더블클릭이 2회 발생한걸로 나올것이다!)

<실행 화면>
간단한 예제로 만들어본 실버라이트 마우스 더블클릭하기 !


Posted by 맨날맑음
,
안녕하세요? 맨날맑음 입니다.

보통 소스 코딩하시는데 각자 취향에 맞는 폰트를 사용하는데요.

소스 코딩시 사용할 폰트는 기본적으로 대문자 아이(I)와 소문자 엘(l)의 구분이 확실해야 보기 편하고,
또한 Width와 Height에 비율에 따른 가독성도 다르다고 합니다.

그래서 제가 검색하던 중에 개발자들이 많이 선호 한다는(?) bitstream-vera을 알게 되었습니다.
그중에 저는 VeraMono를 사용합니다.

이 폰트의 장점은 일단 '무료'이고, 위에 언급한 I와 L의 구분이 분명합니다.
Bitstrem Vera Sans Mono

그림1. Bitstrem Vera Sans Mono 모양

Bistream HomePage : http://www.bitstream.com/
Download : http://ftp.gnome.org/pub/GNOME/sources/ttf-bitstream-vera/1.10/
아래에 빠르게 다운 받아 쓸 수있도록 VeraMono도 첨부해 놓겠습니다.

여러분도 맘에드는 폰트로 즐거운 코딩을 해보세요!!
Posted by 맨날맑음
,

[WPF] Widget 만들기!

.NET/WPF 2008. 12. 26. 23:24

요즘 Widget(gadget)의 사용이 점점 늘고있다!

Widget은 사용자의 컴퓨터 바탕 화면에 놓거나 웹 페이지 위에 호스트할 수 있는
가벼운 단일 목적의 응용 프로그램이다.

WPF를 이용하면 Windows Vista의 사이드바에 놓이는 Widget과 같이 투명한 윈도우창을
구현하여 Widget과 같은 효과를 줄수있다!

여기서 보이는 예제는 간단한 예제이지만 이 응용프로그램에 Web Service나 요즘 한창
이슈가 되어있는 Open API를 이용하여 Mash up 서비스를 구현한다면 우리 입맛에 맞는
멋진 Widget을 만드는것도 어려운 일이 아니다!

Posted by 맨날맑음
,