article search result of 'C#' : 94

  1. 2017.01.30 보다 심플한 C# 싱글턴 만들기
  2. 2016.11.19 상속된 Generic 타입 만들기, 타입의 제약 사항 선언 ( Generics Constraint )
  3. 2016.08.27 WebClient 를 이용한 GET 과 POST 전송하기.
  4. 2015.02.05 키넥트의 장치 ID 알아내기 (Kinect for Windows) (1)
  5. 2015.01.13 [WPF] 멀티쓰레딩 에서 GUI 렌더링과 그것의 속성을 외부에서 접근하기 (1)
  6. 2015.01.08 [C#] 리플렉션 없고 자동완성 되는 PresetLoader.cs (1)
  7. 2015.01.07 [WPF] 이미지 블러링을 원천적으로 해결하 (2)
  8. 2015.01.06 [WPF] 키보드 포커스 가져오기 / 삭제하기
  9. 2015.01.06 [WPF] UserControl 에서 간단 마우스,키보드 이벤트 수신법
  10. 2014.11.05 [WPF] 멀티쓰레드 상황에서 WPF Control 캡처 하기 (4)
  11. 2014.07.30 [메모] 이중 반복문이 느리다. (1)
  12. 2014.07.29 웹캠 포커스 강제 설정방법
  13. 2014.07.11 직렬화된 배열을 비트맵 스타일로 배열하기 , 리사이징 하기
  14. 2014.05.08 [중요 메모] STA Thread 와 COM 객체 사용시 절대 주의 할점
  15. 2014.05.08 c# Emgu 카메라 칼리브레이션 요점 정리
  16. 2014.05.07 [Marshal] byte* to byte[]
  17. 2014.05.06 [WPF] 이미지 byte[] 를 바로 BitmapSource 로 옮기자.
  18. 2014.04.08 [WPF] VisualStudio 에서 [ is not recognized or is not accessible] 에러 해결법
  19. 2013.11.28 XmlDocument 사용법 정리
  20. 2013.01.28 WPF , CacheMode (74)
  21. 2013.01.25 [Surface2]Surface2.0 Simmulator on Windows8 , Solved! (3)
  22. 2013.01.22 [Surface - WPF] Surface 에서의 에니메이션 활용 (ArtefactAnimator) (5)
  23. 2013.01.16 [.NET] 어셈블리 하나로 합치기 (ilmerge 사용안함) (6)
  24. 2013.01.16 [WPF] 트레이 아이콘 만들고 사용하기 (6)
  25. 2013.01.16 [WPF] 윈도우 닫기 명령 무시하기 (6)
  26. 2013.01.15 [asmx] 쿠키 이용하기 , (사용자 인증) (7)
  27. 2013.01.14 [SQL2012] DB 생성부터 사용자 만들기 그리고 SQL 접속하기 (4)
  28. 2013.01.11 sqlMetal 사용법 (10)
  29. 2012.12.29 Activator 를 이용한 Type Instance 생성 (32)
  30. 2012.11.27 [Broadcast Video Streaming] (149)

보다 심플한 C# 싱글턴 만들기

// simple type of c# singleton pattern
public class Communicator
{
    private static Communicator _inst;
    public static Communicator GetInst
    {
        get
        {
            return _inst;
        }
    }
    
    static Communicator()
    {
        _inst = new Communicator();
    }
    
    private Communicator()
    {
        Console.WriteLine("NEW");
    }
}



static 생성자를 통한 싱글턴 만들기.

Yamecoder 야매코더_
C# 2017.01.30 17:43

상속된 Generic 타입 만들기, 타입의 제약 사항 선언 ( Generics Constraint )

출처 : 


http://www.csharpstudy.com/CSharp/CSharp-generics.aspx






Generics 타입 제약(constraint) 

C# Generics를 선언할 때, 타입 파라미터가 Value Type인지 Reference 타입인지, 또는 어떤 특정 베이스 클래스로부터 파생된 타입인지, 어떤 인터페이스를 구현한 타입인지 등등을 지정할 수 있는데, 이는 where T : 제약조건과 같은 식으로 where 뒤에 제약 조건을 붙이면 가능하다. 아래는 다양한 제약을 가한 예제들이다. 

예제

// T는 Value 타입
class MyClass<T> where T : struct 

// T는 Reference 타입
class MyClass<T> where T : class

// T는 디폴트 생성자를 가져야 함
class MyClass<T> where T : new() 

// T는 MyBase의 파생클래스이어야 함
class MyClass<T> where T : MyBase

// T는 IComparable 인터페이스를 가져야 함
class MyClass<T> where T : IComparable

// 좀 더 복잡한 제약들
class EmployeeList<T> where T : Employee,
   IEmployee, IComparable<T>, new()
{
}


Yamecoder 야매코더_
C# 2016.11.19 14:35

WebClient 를 이용한 GET 과 POST 전송하기.

GET 예제 


WebClient wc = new WebClient();
StringBuilder sb = new StringBuilder();
sb.Append("https://openapi.youku.com/v2/uploads/create.json?");
sb.AppendFormat("client_id={0}", client_id);
sb.AppendFormat("&access_token={0}", access_token);
sb.AppendFormat("&title={0}", "jjongun upload test " + time_str);
sb.AppendFormat("&tags={0}", "jjongun");
sb.AppendFormat("&file_md5={0}", hashString);
sb.AppendFormat("&file_name={0}", fileName);
sb.AppendFormat("&file_size={0}", video_data.Length.ToString());

string call_upload_cmd = sb.ToString();
string result = wc.DownloadString(call_upload_cmd);
Console.WriteLine(result);


보통 DownloadString (...) 으로 해결 가능 함.





POST 예제 , string 업로드


sb.Clear();
sb.AppendFormat("upload_token={0}", upload_token);
sb.AppendFormat("&file_size={0}", file_size);
sb.AppendFormat("&ext={0}", ext);
sb.AppendFormat("&slice_length={0}", 10240);
Console.WriteLine(sb.ToString());
result = wc.UploadString(host_addr, sb.ToString());



보통 UploadString 으로 해결 가능 하며 , 상황에 따라 Data 를 전송 할 것인지, Value 들만 전달 할 것인지 결정 할 수 있다.


sb.Clear();
sb.Append(host_addr);
sb.AppendFormat("upload_token={0}", upload_token);
sb.AppendFormat("&slice_task_id={0}", slice_task_id);
sb.AppendFormat("&offset={0}", offset);
sb.AppendFormat("&length={0}", length);

var result_bytes = wc.UploadData(sb.ToString(), "POST", video_data);
result = Encoding.Default.GetString(result_bytes);


위의 예제는 binary 를 전달 한 예제 이고, 결과 역시 byte[] 로 떨어지기 때문에 문자열로 인코딩을 하여 결과를 받아야 한다.



이때 오류 상황을 잘 볼 필요가 있는데, 만약 "400" 오류 가 난다면, 서버는 작동을 하나, 파라메터와 값들이 틀렸다는 것이다. 




//추가


System.Net.Json.dll


는 매우 편리한 JSON 라이브러리 이다.


보통 OAuth 들을 사용하는 서비들의 응답이 JSON 으로 오는 경우가 허다하다. 


JsonTextParser parser = new JsonTextParser();
JsonObject json_obj;
JsonObjectCollection collection;

json_obj = parser.Parse(result);
collection = json_obj as JsonObjectCollection;
collection["video_id"].GetValue();



처럼 직관적인 사용이 가능하다.

..


 



Yamecoder 야매코더_
C# 2016.08.27 18:19

키넥트의 장치 ID 알아내기 (Kinect for Windows)


마이크로 소프트 키넥트 SDK 에서는 UniqueKinectId, DeviceConnectionId 를 제공한다. 

하지만  UniqueKinectId 는 거짓이다. 다중 키넥트 사용시 모두 같은 값을 반환 한다.


그렇다면 DeviceConnectionId 은 어떠한가? 

유니크 해 보이지만, USB 포트를 달리 하거나 허브, 리피터를 꼽을때마다 바뀐다. 

그래서 실제 장치의 시리얼을 뽑을 수가 없다. 사용할 컴퓨터 마다 달라지니 말이다.




하지만 각고의 노력끝에 아래와 같은 항목을 발견 하였다.


형제 라는 항목인데, 

영문 윈도우라면 정확히 어떤 속성 이름인지 알 수 있었겠지만, 일단 [형제ID] 로 지칭 하기로 하였다.

저 아이디는 컴퓨터가 바뀌어도 어떤 키넥트를 정확히 특정 지을 수 있는 ID 이다.



(Kinect for Xbox 360) 은 형제 아이디가 없어서 확인이 불확실하다.



현제 나에게는 4개의 Kinect가 있고 형제ID 는 다음과 같다.

또한 다른 컴퓨터에서도 확인 하였다. 모두 일치하는 값을 출력 하였다.






내컴퓨터 (win7 pro)

1번 Value: USB\VID_045E&PID_02C3\A22596W00092213A
2번 Value: USB\VID_045E&PID_02C3\A22597V01722314A
3번 Value: USB\VID_045E&PID_02C3\A22593W05102233A
4번 Value: USB\VID_045E&PID_02C3\A22596W02492224A



회사테스트 컴퓨터 (win7 pro)

1번 Value: USB\VID_045E&PID_02C3\A22596W00092213A
2번 Value: USB\VID_045E&PID_02C3\A22597V01722314A
3번 Value: USB\VID_045E&PID_02C3\A22593W05102233A
4번 Value: USB\VID_045E&PID_02C3\A22596W02492224A




**씨 컴퓨터 (win8,1 pro)

1번 Value: USB\VID_045E&PID_02C3\A22596W00092213A
2번 Value: USB\VID_045E&PID_02C3\A22597V01722314A
3번 Value: USB\VID_045E&PID_02C3\A22593W05102233A
4번 Value: USB\VID_045E&PID_02C3\A22596W02492224A


실장님 컴퓨터 (win8,1 pro)


1번 Value: USB\VID_045E&PID_02C3\A22596W00092213A
2번 Value: USB\VID_045E&PID_02C3\A22597V01722314A
3번 Value: USB\VID_045E&PID_02C3\A22593W05102233A
4번 Value: USB\VID_045E&PID_02C3\A22596W02492224A






그리고 ManagementObjectSearcher 를 이용하였고 (https://msdn.microsoft.com/en-us/library/aa389273(v=vs.85).aspx) 을 참고 하였다.
왠만하면 컴퓨터에 연결된 장치는 다 순회 할 수 있을듯 하다.


using Microsoft.Kinect;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Management;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace USB_Detection
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();


            //속도 체크용
            int c = 0;
            DispatcherTimer timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(1);
            timer.Tick += delegate {
                this.Title = c.ToString();
                ++c;
            };
            timer.Start();
        }



        /// <summary>
        /// 키넥트의 유일한  ID 를 설정 하기 위하여 "형제" 값을 불러 와야 한다.
        /// (장치관리자->Kinect Camera->자세히->형제)
        /// </summary>
        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            base.OnMouseDown(e);

            string prefix_id = "";



            //step1
            //키넥트의 DeviceConnectionId 를 불러와 아이디의 말머리를 설정한다 (USB\\VID_045E)
            foreach (var item in KinectSensor.KinectSensors)
            {
                string[] _raw = item.DeviceConnectionId.Split('&');
                prefix_id = _raw[0];
            }


            //step2
            //모든 PNP 장치 중에서 USB Composite Device 의 이름을 찾는다.
            var Win32_PnPEntity = "Win32_PnPEntity where Name like 'USB Composite Device'";
            var query = string.Format("select * from {0}", Win32_PnPEntity);
            


            using (var searcher = new ManagementObjectSearcher(query))
            {
                ManagementObjectCollection objectCollection = searcher.Get();
                ManagementBaseObject brotherKinectDev = null;

                Console.WriteLine(objectCollection.Count);
                foreach (ManagementBaseObject managementBaseObject in objectCollection)
                {
                    foreach (PropertyData propertyData in managementBaseObject.Properties)
                    {
                        //참고 : 모든 속성 가져 오기
                        //content.AppendLine(string.Format("Property:  {0}, Value: {1}", propertyData.Name, propertyData.Value));
                        if (propertyData.Name == "HardwareID")
                        {
                            foreach (var _item in (string[])propertyData.Value)
                            {

                                //그중에서 하드웨어 아이디의 값이 DeviceConnectionId 말머리가 포함된것을 찾는다.
                                if (_item.IndexOf(prefix_id) > -1)
                                {
                                    brotherKinectDev = managementBaseObject;
                                    break;
                                }
                            }
                        }
                    }
                }



                //step3
                //검색된 장치의 PNPDeviceID 를 가져온다
                if (brotherKinectDev != null)
                {
                    foreach (PropertyData propertyData in brotherKinectDev.Properties)
                    {
                        if (propertyData.Name == "PNPDeviceID")
                        {
                            tx.Text = string.Format("Value: {0}", propertyData.Value);
                        }
                    }
                }
            }

            Console.WriteLine("complete");
        }
    }
}


Yamecoder 야매코더_
C# 2015.02.05 17:00

[WPF] 멀티쓰레딩 에서 GUI 렌더링과 그것의 속성을 외부에서 접근하기

이전글 을 참고 하자 (http://scripter.co.kr/274

이전 버전은 쓰레드 안에서 View 를 생성하여 while 루프 안에서 RenderTargetBitmap(이하 RTB) 로 찍어 내는 방식이었다.


하지만 쓰레드 안에서 생성한 Element 는 CompositionTarget 등 Dispathcer 관련 서비스를 이용 할 수 없었다.

그래서 전역 메모리 공유 (멤버 변수) 를 통하여 좌표 라던지 크기 등 GUI 요소에 간접 접근 하는 방법 밖에 없었다.


직접 접근 하려면 , 아래와 같은 에러를 볼 수 있다.




그래서 앞서 설명 한 것 처럼 간접 접근을 통하여 while 루프에서 변경을 체크 하여 적용 할 수 밖에 없었는데, 이러한 점 때문에 약간의 딜레이를 감수 해야 했었다.



그리고 이러한 점을 개선 한 방법을 기록한다.


원문 : http://blogs.msdn.com/b/dwayneneed/archive/2007/04/26/multithreaded-ui-hostvisual.aspx





우선 아래와 같은 클래스가 필요하다. VisualTargetPresentationSource.cs


using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Data;
using System.Windows.Controls;
using System.Windows.Markup;

namespace JUtil
{

    /// original post : http://blogs.msdn.com/b/dwayneneed/archive/2007/04/26/multithreaded-ui-hostvisual.aspx
    /// 
    /// 
    /// 
    /// <summary>
    ///     The VisualTargetPresentationSource represents the root
    ///     of a visual subtree owned by a different thread that the
    ///     visual tree in which is is displayed.
    /// </summary>
    /// <remarks>
    ///     A HostVisual belongs to the same UI thread that owns the
    ///     visual tree in which it resides.
    ///     
    ///     A HostVisual can reference a VisualTarget owned by another
    ///     thread.
    ///     
    ///     A VisualTarget has a root visual. 
    ///     
    ///     VisualTargetPresentationSource wraps the VisualTarget and
    ///     enables basic functionality like Loaded, which depends on
    ///     a PresentationSource being available.
    /// </remarks>
    public class VisualTargetPresentationSource : PresentationSource
    {
        public VisualTargetPresentationSource(HostVisual hostVisual)
        {
            _visualTarget = new VisualTarget(hostVisual);
        }

        public override Visual RootVisual
        {
            get
            {
                return _visualTarget.RootVisual;
            }

            set
            {
                Visual oldRoot = _visualTarget.RootVisual;


                // Set the root visual of the VisualTarget.  This visual will
                // now be used to visually compose the scene.
                _visualTarget.RootVisual = value;

                // Hook the SizeChanged event on framework elements for all
                // future changed to the layout size of our root, and manually
                // trigger a size change.
                FrameworkElement rootFE = value as FrameworkElement;
                if (rootFE != null)
                {
                    rootFE.SizeChanged += new SizeChangedEventHandler(root_SizeChanged);
                    rootFE.DataContext = _dataContext;

                    // HACK!
                    if (_propertyName != null)
                    {
                        Binding myBinding = new Binding(_propertyName);
                        myBinding.Source = _dataContext;
                        rootFE.SetBinding(TextBlock.TextProperty, myBinding);
                    }
                }

                // Tell the PresentationSource that the root visual has
                // changed.  This kicks off a bunch of stuff like the
                // Loaded event.
                RootChanged(oldRoot, value);

                // Kickoff layout...
                UIElement rootElement = value as UIElement;
                if (rootElement != null)
                {
                    rootElement.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
                    rootElement.Arrange(new Rect(rootElement.DesiredSize));
                }
            }
        }

        public object DataContext
        {
            get { return _dataContext; }
            set
            {
                _dataContext = value;
                var rootElement = _visualTarget.RootVisual as FrameworkElement;
                if (rootElement != null)
                {
                    rootElement.DataContext = _dataContext;
                }
            }
        }

        // HACK!
        public string PropertyName
        {
            get { return _propertyName; }
            set
            {
                _propertyName = value;

                var rootElement = _visualTarget.RootVisual as TextBlock;
                if (rootElement != null)
                {
                    if (!rootElement.CheckAccess())
                    {
                        throw new InvalidOperationException("What?");
                    }

                    Binding myBinding = new Binding(_propertyName);
                    myBinding.Source = _dataContext;
                    rootElement.SetBinding(TextBlock.TextProperty, myBinding);
                }
            }
        }

        public event SizeChangedEventHandler SizeChanged;

        public override bool IsDisposed
        {
            get
            {
                // We don't support disposing this object.
                return false;
            }
        }

        protected override CompositionTarget GetCompositionTargetCore()
        {
            return _visualTarget;
        }

        private void root_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            SizeChangedEventHandler handler = SizeChanged;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        private VisualTarget _visualTarget;
        private object _dataContext;
        private string _propertyName;
    }







    /// <summary>
    ///     The VisualWrapper simply integrates a raw Visual child into a tree
    ///     of FrameworkElements.
    /// </summary>
    [ContentProperty("Child")]
    public class VisualWrapper<T> : FrameworkElement where T : Visual
    {
        public T Child
        {
            get
            {
                return _child;
            }

            set
            {
                if (_child != null)
                {
                    RemoveVisualChild(_child);
                }

                _child = value;

                if (_child != null)
                {
                    AddVisualChild(_child);
                }
            }
        }

        protected override Visual GetVisualChild(int index)
        {
            if (_child != null && index == 0)
            {
                return _child;
            }
            else
            {
                throw new ArgumentOutOfRangeException("index");
            }
        }

        protected override int VisualChildrenCount
        {
            get
            {
                return _child != null ? 1 : 0;
            }
        }

        private T _child;
    }

    /// <summary>
    ///     The VisualWrapper simply integrates a raw Visual child into a tree
    ///     of FrameworkElements.
    /// </summary>
    public class VisualWrapper : VisualWrapper<Visual>
    {
    }
}












그리고 렌더링 할 UserControl 에 아레와 같은 코드를 넣는다.

주요 기능은 DispatcherTimer 로 지속적으로 화면을 캡처 하여 비트맵으로 만든다.


이때 CompositionTarget 보다 DispatcherTimer가 더욱 지속적이고 처리 속도도 원활 했다. 





using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using Tracker.util;

namespace CrossUiThreading
{
    /// <summary>
    /// Interaction logic for ThreadView.xaml
    /// </summary>
    public partial class ThreadView : UserControl
    {
        //test props
        public static ThreadView _this;
        public static Bitmap _bitmap;
        public static BitmapSource _bsrc;
        public static int _updateCount = 0;
        public static Planerator.Planerator PL2;
        public static int _fps;



        private System.Windows.Media.Imaging.RenderTargetBitmap capture;
        private FPSCounter _fpsCounter = new FPSCounter();
        
        public ThreadView()
        {
            InitializeComponent();

            _this = this;
            this.Loaded += ThreadView_Loaded;
        }

        void ThreadView_Loaded(object sender, RoutedEventArgs e)
        {
            capture = new System.Windows.Media.Imaging.RenderTargetBitmap((int)this.ActualWidth, (int)this.ActualHeight, 96, 96, System.Windows.Media.PixelFormats.Default);
            this.Arrange(new System.Windows.Rect(0, 0, 1320, 320));

            DispatcherTimer timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromTicks(100);
            timer.Tick += timer_Tick;
            timer.Start();
            PL2 = _pl2;
        }

        void timer_Tick(object sender, EventArgs e)
        {
            Render();
        }

        float c = 0;
        private void Render()
        {
            //test move
            double v = 500 + Math.Cos(c) * 100;
            c += 0.1f;
            Canvas.SetLeft(_thumb, v);
            _p1.RotationX = v;


            //bitmap capture 
            capture.Render(this);
            _bitmap = BitmapConvert.BsrcToBitmap(capture);
            _fps = _fpsCounter._CalculateFrameRate();
            _updateCount++;
        }
    }
}







마지막으로 활용이다.


하단에 보면 Invoke 가 가능함을 테스트 할 수 있는 코드가 있다.


using JUtil;
using System;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using Tracker.util;

namespace CrossUiThreading
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private static AutoResetEvent s_event = new AutoResetEvent(false);
        private FPSCounter _fpsConter = new FPSCounter();
        private int old_count = 0;
        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += MainWindow_Loaded;
        }

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            this.Loaded -= MainWindow_Loaded;


            CreateMediaElementOnWorkerThread();
            CompositionTarget.Rendering += CompositionTarget_Rendering;
        }

        void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            this.Title = string.Format("{0} , {1}", _fpsConter._CalculateFrameRate() , ThreadView._fps);

            if (old_count != ThreadView._updateCount)
            {
                System.Drawing.Bitmap bmp = ThreadView._bitmap;
                if (bmp == null)
                    return;

                _img.Source = BitmapConvert.ToBitmapSourceForGDI(bmp);
            }
            old_count = ThreadView._updateCount;
        }

        private HostVisual CreateMediaElementOnWorkerThread()
        {
            HostVisual hostVisual = new HostVisual();

            Thread thread = new Thread(new ParameterizedThreadStart(MediaWorkerThread));
            thread.SetApartmentState(ApartmentState.STA);
            thread.IsBackground = true;
            thread.Start(hostVisual);

            s_event.WaitOne();

            return hostVisual;
        }


        private void MediaWorkerThread(object arg)
        {
            HostVisual hostVisual = (HostVisual)arg;
            VisualTargetPresentationSource visualTargetPS = new VisualTargetPresentationSource(hostVisual);
            s_event.Set();

            ThreadView threadview = new ThreadView();
            visualTargetPS.RootVisual = threadview;//CreateMediaElement();
            System.Windows.Threading.Dispatcher.Run(); //중요!
        }





        /*
         * 다른 스레드에서 속성 접근 가능 
         * 
         * */
        private void Window_KeyUp_1(object sender, KeyEventArgs e)
        {
            if (Key.A == e.Key)
            {
                //별도 쓰레드에서 생성한 객체의 Dispatcher.Invoke 가능!
                ThreadView._this.Dispatcher.Invoke(new Action(()=>{
                    ThreadView.PL2.RotationZ++;
                }));

            }

            //에러!
            //ThreadView.PL2.RotationZ++;
        }
    }
}






이로서 다른 쓰레드에서 생성한 GUI 요소 일 지라도 Dispatcher 로 가능하다.



System.Windows.Threading.Dispatcher.Run();

이것을 성공시키기 위한 아주 중요한 부분이다.


프로젝트 : 

CrossUiThreading.zip



Yamecoder 야매코더_
C# 2015.01.13 21:47

[C#] 리플렉션 없고 자동완성 되는 PresetLoader.cs



비주얼 스튜디오 에서 기본 제공해 주는 *.config 는 상당히 편리한 구석이 있으나 문서 자체가 너무 복잡하게 되어 버릴 경우가 많아서 사용자에게 xml 을 수정 하라는 요구를 하기가 사뭇 꺼려 진다.


하지만 문자열로 xml의 값을 하나 하나 불러 오는것도 인간적인 실수 와 더불어 사용 코드가 그리 깔끔하지 않아 불편함이 있다.

그래서 개선한 버전인 클래스 필드의 변수를 리플렉션 하여 얻어와 값을 인위적으로 넣어 주는 방법이 있었는데, 리플렉션 역시 사용 환경에 따라 제약이 생길 수 있다. (난독화, MONO ,  등등)






그래서 셋팅값의 자동완성도 가능하면서 리플렉션도 사용하지 않는 PresetLoader 를 만들었고 그것의 실체와 사용법은 아래와 같다. 



// // PresetLoader.cs // CallbackTest // // Created by SuperSc on 2015. 1. 8.. // Copyright (c) 2015년 SuperSc. All rights reserved. // using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Xml.Linq; namespace PresetLoader { /* * 실제 사용 예시 * new PresetLoader(); string name = PresetLoader.GetValue(PresetLoader.PresetProp.string_name); int age = PresetLoader.GetValue(PresetLoader.PresetProp.int_age); float fv = PresetLoader.GetValue(PresetLoader.PresetProp.float_floatvalue); int[] bodytypes = PresetLoader.GetValue(PresetLoader.PresetProp.ints_bodyvalues); float[] floats = PresetLoader.GetValue(PresetLoader.PresetProp.floats_floatvalues); string[] alias = PresetLoader.GetValue(PresetLoader.PresetProp.strings_alias); * * */ public class PresetLoader { /* * PresetProp Enum 안에 사용할 Preset 값들을 정의 합니다. * * 선언법 : [값 타입](s)_[이름] * 배열타입으로 선언하기 : [값 타입] 뒤에 s 형태로 복수영문을 표현 하면 배열로 인식 합니다. * * * 예시 : * 1) int_age // int 형인 속성 age * 2) ints_numbers // int[] 형인 numbers 배열 * * */ public enum PresetProp { int_age , float_floatvalue, floats_floatvalues, ints_bodyvalues , string_name, strings_alias } /* * 이 메서드를 이용하여 Preset의 값을 찾아 냅니다. * 극 장점은 바로 자동완성이 된다는 점 입니다. * * 사용법 : int[] numbers = PresetLoader.GetValue(PresetLoader.PresetProp.numbers); * */ public static dynamic GetValue(PresetProp name) { PropTypeValue resultItem = default(PropTypeValue); foreach (PropTypeValue item in _proplist) { if (item.prop_enum_object == name) { resultItem = item; break; } } return resultItem.prop_value; } //---------------------------------------------------------------------PresetLoader #region //---------------------------------------------------------------------define PropTypeValue private struct PropTypeValue { public PresetProp prop_enum_object; public bool prop_isArray; public string prop_name; public Type prop_type; public dynamic prop_value; } //---------------------------------------------------------------------Initializer #region private static readonly string PresetFileName = "Preset.xml"; private static List<PropTypeValue> _proplist; private static XElement _preset_xml; public PresetLoader() { _proplist = new List<PropTypeValue>(); foreach (string item in Enum.GetNames(typeof(PresetProp))) { string[] item_split = item.Split('_'); string _raw_type_name = item_split[0]; string _raw_prop_name = item_split[1]; bool _raw_isArray = false; PresetProp _raw_enum = (PresetProp)Enum.Parse(typeof(PresetProp), item); Type _raw_type = DefineTypeFromString(_raw_type_name); if (_raw_type_name.Substring(_raw_type_name.Length - 1) == "s") { _raw_isArray = true; } _proplist.Add(new PropTypeValue() { prop_enum_object = _raw_enum, prop_isArray = _raw_isArray, prop_name = _raw_prop_name, prop_type = _raw_type, prop_value = null }); } PresetXMLProgress(); //결과 화면 표시 Console.WriteLine("=======preset load reslut======="); foreach (var item in _proplist) { Console.WriteLine("PropName(enum) : " + item.prop_enum_object +" name: " + item.prop_name + " type: " + item.prop_type + " value: " + item.prop_value); } } private Type DefineTypeFromString(string value) { Type result = typeof(string); switch (value.ToLower()) { case "string": result = typeof(string); break; case "strings": result = typeof(string[]); break; case "int": result = typeof(int); break; case "ints": result = typeof(int[]); break; case "float": result = typeof(float); break; case "floats": result = typeof(float[]); break; default : throw new Exception("can't definition type"); } return result; } #endregion //---------------------------------------------------------------------Progress #region private void PresetXMLProgress() { MakeXML(); ReadXML(); } /* * XML 파일을 체크 하여 없다면 새로 생성. * 결과를 전역 변수 _preset_xml 로 대입 * */ private void MakeXML() { if (File.Exists(PresetFileName) == true) { _preset_xml = XElement.Parse(File.ReadAllText(PresetFileName)); return; } XElement xml = new XElement("root"); xml.Add( new XComment(string.Format("{0}{1}{2}", Environment.NewLine, " 0 으로 되어 있는 값을 입력하여야 합니다. 이름뒤에s가 붙은 배열 타입은 ',' 로 구분 합니다. \n (예시> <ints>30,20,10</ints> )" , Environment.NewLine) )); foreach (var item in _proplist) { xml.Add(new XElement(item.prop_name, "0")); } xml.Save(PresetFileName); Console.WriteLine("---create new preset xml---"); Console.WriteLine(xml.ToString()); _preset_xml = xml; } /* * XML 을 읽는 도중 누락된 항목이 발견되면 파일을 리셋. * */ private void ReadXML() { try { for (int i = 0; i < _proplist.Count; i++) { dynamic value = ValueParser(_proplist[i], _preset_xml.Element(_proplist[i].prop_name).Value);//Convert.ChangeType(_preset_xml.Element(_proplist[i].prop_name).Value, _proplist[i].prop_type); PropTypeValue newValue = _proplist[i]; newValue.prop_value = value; _proplist[i] = newValue; } } catch(NullReferenceException) { Console.WriteLine("ERR! > XML Parse Error "); File.Delete(PresetFileName); PresetXMLProgress(); } } /* * 속성의 type들을 검사 하여 실제 값(xml의 값)을 파싱 하여 대입. * */ private dynamic ValueParser(PropTypeValue target , string xml_value) { dynamic result = null; if (target.prop_isArray == true) { string[] raw_values = xml_value.Split(','); if (target.prop_type == typeof(int[])) { result = CovertArray<int>(raw_values); } else if (target.prop_type == typeof(System.Single[])) { result = CovertArray<float>(raw_values); } else if (target.prop_type == typeof(string[])) { result = CovertArray<string>(raw_values); } } else { result = Convert.ChangeType(xml_value, target.prop_type); } return result; } /* * 배열 타입의 속성을 위한 템플릿 유틸 메서드. * */ private T[] CovertArray<T>(string[] raw_values) { T[] arr = new T[raw_values.Length]; for (int i = 0; i < raw_values.Length; i++) { arr[i] = (dynamic)Convert.ChangeType(raw_values[i], typeof(T)); } return arr; } #endregion #endregion } }



Yamecoder 야매코더_
C# 2015.01.08 17:27

[WPF] 이미지 블러링을 원천적으로 해결하




XAML 로 이미지를 위치 시킬경우 빌드 하면 가끔씩 이미지가 흐려 보이는 현상이 보일때가 있다. 

이것을 해결 하려 구글링 하면 SnapsToDevicePixels , RenderOptions , UseLayoutRounding 등등의 방법이 난무 하지만 잘 안먹힐때가 많이 있다.


또한 이러한 현상은 왠지 낯설지가 않다.

플래시 에서도 이러한 현상을 볼 수 있는데, 이유는 픽셀 시작점이 정수가 아니라 소수점으로 떨어 질 경우 정확한 필셀이 화면에 그려지지 않고 두 픽셀에 걸쳐서 색을 섞어 버리니 결국 흐려 보이는 것이다.


이러한 배경을 가지고 실제로 포지션을 구해보면, ...



Window window = Window.GetWindow(target);
Point actualTargetPoint = target.TransformToAncestor(window).Transform(new Point(0, 0));



(target 은 이미지 객체나 텍스쳐를 활용하는 UIElement 가 되겠다)

actualTargetPoint 의 X 나 Y 값이 정수가 아닌 소수점으로 떨어지는것을 볼 수 있다. 예를 들어 (123.32,342.5)

(참고로 WPF 는 double 형의 포지션 을 가진다.)


그래서 이것을 인위적으로 소수점 자리만큼 빼주어 정상 위치를 확보 할 수 있다.


간단히 말해 소수점이 발생하는 X Y 포인트를 가장 가까운 정수 자리로 Translation 해준다.

이것을 구현 하는 코드는 아래와 같다.




        public static void PixelSnapping(UIElement target)
        {
            Window window = Window.GetWindow(target);
            Point actualTargetPoint = target.TransformToAncestor(window).Transform(new Point(0, 0));
            int _vx = (int)actualTargetPoint.X;
            double result = actualTargetPoint.X - _vx;

            double push_x = GetPushValue(actualTargetPoint.X);
            double push_y = GetPushValue(actualTargetPoint.Y);

            target.RenderTransform = new TranslateTransform(push_x, push_y);
        }


        /*
         * 입력값이 가장 가까운 정수로 가기위한 소수점 값을 반환한다.
         * */
        public static double GetPushValue(double orignal_value)
        {
            double round_value = Math.Round(orignal_value);
            double pushPosition = 0;

            if (orignal_value < round_value)
            {
                pushPosition = (orignal_value - round_value) * -1;
            }
            else
            {
                pushPosition = round_value - orignal_value;
            }

            return pushPosition;
        }



활용은 간단히 객체를 넣어 주면 된다.

ImageUtil.PixelSnapping(_topLogo);



그러면 결과는 아래와 같다.








//comment : 2015.01.09

PixelSnapping 을 사용할 경우 비주얼 스튜디오의 XAML 디자인뷰 에서 에러가 날 수 있는데 이때는 try...catch 로 감싸 주면 된다.




Yamecoder 야매코더_
C# 2015.01.07 17:24

[WPF] 키보드 포커스 가져오기 / 삭제하기


키보드로 컨트롤이 절실한 경우가 있다. 컨트롤 들의 미세한 컨트를을 위해서 이다.(예를 들면 Slider 류) 

그런데 한 화면에 Textbox 가 있고, 이것은 키보드 포커스를 뺏어가서 반환 하지 않는다. 그래서 아래와 같은 방법으로 처리 할 수 있다.



0. 그전에, 사용자의 컨트롤 밖에 클릭을 감지 하기 위해 현제 윈도우의 마우스 이벤트를 이용하여 포커스를 죽여도 좋다는 상황을 만들어 보자.

아래의 메서드를 이용한다.


        /*
         * 사용방법
         *  Window.GetWindow(this).PreviewMouseDown += MainWindow_PreviewMouseDown;
         *          ...
         *  void MainWindow_PreviewMouseDown(object sender, MouseButtonEventArgs e)
            {
                Window.GetWindow(this).PreviewMouseDown -= MainWindow_PreviewMouseDown;
                Point pt = e.GetPosition((UIElement)sender);
                bool result = HitUtil.HitVisualFromMainWindow(pt, this);
         
                Console.WriteLine(">>>>>>>>>>>>" + result);
                if (result == false)
                {
                    //out interesting
                }
            }
         * 
         * 
         * */

        public static bool HitVisualFromMainWindow(Point globalMousePoint, UIElement target)
        {
            Window window = Window.GetWindow(target);

            Point actualTargetPoint = target.TransformToAncestor(window).Transform(new Point(0, 0));
            Point r_pt = new Point(globalMousePoint.X - actualTargetPoint.X, globalMousePoint.Y - actualTargetPoint.Y);
            HitTestResult result = VisualTreeHelper.HitTest(target, r_pt);
            if (result != null)
            {
                return true;
            }
            else
            {
                return false;
            }
        }


그럼 위의 메서드를 활용하여 ..




1. 텍스트 박스의 포커스를 반환 하는법

        //-----------------------------------------------------------------events

        private void _tf_GotKeyboardFocus_1(object sender, KeyboardFocusChangedEventArgs e)
        {
            Window.GetWindow(this).PreviewMouseDown -= MainWindow_PreviewMouseDown;
            Window.GetWindow(this).PreviewMouseDown += MainWindow_PreviewMouseDown;
        }

        private void MainWindow_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            Window.GetWindow(this).PreviewMouseDown -= MainWindow_PreviewMouseDown;
            Point pt = e.GetPosition((UIElement)sender);
            bool result = HitUtil.HitVisualFromMainWindow(pt, this);
            if (result == false)
            {
                Keyboard.ClearFocus();
            }
        }


바로 Keyboard.ClearFocus() 를 호출하면 깔끔히 포커스를 반환 한다





2. 그렇다면, 이제 다른 컨트롤에 포커스를 할당 하여 보자. (마우스로 클릭과 동시에...)


        public SNCircleThumb()
        {
            InitializeComponent();
            this.Focusable = true; //중요!
        }





        //----------------------------------------------------------events

        #region

        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            base.OnMouseDown(e);
            this.Focus(); //중요!

            Console.WriteLine("req focus");
        }

        //키보드 테스트
        protected override void OnPreviewKeyDown(KeyEventArgs e)
        {
            base.OnPreviewKeyDown(e);
            Console.WriteLine("press Key : " + e.Key);
        }


 중요 라고 주석 한 곳을 참고 한다.

ㅁㅁ




위 와 같은 방법으로 비 텍스트필드 류의 컨트롤 에도 포커스를 할당 할 수 있다.


Yamecoder 야매코더_
C# 2015.01.06 18:15

[WPF] UserControl 에서 간단 마우스,키보드 이벤트 수신법


지울 필요가 없거나 충분히 on off 를 조절 하여 사용할 수 있는 환경이라면 구지 XAML 이나 += 로 추가 하지 않아도 아래와 같은 방법으로 override 하여 사용하면 깔끔하다.


 

        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            base.OnMouseDown(e);
            this.Focus();

            Console.WriteLine("req focus");
        }

        protected override void OnMouseEnter(MouseEventArgs e)
        {
            ((SolidColorBrush)(_circle.Fill)).Color = OverColor;
        }

        protected override void OnMouseLeave(MouseEventArgs e)
        {
            ((SolidColorBrush)(_circle.Fill)).Color = NormalColor;
        }


        protected override void OnPreviewKeyDown(KeyEventArgs e)
        {
            base.OnPreviewKeyDown(e);
            Keyboard_Press_ArrowType key_type = Keyboard_Press_ArrowType.NONE;
            if (e.Key == Key.OemComma)
            {
                key_type = Keyboard_Press_ArrowType.LEFT;
            }
            else if (e.Key == Key.OemPeriod)
            {
                key_type = Keyboard_Press_ArrowType.RIGHT;
            }

            if (key_type != Keyboard_Press_ArrowType.NONE)
            {
                if (KeyboardPressEvent != null)
                {
                    KeyboardPressEvent(this, new SNCircleThumbEvent() { keyPressType = key_type });
                }
            }
        }


Yamecoder 야매코더_
C# 2015.01.06 18:03

[WPF] 멀티쓰레드 상황에서 WPF Control 캡처 하기

WPF 의 Shape 그리기나 , Shader Effect , Brushes 등등이 WPF 를 사용하면 아주 쉽고 처리속도에도 이점이 많다. 하지만 일반적인 방법으로는 메인쓰레드에서만 비주얼 요소를 사용할 수 있어 사용이 제한적이고 , 별도의 프로세싱을 위하여 사용 할 경우 CPU 사용량이 높아져 전체적인 GUI 가 버벅되는 현상이 발생 할 수도 있다.


이를 극복하기 위하여 멀티 쓰레드 상황에서 WPF 컨트롤에 접근 하는 방법을 알아 보자.



using System;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using WPF_Tilt;

namespace ThreadCaptureWPFTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Thread captureThread;
        public MainWindow()
        {
            InitializeComponent();


            //쓰레드 생성
            captureThread = new Thread(new ThreadStart(Ready));
            // STA 형태의 쓰레드 이여야 함
            captureThread.SetApartmentState(ApartmentState.STA); 
        }


        // 쓰레드
        private void Ready()
        {
            //ViewBox, Grid , Canvas 등.. 생성
            Grid vb = new Grid();

            //XAML 로 만든 UserControl 도 가능함.
            vb.Children.Add(new View());
            vb.Arrange(new Rect(0, 0, 500, 500)); //중요!

            //RenderTargetBitmap 생성
            RenderTargetBitmap capture = new RenderTargetBitmap((int)vb.ActualWidth, (int)vb.ActualHeight, 96, 96, PixelFormats.Default);
            capture.Render(vb);

            var bmp = BitmapConvertUtil.ToBitmap(capture);
            bmp.Save(@"TestCap1.jpg");
            Console.WriteLine("CAP!"); 
        }



        private void root_KeyUp_1(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.A)
            {
                captureThread.Start();
            }
        }
    }
}

 


Yamecoder 야매코더_
C# 2014.11.05 14:23

[메모] 이중 반복문이 느리다.

                if (true)
                {
                    int c = 0 , d = 0;
                    int x = 0, y = 0;

                    for (int i = 0; i < this.depthPixels.Length; i++)
                    {
                        if (i % depthWidth == 0 && i > 0)
                        {
                            ++y;
                            x = 0;
                        }

                        if (this.depthPixels[i].PlayerIndex > 0)
                        {
                            maskedImage.Data[y, x, 0] = 30;
                            maskedImage.Data[y, x, 1] = 250;
                            maskedImage.Data[y, x, 2] = 30;
                        }

                        ++x;
                    }

                    #region
                    // 아래와 같이 x y 이중 반복문은 위의 알고리즘 보다 훨씬 느리다.
                    //for (int x = 0; x < maskedImage.Height; x++)
                    //{
                    //    for (int y = 0; y < maskedImage.Width; y++)
                    //    {
                    //        if(this.depthPixels[c].PlayerIndex > 0)
                    //        {
                    //            maskedImage.Data[x, y, 0] = 30;
                    //            maskedImage.Data[x, y, 1] = 250;
                    //            maskedImage.Data[x, y, 2] = 30;

                    //            ++d;
                    //        }
                    //        ++c;
                    //    }
                    //}
                    #endregion
                }
Yamecoder 야매코더_
C# 2014.07.30 18:09

웹캠 포커스 강제 설정방법

로지텍 캠의 고질적인 문제는 오토포커스 설정이 재부팅 시 원복 된다는 점이다. 

그러나 아래의 DirectShow  를 이용한 메서드 들로 해결 할 수 있다.



( 출처 :  http://stackoverflow.com/questions/18124646/manually-focus-camera-in-emgu-cv)


        private void SetCameraControl()
        {
            Console.WriteLine("Camera Setting ! ");

            DsDevice dev = GetPCCamDev();
            if (dev == null) return;

            IFilterGraph2 graphBuilder = new FilterGraph() as IFilterGraph2;
            IBaseFilter capFilter = null;
            if (graphBuilder != null)
                graphBuilder.AddSourceFilterForMoniker(dev.Mon, null, dev.Name, out capFilter); //getting capture filter for converting it into IAMCameraControl
            IAMCameraControl _camera = capFilter as IAMCameraControl;
            _camera.Set(CameraControlProperty.Focus, 0, CameraControlFlags.Manual); //Setting focus to macro (in my camera, range between 0 - 250)
        }

        private DsDevice GetPCCamDev()
        {
            DsDevice[] devs = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
            foreach (var item in devs)
            {
                if (item.Name.StartsWith("Point Grey") == true) continue;

                Console.WriteLine(item.Name);
            }
            return devs[0];
        }


Yamecoder 야매코더_
C# 2014.07.29 13:43

직렬화된 배열을 비트맵 스타일로 배열하기 , 리사이징 하기

1) 직렬화된 배열을 비트맵 스타일로 배열하기 , 

2) 직렬화된 배열을 비트맵 스타일로 리사이징 하기


위의 요건이 이번 프로젝트 에 필요하게 되었다.


상황은 키넥트에서 받는 DepthFrame 을 이용하여 유니티에서 1:1 로 파티클을 매칭 한다.

이때 파티클은 1개의 매쉬 에 동적으로 그려진 버텍스 들이다. 


그리고 버택스 개수는 약 6만5천개로 제한적이다.


그리고 일정 개수 이상 넘어 가고, 이것들을 루프에 돌릴때, 메인쓰레드의 FPS 가 떨어지는 불상사가 일어난다.


그래서 품질과 퍼포먼서의 적정 수준인 160 x 120 해상도의 DepthFrame 이 필요한데, 안타깝게도 키넥트에서는 저 해상도를 지원하지 않는다.


그러나 비트맵으로 변경하여 리사이징 하면 간편하다. 하지만, 이렇게 할 경우 이미징 과정에서 생기는 노이즈와 Depth 단계를 256 단계 밖에 못 쓰므로 풍성한 양감을 얻기 힘들다. 


따라서 DepthFrame[] 을 리사이징 해야 한다. 


방법은 각 배열을 비트맵으로 생각한다음 지정된 가로 사이즈 만큼 나누어 줄을 내린다.


그다음 그 비트맵의 상하좌우 4칸을 잡은 다음 좌측 상단 픽셀만 따로 골라 별도의 배열에 담는다.




(회색부분을 전체 비트맵 이라 생각 했을때 빨간색 픽셀만 골라 낸다) 

 

그러면 계산 상 1/4 배로 사이즈가 줄어 들게 된다.


이 일련의 과정을 간단한 코드로 재현 해 보았다. 


다방면으로 이용 할 수 있는 방법인듯 하다.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;

namespace DepthBitmapFromKinectDepth
{
    class Program
    {
        static int bmpWidth = 320;
        static int bmpHeight = 240;
        static void Main(string[] args)
        {
            Program p = new Program();
        }

        public Program()
        {
            DateTime dt = DateTime.Now;
            //ReadDepthToImage(); - ok
            //ReadDepthFrameToImage(ParseDepthFrame()); - ok
            ResizeQuater();

            Console.WriteLine("process time (ms) > " + (DateTime.Now - dt).Milliseconds);
            Console.ReadKey();
        }
        




        // 사이즈 변경
        // 320 x 240 -> 160 x 120
        private void ResizeQuater()
        {
            var depthframes = ParseDepthFrame();
            var resizeFrmaes = new DATA.DepthFrame[depthframes.Length/4];
            int x = 0, y = 0 , c = 0;
            for (int i = 0; i < depthframes.Length; i++)
            {
                if (i % bmpWidth == 0 && i > 0)
                {
                    ++y;
                    x = 0;
                }

                if (x % 2 == 0)
                {
                    if (y % 2 == 0)
                    {
                        resizeFrmaes[c] = depthframes[i];
                        ++c;
                    }
                }
                ++x;
            }

            Console.WriteLine(x + " " + y + " " + c);
            ReadDepthFrameToImage(resizeFrmaes, new Size(160, 120));
        }





        /// <summary>
        /// 유틸 메서드들 
        /// </summary>
        private byte[] ReadDepthDatFile()
        {
            // 키넥트에서 320 x 240 사이즈의 Depth 이미지의 뎁스 와 플레이어 인덱스를 별토 파일로 저장함.
            // 즉 , 1묶음이 3바이트로 구성되어 있는데 ,[byte : 플레이어 인덱스] [[byte],[] : Short 형 Depth 값 ] 이다. 
            return File.ReadAllBytes(Environment.CurrentDirectory + "/DepthData.dat");
        }

        private DATA.DepthFrame[] ParseDepthFrame()
        {
            byte[] _org_data = ReadDepthDatFile();
            DATA.DepthFrame[] depthFrames = new DATA.DepthFrame[_org_data.Length / 3];

            Console.WriteLine("parse depthFrames : " + depthFrames.Length);

            for (int i = 0; i < _org_data.Length / 3; i++)
            {
                byte playerIndex = _org_data[(3 * i) + 0];
                short depth = BitConverter.ToInt16(_org_data, (3 * i) + 1);

                depthFrames[i] = new DATA.DepthFrame() { PlayerIndex = playerIndex, Depth = depth };
            }

            return depthFrames;
        }

        private void ReadDepthFrameToImage(DATA.DepthFrame[] depthFrames, Size bmpSize)
        {
            int x, y;
            Color[] colors = new Color[bmpSize.Width * bmpSize.Height];
            x = 0;
            y = 0;

            for (int i = 0; i < depthFrames.Length; i++)
            {
                short depth = depthFrames[i].Depth;
                byte depthToByte = (byte)depth;
                colors[i] = Color.FromArgb(depthToByte, depthToByte, depthToByte);

                if (i % bmpSize.Width == 0 && i > 0)
                {
                    ++y;
                    x = 0;
                }
                ++x;
            }

            WriteBitmap(colors, bmpSize, "save2.jpg");
        }

        private void WriteBitmap(Color[] colors, Size bmpSize, string fileName)
        {
            int x, y;
            Bitmap bmp = new Bitmap(bmpSize.Width, bmpSize.Height);
            x = 0;
            y = 0;
            for (int i = 0; i < colors.Length; i++)
            {
                if (i % bmpSize.Width == 0 && i > 0)
                {
                    ++y;
                    x = 0;
                }

                bmp.SetPixel(x, y, colors[i]);
                ++x;
            }
            bmp.Save(Environment.CurrentDirectory + "/" + fileName); // -ok
            Console.WriteLine("write complete");
        }






        /// <summary>
        /// 기본 테스트
        /// </summary>
        private void ReadDepthToImage_Pure()
        {
            int min = int.MaxValue;
            int max = int.MinValue;

            byte[] _org_data = ReadDepthDatFile();

            Color[] colors = new Color[bmpWidth * bmpHeight];
            int x, y;

            //to Depth Image
            x = 0;
            y = 0;
            for (int i = 0; i < _org_data.Length / 3; i++)
            {
                byte playerIndex = _org_data[(3 * i) + 0];
                short depth = BitConverter.ToInt16(_org_data, (3 * i) + 1);

                if (min > depth)
                {
                    min = depth;
                }

                if (max < depth)
                {
                    max = depth;
                }

                byte depthToByte = (byte)depth;
                colors[i] = Color.FromArgb(depthToByte, depthToByte, depthToByte);

                if (i % bmpWidth == 0 && i > 0)
                {
                    ++y;
                    x = 0;
                }
                ++x;
            }

            // 숫자 검증
            Console.WriteLine("min : " + min);
            Console.WriteLine("max : " + max);
            Console.WriteLine("Color len : " + colors.Length);

            Bitmap bmp = new Bitmap(320, 240);
            x = 0;
            y = 0;
            for (int i = 0; i < colors.Length; i++)
            {

                if (i % bmpWidth == 0 && i > 0)
                {
                    ++y;
                    x = 0;
                    Console.WriteLine("Reteral");
                }

                bmp.SetPixel(x, y, colors[i]);

                ++x;
            }
            bmp.Save(Environment.CurrentDirectory + "/Save.jpg"); // -ok 320 x 240
        }
    }

    public class DATA
    {
        public struct DepthFrame
        {
            public byte PlayerIndex;
            public short Depth;
        }
    }
}


Yamecoder 야매코더_
C# 2014.07.11 17:31

[중요 메모] STA Thread 와 COM 객체 사용시 절대 주의 할점

while (true)
            {
                for (i = 0; i < cam.GetCamLength; ++i)
                {
                    camImages[i].Update();
                }

                // COM 객체나 하드웨어 접근을 사용하는 어플리케이션에서는 Join 메서드를 꼭 사용하여야 한다. 안그러면 , 알지못하는 메모리 릭이 발생한다. OS 가 뒤질때 까지...
                rendererThread.Join(1);
            }

COM 객체나 하드웨어 접근을 사용하는 어플리케이션에서는 Join 메서드를 꼭 사용하여야 한다. 안그러면 , 알지못하는 메모리 릭이 발생한다. OS 가 뒤질때 까지...

Yamecoder 야매코더_
C# 2014.05.08 20:54

c# Emgu 카메라 칼리브레이션 요점 정리

요점만..





위의 사진을 사용하여 키보드 [1], [3] 을 번갈아 누르면, 점차 정확한 이미지를 얻을 수 있다.




위의 이미지는 대략 10번 정도 반복한 결과 이다.

원리는 컬리브레이션 결과를 다시 컬리브레이션 하는 반복 과정 이다.



using Emgu.CV;
using Emgu.CV.Structure;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace CCT_form
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.Load += Form1_Load;
        }
        private Size patternSize = new Size(9, 6);
        private Image<Gray, byte> raw_image;
        void Form1_Load(object sender, EventArgs e)
        {
            raw_image = new Image<Gray, byte>(@"C:\temp\ChessBoard-1.jpg");
            this.pictureBox1.Image = raw_image.Bitmap;

            this.KeyUp += Form1_KeyUp;
        }

        private PointF[][] corners = new PointF[1][];
        private void FindChessboard(Image<Gray, byte> org_img)
        {

            Image<Bgr, byte> c_image = org_img.Clone().Convert<Bgr, byte>();
            PointF[] _corners_1 = CameraCalibration.FindChessboardCorners(raw_image, patternSize, Emgu.CV.CvEnum.CALIB_CB_TYPE.ADAPTIVE_THRESH);
            raw_image.FindCornerSubPix(new PointF[1][] { _corners_1 }, new Size(11, 11), new Size(-1, -1), new MCvTermCriteria(30, 0.1));

            for (int i = 0; i < _corners_1.Length; ++i)
            {
                if (i < _corners_1.Length - 1)
                    c_image.Draw(new LineSegment2DF(_corners_1[i], _corners_1[i + 1]), new Bgr(Color.Red), 1);

                c_image.Draw(new CircleF(_corners_1[i], 3), new Bgr(Color.Cyan), 3);
            }

            corners[0] = _corners_1;
            this.pictureBox1.Image = c_image.Bitmap;
        }

        private IntrinsicCameraParameters IC = new IntrinsicCameraParameters();
        private ExtrinsicCameraParameters[] EX_Param;
        private void Calibration()
        {
            MCvPoint3D32f[][] refPoints = new MCvPoint3D32f[1][];//[patternSize.Width * patternSize.Height];
            MCvPoint3D32f[] _refPoints_1 = new MCvPoint3D32f[patternSize.Width * patternSize.Height];

            int c = 0;
            for (int i = 0; i < patternSize.Height; ++i)
            {
                for (int j = 0; j < patternSize.Width; ++j)
                {
                    _refPoints_1[c] = (new MCvPoint3D32f(j * 20.0f, i * 20.0f, 0.0f));
                    ++c;
                }
            }
            refPoints[0] = _refPoints_1;


            double resultValue = CameraCalibration.CalibrateCamera(refPoints, corners, raw_image.Size, IC, Emgu.CV.CvEnum.CALIB_TYPE.CV_CALIB_RATIONAL_MODEL, new MCvTermCriteria(30, 0.1), out EX_Param);
            Console.WriteLine("calib result : " + resultValue);


            Matrix<float> map_x, map_y;
            IC.InitUndistortMap(raw_image.Width, raw_image.Height, out map_x, out map_y);

            Image<Gray, byte> blankImage = raw_image.CopyBlank();
            CvInvoke.cvRemap(raw_image, blankImage, map_x, map_y, 0, new MCvScalar(0));
            raw_image = blankImage.Copy();

            this.pictureBox1.Image = raw_image.Bitmap;
        }

        void Form1_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.D1)
            {
                FindChessboard(raw_image);
            }

            if (e.KeyCode == Keys.D2)
            {

            }

            if (e.KeyCode == Keys.D3)
            {
                Calibration();
            }
        }
    }
}


Yamecoder 야매코더_
C# 2014.05.08 00:49

[Marshal] byte* to byte[]

        protected override void CamStreamStart()
        {
            uint i = 0;
            SNCameraStreamEvent evtarg = new SNCameraStreamEvent();
            while (true)
            {
                for (i = 0; i < cams.Length; ++i)
                {
                    cams[i].m_cameras.RetrieveBuffer(cams[i].m_rawImages);

                    int length = (int)(cams[i].m_rawImages.rows * cams[i].m_rawImages.stride);
                    unsafe
                    {
                        byte[] dstbytes = new byte[length];

                        // [ cams[i].m_rawImages.data ] is [ byte * ] 
                        Marshal.Copy((IntPtr)cams[i].m_rawImages.data, dstbytes, 0 , length);

                        cams[i].m_processedSrc = BitmapSource.Create(
                        (int)cams[i].m_rawImages.cols,
                        (int)cams[i].m_rawImages.rows,
                        96, 96,
                        System.Windows.Media.PixelFormats.Gray8,
                        null,
                        dstbytes,
                        (int)cams[i].m_rawImages.stride);
                        cams[i].m_processedSrc.Freeze();
                    }
                }

                if (CameraEvent != null)
                {
                    evtarg.state = STATE.UPDATE;
                    Application.Current.Dispatcher.Invoke((Action)delegate
                    {
                        CameraEvent(this, evtarg);
                    });
                }

                //Thread.Sleep(1000);
            }
        }

Marshal.Copy 주목.


Yamecoder 야매코더_
C# 2014.05.07 12:32

[WPF] 이미지 byte[] 를 바로 BitmapSource 로 옮기자.

바로  BitmapSource.Create(...)  를 이용하는 방법이다.

이전까지 WriteableBitmap 을 사용하였지만, 이방법이 더욱 간단하고 처리과정에서 이슈도 적다.

 

보통 별도 쓰레드 루프 에서 지속적인 이미지 byte[] 를 얻고 아래의 코드를 활용하여 GUI 에서 처리 한다.


신경을 써야 하는 부분은  간혹   InvalidOperationException   이 발생한다.

try
{
    bsrc = BitmapSource.Create(screenRenderSize.Width, screenRenderSize.Height, 96, 96, PixelFormats.Rgb24, null, W_RawSource_data, REGB24Stride);
    bsrc.Freeze();

}
catch (InvalidOperationException)
{
    return null;
}

또한 원본 데이터의 Stride 선택에 신경을 써 줘야 한다.




참고)

파이어플라이 캠의 FlyCapture2Managedd_v100 중 종속성 오류가 지속될 경우 VisualStudio 2010 을 설치 한다.

아마 그 안에  VC++90 이 설치가 되기 때문일것으로 생각 됨.

Yamecoder 야매코더_
C# 2014.05.06 13:36

[WPF] VisualStudio 에서 [ is not recognized or is not accessible] 에러 해결법


위와 같은 에러메시지.. 아무리 컨트롤들을 잘 잡아도 계속되는 고질적인것은..



 
Here's the solution. In the application's .csproj file, change this:

<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
to this:

<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
Do not be fooled by the fact that Visual Studio reports that you are running in AnyCPU more in the configuration manager. You must hand-edit the .csproj file





하고 한번 빌드해주면 된다. 아니면 F5 하던지..







Yamecoder 야매코더_
C# 2014.04.08 22:07

XmlDocument 사용법 정리


XML 문서

<?xml version="1.0" encoding="utf-8" ?>
<root>
  <attract>
    <time type="bboy" sp="0:0:0" ep="0:0:13"/>
    <time type="km" sp="0:0:13" ep="0:0:32"/>
    <time type="bboy" sp="0:0:32" ep="0:0:55"/>
    <time type="magic" sp="0:0:55" ep="0:1:27"/>
    <time type="pid" sp="0:1:27" ep="0:1:40"/>
    <time type="km" sp="0:1:40" ep="0:1:55"/>
    <time type="bboy" sp="0:1:55" ep="0:2:13"/>
    <time type="km" sp="0:2:13" ep="0:2:36"/>
    <time type="magic" sp="0:2:36" ep="0:3:00"/>
    <time type="pid" sp="0:3:00" ep="0:3:19"/>
  </attract>
</root>



c#

attractTimeTable = new List<KBVideoItem>();
            XmlDocument xml = new XmlDocument();
            xml.Load(Environment.CurrentDirectory + "/config/KBVideoTimeTable.xml");


            XmlNodeList _attract_list = xml.SelectNodes("/root/attract/time");
            Console.WriteLine(_attract_list.Count);
            foreach (XmlNode xn in _attract_list)
            {
                Console.WriteLine("----------------------------");
                Console.WriteLine(xn.Attributes["type"].InnerText);
                Console.WriteLine(xn.Attributes["sp"].InnerText);
                Console.WriteLine(xn.Attributes["ep"].InnerText);
            }



Yamecoder 야매코더_
C# 2013.11.28 10:46

WPF , CacheMode

CacheMode 의 사용과 비 사용의 테스트 이다.

 

테스트 방법은 사진 640 , 480 ,사이즈의 이미지 플레이트 들을 60장 생성하고 이를 겹겹이 겹쳐 놓은 다음 최상단 플레이트를 크게 움직였다.

 

첫번째는 캐쉬를 설정하지 않은 경우 이다.

 

 

FPS 가 6 정도 나왔다.

거의 사용이 불가능 하다.

 

 

다음은 캐쉬를 설정한 경우이다.

 

 

캐쉬 적용 시점은 이미지의 로드가  완료 된 후 이미지 플레이트 전체에 설정 하였다.

 

 

참고 :

선택할경우 테두리의 알파값이 변하는 애니메이션이 존재한다.

FPS 수치는 절대적인 수치가 아니라 상대적으로 이해 하는것이 맞다.

테스트 PC 사양 : i5 3세대 (1.7 ~ 2.4)Ghz , 4G RAM , Intel HD 4000 (노트북)

 

 

결론 :

비주얼에 캐쉬를 설정하는것은 비주얼을 일종의 비트맵 블리팅 시키는것이다. 또한 필요한 부분만 다시 렌더링 한다.

아마 큰 비주얼 수정이나 재 로딩 이 있을 경우 다시 설정하여여 할것으로 예상된다.

퍼포먼스는 상당이 만족 스럽다.

Yamecoder 야매코더_
C# 2013.01.28 00:28

[Surface2]Surface2.0 Simmulator on Windows8 , Solved!

 

 

윈도우8 에서 Surface SDK 가 설치되지 않는다.

하지만 dll 만 있다면 개발은 할수 있다.

 

그러나 시뮬레이터는 사용할수가 없어 완전한 개발을할수 없었다.

그러던 어느날 , 설치가 되었다. 어떻게 되었는지는 확실치 않으나

실제 경로 C:\Program Files (x86)\Microsoft SDKs\Surface\v2.0 에 정확히 파일이 있고 ,

C:\Program Files (x86)\Microsoft SDKs\Surface\v2.0\Tools 에도 모든 유틸리티가 존재 한다.

아마도 그냥 한번 윈도우7 의 것을 그대로 복사를 했나 보다.

 

 

지원 하지 않는다는 글 ,

http://social.technet.microsoft.com/Forums/et-EE/surfacesoftware2/thread/c9439b5b-44a9-4643-910a-2eb4d2a62d35

 

 

Yamecoder 야매코더_
C# 2013.01.25 22:35

[Surface - WPF] Surface 에서의 에니메이션 활용 (ArtefactAnimator)

 

출처 : http://artefactanimator.codeplex.com/

 

기존 WPF 의 애니메이션 중 스토리 보드(Storyboard) 라는 극악의 사용성을 가진 방법이 존재 한다.

AS3 의 트윈라이트 (TweenLite , TweenMax) 처럼 산뜻하지 않고 왠만한 복합에니메이션을 구현하려면 한바닥이 꽉 찬다.

이건 , 머 차라리 자체적으로 트윈 클래스를 만들라는 숨은 의도 같다.

그러던 도중 artefactanimator 라는 것을 발견했고 이것이 AS3 의 TweenLite 를 본따서 만들었다고 한다.

사용법이 간단하다.

그러나 보통의 UIElement 에서는 잘 동작 하나 , Surface2.0 용 컨트롤 에서는 당췌 동작하지 않는다.

이유를 살펴 보니 각 속성이 getter setter 로 잘 지켜져야 한다. 마땅하다. 그러나 AS3 의 비주얼 객체들과 달리 WPF 의 객체들의 비주얼 속성 을 살펴 보면 간단히 getter setter 로 잘 되어 있지 않은것이 많다.

대표적인것이 ScatterViewItem 의 위치 를 설정할때 item.Center = new point(*.*) 식으로 설정 해야 한다.

이러한 형태로 트위닝은 보통 방법으로는 어렵다.

AS3 의 TweenMax 류 에서는 별도의 var obj = {prop : 100} 로 설정한다음 obj 에 Tween을 걸었다. 이와 비슷한 방법으로 artefactanimator 를 활용하는 방법을 알아본다.

 

 
//트위너 설정
            var customTween = new GetterSetter
            {
                Getter = (obj, data) => obj,
                Setter = (obj, data, per) =>
                {
                    //변위
                    var c = EaseHelper.EaseValue((Point)data.ValueStart, (Point)data.ValueEnd, per);

                    //트위닝 타겟
                    item.Center = c;
                }
            };

            //초기객체 설정
            Point movePoint = new Point(0, 0);

            //Prop 레지스터 등록 , 같은 이름으로 등록을 시도하면 등록이 안된다. 따라서 밑에 것은 무시되어 걱정할필요 없다.
            var b1 = AnimationTypes.RegisterGetterSetter(movePoint.GetType().ToString(), customTween);
            var b2 = AnimationTypes.RegisterGetterSetter(movePoint.GetType().ToString(), customTween);
            Console.WriteLine("b1 " + b1);
            Console.WriteLine("b2 " + b2);

            //실제 트위닝 명령
            ArtefactAnimator.AddEase(movePoint, movePoint.GetType().ToString(), new Point(323, 211), 3, AnimationTransitions.CubicEaseIn);

            //5초 후에 다시 트위닝
            movePoint.X = 323;
            movePoint.Y = 211;
            ArtefactAnimator.AddEase(movePoint, movePoint.GetType().ToString(), new Point(323, 0), 3, AnimationTransitions.CubicEaseIn, 5);

 

 

Yamecoder 야매코더_
C# 2013.01.22 15:45

[.NET] 어셈블리 하나로 합치기 (ilmerge 사용안함)

 

코딩을 하다보면 dll 들이 엄청 늘어 날때가 있다.

폴더가 지저분해진다.

보기 않좋다.

 

그래서 모든 dll 을 Embed 시키는 방법을 알아 본다.

기존의 ilmerge 라는 툴이 있지만 WPF 등과 같은 프레임웤에 사용하려면 관련된 dll 을 다 열거 하라고 하고 사용법 또한 그리 스마트 하지 않다.

AppDomain.CurrentDomain.AssemblyResolve 를 이용하여 하나로 합칠수가 있다.

우선 사용될 모든 dll 을 비주얼 스튜디오 안으로 끌어 온다

 

.

 

그다음 이 모든 dll 들을 포함 리소스로 만들어 준다.

 

그리고 App 클래스로 이동하여 아래와 같이 코딩 한다.

 

 

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;

namespace Test_Marge
{
    public partial class App : Application
    {
        public App()
        {
            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(ResolveAssembly);
        }

        static Assembly ResolveAssembly(object sender, ResolveEventArgs args)
        {
            //We dont' care about System Assembies and so on...
            //if (!args.Name.ToLower().StartsWith("Test")) return null;

            Assembly thisAssembly = Assembly.GetExecutingAssembly();

            //Get the Name of the AssemblyFile
            var name = args.Name.Substring(0, args.Name.IndexOf(',')) + ".dll";

            //Load form Embedded Resources - This Function is not called if the Assembly is in the Application Folder
            var resources = thisAssembly.GetManifestResourceNames().Where(s => s.EndsWith(name));
            if (resources.Count() > 0)
            {
                var resourceName = resources.First();
                using (Stream stream = thisAssembly.GetManifestResourceStream(resourceName))
                {
                    if (stream == null) return null;
                    var block = new byte[stream.Length];
                    stream.Read(block, 0, block.Length);
                    return Assembly.Load(block);
                }
            }
            return null;
        }
    }
}

 

 

그리고 난 다음 빌드된 폴더의 exe 만 따로 꺼내어 테스트 해본다.

 

 

출처 : http://blog.mahop.net/post/Merge-WPF-Assemblies.aspx

 

 

참고 : Winform 에서는 Program.cs 의 Application.Run(new Form1()); 위에 작성한다.

Yamecoder 야매코더_
C# 2013.01.16 16:18

[WPF] 트레이 아이콘 만들고 사용하기

 

트레이 아이콘을 만들고 , 무언가 알림이 있을때 풍선메시지를 만들어 본다.

먼저 간단히 아이콘을 만들어 리소스에 넣어 본다.

* [프로젝트 속성] - 리소스 - 리소스추가 - 아이콘 추가

를 하면 기본 아이콘이 생성된다.

이를

Properties.Resources.Icon1;

로 접근 할수 있다.

 

사용법은 아래와 같다.

 
private System.Windows.Forms.NotifyIcon trayIcon;
        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);

            //make up tray icon
            trayIcon = new System.Windows.Forms.NotifyIcon();
            trayIcon.BalloonTipText = "this app has been minimised";
            trayIcon.BalloonTipTitle = "BalloonTipTitle";
            trayIcon.Text = "Text";
            trayIcon.Icon = Properties.Resources.Icon1;
            trayIcon.Click += m_notifyIcon_Click;

            //make up test timer.
            DispatcherTimer timer = new DispatcherTimer();
            timer.Interval = new TimeSpan(0, 0, 2);
            timer.Tick += timer_Tick;
            timer.Start();
        }


        private int c = 0;
        void timer_Tick(object sender, EventArgs e)
        {
            //if you want alert something , use this method. and change Text
            trayIcon.ShowBalloonTip(1000);
            trayIcon.BalloonTipTitle = "count " + c;
            trayIcon.BalloonTipText = "alert test";
            ++c;
        }

        void m_notifyIcon_Click(object sender, EventArgs e)
        {
            Show();
            //restore window state
            WindowState = System.Windows.WindowState.Normal;
        }

        
        private void Window_IsVisibleChanged_1(object sender, DependencyPropertyChangedEventArgs e)
        {
            // when window is unvisible , change visible option tray icon .
            if (IsVisible == false)
                trayIcon.Visible = true;
        }

        private void Window_StateChanged_1(object sender, EventArgs e)
        {
            if (WindowState == System.Windows.WindowState.Minimized)
            {
                Hide();
                trayIcon.ShowBalloonTip(2000);
            }
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosed(e);
            //when user click The [Close button] , this app will not work window close command.
            //instead , this app window change to minimized state. 
            WindowState = System.Windows.WindowState.Minimized;
            e.Cancel = true;
        }

Yamecoder 야매코더_
C# 2013.01.16 13:29

[WPF] 윈도우 닫기 명령 무시하기

 

윈도우 유틸 어플리케이션을 만들경우 윈도우 닫기를 눌러도 무시해야 하는 경우가 생긴다.

닫이면 안된다는것이다.

WIN32 를 건드리지 않고서라도 간단히 해결할수 있는 방법이 있다.

 

protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosed(e);
            //do something
            //WindowState = System.Windows.WindowState.Minimized;
            e.Cancel = true;
        }
 

OnClosing을 오버라이드 하면 된다.

 

 

Yamecoder 야매코더_
C# 2013.01.16 12:37

[asmx] 쿠키 이용하기 , (사용자 인증)

서버측 코드

 

 
[WebMethod]
        public string LoginService(string _userId , string pw)
        {
            var query = from user in db.DbAccounts.Accounts
                        where (user.User_id == _userId)
                        select user;


            if (query.Count() > 0)
            {
                //success
                HttpContext.Current.Response.Cookies["User_id"].Value = _userId;
                //HttpContext.Current.Response.Cookies["User_id"].Expires = DateTime.Now.AddMinutes(10);
                return "ok";
            }
            else
            {
                //fail
                return "fail";
            }
        }

로그인을 하여 아이디가 검출 되면 쿠키를 발행 한다.

밑에 주석 되어 있는 코드는 쿠키의 유효 시간이다.

 

 

클라이언트 측 코드

 

 
private static void loginTest()
        {
            Login.LoginSoapClient service = new Login.LoginSoapClient();

            var result = service.LoginService("testid", "testpw");
            Console.WriteLine(result);

            int c = 0;
            while(c < 300)
            {
                try
                {
                    Console.WriteLine(c + " " + service.dosomething());
                }
                catch (Exception eee)
                {
                    Console.WriteLine("cookieErr");
                    //Console.WriteLine(eee);
                }
                Thread.Sleep(1000);
                ++c;
            }

 

로그인 서비스를 호출한뒤 , 쿠키가 유효한지 검사한다.

하지만 아무리 해도 안될것이다. 이유는 클라이언트 어플리케이션 에서 쿠키 설정을 해줘야 한다.

app.config

 

위와 같이 설정해주면 된다.

 

Yamecoder 야매코더_
C# 2013.01.15 17:25

[SQL2012] DB 생성부터 사용자 만들기 그리고 SQL 접속하기

asmx 를 시도중이다.

그리고 원격 서버의 DB 를 접근 하려면 꼭 계정정보가 원격 코드에 입력이 되어 있어야 사용가능하다. 그렇지 않으면 인증 오류가 난다.

 

MS SQL 2012 기준으로 데이터베이스 생성부터 사용자 만들기 , SQL 에 접근 하기 를 기록하겠다. 

1) 데이터 베이스 생성 과정

 

 

2) 테이블 생성 완료

 

 

3) 계성 생성

 

 

4) 생성된 계정의 정보 보기

 

 

5) 비밀번호 재 설정

 

6) SQL 접근

 

 

 

 

* 누락사항 : SQL 의 DB 속성에서 Permissions 에 사용자를 할당하여 권한설정을 해주어야 한다.

Yamecoder 야매코더_
C# 2013.01.14 15:00

sqlMetal 사용법

 

 

 

외부의 SQL Database 라도 손쉽게 dbml 혹은 맞춤 클래스와 맵 을 얻을수 있다.

우선 VisualStudo 명령 프롬프트 에서 적당한 디렉토리로 이동후 아래의 명령을 타이핑 한다.

 

sqlmetal /Server:plasticserver_ /Database:TEST_DB /Code:LinqTest.cs /Map:LinqTest.xml /Pluralize /Functions /Sprocs /Views
sqlmetal /Server:plasticserver_ /Database:TEST_DB /dbml:linqTest.dbml /Pluralize /Functions /Sprocs /Views

 

위의 것은 .cs 파일과 맵XML 생성 ,

아래것은 dbml 생성 한다.

Yamecoder 야매코더_
C# 2013.01.11 21:37

Activator 를 이용한 Type Instance 생성

 

이러한 표현을 하고 싶을 때가 있다

public void setType( Class TTT)

{

var t = new TTT(...);

t.a = 123;

t.b = "azc";

}

 

하지만 C# 에서 위와 같은 표현은 허락 하지 않는다.

 

현제

로컬 DB 라이브러리를 만들고 있다. 불러들일 로컬 DB의 Column 을 개발자는 미리 알고 있지만 생성기를 통하지 않고서는

각 로우에 맞는 클래스를 자동으로 만들어 주지는 않는다.

그래서 위와 같은 표현이 아쉬운것이다. TTT 라는 클래스에 DB의 테이블에 맞는 클래스를 작성한다음 활용 하면 좋은데..

 

그래서 아래와 같은 방법을 생각했다. 가능하다. 하지만 많은 UnBoxing 과 리플렉션이 사용됨으로 사용횟수에 따라

성능차이가 날것이다.

 

 

 
//

            Type type = typeof(TEST);
            var inst = Activator.CreateInstance(type);

            PropertyInfo info = type.GetProperty("TestProperty1");
            info.SetValue(inst, "testname123", null);

            //결과 확인
            Console.WriteLine(((TEST)inst).TestProperty1);

'C#' 카테고리의 다른 글

[SQL2012] DB 생성부터 사용자 만들기 그리고 SQL 접속하기  (4) 2013.01.14
sqlMetal 사용법  (10) 2013.01.11
Activator 를 이용한 Type Instance 생성  (32) 2012.12.29
[Broadcast Video Streaming]  (149) 2012.11.27
[Tcp] 연속적인 정보를 송출시 유의점  (91) 2012.11.04
[MEMO]  (58) 2012.10.14
Yamecoder 야매코더_
C# 2012.12.29 22:41

[Broadcast Video Streaming]

 

 

 

640 * 480 * 4 만큼의 컬러 바이트 배열을 실시간으로 각 SWF 로 전송하여 그 컬러 배열 대로 bitmap을 만들어 실시간으로 업데이트 했다.

초당 1.2 M 전송율 , 로컬 네트워크로 묶을 경우 대역폭을 생각해서 공유기를 선택하면 효율적일듯 함.

 

문제

화면 깜빡거림 문제 : 82 바이트 만큼의 크기가 맞지 않는다.

화면 색 : 전송되는 컬러 바이트 배열순서와 복원 되는 컬러 바이트 배열 순서가 서로 틀려서 나온 결과

ARGB , BGRA , RGBA

 

 

결과 ㅡ

돈주고 화면 스트림 장비나 , 서버를 산다던데,,, 구지,,,

 

 

 

'C#' 카테고리의 다른 글

sqlMetal 사용법  (10) 2013.01.11
Activator 를 이용한 Type Instance 생성  (32) 2012.12.29
[Broadcast Video Streaming]  (149) 2012.11.27
[Tcp] 연속적인 정보를 송출시 유의점  (91) 2012.11.04
[MEMO]  (58) 2012.10.14
[WCF] 간단한 채팅 샘플  (61) 2012.05.12
Yamecoder 야매코더_
C# 2012.11.27 19:05
Powerd by Tistory, designed by criuce
rss