WinForms와 WPF의 한가지 가장 큰 차이점은 WinForms는 단순히 Standard Windows Control(e.g a TextBox)의 최상단 레이어인 반면에 WPF는 맨처음부터 거의 모든 경우에 Standard Windows Control에 의존하지 않도록 만들어졌다.

# winform이 먼저 발표되었습니다.

마소(마이크로소프트)에서 개발한 윈도우 환경에서 개발자들이 프로그램을 개발하기 위해서는 기계어를 알아야 했지만, 개발 생산성을 올리기 위해서 다양한 프레임워크가 탄생하게 되었는데요. 그중에서 .Net Framework가 있고, 그 중에서 C#으로 개발하는데 사용되는 UI 개발도구로 Winform과 Wpf가 있습니다.

Winform의 경우 .Net 1.0 부터 지원되었고, 이는 드레그 앤 드롭 방식으로 자신이 생성하고 싶은 컨트롤을 UI 개발창에 올리면 자동으로 코드가 생성되고, 결과는 개발자가 볼 수 있는 방식이였습니다. 이는 매우 직관적이고 초보자도 쉽게 개발 할 수 있다는 장점이 있었습니다. 

이런식으로 버튼 하나를 선택해서 원하는 위치에 올리면 Control이 생성되는 방식입니다. 이때 해당 Form에는 디자인코드와 소스코드가 생성되는데요. 디자인코드는 코드보기를 선택하여 해당 Form의 디자인코드를 볼 수 있습니다. 

하지만 이 디자인 코드는 자동으로 생성이 되기 때문에 별도로 수정을 하지 않아도 어느정도 자신이 원하는 컨트롤을 만들 수 있습니다. 

Wpf의 경우 .Net 3.0 부터 지원이 되었고, Winform이 갖고 있던 다양한 한계를 해결하고 만들어졌습니다. 그래서 Winform에 비해서 더 다양한 기능과 확장성을 갖고 있습니다. 

Winform에서는 Form이라면 Wpf에서는 Control이 있습니다. Control을 상속 받아서 다양한 Control이 생성되는데요. Window, UserControl, Button 처럼 다양한 Control을 만들 수 있습니다. 

처음 Wpf 프로젝트를 생성하면 MainWindow.xaml 이라는 것을 볼 수 있는데요. 이는 C# 코드와 xaml 코드가 합쳐진 형태입니다. 그래서 xaml 코드를 이용해서 디자인 작업을 하고 C# 코드를 이용해서 필요한 기능을 구현하기도 합니다. 

위쪽이 C# 코드이고 아래쪽이 xaml 코드입니다. 실제로 xaml 코드는 다양한 곳에서 사용되는데요. 여기서 xaml은 Extensible Application Markup Language 의 약자로 흔히 마크업 언어라고 불리는 언어들 중에 하나인데요. 인터넷 브라우저에서 F12를 누르면 나오는 코드들과 비슷한 형태의 코드라고 보시면 됩니다. 

WPF는 Winform의 한계를 극복하기 위해서 그리고 더 다양한 확장성을 갖기 위해서 만들어진 UI 개발 프레임워크인데요. 처음 WPF와 Winform을 접하는 분들에게는 Winform 더 직관적이고 쉬울 수 있으나, 실제 실무에서는 Winform 보다는 Wpf를 더 많이 사용하고 있고, 다양한 클라이언트의 요구를 만족시키기 위해서라도 Wpf가 더 좋은 선택이라고 생각하는데요. 한번 배우는데, 오래 걸리고 MVVM이나 Binding, DependencyProperty 와 같은 생소한 개념들이 있기 때문에 거부감이 들 수 있지만, 이러한 기능들은 개발자의 편의를 위해서 개발된 기능이기 때문에 충분히 익힌다면, 오히려 도움이 될 것이라고 생각합니다. 


In C#,,,,,,,,

When Owner draw Control ,,,,,,,,,,,,

ex105.cs
0.00MB

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

...

/// <summary>
/// 메시지 보내기
/// </summary>
/// <param name="windowHandle">윈도우 핸들</param>
/// <param name="message">메시지</param>
/// <param name="wParam">WORD 파리미터</param>
/// <param name="lParam">LONG 파라미터</param>
/// <returns>처리 결과</returns>
[DllImport("User32.dll")]
public static extern Int64 SendMessage(IntPtr windowHandle, uint message, IntPtr wParam, IntPtr lParam);

...

/// <summary>
/// WM_PAINT
/// </summary>
private const int WM_PAINT = 0x000f;

...

#region ForcePaint(form)

/// <summary>
/// 강제로 칠하기
/// </summary>
/// <param name="form">폼</param>
public void ForcePaint(Form form)
{
    SendMessage(form.Handle, WM_PAINT, IntPtr.Zero, IntPtr.Zero);
}

#endregion


설명) Form에 테트리스게임이 수행되고 인는중이라도, 백그라운드로 쓰레드 2개가 현재 동작하는 모습을 나타냅니다.
여러모로 실전활용가능한 모델입니다.

1. Form Activate & Other Statistic Possible(Threading Background)
2. BackgroundWorker
3. Form Drawing
4. Data set,get
5. Tris
6. Form - WM_PAINT Logic

basic !!

ex11.cs
0.01MB

Background class
Tris class divide!!!

ex12.cs
0.01MB

static class ----> #define instead!!

ex13.cs
0.01MB

design pattern various!!

ex14.cs
0.01MB

/*
 * BackgroundWorker 사용법 : Form 혹은 Console이 사라지면 함께 작동을 멈춘다.
 * BackgroundWorker 클래스
   네임스페이스: System.ComponentModel
 */


using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Threading;

public class Program : Form
{
int toggle=0;

public Program()
{
this.Text="BackgroungWorker Thread Process!!";
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if ((msg.Msg == WM_KEYDOWN) || (msg.Msg == WM_SYSKEYDOWN))
{
         switch (keyData)
         {
         case Keys.S:
             break; 
         case Keys.F5:
             break; 
         case Keys.Enter:
             Application.Exit();
             break;
         case Keys.Tab:
             break;
         default:
             break;
         }
     }
return base.ProcessCmdKey(ref msg, keyData);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);

try
{
switch(m.Msg)
{
default:
if(toggle==0)
{
BackgroundMakeCls nm = new BackgroundMakeCls();
nm.running();

toggle=100; //Form이 실행시에 오직 한번만 수행하도록 한다.
}
break;
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Program());
}
}

public class BackgroundMakeCls
{
BackgroundWorker recvWorker = new BackgroundWorker();
BackgroundWorker sendWorker = new BackgroundWorker();

public void running()
{
recvWorker.DoWork += new DoWorkEventHandler(recvWorker_DoWork);
recvWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(recvWorker_RunWorkerCompleted);

sendWorker.DoWork += new DoWorkEventHandler(sendWorker_DoWork);
sendWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(sendWorker_RunWorkerCompleted);

recvWorker.RunWorkerAsync();
}
void recvWorker_DoWork(object sender, DoWorkEventArgs e)
{
Console.WriteLine(">>>>recvWorker_DoWork");
}
void recvWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
Console.WriteLine(">>>>recvWorker_RunWorkerCompleted");

try
{
if(! sendWorker.IsBusy) sendWorker.RunWorkerAsync();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
void sendWorker_DoWork(object sender, DoWorkEventArgs e)
{
Console.WriteLine(">>>>recvWorker_DoWork");
}
void sendWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine(">>>>recvWorker_RunWorkerCompleted");

try
{
if(! recvWorker.IsBusy) recvWorker.RunWorkerAsync();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;


class Program
{
public static void Main(string[] args)
{
ContinueNoLoginCls nm = new ContinueNoLoginCls();
nm.running();
}
}

class ContinueNoLoginCls
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

[DllImport("User32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("User32.dll")]
public static extern IntPtr FindWindowEx(int hWnd1, int hWnd2, string lpClassName, string lpWindowName);

const uint WM_KEYDOWN = 0x0100;
const uint WM_KEYUP = 0x0101;
const uint WM_CHAR = 0x0102;
const int VK_TAB = 0x09;
const int VK_ENTER = 0x0D;
const int VK_UP = 0x26;
const int VK_DOWN = 0x28;
const int VK_RIGHT = 0x27;
const int VK_F5 = 0x74;
const int VK_F6 = 0x75;
 
//According to SPY++ in IE

//ENTER key is
// P KEYDOWN
// P CHAR
// S CHAR
// P KEY_UP

//TAB key is
// P KEYDOWN
// P KEYUP

//DOWN, UP, RIGHT, LEFT is
// P KEYDOWN
// S KEYDOWN
// P KEYUP

//Letters is
// P KEYDOWN
// S KEYDOWN
// P CHAR
// S CHAR
// P KEYUP

IntPtr tailHandle = IntPtr.Zero;
IntPtr Handle_1 = IntPtr.Zero;
IntPtr Handle_2 = IntPtr.Zero;
//const string captionmsg="파일 탐색기";
//const string captionmsg="명령 프롬프트";
const string captionmsg="네이버 부동산 - Microsoft Edge";

public void running()
{
Console.Title = "";
tailHandle = FindWindow(null, captionmsg);

ConsoleKeyInfo keyinfo;

while(true)
{
keyinfo=Console.ReadKey(true);

debug(">>>>KEY:[" + keyinfo.Key.ToString() + "]");

if(keyinfo.Key==ConsoleKey.Enter)
{
debug(">>>>SendTab() method call!!");
SendTab();
}
else if(keyinfo.Key==ConsoleKey.RightArrow)
{
debug(">>>>SendArrowKey() method call!!");
SendChar(VK_F5);
}
else if(keyinfo.Key==ConsoleKey.Spacebar)
{
debug(">>>>SendArrowKey() method call!!");
SendArrowKey(VK_F5);
}

else if(keyinfo.Key==ConsoleKey.Escape)
{
debug(">>>>Quit() method call!!");
break;
}
}
}

void debug(string str)
{
Console.WriteLine(str);
}

    private void SendEnter()
    {
        PostMessage(tailHandle, WM_KEYDOWN, (IntPtr)VK_ENTER, IntPtr.Zero);
        PostMessage(tailHandle, WM_CHAR, (IntPtr)VK_ENTER, IntPtr.Zero);
        SendMessage(tailHandle, WM_CHAR, (IntPtr)VK_ENTER, IntPtr.Zero);
        PostMessage(tailHandle, WM_KEYUP, (IntPtr)VK_ENTER, IntPtr.Zero);
    }

    private void SendTab()
    {
        PostMessage(tailHandle, WM_KEYDOWN, (IntPtr)VK_TAB, IntPtr.Zero);
        PostMessage(tailHandle, WM_KEYUP, (IntPtr)VK_TAB, IntPtr.Zero);
    }

    private void SendArrowKey(int key)
    {
        PostMessage(tailHandle, WM_KEYDOWN, (IntPtr)key, IntPtr.Zero);
        SendMessage(tailHandle, WM_KEYDOWN, (IntPtr)key, IntPtr.Zero);
        PostMessage(tailHandle, WM_KEYUP, (IntPtr)key, IntPtr.Zero);
    }

    private void SendChar(int key)
    {
        //Keydown wParam values are 0x020 less than WM_CHAR wParam
        PostMessage(tailHandle, WM_KEYDOWN, (IntPtr)(key - 0x020), IntPtr.Zero);
        SendMessage(tailHandle, WM_KEYDOWN, (IntPtr)(key - 0x020), IntPtr.Zero);
        PostMessage(tailHandle, WM_CHAR, (IntPtr)key, IntPtr.Zero);
        SendMessage(tailHandle, WM_CHAR, (IntPtr)key, IntPtr.Zero);
        PostMessage(tailHandle, WM_KEYUP, (IntPtr)(key - 0x020), IntPtr.Zero);
    }
}



Assembly.LoadFrom() : DLL 활용하여, Form을 띄우기
/*----------------------------------------------------------------------
Description : 클래스라이브러리로 생성되어진 폼을 띄울때에 사용되어진다.(폼형태만 가지고 인는것을 폼처럼 만들어서 띄울수있다.)
ex) 
1. frm's name : UAPDBMQ0010
2. dll's name : DBM.DLL
----------------------------------------------------------------------*/

sample code>>

string formName = "UAPDBMQ0010";
string dllName = formName.Substring(3,3); //DBM.DLL
string assembly = dllName + ".DLL";
string classname = dllName + "." + formName;

Assembly asm = Assembly.LoadFrom(assembly);
object o = asm.CreateInstance(classname);
var doc = (Form)o;

Form frm = doc;
frm.Tag = assembly;
if(frm == null) return null;

frm.MdiParent = this; //MDI CASE
frm.FormBorderStyle = FormBorderStyle.None; //NEW FORM
frm.Dock = DockStyle.Fill //POPUP, WHEN DELETE

frm.Text="";
frm.TopLevel=false;
frm.Parent=this;
frm.Show();

[C#] PDB(*.pdb) 파일(?)

PDB 파일이란 무엇이며 솔루션을 다시 빌드 할 때 릴리스 폴더에서 PDB 파일을 어떻게 제외시킬 수 있습니까?

PDB 파일에는 디버거가 작업 할 정보가 들어 있습니다. 
릴리스 빌드에는 디버그 빌드보다 정보가 적습니다. 
그러나 전혀 생성하지 않으려면 프로젝트의 빌드 속성으로 이동하여 릴리스 구성을 선택하고 “고급 …”을 클릭 한 다음 
"디버그 정보"에서 "없음"을 선택하십시오.

오늘까지는 Exception.StackTrace예외를 해결하는 데 필요한 파일 및 줄 번호 정보가없는 메시지 상자에 왜 누락 되었는지 알아 내려고 시도 할 때까지 모든 것이 제대로 작동했습니다 . 
이 게시물을 다시 읽고 중요한 정보를 발견했습니다 
.PDB는 앱을 실행하는 데 필요하지 않지만 파일과 줄 번호가 StackTrace문자열 에 있어야 합니다. 
PDB 파일을 실행 가능 폴더에 포함 시켰으며 이제는 모두 정상입니다.

PDB 는 P rogram D ata B ase 의 약자입니다. 
이름에서 알 수 있듯이 프로그램을 디버그 모드로 실행하는 데 필요한 정보를 유지 관리하는 저장소 (데이터베이스와 같은 영구 저장소)입니다. 
여기에는 코드를 디버깅하는 동안 (Visual Studio에서) 디버거가 Visual Studio에서 중단 될 것으로 예상되는 지점을 삽입 한 지점과 같은 중요한 관련 정보가 많이 포함되어 있습니다.

*.pdb디버그 폴더에서 파일 을 제거하면 Visual Studio가 중단 점에 여러 번 실패하는 이유 입니다. Visual Studio 디버거는 파일을 사용하여 스택 추적에서 예외가 발생한 정확한 줄 번호의 코드 파일을 알려줄 수도 *.pdb있습니다. 따라서 효과적으로 pdb 파일은 프로그램을 디버깅하는 동안 개발자에게 큰 도움이됩니다.

일반적으로 *.pdb파일 생성을 제외하지 않는 것이 좋습니다 . 
프로덕션 릴리스 관점에서해야 할 일은 pdb 파일을 작성하지만 제품 설치 프로그램의 고객 사이트에는 제공하지 않는 것입니다. 
생성 된 모든 PDB 파일을 필요한 경우 나중에 사용 / 참조 할 수있는 기호 서버에 보존하십시오. 
특히 프로세스 충돌과 같은 문제를 디버깅하는 경우에 적합합니다. 
크래시 덤프 파일 분석을 시작하고 *.pdb빌드 프로세스 중에 만들어진 원본 파일이 유지되지 않으면 Visual Studio에서 크래시를 일으키는 정확한 코드 줄을 만들 수 없습니다 .

PDB 파일은 디버거에 의해 사용되는 정보가 포함되어 있습니다. 
응용 프로그램을 실행할 필요가 없으며 릴리스 된 버전에 포함시킬 필요가 없습니다.

Visual Studio에서 pdb 파일이 생성되지 않도록 설정할 수 있습니다. 
명령 행 또는 스크립트에서 빌드하는 경우 /Debug스위치 를 생략하십시오.


C#프로젝트를 빌드하면, exe 혹은 dll파일과 함께 pdb파일도 함께 나오는 것을 종종 확인하셨을 것입니다.
pdb파일은 프로그램을 디버깅할 때 필요한 파일입니다.
pdb파일 속에는 디버깅에 필요한 정보들이 포함되어 있습니다.
이 말을 뒤집으면 프로그램을 배포할 때에는 pdb파일이 있어선 안 되겠죠.
그래서 혹시 배포 패키지에 pdb파일이 섞여 들어가는 것을 막기 위해 빌드 옵션을 설정할 수가 있습니다.
그럼 지금부터 pdb파일을 나오게 하는 법, 안 나오게 하는법에 대해 알아보도록 하겠습니다.

>>>>PDB파일 안나오게 하는 법

1. 프로젝트 우클릭 2. Properties 클릭 3. 좌측의 Build 클릭 4. Advanced 클릭 5. Debugging information을 Pdb-only로 설정

 

+ Recent posts