달력

0

« 2025/6 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
2016. 8. 26. 16:49

예외 및 예외 처리 프로그래밍/C#2016. 8. 26. 16:49

https://msdn.microsoft.com/ko-kr/library/ms173160.aspx



예외 및 예외 처리


1. C# 언어에서는 프로그램 실행 중에 발생하는 예기치 않은 상황이나 예외 상황을 처리하기 위한 예외 처리 기능을 제공합니다.

2. 예외 처리에는 성공하지 않을 수 있는 작업을 시도하고, 작업을 수행할 이유가 있는지 결정되었을 때 오류를 처리하고, 나중에 리소스를 정리하기 위한 try, catch 및 finally 키워드가 사용됩니다.

3. 예외는 CLR(공용 언어 런타임), .NET Framework나 타사 라이브러리 또는 응용 프로그램 코드에서 발생할 수 있습니다.

4. 이러한 예외는 throw 키워드를 사용하여 생성됩니다.

5. 대부분의 경우 예외는 코드에서 직접 호출한 메서드가 아니라 호출 스택 아래쪽에 있는 다른 메서드에서 throw됩니다.

6. 이런 경우 CLR에서는 스택을 해제하여 특정 예외 형식에 대한 catch 블록이 있는 메서드를 찾고, 찾은 경우 첫 번째 catch 블록을 실행합니다.

7. 호출 스택에서 해당하는 catch 블록을 찾지 못한 경우 CLR은 프로세스를 종료하고 사용자에게 메시지를 표시합니다.

8. 이 예제의 메서드에서는 0으로 나누기 여부를 테스트하고 오류를 catch합니다.

9. 예외를 처리하지 않는다면 이 프로그램은 DivideByZeroException was unhandled 오류 메시지와 함께 종료됩니다.


class ExceptionTest
{
    static double SafeDivision(double x, double y)
    {
        if (y == 0)
            throw new System.DivideByZeroException();
        return x / y;
    }
    static void Main()
    {
        // Input for test purposes. Change the values to see
        // exception handling behavior.
        double a = 98, b = 0;
        double result = 0;

        try
        {
            result = SafeDivision(a, b);
            Console.WriteLine("{0} divided by {1} = {2}", a, b, result);
        }
        catch (DivideByZeroException e)
        {
            Console.WriteLine("Attempted divide by zero.");
        }
    }
}


예외 개요

1. 예외에는 다음과 같은 속성이 있습니다.

1) 예외는 모두 궁극적으로 System.Exception에서 파생되는 형식입니다.

2) 예외가 throw될 가능성이 있는 문 주위에 try 블록을 추가합니다.

3) try 블록 내에서 예외가 발생한 경우 호출 스택에 있는 첫 번째 관련 예외 처리기로 제어 흐름이 이동합니다. C#에서 예외 처리기를 정의하는 데는 catch 키워드가 사용됩니다.

4) 발생한 예외에 대한 예외 처리기가 없으면 프로그램의 실행이 중지되고 오류 메시지가 나타납니다.

5) 예외를 처리할 수 없는 경우 예외를 catch하지 않고 응용 프로그램을 알려진 상태로 두어야 합니다. System.Exception을 catch한 경우 catch 블록 끝에서 throw 키워드를 사용하여 다시 throw합니다.

6) catch 블록에 예외 변수가 정의된 경우 이를 통해 발생한 예외 형식에 대한 자세한 정보를 확인할 수 있습니다.

7) throw 키워드를 사용하면 프로그램에서 예외를 명시적으로 생성할 수 있습니다.

8) 예외 개체에는 호출 스택의 상태와 오류를 설명하는 텍스트를 비롯하여 오류에 대한 자세한 정보가 포함됩다.

9) finally 블록의 코드는 예외가 throw되어도 실행되므로 finally 블록을 사용하여 리소스를 해제합니다. 예를 들어, try 블록에 열려 있는 스트림이나 파일을 닫습니다.

10) .NET Framework의 관리되는 예외는 Win32 구조적 예외 처리 메커니즘을 기반으로 구현됩니다. 자세한 내용은 구조적 예외 처리 (C/C++) 및 A Crash Course on the Depths of Win32 Structured Exception Handling을 참조하십시오.




예외 사용


1. C#의 경우 런타임에 발생하는 프로그램 오류는 예외라는 메커니즘을 사용하여 프로그램을 통해 전파됩니다.

2. 예외는 오류를 발견한 코드에서 throw되고 오류를 수정할 수 있는 코드에서 catch됩니다.

3. 예외는 .NET Framework CLR(공용 언어 런타임)을 통해 throw되거나 프로그램의 코드를 통해 throw될 수 있습니다.

4. throw된 예외는 예외에 대한 catch 문을 만날 때까지 호출 스택을 거슬러 올라가며 전파됩니다.

5. catch되지 않은 예외는 대화 상자를 표시하는 시스템에서 제공하는 제네릭 예외 처리기를 사용하여 처리됩니다.

6. 예외를 나타내는 데는 Exception에서 파생된 클래스가 사용됩니다.

7. 예외의 형식을 식별하는 이 클래스에는 예외에 대한 자세한 정보가 있는 속성이 들어 있습니다.

8. 예외를 throw하려면 예외 파생 클래스의 인스턴스를 만들고 선택적으로 예외의 속성을 구성한 다음 throw 키워드를 사용하여 개체를 throw해야 합니다.

9. 예를 들면 다음과 같습니다.


class CustomException : Exception
{
    public CustomException(string message)
    {

    }

}
private static void TestThrow()
{
    CustomException ex =
        new CustomException("Custom exception in TestThrow()");

    throw ex;
}


10. 예외가 throw되면 런타임에서는 현재 문이 try 블록 내에 있는지 검사합니다.

11. 현재 문이 이 블록 내에 있으면 try 블록과 관련된 catch 블록을 모두 검사하여 예외를 catch할 수 있는지 확인합니다.

12. Catch 블록은 일반적으로 예외 형식을 지정합니다.

13. catch 블록의 형식이 예외의 형식과 동일하거나 예외의 기본 클래스와 동일한 형식이면 catch 블록에서 메서드를 처리할 수 있습니다. 예를 들면 다음과 같습니다.


static void TestCatch()
{
    try
    {
        TestThrow();
    }
    catch (CustomException ex)
    {
        System.Console.WriteLine(ex.ToString());
    }
}


14. 예외를 throw하는 문이 try 블록 안에 있지 않거나 이를 포함하는 try 블록에 대응하는 catch 블록이 없는 경우 런타임에서는 catch 블록과 try 문을 찾기 위해 호출 메서드를 검사합니다.

15. 런타임은 호출 스택을 거슬러 올라가며 호환되는 catch 블록을 계속 찾습니다.

16. catch 블록을 찾아 실행한 후에는 제어가 catch 블록 다음에 있는 문으로 전달됩니다.

17. try 문에는 catch 블록이 여러 개 포함될 수 있습니다.

18. 예외를 처리할 수 있는 첫 번째 catch 문이 실행되고 이후의 catch 문은 호환되는 문이어도 모두 무시됩니다.

19. 따라서, 항상 가장 구체적인(또는 가장 많이 파생되는) 경우부터 가장 일반적인 경우의 순서로 catch 블록을 지정해야 합니다.

20. 예를 들면 다음과 같습니다.


static void TestCatch2()
{
    System.IO.StreamWriter sw = null;
    try
    {
        sw = new System.IO.StreamWriter(@"C:\test\test.txt");
        sw.WriteLine("Hello");
    }

    catch (System.IO.FileNotFoundException ex)
    {
        // Put the more specific exception first.
        System.Console.WriteLine(ex.ToString());  
    }

    catch (System.IO.IOException ex)
    {
        // Put the less specific exception last.
        System.Console.WriteLine(ex.ToString());  
    }
    finally 
    {
        sw.Close();
    }

    System.Console.WriteLine("Done"); 
}


21. catch 블록을 실행하기 전에 런타임은 finally 블록을 확인합니다.

22. Finally 블록을 사용하면 취소된 try 블록에서 남겨질 수 있는 모호한 상태를 모두 정리할 수 있고 런타임에 가비지 수집기가 개체를 종결하기를 기다리지 않고도 그래픽 핸들, 데이터베이스 연결, 파일 스트림 등의 외부 리소스를 해제할 수 있습니다.

23. 예를 들면 다음과 같습니다.


static void TestFinally()

{
    System.IO.FileStream file = null;
    //Change the path to something that works on your machine.
    System.IO.FileInfo fileInfo = new System.IO.FileInfo(@"C:\file.txt");

    try
    {
        file = fileInfo.OpenWrite();
        file.WriteByte(0xF);
    }
    finally
    {
        // Closing the file allows you to reopen it immediately - otherwise IOException is thrown.
        if (file != null)
        {
            file.Close();
        }
    }

    try
    {
        file = fileInfo.OpenWrite();
        System.Console.WriteLine("OpenWrite() succeeded");
    }
    catch (System.IO.IOException)
    {
        System.Console.WriteLine("OpenWrite() failed");
    }
}


24. WriteByte()에서 예외를 throw한 경우 file.Close()를 호출하지 않으면 파일을 다시 열려고 하는 두 번째 try 블록의 코드가 실패하고 해당 파일은 잠금 상태로 유지됩니다.

25. finally 블록은 예외가 throw되는지 여부와 상관없이 실행되므로 위 예제에서 finally 블록을 사용하면 파일을 올바르게 닫고 오류를 방지할 수 있습니다.

26. 예외가 throw된 후에 호출 스택에서 호환되는 catch 블록을 찾지 못하면 다음 세 가지 결과 중 하나가 발생합니다.

1) 예외가 소멸자 내에 있는 경우에는 소멸자가 취소되고 기본 생성자가 있으면 이 생성자가 호출됩니다.

2) 호출 스택에 정적 생성자 또는 정적 필드 이니셜라이저가 있는 경우에는 원래 예외가 새 예외의 InnerException 속성에 할당된 상태로 TypeInitializationException이 throw됩니다.

3) 스레드의 시작 부분에 도달하면 스레드가 종료됩니다.




예외 처리


1. try 블록은 C# 프로그래머가 예외의 영향을 받을 수 있는 코드를 분할하는 데 사용됩니다.

2. 관련 catch 블록은 예외 결과를 처리하는 데 사용됩니다.

3. finally 블록에는 try 블록에 할당된 리소스의 해제 같이 try 블록에서 예외가 throw되는지 여부에 관계 없이 실행되는 코드가 포함되어 있습니다.

4. try 블록에서는 하나 이상의 관련 catch 블록이나 finally 블록, 또는 두 블록 모두를 필요로 합니다.

5. 다음 예제는 try-catch 문, try-finally 문 및 try-catch-finally 문을 보여 줍니다.


try
{
    // Code to try goes here.
}
catch (SomeSpecificException ex)
{
    // Code to handle the exception goes here.
    // Only catch exceptions that you know how to handle.
    // Never catch base class System.Exception without
    // rethrowing it at the end of the catch block.
}


try
{
    // Code to try goes here.
}
finally
{
    // Code to execute after the try block goes here.
}


try
{
    // Code to try goes here.
}
catch (SomeSpecificException ex)
{
    // Code to handle the exception goes here.
}
finally
{
    // Code to execute after the try (and possibly catch) blocks 
    // goes here.
}


catch 또는 finally 블록이 없는 try 블록은 컴파일러 오류가 발생합니다.


catch 블록

1. catch 블록에서는 catch할 예외 형식을 지정할 수 있습니다.

2. 형식 지정을 예외 필터라고 합니다.

3. 예외 형식은 Exception에서 파생되어야 합니다.

4. 일반적으로, try 블록에서 throw될 수 있는 모든 예외를 처리하는 방법을 명확히 알고 있거나 catch 블록의 끝에 throw 문을 포함하는 경우가 아니라면 Exception을 예외 필터로 지정해서는 안 됩니다.

5. 예외 필터가 서로 다른 여러 개의 catch 블록을 함께 연결할 수 있습니다.

6. catch 블록이 코드 내 위에서 아래 순으로 계산되지만 throw된 각 예외에 대해서는 catch 블록이 하나만 실행됩니다.

7. throw된 예외의 정확한 형식이나 기본 클래스를 지정하는 첫 번째 catch 블록이 실행됩니다.

8. 일치하는 예외 필터를 지정하는 catch 블록이 없는 경우 문에 블록이 표시된 경우 필터가 없는 catch 블록이 선택됩니다.

9. catch 블록은 가장 구체적인, 즉 가장 많이 파생되는 예외 형식에 먼저 배치해야 합니다.

10. 다음 조건에 해당되면 예외를 catch해야 합니다.

1) 이제 예외가 throw될 수 있는 이유에 대해 올바르게 이해했으며 FileNotFoundException 개체를 catch할 때 새 파일 이름을 입력하라는 메시지가 표시되는 경우와 같이 상황에 맞게 적절한 복구를 구현할 수 있습니다.

2) 더 구체적인 새 예외를 만들고 throw할 수 있는 경우입니다.


int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch(System.IndexOutOfRangeException e)
    {
        throw new System.ArgumentOutOfRangeException(
            "Parameter index is out of range.");
    }
}


3) 추가 처리를 위해 전달하기 전에 예외를 부분적으로 처리합니다. 다음 예제에서 catch 블록은 예제를 다시 throw하기 전에 오류 로그에 항목을 추가하는 데 사용됩니다.


try
{
    // Try to access a resource.
}
catch (System.UnauthorizedAccessException e)
{
    // Call a custom error logging procedure.
    LogError(e);
    // Re-throw the error.
    throw;     
}


finally 블록

1. finally 블록에서는 try 블록에서 수행되는 작업을 정리할 수 있습니다.

2. finally 블록이 있는 경우 이 블록은 try 및 일치하는 모든 catch 블록을 실행한 후에 마지막으로 실행됩니다.

3. finally 블록은 예외가 throw되었는지 여부나 예외 형식이 일치하는 catch 블록을 찾았는지 여부와 상관없이 항상 실행됩니다.

4. finally 블록을 사용하면 런타임에 가비지 수집기가 개체를 종료할 때까지 기다리지 않고도 파일 스트림, 데이터베이스 연결, 그래픽 핸들 등의 리소스를 해제할 수 있습니다.

5. 자세한 내용은 using 문(C# 참조)를 참조하십시오.

6. 다음 예제에서 finally 블록은 try 블록에 열려 있는 파일을 닫는 데 사용됩니다.

7. 파일을 닫기 전에 파일 핸들의 상태를 검사합니다.

8. try 블록에서 파일을 열 수 없는 경우 파일 핸들에는 null 값이 여전히 있으며 finally 블록을 닫기 위한 시도를 하지 않습니다.

9. 또는 try 블록에서 파일이 성공적으로 열린 경우 finally 블록은 열린 파일을 닫습니다.


System.IO.FileStream file = null;
System.IO.FileInfo fileinfo = new System.IO.FileInfo("C:\\file.txt");
try
{
    file = fileinfo.OpenWrite();
    file.WriteByte(0xF);
}
finally
{
    // Check for null because OpenWrite might have failed.
    if (file != null)
    {
        file.Close();
    }
}




예외 만들기 및 Throw


1. 예외는 프로그램을 실행하는 동안 오류가 발생한 경우 이를 알리는 데 사용됩니다.

2. 오류를 설명하는 예외 개체가 작성된 다음 throw 키워드를 사용하여 throw됩니다.

3. 런타임에서는 가장 적합한 예외 처리기를 검색합니다.

4. 프로그래머는 다음과 같은 조건 중 하나 이상이 true일 때 예외를 throw해야 합니다.

1) 메서드의 정의된 기능을 완료할 수 없는 경우.

2) 메서드의 매개 변수 값이 잘못된 경우를 예로 들 수 있습니다.


static void CopyObject(SampleClass original)
{
    if (original == null)
    {
        throw new System.ArgumentException("Parameter cannot be null", "original");
    }

}


3) 개체 상태를 기준으로 개체에 대한 적절하지 않은 호출을 수행한 경우.

읽기 전용 파일에 쓰려고 하는 경우를 예로 들 수 있습니다. 개체 상태 때문에 작업을 수행할 수 없는 경우 InvalidOperationException의 인스턴스나 이 클래스의 파생을 기반으로 한 개체가 throw됩니다. 다음은 InvalidOperationException 개체를 throw하는 메서드의 예제입니다.


class ProgramLog
{
    System.IO.FileStream logFile = null;
    void OpenLog(System.IO.FileInfo fileName, System.IO.FileMode mode) {}

    void WriteLog()
    {
        if (!this.logFile.CanWrite)
        {
            throw new System.InvalidOperationException("Logfile cannot be read-only");
        }
        // Else write data to the log and return.
    }
}


4) 메서드에 대한 인수로 인해 예외가 발생하는 경우.

이 경우 원래 예외를 catch하고 ArgumentException 인스턴스를 만들어야 합니다. 원래 예외를 ArgumentException의 생성자에 InnerException 매개 변수로 전달해야 합니다.


static int GetValueFromArray(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch (System.IndexOutOfRangeException ex)
    {
        System.ArgumentException argEx = new System.ArgumentException("Index is out of range", "index", ex);
        throw argEx;
    }
}


5. 예외에는 StackTrace라는 속성이 있습니다.

6. 이 문자열에는 현재 호출 스택에 포함된 메서드의 이름이 각 메서드에 대해 예외가 throw된 파일 이름 및 줄 번호와 함께 포함됩니다.

7. StackTrace 개체는 throw 문이 실행되는 지점에서 CLR(공용 언어 런타임)에 의해 자동으로 작성되므로 스택 추적을 시작해야 할 지점에서 예외가 throw됩니다.

8. 모든 예외에는 Message라는 속성이 있습니다.

9. 이 문자열에는 예외의 원인에 대한 설명을 설정해야 합니다.

10. 메시지 텍스트에는 중요한 보안 정보가 포함되지 않도록 주의해야 합니다.

11. ArgumentException에는 Message 이외에 ParamName이라는 속성도 있으며, 이 속성에는 throw할 예외를 발생시킨 인수의 이름을 설정해야 합니다.

12. 속성 setter의 경우 ParamName은 value로 설정해야 합니다.

13. 공용 메서드와 보호된 메서드 멤버는 해당 함수를 완료할 수 없을 때마다 예외를 throw해야 합니다.

14. throw되는 예외 클래스는 오류 조건에 맞는 가장 구체적인 예외여야 합니다.

15. 이러한 예외는 클래스 기능의 일부로 문서화해야 하며 원본 클래스에 대한 업데이트나 파생 클래스는 역호환성을 위해 이와 동일한 동작을 유지해야 합니다.


예외를 throw할 때 주의해야 할 사항

1. 다음은 예외를 throw할 때 주의해야 할 사항입니다.

1) 예외는 일반적인 실행의 일부로 프로그램의 흐름을 변경하는 데 사용하면 안 됩니다. 예외는 오류를 보고하고 처리하는 용도로만 사용해야 합니다.

2) 예외는 반환 값이나 매개 변수로 반환하지 말고 반드시 throw해야 합니다.

3) 사용자가 직접 작성한 코드에서 System.Exception, System.SystemException, System.NullReferenceException 또는 System.IndexOutOfRangeException을 고의적으로 throw하면 안 됩니다.

4) 릴리스 모드가 아니라 디버그 모드에서 throw될 수 있는 예외는 만들면 안 됩니다. 개발 단계에서 런타임 오류를 식별하려면 Debug Assert를 대신 사용하십시오.


예외 클래스 정의

1. 프로그램에서는 앞서 언급한 경우를 제외하고 System 네임스페이스에 미리 정의된 예외 클래스를 throw하거나 Exception에서 파생된 고유한 예외 클래스를 만들 수 있습니다.

2. 파생 클래스에서는 기본 생성자, 메시지 속성을 설정하는 생성자, Message 및 InnerException 속성을 모두 설정하는 생성자 등 적어도 네 개의 생성자를 정의해야 합니다.

3. 네 번째 생성자는 예외를 serialize하는 데 사용됩니다.

4. 새 예외 클래스는 serialize 가능해야 합니다.

5. 예를 들면 다음과 같습니다.


[Serializable()]
public class InvalidDepartmentException : System.Exception
{
    public InvalidDepartmentException() : base() { }
    public InvalidDepartmentException(string message) : base(message) { }
    public InvalidDepartmentException(string message, System.Exception inner) : base(message, inner) { }

    // A constructor is needed for serialization when an
    // exception propagates from a remoting server to the client. 
    protected InvalidDepartmentException(System.Runtime.Serialization.SerializationInfo info,
        System.Runtime.Serialization.StreamingContext context) { }
}


6. 새 속성은 예외를 해결하는 데 유용한 데이터를 제공하는 경우 예외 클래스에만 추가해야 합니다.

7. 새 속성을 파생된 예외 클래스에 추가하면 추가된 정보를 반환하도록 ToString()을 재정의해야 합니다.



컴파일러 생성 예외


1. 기본 작업이 실패하면 몇 가지 예외가 .NET Framework의 CLR(공용 언어 런타임)에서 자동으로 throw됩니다.

2. 다음 표에서는 이러한 예외와 오류 조건을 보여 줍니다.


Exception

설명

ArithmeticException

DivideByZeroException 및 OverflowException 등의 산술 연산 과정에서 발생하는 예외에 대한 기본 클래스

ArrayTypeMismatchException

저장된 요소의 실제 형식이 배열의 실제 형식과 호환되지 않기 때문에 배열에서 해당 요소를 저장하지 못하는 경우

DivideByZeroException

정수 계열 값을 0으로 나누려고 한 경우

IndexOutOfRangeException

배열을 인덱싱하려 할 때 인덱스가 0보다 작거나 배열 경계를 벗어난 경우

InvalidCastException

런타임에 기본 형식에서 인터페이스나 파생 형식으로의 명시적 변환이 실패한 경우

NullReferenceException

값이 null인 개체를 참조할 경우

OutOfMemoryException

new 연산자를 사용하여 메모리를 할당하는 데 실패한 경우. 이는 공용 언어 런타임에 사용할 수 있는 메모리가 부족하다는 것을 의미합니다.

OverflowException

checked 컨텍스트에서 산술 연산이 오버플로된 경우

StackOverflowException

보류된 메서드 호출이 너무 많아서 실행 스택이 부족한 경우. 일반적으로 너무 깊은 재귀 호출이나 무한 재귀 호출을 나타냅니다.

TypeInitializationException

정적 생성자가 예외를 throw했지만 이를 catch할 catch 절이 없는 경우



방법: try/catch를 사용하여 예외 처리


1. try-catch 블록의 사용 목적은 작업 코드에서 발생하는 예외를 catch하여 처리하는 것입니다.

2. 일부 예외는 catch 블록에서 처리할 수 있고 예외를 다시 throw할 필요 없이 문제가 해결됩니다.

3. 그러나 대부분의 경우에는 적절한 예외가 throw되었는지 확인하는 작업만 할 수 있습니다.


예제

1. 다음 예제에서 IndexOutOfRangeException은 가장 적절한 예외가 아닙니다.

2. 이 오류는 호출자가 전달한 index 인수 때문에 발생한 것이므로 해당 메서드에는 ArgumentOutOfRangeException이 보다 적절합니다.


class TestTryCatch
{
    static int GetInt(int[] array, int index)
    {
        try
        {
            return array[index];
        }
        catch (System.IndexOutOfRangeException e)  // CS0168
        {
            System.Console.WriteLine(e.Message);
            // Set IndexOutOfRangeException to the new exception's InnerException.
            throw new System.ArgumentOutOfRangeException("index parameter is out of range.", e);
        }
    }
}


설명

1. 예외가 발생한 코드는 try 블록으로 묶여 있습니다.

2. 예외가 발생할 때 IndexOutOfRangeException을 처리하기 위한 catch 문이 바로 다음에 추가되어 있습니다.

3. catch 블록에서는 IndexOutOfRangeException을 처리하고 보다 적합한 ArgumentOutOfRangeException 예외를 대신 throw합니다.

4. 호출자에 가능한 한 많은 정보를 제공하려면 원래 예외를 새 예외의 InnerException으로 지정하는 것이 좋습니다.

5. InnerException 속성은 읽기 전용이므로 새 예외의 생성자에서 이 속성을 할당해야 합니다.




방법: finally를 사용하여 정리 코드 실행


1. finally 문의 목적은 예외가 throw되더라도 개체에 필요한 정리 작업을 즉시 수행하는 데 있습니다.

2. 이러한 개체는 일반적으로 외부 리소스를 사용하는 개체입니다.

3. 이러한 정리 작업의 예로는 다음과 같이 공용 언어 런타임에 의해 개체가 가비지 수집되기를 기다리는 대신 사용 직후에 FileStream에 대해 Close를 호출하는 경우를 들 수 있습니다.


static void CodeWithoutCleanup()
{
    System.IO.FileStream file = null;
    System.IO.FileInfo fileInfo = new System.IO.FileInfo("C:\\file.txt");

    file = fileInfo.OpenWrite();
    file.WriteByte(0xF);

    file.Close();
}


예제

1. 위 코드를 try-catch-finally 문으로 변환하려면 다음과 같이 정리 코드를 작업 코드와 분리해야 합니다.


static void CodeWithCleanup()
{
    System.IO.FileStream file = null;
    System.IO.FileInfo fileInfo = null;

    try
    {
        fileInfo = new System.IO.FileInfo("C:\\file.txt");

        file = fileInfo.OpenWrite();
        file.WriteByte(0xF);
    }
    catch(System.UnauthorizedAccessException e)
    {
        System.Console.WriteLine(e.Message);
    }
    finally
    {
        if (file != null)
        {
            file.Close();
        }
    }
}


1. OpenWrite() 호출 이전에 try 블록 내에서 언제든지 예외가 발생할 수 있고 OpenWrite() 호출 자체가 실패할 수도 있으므로 파일을 닫으려고 할 때 해당 파일이 열려 있으리라는 보장이 없습니다.

2. finally 블록은 사용자가 Close 메서드를 호출하기 전에 FileStream 개체가 null이 아닌지 확인하기 위한 검사를 추가합니다.

3. null 검사를 수행하지 않으면 finally 블록에서 자체적으로 NullReferenceException을 throw할 수 있습니다.

4. finally 블록에서 예외가 throw되는 경우는 가능한 한 피해야 합니다.

5. finally 블록에서 닫을 수 있는 또 다른 후보 중 하나로는 데이터베이스 연결이 있습니다.

6. 데이터베이스 서버에 대해 허용된 연결의 수는 제한될 수 있으므로 가능한 한 빨리 데이터베이스 연결을 닫아야 합니다.

7. 연결을 닫기 전에 예외가 throw되면 이 경우에도 가비지 수집을 기다리는 것보다 finally 블록을 사용하는 것이 좋습니다.




방법: CLS 규격이 아닌 예외 catch


1. C++/CLI를 비롯한 일부 .NET 언어에서는 개체가 Exception에서 파생되지 않은 예외를 throw할 수 있습니다.

2. 이러한 예외를 CLS 규격이 아닌 예외 또는 예외가 아닌 항목이라고 합니다.

3. Visual C#에서는 CLS 규격이 아닌 예외를 throw할 수 없지만 다음 두 가지 방법으로 이러한 예외를 catch할 수 있습니다.

1) catch (Exception e) 블록 내에서 RuntimeWrappedException으로 catch

기본적으로 Visual C# 어셈블리에서는 CLS 규격이 아닌 예외를 래핑된 예외로 catch합니다. WrappedException 속성을 통해 액세스할 수 있는 원래 예외에 액세스해야 하는 경우 이 메서드를 사용합니다. 이 항목의 뒷부분에 있는 절차에서는 이 방법으로 예외를 catch하는 방법을 설명합니다.

2) catch (Exception) 또는 catch (Exception e) 블록 다음에 있는 일반적인 catch 블록(예외 형식이 지정되지 않은 catch 블록) 내에서 catch

CLS 규격이 아닌 예외에 대한 응답으로 로그 파일에 쓰기 등의 일부 작업을 수행하려고 하며 예외 정보에 액세스할 필요가 없는 경우 이 메서드를 사용합니다. 기본적으로 공용 언어 런타임에서는 모든 예외를 래핑합니다. 이 동작을 사용하지 않으려면 코드(대개 AssemblyInfo.cs 파일의 코드)에 [assembly: RuntimeCompatibilityAttribute(WrapNonExceptionThrows = false)]와 같이 이 어셈블리 수준의 특성을 추가합니다.


CLS 규격이 아닌 예외를 catch하려면

1. catch(Exception e) block 내에서 as 키워드를 사용하여 e를 RuntimeWrappedException으로 캐스팅할 수 있는지 테스트합니다.

2. WrappedException 속성을 통해 원래 예외에 액세스합니다.


예제

1. 다음 예제에서는 C++/CLR로 작성된 클래스 라이브러리에서 throw된 CLS 규격이 아닌 예외를 catch하는 방법을 보여 줍니다.

2. 이 예제에서 Visual C# 클라이언트 코드는 throw되는 예외 형식이 System.String이라는 것을 미리 알고 있습니다.

3. 코드에서 원래 형식에 액세스할 수 있으면 WrappedException 속성을 해당 형식으로 다시 캐스팅할 수 있습니다.


// Class library written in C++/CLR.
   ThrowNonCLS.Class1 myClass = new ThrowNonCLS.Class1();

   try
   {
    // throws gcnew System::String(
    // "I do not derive from System.Exception!");
    myClass.TestThrow(); 
   }


   catch (Exception e)
   {
    RuntimeWrappedException rwe = e as RuntimeWrappedException;
    if (rwe != null)    
    {
      String s = rwe.WrappedException as String;
      if (s != null)
      {
        Console.WriteLine(s);
      }
    }
    else
    {
       // Handle other System.Exception types.
    }
   }




'프로그래밍 > C#' 카테고리의 다른 글

DateTime, TimeSpan  (0) 2016.10.12
C# 코딩 규칙  (0) 2016.08.28
파일 시스템 및 레지스트리  (0) 2016.08.25
형식 참조 테이블  (0) 2016.08.23
클래스 및 구조체  (0) 2016.08.05
:
Posted by 지훈2
2016. 8. 26. 15:16

Windows Presentation Foundation 프로그래밍/WPF2016. 8. 26. 15:16

https://msdn.microsoft.com/ko-kr/library/ms754130(v=vs.110).aspx


WPF 연습

https://msdn.microsoft.com/ko-kr/library/ee649089(v=vs.110).aspx

연습: WPF Designer를 사용하여 간단한 WPF 응용 프로그램 만들기


XAML

<Window x:Class="WpfApplication2.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:my="clr-namespace:WpfApplication2"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        xmlns:local="clr-namespace:WpfApplication2"

        mc:Ignorable="d"

        Title="Folder Explorer" Height="350" Width="525">

    <Window.Resources>


        <ObjectDataProvider x:Key="RootFolderDataProvider" >

            <ObjectDataProvider.ObjectInstance>

                <my:Folder FullPath="d:\"/>

            </ObjectDataProvider.ObjectInstance>

        </ObjectDataProvider>


        <HierarchicalDataTemplate 

   DataType    = "{x:Type my:Folder}"

            ItemsSource = "{Binding Path=SubFolders}">

            <TextBlock Text="{Binding Path=Name}" />

        </HierarchicalDataTemplate>


    </Window.Resources>

    <Grid>

        <Grid.RowDefinitions>

            <RowDefinition Height="*"/>

            <RowDefinition Height="*"/>

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="*"/>

            <ColumnDefinition Width="2*"/>

        </Grid.ColumnDefinitions>

        <TreeView Grid.ColumnSpan="1" Grid.RowSpan="2" Margin="0,0,0,0" Name="treeView1" >

            <TreeViewItem ItemsSource="{Binding Path=SubFolders, Source={StaticResource RootFolderDataProvider}}" Header="Folders"  />

        </TreeView>

        <ListView Name="listView1" 

ItemsSource="{Binding Path=SelectedItem.SubFolders, ElementName=treeView1, Mode=OneWay}" 

Grid.Column="1" 

Grid.RowSpan="1" />


        <ListView Name="listView2" 

ItemsSource="{Binding Path=SelectedItem.Files, ElementName=treeView1, Mode=OneWay}" 

Grid.Column="1" 

Grid.Row="1" />


    </Grid>

</Window>


Folder.cs

using System;

using System.IO;

using System.Linq;

using System.Collections.Generic;

using System.Collections.ObjectModel;

using System.Text;


namespace WpfApplication2

{

    public class Folder

    {

        private DirectoryInfo _folder;

        private ObservableCollection<Folder> _subFolders;

        private ObservableCollection<FileInfo> _files;


        public Folder()

        {

            this.FullPath = @"c:\";

        }


        public string Name

        {

            get

            {

                return this._folder.Name;

            }

        }


        public string FullPath

        {

            get

            {

                return this._folder.FullName;

            }


            set

            {

                if (Directory.Exists(value))

                {

                    this._folder = new DirectoryInfo(value);

                }

                else

                {

                    throw new ArgumentException("must exist", "fullPath");

                }

            }

        }


        public ObservableCollection<FileInfo> Files

        {

            get

            {

                if (this._files == null)

                {

                    this._files = new ObservableCollection<FileInfo>();


                    FileInfo[] fi = this._folder.GetFiles();


                    for (int i = 0; i < fi.Length; i++)

                    {

                        this._files.Add(fi[i]);

                    }

                }

                return this._files;

            }

        }


        public ObservableCollection<Folder> SubFolders

        {

            get

            {

                if (this._subFolders == null)

                {

                    this._subFolders = new ObservableCollection<Folder>();                     


                    DirectoryInfo[] di = this._folder.GetDirectories();


                    for (int i = 0; i < di.Length; i++)

                    {

                        Folder newFolder = new Folder();

                        newFolder.FullPath = di[i].FullName;

                        this._subFolders.Add(newFolder);

                    }

                }

                return this._subFolders;

            }

        }

    }

}




WPF 소개


https://msdn.microsoft.com/ko-kr/library/mt149842.aspx

1. WPF(Windows Presentation Foundation)를 사용하면 시각적으로 뛰어난 사용자 환경을 통해 Windows용 데스크톱 클라이언트 응용 프로그램을 만들 수 있습니다.

2. WPF의 핵심은 최신 그래픽 하드웨어를 활용하도록 작성된 해상도 독립적인 벡터 기반 렌더링 엔진입니다.

3. WPF는 XAML(Extensible Application Markup Language), 컨트롤, 데이터 바인딩, 레이아웃, 2차원 및 3차원 그래픽, 애니메이션, 스타일, 템플릿, 문서, 미디어, 텍스트 및 입력 체계를 포함하는 포괄적인 응용 프로그램 개발 기능을 사용하여 핵심을 확장합니다.

4. WPF는 .NET Framework에 포함되어 있으므로 .NET Framework 클래스 라이브러리의 다른 요소를 통합하는 응용 프로그램을 빌드할 수 있습니다.

5. 이 개요는 초보자를 위한 것이며 WPF의 주요 기능 및 개념에 대해 설명합니다.


WPF를 사용한 프로그래밍

1. WPF는 대부분 System.Windows 네임스페이스에 있는 .NET Framework 형식의 하위 집합으로 존재합니다.

2. 이전에 ASP.NET 및 Windows Forms와 같은 관리되는 기술을 사용하여 .NET Framework로 응용 프로그램을 빌드한 적이 있는 경우 기본적인 WPF 프로그래밍 환경이 친숙할 것입니다.

3. 모두 C# 또는 Visual Basic과 같은 원하는 .NET 프로그래밍 언어를 사용하여 클래스를 인스턴스화하고, 속성을 설정하고, 메서드를 호출하고, 이벤트를 처리합니다.

4. WPF에는 속성 및 이벤트를 향상시키는 종속성 속성 및 라우트된 이벤트와 같은 추가 프로그래밍 구문이 포함되어 있습니다.


태그 및 코드 숨김

1. WPF를 사용하면 ASP.NET 개발자에게 익숙한 환경인 태그 및 코드 숨김 둘 다를 통해 응용 프로그램을 개발할 수 있습니다.

2. 일반적으로 XAML 태그를 사용하여 응용 프로그램의 모양을 구현하고 관리되는 프로그래밍 언어(코드 숨김)를 사용하여 해당 동작을 구현합니다. 모양 및 동작의 이러한 분리는 다음과 같은 이점이 있습니다.

1) 모양 관련 태그가 동작 관련 코드와 밀접하게 결합되지 않으므로 개발 및 유지 관리 비용이 줄어듭니다.

2) 디자이너가 응용 프로그램의 동작을 구현하는 개발자와 동시에 응용 프로그램의 모양을 구현할 수 있으므로 개발이 보다 효율적입니다.

3) WPF 응용 프로그램에 대한 전역화 및 지역화가 간소화됩니다.

3. 다음은 WPF 태그 및 코드 숨김에 대한 간략한 소개입니다.


태그

1. XAML은 선언적으로 응용 프로그램의 모양을 구현하는 데 사용되는 XML 기반 태그 언어입니다.

2. 일반적으로 창, 대화 상자, 페이지 및 사용자 정의 컨트롤을 만들고 컨트롤, 도형 및 그래픽으로 채우는 데 사용됩니다.

3. 다음 예제에서는 XAML을 사용하여 단일 단추가 포함된 창의 모양을 구현합니다.



<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Title="Window with Button" Width="250" Height="100"> <!-- Add button to window --> <Button Name="button">Click Me!</Button> </Window>


4. 특히, 이 XAML은 각각 Window 및 Button 요소를 사용하여 창과 단추를 정의합니다.

5. 각 요소는 창의 제목 표시줄 텍스트를 지정하는 Window 요소의 Title 특성과 같은 특성으로 구성됩니다.

6. 런타임에 WPF는 태그에 정의된 요소와 특성을 WPF 클래스 인스턴스로 변환합니다.

7. 예를 들어 Window 요소는 Title 속성이 Title 특성의 값인 Window 클래스 인스턴스로 변환됩니다.

8. 다음 그림은 이전 예제에서 XAML로 정의된 UI(사용자 인터페이스)를 보여 줍니다.

9. XAML은 XML 기반이기 때문에 XAML로 작성한 UI는 요소 트리라고 하는 중첩된 요소 계층 구조로 어셈블됩니다. 10. 요소 트리는 UI를 만들고 관리하는 논리적이고 직관적인 방법을 제공합니다.


코드 숨김

1. 응용 프로그램의 기본 동작은 이벤트 처리(예: 메뉴, 도구 모음 또는 단추 클릭) 및 응답으로 비즈니스 논리 및 데이터 액세스 논리 호출을 포함하여 사용자 조작에 응답하는 기능을 구현하는 것입니다.

2. WPF에서 이 동작은 일반적으로 태그와 연결된 코드에서 구현됩니다.

3. 이러한 종류의 코드를 코드 숨김이라고 합니다.

4. 다음 예제에서는 이전 예제의 업데이트된 태그 및 코드 숨김을 보여 줍니다.


<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SDKSample.AWindow" Title="Window with Button" Width="250" Height="100"> <!-- Add button to window --> <Button Name="button" Click="button_Click">Click Me!</Button> </Window>


using System.Windows; // Window, RoutedEventArgs, MessageBox namespace SDKSample { public partial class AWindow : Window { public AWindow() { // InitializeComponent call is required to merge the UI // that is defined in markup with this class, including // setting properties and registering event handlers InitializeComponent(); } void button_Click(object sender, RoutedEventArgs e) { // Show message box when button is clicked MessageBox.Show("Hello, Windows Presentation Foundation!"); } } }


5. 이 예제에서 코드 숨김은 Window 클래스에서 파생된 클래스를 구현합니다.

6. x:Class 특성은 태그를 코드 숨김 클래스와 연결하는 데 사용됩니다.

7. InitializeComponent는 코드 숨김 클래스를 사용하여 태그에서 정의된 UI를 병합하기 위해 코드 숨김 클래스의 생성자에서 호출됩니다.

8. InitializeComponent는 응용 프로그램을 빌드할 때 자동으로 생성되므로 직접 구현할 필요가 없습니다.

9. x:Class 및 InitializeComponent를 조합하면 구현을 만들 때마다 올바르게 초기화됩니다.

10. 코드 숨김 클래스는 단추의 Click 이벤트에 대한 이벤트 처리기도 구현합니다.

11. 단추를 클릭하면 이벤트 처리기가 MessageBox.Show 메서드를 호출하여 메시지 상자를 표시합니다.

12. 다음 그림은 단추를 클릭할 때의 결과를 보여 줍니다.


컨트롤

1. 응용 프로그램 모델에서 제공하는 사용자 환경은 생성된 컨트롤입니다.

2. WPF에서 "컨트롤"은 창이나 페이지에서 호스트되고 사용자 인터페이스가 있으며 일부 동작을 구현하는 WPF 클래스의 한 범주에 적용되는 포괄적인 용어입니다.

3. 자세한 내용은 컨트롤을 참조하세요.


기능별 WPF 컨트롤

1. 기본 제공 WPF 컨트롤은 다음과 같습니다.

1. 단추: Button 및 RepeatButton

2. 데이터 표시: DataGrid, ListView 및 TreeView

3. 날짜 표시 및 선택: Calendar 및 DatePicker

4. 대화 상자: OpenFileDialog, PrintDialog 및 SaveFileDialog

5. 디지털 잉크: InkCanvas 및 InkPresenter

6. 문서: DocumentViewer, FlowDocumentPageViewer, FlowDocumentReader, FlowDocumentScrollViewer 및 StickyNoteControl

7. 입력: TextBox, RichTextBox 및 PasswordBox

8. 레이아웃: Border, BulletDecorator, Canvas, DockPanel, Expander, Grid, GridView, GridSplitter, GroupBox, Panel, ResizeGrip, Separator, ScrollBar, ScrollViewer, StackPanel, Thumb, Viewbox, VirtualizingStackPanel, Window 및 WrapPanel

9. 미디어: Image, MediaElement 및 SoundPlayerAction

10. 메뉴: ContextMenu, Menu 및 ToolBar

11. 탐색: Frame, Hyperlink, Page, NavigationWindow 및 TabControl

12. 선택: CheckBox, ComboBox, ListBox, RadioButton 및 Slider

13. 사용자 정보: AccessText, Label, Popup, ProgressBar, StatusBar, TextBlock 및 ToolTip


입력 및 명령

1. 컨트롤은 대체로 사용자 입력을 감지하고 응답합니다.

2. WPF 입력 시스템은 직접 및 라우트된 이벤트를 사용하여 텍스트 입력, 포커스 관리 및 마우스 위치 지정을 지원합니다.

3. 응용 프로그램에 복잡한 입력 요구 사항이 있는 경우가 많습니다.

4. WPF는 사용자 입력 작업을 이러한 작업에 응답하는 코드에서 분리하는 명령 시스템을 제공합니다.


레이아웃

1. 사용자 인터페이스를 만들 때 위치 및 크기별로 컨트롤을 정렬하여 레이아웃을 구성합니다.

2. 모든 레이아웃의 주요 요구 사항은 창 크기와 표시 설정의 변경 내용에 맞게 조정되는 것입니다.

3. 이러한 상황에서 레이아웃을 조정하는 코드를 작성하도록 요구하는 대신 WPF는 확장 가능한 뛰어난 레이아웃 시스템을 제공합니다.

4. 이 레이아웃 시스템의 토대는 상대 위치 지정으로, 변화하는 창과 표시 조건에 맞게 조정하는 기능을 향상시킵니다.

5. 또한 이 레이아웃 시스템은 레이아웃을 결정하기 위한 컨트롤 간의 협상을 관리합니다.

6. 협상은 2단계 프로세스입니다.

7. 첫 번째로, 컨트롤이 필요한 위치 및 크기를 부모에게 알립니다.

8. 두 번째로, 부모가 사용할 수 있는 공간을 컨트롤에 알립니다.

9. 이 레이아웃 시스템은 기본 WPF 클래스를 통해 자식 컨트롤에 노출됩니다.

10. 그리드, 스택 및 도킹과 같은 일반적인 레이아웃을 위해 WPF는 여러 레이아웃 컨트롤을 포함합니다.


1. Canvas: 자식 컨트롤이 자체 레이아웃을 제공합니다.

2. DockPanel: 자식 컨트롤이 패널 가장자리에 맞춰집니다.

3. Grid: 자식 컨트롤이 행 및 열별로 배치됩니다.

4. StackPanel: 자식 컨트롤이 가로 또는 세로로 포개집니다.

5. VirtualizingStackPanel: 자식 컨트롤이 가상화되고 가로 또는 세로 방향인 한 줄에 정렬됩니다.

6. WrapPanel: 자식 컨트롤이 왼쪽에서 오른쪽 순서로 배치되고 공간에 허용되는 것보다 더 많은 컨트롤이 현재 줄에 있는 경우 다음 줄로 줄 바꿈됩니다.


11. 다음 예제에서는 DockPanel 하나를 사용하여 여러 TextBox 컨트롤을 레이아웃합니다.


<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.LayoutWindow"
    Title="Layout with the DockPanel" Height="143" Width="319">

  <!--DockPanel to layout four text boxes--> 
  <DockPanel>
    <TextBox DockPanel.Dock="Top">Dock = "Top"</TextBox>
    <TextBox DockPanel.Dock="Bottom">Dock = "Bottom"</TextBox>
    <TextBox DockPanel.Dock="Left">Dock = "Left"</TextBox>
    <TextBox Background="White">This TextBox "fills" the remaining space.</TextBox>
  </DockPanel>

</Window>


12. DockPanel을 사용하면 자식 TextBox 컨트롤이 정렬 방법을 알려줄 수 있습니다.

13. 이 작업을 수행하기 위해 DockPanel은 각각 도킹 스타일을 지정할 수 있도록 자식 컨트롤에 노출되는 Dock 속성을 구현합니다.


참고

자식 컨트롤에서 사용할 수 있도록 부모 컨트롤이 구현하는 속성은 연결된 속성이라는 WPF 구문입니다.


14. 다음 그림에서는 이전 예제의 XAML 태그 결과를 보여 줍니다.


데이터 바인딩

1. 대부분의 응용 프로그램은 데이터를 보고 편집할 수 있는 수단을 사용자에게 제공하기 위해 생성됩니다.

2. WPF 응용 프로그램의 경우 데이터를 저장 및 액세스하는 작업이 SQL Server 및 ADO .NET과 같은 기술에 의해 이미 제공됩니다.

3. 데이터에 액세스하고 응용 프로그램의 관리되는 개체에 로드한 후 WPF 응용 프로그램에 대한 힘든 작업이 시작됩니다.

4. 기본적으로 다음 두 가지가 포함됩니다.

1) 관리되는 개체에서 데이터를 표시 및 편집할 수 있는 컨트롤로 데이터 복사

2) 컨트롤을 사용한 데이터 변경 내용이 관리되는 개체에 다시 복사되는지 확인

5. 응용 프로그램 개발을 간소화하기 위해 WPF는 이러한 단계를 자동으로 수행하는 데이터 바인딩 엔진을 제공합니다.

6. 데이터 바인딩 엔진의 핵심 단위는 Binding 클래스로, 컨트롤(바인딩 대상)을 데이터 개체(바인딩 소스)에 바인딩하는 작업을 수행합니다.

7. 이 관계는 다음 그림에 나와 있습니다.




8. 다음 예제에서는 TextBox를 사용자 지정 Person 개체의 인스턴스에 바인딩하는 방법을 보여 줍니다.

9. Person 구현은 다음 코드에 나와 있습니다.


namespace SDKSample
{
    class Person
    {
        string name = "No Name";

        public string Name
        {
            get { return name; }
            set { name = value; }
        }
    }
}


<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.DataBindingWindow">


<!-- Bind the TextBox to the data source (TextBox.Text to Person.Name) -->
<TextBox Name="personNameTextBox" Text="{Binding Path=Name}" />


</Window>


using System.Windows; // Window

namespace SDKSample
{
    public partial class DataBindingWindow : Window
    {
        public DataBindingWindow()
        {
            InitializeComponent();

            // Create Person data source
            Person person = new Person();

            // Make data source available for binding
            this.DataContext = person;
        }
    }
}


10. 이 예제에서 Person 클래스는 코드 숨김에서 인스턴스화되고 DataBindingWindow에 대한 데이터 컨텍스트로 설정됩니다.

11. 태그에서 TextBox의 Text 속성은 "{Binding ... }" XAML 구문을 사용하여 Person.Name 속성에 바인딩됩니다.

12. 이 XAML은 창의 DataContext 속성에 저장된 Person 개체에 TextBox 컨트롤을 바인딩하도록 WPF에 알립니다.

13. WPF 데이터 바인딩 엔진은 유효성 검사, 정렬, 필터링 및 그룹화를 포함하는 추가 지원을 제공합니다.

14. 또한 데이터 바인딩은 표준 WPF 컨트롤에 의해 표시되는 사용자 인터페이스가 적절하지 않은 경우 데이터 템플릿을 사용하여 바인딩된 데이터에 대한 사용자 지정 사용자 인터페이스를 만들 수 있도록 지원합니다.

15. 자세한 내용은 데이터 바인딩 개요를 참조하세요.


그래픽

1. WPF는 다음과 같은 이점이 있는 광범위하고 확장 가능하며 유연한 그래픽 집합을 도입합니다.

1. 해상도 및 장치 독립적인 그래픽. WPF 그래픽 시스템의 기본 측정 단위는 실제 화면 해상도에 관계없이 1/96 인치인 장치 독립적 픽셀이며, 해상도 및 장치 독립적인 렌더링을 위한 토대를 제공합니다. 각 장치 독립적 픽셀은 렌더링되는 시스템의 dpi(인치당 도트 수) 설정에 맞게 자동으로 확장됩니다.

2. 향상된 정밀도. WPF 좌표계는 단정밀도 대신 배정밀도 부동 소수점 숫자로 측정됩니다. 변환 및 불투명도 값도 배정밀도로 표현됩니다. 또한 WPF는 광범위한 색 영역(scRGB)을 지원하며 여러 색 공간의 입력을 관리하기 위한 통합 지원을 제공합니다.

3. 고급 그래픽 및 애니메이션 지원. WPF는 애니메이션 장면을 관리하여 그래픽 프로그래밍을 간소화합니다. 장면 처리, 렌더링 루프 및 쌍선형 보간에 대해 걱정할 필요가 없습니다. 또한 WPF는 적중 테스트 및 전체 알파 합치기를 지원합니다.

4. 하드웨어 가속. WPF 그래픽 시스템은 그래픽 하드웨어를 활용하여 CPU 사용량을 최소화합니다.


2차원 도형

1. WPF는 다음 그림에 표시된 사각형 및 타원과 같은 일반적인 벡터 기반의 2차원 도형 라이브러리를 제공합니다.




2. 도형의 흥미로운 기능은 표시에 사용되는 것뿐 아니라 키보드 및 마우스 입력을 비롯하여 컨트롤에서 기대하는 기능을 대부분 구현한다는 것입니다.

3. 다음 예제에서는 Ellipse의 MouseUp 이벤트가 처리되는 과정을 보여 줍니다.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.EllipseEventHandlingWindow"
    Title="Click the Ellipse">
    <Ellipse Name="clickableEllipse" Fill="Blue" MouseUp="clickableEllipse_MouseUp" />
</Window>


using System.Windows; // Window, MessageBox
using System.Windows.Input; // MouseButtonEventHandler

namespace SDKSample
{
    public partial class EllipseEventHandlingWindow : Window
    {
        public EllipseEventHandlingWindow()
        {
            InitializeComponent();
        }

        void clickableEllipse_MouseUp(object sender, MouseButtonEventArgs e)
        {
            // Display a message
            MessageBox.Show("You clicked the ellipse!");
        }
    }
}


4. 다음 그림은 위의 코드에서 생성되는 내용을 보여 줍니다.


5. 자세한 내용은 WPF에서 Shape 및 기본 그리기 개요를 참조하세요.


2차원 기하 도형

1. WPF에서 제공하는 2차원 도형은 기본 도형의 표준 집합을 다룹니다.

2. 그러나 사용자 지정 사용자 인터페이스의 디자인이 용이하도록 사용자 지정 도형을 만들어야 할 수도 있습니다. 

3. 이 용도로 WPF는 기하 도형을 제공합니다. 다음 그림은 기하 도형을 사용하여 직접 그리거나, 브러시로 사용하거나, 다른 도형 및 컨트롤을 자르는 데 사용할 수 있는 사용자 지정 도형을 만드는 과정을 보여 줍니다.

4. Path 개체는 닫혔거나 열린 도형, 여러 도형 및 곡선 도형을 그리는 데 사용할 수 있습니다.

5. Geometry 개체는 자르기, 적중 테스트 및 2차원 그래픽 데이터 렌더링에 사용할 수 있습니다.


2차원 효과

1. WPF 2차원 기능의 하위 집합에는 그라데이션, 비트맵, 그리기, 비디오로 그리기, 회전, 크기 조정 및 기울이기와 같은 시각 효과가 포함됩니다. 브러시를 통해 이러한 모든 효과를 얻을 수 있습니다.

2. 다음 그림에서는 몇 가지 예를 보여 줍니다.



3차원 렌더링

1. WPF에는 더 흥미로운 사용자 인터페이스를 만들 수 있도록 2차원 그래픽을 통합하는 3차원 렌더링 기능도 포함되어 있습니다.

2. 예를 들어 다음 그림에서는 3차원 도형에 렌더링된 2차원 이미지를 보여 줍니다.


애니메이션

1. WPF 애니메이션 지원을 사용하면 컨트롤이 커지거나, 흔들리거나, 회전하거나, 사라지도록 하여 흥미로운 페이지 전환 등을 만들 수 있습니다.

2. 사용자 지정 클래스를 비롯한 대부분의 WPF 클래스에 애니메이션 효과를 줄 수 있습니다.

3. 다음 그림에서는 간단한 애니메이션의 작동을 보여 줍니다.


4. 자세한 내용은 애니메이션 개요를 참조하세요.


미디어

1. 풍부한 콘텐츠를 전달하는 한 가지 방법은 시청각 미디어를 사용하는 것입니다.

2. WPF는 이미지, 비디오 및 오디오에 대한 특별한 지원을 제공합니다.


이미지

1. 이미지는 대부분의 응용 프로그램에서 공통적으로 사용되며 WPF는 이미지를 사용하는 여러 방법을 제공합니다.

2. 다음 그림에서는 미리 보기 이미지를 포함하는 목록 상자가 있는 사용자 인터페이스를 보여 줍니다.

3. 미리 보기를 선택하면 이미지가 전체 크기로 표시됩니다.


4. 자세한 내용은 이미징 개요를 참조하세요.


비디오 및 오디오

1. MediaElement 컨트롤은 비디오와 오디오를 둘 다 재생할 수 있으며 사용자 지정 미디어 플레이어의 토대가 될 수 있을 정도로 유연합니다.

2. 다음 XAML 태그는 미디어 플레이어를 구현합니다.

<MediaElement 
  Name="myMediaElement" 
  Source="media/wpf.wmv" 
  LoadedBehavior="Manual" 
  Width="350" Height="250" />


3. 다음 그림의 창에서는 MediaElement 컨트롤의 작동을 보여 줍니다.


4. 자세한 내용은 WPF 그래픽, 애니메이션 및 미디어 개요를 참조하세요.


텍스트 및 입력 체계

1. 고품질 텍스트 렌더링이 용이하도록 WPF는 다음 기능을 제공합니다.

1) OpenType 글꼴 지원

2) ClearType 향상

3) 하드웨어 가속을 활용하는 고성능

4) 미디어, 그래픽 및 애니메이션과 텍스트 통합

5) 국가별 글꼴 지원 및 대체(fallback) 메커니즘


2. 텍스트와 그래픽 통합의 데모로, 다음 그림에서는 텍스트 장식의 응용을 보여 줍니다.


WPF 응용 프로그램 사용자 지정

1. 지금까지 응용 프로그램을 개발하기 위한 핵심 WPF 구성 요소를 살펴봤습니다.

2. 응용 프로그램 모델을 사용하여 주로 컨트롤로 구성된 응용 프로그램 콘텐츠를 호스트 및 제공합니다.

3. 사용자 인터페이스에서 컨트롤 정렬을 간소화하고 창 크기 및 디스플레이 설정이 변경되어도 정렬이 유지되도록 하기 위해 WPF 레이아웃 시스템을 사용합니다.

4. 대부분의 응용 프로그램은 사용자의 데이터 조작을 허용하므로 데이터 바인딩을 사용하여 사용자 인터페이스와 데이터 통합 작업을 줄입니다.

5. 응용 프로그램의 시각적 모양을 개선하려면 WPF에서 제공하는 광범위한 그래픽, 애니메이션 및 미디어 지원을 사용합니다.

6. 하지만 기본 사항이 고유하고 시각적으로 멋진 사용자 환경을 만들고 관리하는 데 충분하지 않은 경우도 많습니다.

7. 표준 WPF 컨트롤이 원하는 응용 프로그램 모양과 통합되지 않을 수 있습니다.

8. 데이터가 가장 효율적인 방식으로 표시되지 않을 수도 있습니다.

9. 응용 프로그램의 전반적인 사용자 환경이 Windows 테마의 기본 모양과 느낌에 적합하지 않을 수 있습니다.

10. 여러 측면에서 프레젠테이션 기술은 다른 종류의 확장성만큼 시각적 확장성을 필요로 합니다.

11. 이런 이유로 WPF는 컨트롤, 트리거, 컨트롤 및 데이터 템플릿, 스타일, 사용자 인터페이스 리소스, 테마 및 스킨에 대한 풍부한 콘텐츠 모델을 포함하여 고유한 사용자 환경을 만들기 위한 다양한 메커니즘을 제공합니다.


콘텐츠 모델

1. 대부분의 WPF 컨트롤은 주로 콘텐츠를 표시하는 데 사용됩니다.

2. WPF에서 컨트롤의 콘텐츠를 구성할 수 있는 항목의 유형과 개수를 컨트롤의 콘텐츠 모델이라고 합니다.

3. 일부 컨트롤은 단일 항목 및 유형의 콘텐츠를 포함할 수 있습니다.

4. 예를 들어 TextBox의 콘텐츠는 Text 속성에 할당되는 문자열 값입니다.

5. 다음 예제에서는 TextBox의 콘텐츠를 설정합니다.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.TextBoxContentWindow"
    Title="TextBox Content">


<TextBox Text="This is the content of a TextBox." />


</Window>


6. 다음 그림에서는 결과를 보여 줍니다.


7. 그러나 다른 컨트롤은 다양한 콘텐츠 형식의 여러 항목을 포함할 수 있습니다.

8. Content 속성으로 지정된 Button의 콘텐츠에는 레이아웃 컨트롤, 텍스트, 이미지 및 도형을 포함하여 다양한 항목이 포함될 수 있습니다.

9. 다음 예제에서는 DockPanel, Label, Border 및 MediaElement를 포함하는 콘텐츠가 있는 Button을 보여 줍니다.


<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.ButtonContentWindow"
    Title="Button Content">


<Button Margin="20">
  <!-- Button Content -->
  <DockPanel Width="200" Height="180">
    <Label DockPanel.Dock="Top" HorizontalAlignment="Center">Click Me!</Label>
    <Border Background="Black" BorderBrush="Yellow" BorderThickness="2" 
      CornerRadius="2" Margin="5">
      <MediaElement Source="media/wpf.wmv" Stretch="Fill" />
    </Border>
  </DockPanel>
</Button>


</Window>


10. 다음 그림에서는 이 단추의 콘텐츠를 보여 줍니다.




11. 다양한 컨트롤에서 지원하는 콘텐츠 종류에 대한 자세한 내용은 WPF 콘텐츠 모델을 참조하세요.


트리거

1. XAML 태그의 주요 용도는 응용 프로그램의 모양을 구현하는 것이지만 XAML을 사용하여 응용 프로그램 동작의 일부 측면을 구현할 수도 있습니다.

2. 한 가지 예는 트리거를 사용하여 사용자 조작에 따라 응용 프로그램의 모양을 변경하는 것입니다.

3. 자세한 내용은 스타일 지정 및 템플릿을 참조하세요.


컨트롤 템플릿

1. WPF 컨트롤의 기본 사용자 인터페이스는 일반적으로 다른 컨트롤 및 도형에서 구성됩니다.

2. 예를 들어 Button은 ButtonChrome 및 ContentPresenter 컨트롤 둘 다로 구성됩니다.

3. ButtonChrome은 표준 단추 모양을 제공하는 반면, ContentPresenter는 Content 속성에 지정된 대로 단추의 콘텐츠를 표시합니다.

4. 컨트롤의 기본 모양이 응용 프로그램의 전반적인 모양에 맞지 않을 수도 있습니다.

5. 이 경우 ControlTemplate을 사용하여 해당 콘텐츠 및 동작을 변경하지 않고 컨트롤의 사용자 인터페이스 모양을 변경할 수 있습니다.

6. 예를 들어 다음 예제에서는 ControlTemplate을 사용하여 Button의 모양을 변경하는 방법을 보여 줍니다.


<Window 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.ControlTemplateButtonWindow"
  Title="Button with Control Template" Height="158" Width="290">

  <!-- Button using an ellipse -->
  <Button Content="Click Me!" Click="button_Click">
    <Button.Template>
      <ControlTemplate TargetType="{x:Type Button}">
        <Grid Margin="5">
          <Ellipse Stroke="DarkBlue" StrokeThickness="2">
            <Ellipse.Fill>
              <RadialGradientBrush Center="0.3,0.2" RadiusX="0.5" RadiusY="0.5">
                <GradientStop Color="Azure" Offset="0.1" />
                <GradientStop Color="CornflowerBlue" Offset="1.1" />
              </RadialGradientBrush>
            </Ellipse.Fill>
          </Ellipse>
          <ContentPresenter Name="content" HorizontalAlignment="Center" 
            VerticalAlignment="Center"/>
        </Grid>
      </ControlTemplate>
    </Button.Template>

  </Button>

</Window>


using System.Windows; // Window, RoutedEventArgs, MessageBox

namespace SDKSample
{
    public partial class ControlTemplateButtonWindow : Window
    {
        public ControlTemplateButtonWindow()
        {
            InitializeComponent();
        }

        void button_Click(object sender, RoutedEventArgs e)
        {
            // Show message box when button is clicked
            MessageBox.Show("Hello, Windows Presentation Foundation!");
        }
    }
}


7. 이 예제에서는 기본 단추 사용자 인터페이스가 진한 파란색 테두리가 있는 Ellipse로 대체되고 RadialGradientBrush를 사용하여 채워집니다.

8. ContentPresenter 컨트롤은 Button의 콘텐츠인 "Click Me!"를 표시합니다. Button을 클릭하면 Click 이벤트가 Button 컨트롤의 기본 동작의 일부로 여전히 발생합니다. 결과는 다음 그림에 나와 있습니다.



데이터 템플릿

1. 컨트롤 템플릿을 사용하면 컨트롤의 모양을 지정할 수 있는 반면 데이터 템플릿을 사용하면 컨트롤 콘텐츠의 모양을 지정할 수 있습니다.

2. 데이터 템플릿은 바인딩된 데이터가 표시되는 방식을 개선하는 데 자주 사용됩니다.

3. 다음 그림은 각 작업에 이름, 설명 및 우선 순위가 있는 Task 개체의 컬렉션에 바인딩된 ListBox의 기본 모양을 보여 줍니다.



4. 기본 모양은 ListBox에서 예상되는 모양입니다.

5. 그러나 각 작업의 기본 모양은 작업 이름만 포함합니다.

6. 작업 이름, 설명 및 우선 순위를 표시하려면 DataTemplate을 사용하여 ListBox 컨트롤의 바인딩된 목록 항목에 대한 기본 모양을 변경해야 합니다.

7. 다음 XAML은 ItemTemplate 특성을 사용하여 각 작업에 적용되는 이러한 DataTemplate을 정의합니다.


<Window
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.DataTemplateWindow"
  Title="With a Data Template">


<Window.Resources>

  <!-- Data Template (applied to each bound task item in the task collection) -->
  <DataTemplate x:Key="myTaskTemplate">
    <Border Name="border" BorderBrush="DarkSlateBlue" BorderThickness="2" 
      CornerRadius="2" Padding="5" Margin="5">
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition/>
          <RowDefinition/>
          <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="Auto" />
          <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Row="0" Grid.Column="0" Padding="0,0,5,0" Text="Task Name:"/>
        <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path=TaskName}"/>
        <TextBlock Grid.Row="1" Grid.Column="0" Padding="0,0,5,0" Text="Description:"/>
        <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Path=Description}"/>
        <TextBlock Grid.Row="2" Grid.Column="0" Padding="0,0,5,0" Text="Priority:"/>
        <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Path=Priority}"/>
      </Grid>
    </Border>  
  </DataTemplate>
</Window.Resources>


<!-- UI -->
<DockPanel>
  <!-- Title -->
  <Label DockPanel.Dock="Top" FontSize="18" Margin="5" Content="My Task List:"/>

  <!-- Data template is specified by the ItemTemplate attribute -->
  <ListBox 
    ItemsSource="{Binding}" 
    ItemTemplate="{StaticResource myTaskTemplate}" 
    HorizontalContentAlignment="Stretch" 
    IsSynchronizedWithCurrentItem="True" 
    Margin="5,0,5,5" />

</DockPanel>


</Window>


8. 다음 그림에서는 이 코드의 영향을 보여 줍니다.



9. ListBox의 동작과 전반적인 모양은 유지되고 목록 상자에 표시되는 콘텐츠의 모양만 변경되었습니다.

10. 자세한 내용은 데이터 템플릿 개요를 참조하세요.


스타일

1. 스타일을 사용하면 개발자와 디자이너가 해당 제품에 대해 특정 모양을 표준화할 수 있습니다.

2. WPF는 Style 요소를 기반으로 하는 강력한 스타일 모델을 제공합니다.

3. 다음 예제에서는 창에 있는 모든 Button의 배경색을 Orange로 설정하는 스타일을 만듭니다.


<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.StyleWindow"
    Title="Styles">


<!-- Style that will be applied to all buttons -->
<Style TargetType="{x:Type Button}">
  <Setter Property="Background" Value="Orange" />
  <Setter Property="BorderBrush" Value="Crimson" />
  <Setter Property="FontSize" Value="20" />
  <Setter Property="FontWeight" Value="Bold" />
  <Setter Property="Margin" Value="5" />
</Style>


<!-- This button will have the style applied to it -->
<Button>Click Me!</Button>

<!-- This label will not have the style applied to it -->
<Label>Don't Click Me!</Label>

<!-- This button will have the style applied to it -->
<Button>Click Me!</Button>


</Window>


4. 이 스타일은 모든 Button 컨트롤을 대상으로 하기 때문에 다음 그림과 같이 창에 있는 모든 단추에 스타일이 자동으로 적용됩니다.



5. 자세한 내용은 스타일 지정 및 템플릿을 참조하세요.


리소스

1. 응용 프로그램의 컨트롤은 글꼴 및 배경색부터 컨트롤 템플릿, 데이터 템플릿 및 스타일까지 모든 항목을 포함할 수 있는 동일한 모양을 공유해야 합니다.

2. 사용자 인터페이스 리소스에 대한 WPF 지원을 사용하여 재사용을 위해 이러한 리소스를 단일 위치에 캡슐화할 수 있습니다.

3. 다음 예제에서는 Button 및 Label에서 공유하는 공통 배경색을 정의합니다.


<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.ResourcesWindow"
    Title="Resources Window">

  <!-- Define window-scoped background color resource -->
  <Window.Resources>
    <SolidColorBrush x:Key="defaultBackground" Color="Red" />
  </Window.Resources>


<!-- Button background is defined by window-scoped resource -->
<Button Background="{StaticResource defaultBackground}">One Button</Button>

<!-- Label background is defined by window-scoped resource -->
<Label Background="{StaticResource defaultBackground}">One Label</Label>


</Window>


4. 이 예제에서는 Window.Resources 속성 요소를 사용하여 배경색 리소스를 구현합니다.

5. 이 리소스는 Window의 모든 자식에서 사용할 수 있습니다.

6. 다음을 포함하여 다양한 리소스 범위가 있습니다(확인되는 순서대로 나열됨).

1) 개별 컨트롤(상속된 FrameworkElement.Resources 속성 사용)

2) Window 또는 Page(또한 상속된 FrameworkElement.Resources 속성 사용)

3) Application(Application.Resources 속성 사용)

7. 다양한 범위는 리소스를 정의 및 공유하는 방법과 관련해서 유연성을 제공합니다.

8. 리소스를 특정 범위에 직접 연결하는 대신, 응용 프로그램의 다른 부분에서 참조할 수 있는 별도  ResourceDictionary를 사용하여 하나 이상의 리소스를 패키지할 수 있습니다.

9. 예를 들어 다음 예제에서는 리소스 사전의 기본 배경색을 정의합니다.


<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

  <!-- Define background color resource -->
  <SolidColorBrush x:Key="defaultBackground" Color="Red" />

  <!-- Define other resources -->


</ResourceDictionary>


10. 다음 예제에서는 응용 프로그램 간에 공유되도록 이전 예제에서 정의된 리소스 사전을 참조합니다.


<Application

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.App">

  <Application.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="BackgroundColorResources.xaml"/>
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Application.Resources>


</Application>


11. 리소스 및 리소스 사전은 테마 및 스킨에 대한 WPF 지원의 기반이 됩니다.

12. 자세한 내용은 리소스 개요를 참조하세요.


사용자 지정 컨트롤

1. WPF는 다양한 사용자 지정 지원을 제공하지만 기존 WPF 컨트롤이 응용 프로그램 또는 해당 사용자의 요구를 충족하지 않는 경우가 발생할 수 있습니다.

2. 이 오류는 다음과 같은 경우에 발생할 수 있습니다.

1) 기존 WPF 구현의 모양과 느낌을 사용자 지정하여 필요한 사용자 인터페이스를 만들 수 없는 경우

2) 필요한 동작이 기존 WPF 구현에서 지원되지 않는 경우(또는 쉽게 지원되지 않는 경우)

3. 그러나 이제 세 가지 WPF 모델 중 하나를 활용하여 새 컨트롤을 만들 수 있습니다.

4. 각 모델은 특정 시나리오를 대상으로 하며, 특정 WPF 기본 클래스에서 사용자 지정 컨트롤을 파생시켜야 합니다. 5. 세 가지 모델은 다음과 같습니다.

1) 사용자 정의 컨트롤 모델. 사용자 지정 컨트롤은 UserControl에서 파생되며 하나 이상의 다른 컨트롤로 구성됩니다.

2) 컨트롤 모델. 사용자 지정 컨트롤은 Control에서 파생되며 대부분의 WPF 컨트롤과 마찬가지로 템플릿을 사용하여 모양과 동작을 구분하는 구현을 작성하는 데 사용됩니다. Control에서 파생시키는 경우 사용자 정의 컨트롤보다 더 자유롭게 사용자 지정 사용자 인터페이스를 만들 수 있지만 더 많은 노력이 필요할 수 있습니다.

3) 프레임워크 요소 모델. 사용자 지정 컨트롤은 모양이 사용자 지정 렌더링 논리(템플릿 아님)에 의해 정의되는 경우 FrameworkElement에서 파생됩니다.

6. 다음 예제에서는 UserControl에서 파생되는 사용자 지정 숫자 위로/아래로 컨트롤을 보여 줍니다.


<UserControl
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.NumericUpDown">

  <Grid>

    <Grid.RowDefinitions>
      <RowDefinition/>
      <RowDefinition/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition/>
      <ColumnDefinition/>
    </Grid.ColumnDefinitions>

    <!-- Value text box -->
    <Border BorderThickness="1" BorderBrush="Gray" Margin="2" Grid.RowSpan="2" 
      VerticalAlignment="Center" HorizontalAlignment="Stretch">
      <TextBlock Name="valueText" Width="60" TextAlignment="Right" Padding="5"/>
    </Border>

    <!-- Up/Down buttons -->
    <RepeatButton Name="upButton" Click="upButton_Click" Grid.Column="1" 
      Grid.Row="0">Up</RepeatButton>
    <RepeatButton Name="downButton" Click="downButton_Click" Grid.Column="1" 
      Grid.Row="1">Down</RepeatButton>

  </Grid>

</UserControl>


using System; // EventArgs
using System.Windows; // DependencyObject, DependencyPropertyChangedEventArgs,
                      // FrameworkPropertyMetadata, PropertyChangedCallback, 
                      // RoutedPropertyChangedEventArgs
using System.Windows.Controls; // UserControl

namespace SDKSample
{
    public partial class NumericUpDown : UserControl
    {
        // NumericUpDown user control implementation


}

}




7. 다음 예제에서는 사용자 정의 컨트롤을 Window에 통합하는 데 필요한 XAML을 보여 줍니다.


<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.UserControlWindow"
    xmlns:local="clr-namespace:SDKSample" 
    Title="User Control Window">


<!-- Numeric Up/Down user control -->
<local:NumericUpDown />


</Window>


8. 다음 그림에서는 Window에 호스트된 NumericUpDown 컨트롤을 보여 줍니다.



9. 사용자 지정 컨트롤에 대한 자세한 내용은 컨트롤 제작 개요를 참조하세요.


WPF 모범 사례

1. 모든 개발 플랫폼과 마찬가지로 WPF를 다양한 방법으로 사용하여 원하는 결과를 얻을 수 있습니다.

2. WPF 응용 프로그램이 필요한 사용자 환경을 제공하고 일반적인 사용자 요구를 충족하도록 하는 한 가지 방법으로 접근성, 전역화 및 지역화, 성능에 대한 권장 모범 사례가 있습니다.

3. 자세한 내용은 다음을 참조하세요.

1) 접근성 모범 사례접근성 모범 사례

2) WPF 전역화 및 지역화 개요

3) WPF 응용 프로그램 성능 최적화

4) Windows Presentation Foundation 보안


요약

1. WPF는 시각적으로 멋진 다양한 클라이언트 응용 프로그램을 빌드하기 위한 포괄적인 프레젠테이션 기술입니다.

2. 이 소개에서는 WPF의 주요 기능을 살펴봤습니다.

3. 다음 단계는 WPF 응용 프로그램을 빌드하는 것입니다.

4. 빌드하는 동안 이 소개로 돌아와서 주요 기능을 복습하고 이 소개에 포함된 기능의 자세한 설명에 대한 참조를 찾을 수 있습니다.




연습: 동적 레이아웃 만들기

https://msdn.microsoft.com/ko-kr/library/bb514519(v=vs.110).aspx

1. 동적 위치 지정 방법에서는 자식 요소의 정렬 방식과 부모 요소를 기준으로 한 줄 바꿈 방식을 지정하여 자식 요소를 정렬합니다.

2. 창 및 컨트롤의 내용이 늘어날 때 해당 창 및 컨트롤이 자동으로 늘어나도록 설정할 수도 있습니다.

3. 자세한 내용은 절대 및 동적 위치를 사용하는 레이아웃을 참조하십시오.

4. WPF Designer for Visual Studio에서는 동적 위치를 지원하는 여러 가지 Panel 컨트롤을 제공합니다.

5. 한 패널 컨트롤을 다른 패널 컨트롤의 자식으로 추가하여 패널 컨트롤을 조합할 수 있습니다.

6. 다음 패널 컨트롤을 사용하여 응용 프로그램에서 요소의 동적 위치를 지정할 수 있습니다.

1) Grid

2) DockPanel

3) WrapPanel

4) StackPanel

5) UniformGrid


중요

1. 가능하면 동적 레이아웃을 사용하는 것이 좋습니다.

2. 동적 레이아웃은 가장 유연할 뿐 아니라 지역화되는 경우와 같이 내용이 변경될 경우 적절히 조정되고 최종 사용자가 사용 환경을 가장 잘 제어할 수 있게 해 줍니다. 

3. 절대 레이아웃의 예제를 보려면 연습: 절대 위치를 기반으로 하는 레이아웃 만들기를 참조하십시오.


7. 이 연습에서는 다음 작업을 수행합니다.

1) WPF 응용 프로그램을 만듭니다.

2) 기본 Grid 패널 컨트롤을 구성합니다.

3) 패널에 컨트롤을 추가합니다.

4) 레이아웃을 테스트합니다.

8. 다음 그림에서는 응용 프로그램의 모양을 보여 줍니다.



Note

1. 표시되는 대화 상자와 메뉴 명령은 활성 설정이나 버전에 따라 도움말에서 설명하는 것과 다를 수 있습니다.

2. 설정을 변경하려면 도구 메뉴에서 설정 가져오기 및 내보내기를 선택합니다.

3. 자세한 내용은 Visual Studio 설정을 참조하십시오.


종합
1. 완    성된 MainWindow.xaml 파일은 다음과 같습니다.


<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="200" Width="400" SizeToContent="WidthAndHeight">
    <Grid ShowGridLines="True">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <Label Grid.Column="0" Grid.Row="0" Margin="20,20,10,10" Width="Auto" Height="23" HorizontalAlignment="Stretch" VerticalAlignment="Top" Name="Label1">Name:</Label>
        <Label Grid.Column="0" Grid.Row="1" Margin="20,10,10,10" Width="Auto" Height="23" HorizontalAlignment="Stretch" VerticalAlignment="Top" Name="Label2">Password:</Label>
        <TextBox Grid.Column="1" Grid.Row="0" Margin="10,20,20,10" Grid.ColumnSpan="3" Height="Auto" VerticalAlignment="Stretch" Name="TextBox1" />
        <TextBox Grid.Column="1" Grid.Row="1" Margin="10,10,20,10" Grid.ColumnSpan="3" Name="TextBox2" />
        <Button Grid.Column="2" Grid.Row="3" Margin="10,10,6,20" Width="75" Height="23" HorizontalAlignment="Stretch" Name="Button1">OK</Button>
        <Button Grid.Column="3" Grid.Row="3" Margin="6,10,20,20" Width="75" Height="23" Name="Button2">Cancel</Button>
    </Grid>
</Window>


다음 단계

1. 이 연습의 Grid 패널을 다음 패널로 대체해 보면 동적 레이아웃을 사용하여 다양한 효과를 얻는 방법을 알 수 있습니다.

1) DockPanel

2) WrapPanel

3) StackPanel

4) UniformGrid




연습: WPF Designer를 사용하여 크기를 조정할 수 있는 응용 프로그램 만들기

https://msdn.microsoft.com/ko-kr/library/bb546954(v=vs.110).aspx

1. GridSplitter 컨트롤과 Grid 컨테이너 컨트롤을 함께 사용하여 런타임에 사용자가 크기를 조정할 수 있는 창 레이아웃을 만들 수 있습니다.

2. 예를 들어 UI가 여러 영역으로 분할된 응용 프로그램의 경우 사용자가 분할자를 마우스로 끌어 더 많이 표시하려는 영역을 넓힐 수 있습니다.

3. 이 연습에서는 메신저 스타일 응용 프로그램의 레이아웃을 만듭니다.

4. 이 연습에서는 다음 작업을 수행합니다.

1) WPF 응용 프로그램을 만듭니다.

2) 기본 모눈 패널을 구성합니다.

3) 가로 GridSplitter를 추가합니다.

4) 도킹 패널 및 컨트롤을 추가합니다.

5) 모눈 패널 및 컨트롤을 추가합니다.

6) 응용 프로그램을 테스트합니다.

5. 다음 그림에서는 응용 프로그램의 모양을 보여 줍니다.



종합

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="300" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
            <RowDefinition MinHeight="70" />
        </Grid.RowDefinitions>
        <DockPanel Grid.Row="0" Grid.RowSpan="1" HorizontalAlignment="Stretch" Margin="0" Name="DockPanel1">
            <Label DockPanel.Dock="Top" Height="23" Width="Auto" Background="Blue" Foreground="White" Name="Label1">Display</Label>
            <RichTextBox DockPanel.Dock="Bottom" Height="Auto" Width="Auto" Background="LightBlue" IsReadOnly="True" Name="RichTextBox1" />
        </DockPanel>
        <GridSplitter Grid.Row="1" Grid.RowSpan="1" ResizeDirection="Rows" Width="Auto" Height="10" HorizontalAlignment="Stretch" Margin="0" Name="GridSplitter1" />
        <Grid Grid.Row="2" HorizontalAlignment="Stretch" Margin="0" Name="Grid1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <Button Grid.Column="1" HorizontalAlignment="Stretch" Margin="5" Width="60" Height="60" Name="Button1">OK</Button>
            <RichTextBox Grid.Column="0" Grid.ColumnSpan="1" HorizontalAlignment="Stretch" Margin="0" Background="PaleGoldenrod" Name="RichTextBox2" />
        </Grid>
    </Grid>
</Window>




연습: WPF Designer를 사용하여 데이터 바인딩 만들기

https://msdn.microsoft.com/ko-kr/library/dd434207(v=vs.110).aspx

1. 이 연습에서는 WPF Designer for Visual Studio를 사용하여 데이터를 컨트롤에 연결하는 데이터 바인딩을 만드는 방법을 보여 줍니다. 

2. 이 연습에서는 다음 작업을 수행합니다.

1) 프로젝트를 만듭니다.

2) Student 클래스 및 StudentList 컬렉션을 만듭니다.

3) 데이터 바인딩을 통해 StudentList 컬렉션을 표시하는 ListBox 컨트롤을 만듭니다.

4) IValueConverter 를 사용하여 부울 속성의 모양을 사용자 지정하는 사용자 지정 DataTemplate을 만듭니다.

3. 연습을 마치면 학생 목록에 바인딩된 목록 상자가 완성됩니다.

4. 목록 상자의 각 항목에 대해 학생이 현재 등록되어 있는지 여부를 나타내는 색칠된 사각형이 표시됩니다.


Student.cs

using System;
using System.Collections.ObjectModel;
using System.Windows;

namespace DataBindingDemo
{
    // Student is a simple class that stores a name and an
    // IsEnrolled value.
    public class Student 
    {   
        // The default constructor is required for creation from XAML.
        public Student()
        {
        }

        // The StudentName property is a string that holds the first and last name.
        public string StudentName { get; set; }

        // The IsEnrolled property gets or sets a value indicating whether
        // the student is currently enrolled.
        public bool IsEnrolled { get; set; }
    }

    // The StudentList collection is declared for convenience,
    // because declaring generic types in XAML is inconvenient.
    public class StudentList : ObservableCollection<Student>
    {

    }
}


BoolToBrushConverter.cs

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Windows.Media;

namespace DataBindingDemo
{
    // The BoolToBrushConverter class is a value converter
    // that helps to bind a bool value to a brush property.
    [ValueConversion(typeof(bool), typeof(Brush))]
    public class BoolToBrushConverter : IValueConverter
    {
        public object Convert(
            object value, 
            Type targetType, 
            object parameter, 
            CultureInfo culture)
        {
            Brush b = null;

            // Only apply the conversion if value is assigned and
            // is of type bool.
            if (value != null &&
                value.GetType() == typeof(bool))
            {
                // true is painted with a green brush, 
                // false with a red brush.
                b = (bool)value ? Brushes.Green : Brushes.Red;
            }

            return b;
        }

        // Not used.
        public object ConvertBack(
            object value, 
            Type targetType, 
            object parameter, 
            CultureInfo culture)
        {
            return null;
        }
    }
}


MainWindow.xaml


    <Window x:Class="DataBindingDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DataBindingDemo"
        Title="Databinding Demo" Height="300" Width="300">
    <Window.Resources>

        <local:StudentList x:Key="studentCollection" >
            <local:Student StudentName="Syed Abbas" IsEnrolled="false" />
            <local:Student StudentName="Lori Kane" IsEnrolled="true" />
            <local:Student StudentName="Steve Masters" IsEnrolled="false" />
            <local:Student StudentName="Tai Yee" IsEnrolled="true" />
            <local:Student StudentName="Brenda Diaz" IsEnrolled="true" />
        </local:StudentList>

        <local:BoolToBrushConverter x:Key="boolToBrushConverter" />

        <DataTemplate x:Key="listBoxTemplate">
            <StackPanel Orientation="Horizontal" >
                <Rectangle Fill="{Binding Path=IsEnrolled, Converter={StaticResource boolToBrushConverter}}"
                           Height="10" 
                           Width="10" 
                           Margin="0,0,5,0" />
                <TextBlock Text="{Binding Path=StudentName}" />
            </StackPanel>
        </DataTemplate>

    </Window.Resources>
    <Grid></Grid>

</Window>


데이터 바인딩

<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="209" Margin="40,23,0,0" VerticalAlignment="Top" Width="188" ItemsSource="{Binding Mode=OneWay, Source={StaticResource studentCollection}}" DisplayMemberPath="StudentName" />


값 변환기를 사용하여 데이터 바인딩

<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="209" Margin="40,23,0,0" VerticalAlignment="Top" Width="188" ItemTemplate="{StaticResource listBoxTemplate}" ItemsSource="{Binding Mode=OneWay, Source={StaticResource studentCollection}}" />




연습: DesignInstance를 사용하여 디자이너의 데이터에 바인딩

https://msdn.microsoft.com/ko-kr/library/dd490796(v=vs.110).aspx

1. 이 연습에서는 WPF Designer for Visual Studio를 사용하여 런타임에 할당되는 데이터 컨텍스트에 대해 디자인 타임에 데이터 바인딩을 만드는 방법을 보여 줍니다.

2. 데이터 바인딩을 만들려면 데이터 바인딩 작성기를 사용하여 특수한 디자인 타임 데이터 컨텍스트를 만들고 DesignInstance를 비즈니스 개체 형식으로 설정합니다.

3. DesignInstance는 디자인 타임 속성입니다. 

4. 이 연습에서는 다음 작업을 수행합니다.  


1) • 프로젝트를 만듭니다.  

2) • Customer 클래스 비즈니스 개체를 만듭니다.   

3) • TextBox  컨트롤을 데이터 컨텍스트에 있는 Customer 클래스의 디자인 타임 인스턴스에 데이터 바인딩합니다.  


5. 연습을 마치면 런타임에 비즈니스 개체에 바인딩된 텍스트 상자가 완성됩니다. 

6. 데이터 바인딩은 WPF Designer에서 설정됩니다. 



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

namespace DataBindingDemo
{
    public class Customer
    {   
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}

1. Window 여는 태그 수정
xmlns:local="clr-namespace:DataBindingDemo"

2. Grid 여는 태그 수정
<Grid d:DataContext="{d:DesignInstance Type=local:Customer}" Name="_grid">

3. TextBox 컨트롤을 만든 후 Text 속성에서 Customer 개체의 FirstName 속성에 바인딩.

public MainWindow()
{
    InitializeComponent();

    Customer c = new Customer();
    c.FirstName = "Brenda";
    c.LastName = "Diaz";

    this._grid.DataContext = c;
}



연습: XAML을 사용하여 단추 만들기

https://msdn.microsoft.com/ko-kr/library/bb613545(v=vs.110).aspx

1. 이 연습에서는 WPF(Windows Presentation Foundation) 응용 프로그램에서 사용할 애니메이션 단추를 만드는 방법에 대해 알아 봅니다.

2. 이 연습에서는 스타일과 템플릿을 사용하여 코드를 다시 사용할 수 있고 단추 논리와 단추 선언을 분리할 수 있는 사용자 지정된 단추 리소스를 만듭니다.

3. 이 연습에서는 전체 코드를 XAML(Extensible Application Markup Language)로 작성합니다.



기본 단추 만들기


MainWindow.xaml

<Window x:Class="AnimatedButton.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="AnimatedButton" Height="300" Width="300" 
  Background="Black">

  <!-- Buttons arranged vertically inside a StackPanel. -->
  <StackPanel HorizontalAlignment="Left">
    <Button>Button 1</Button>
    <Button>Button 2</Button>
    <Button>Button 3</Button>
  </StackPanel>

</Window>


기본 속성 설정


app.xaml


Application.Resources 블록 정의

<Application x:Class="AnimatedButton.App"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  StartupUri="Window1.xaml"
  >
  <Application.Resources>

    <!-- Resources for the entire application can be 
         defined here. -->

  </Application.Resources>
</Application>


스타일을 만들고 스타일을 사용하여 기본 속성 값 정의

<Application.Resources>

  <Style TargetType="Button">
    <Setter Property="Width" Value="90" />
    <Setter Property="Margin" Value="10" />
  </Style>

</Application.Resources>


스타일 속성 값을 리소스로 설정

<Application.Resources>

  <LinearGradientBrush x:Key="GrayBlueGradientBrush" 
    StartPoint="0,0" EndPoint="1,1">
    <GradientStop Color="DarkGray" Offset="0" />
    <GradientStop Color="#CCCCFF" Offset="0.5" />
    <GradientStop Color="DarkGray" Offset="1" />
  </LinearGradientBrush>

  <Style TargetType="{x:Type Button}">
    <Setter Property="Background" 
      Value="{StaticResource GrayBlueGradientBrush}" />
    <Setter Property="Width" Value="80" />
    <Setter Property="Margin" Value="10" />
  </Style>

</Application.Resources>


단추의 모양을 정의하는 템플릿 만들기


템플릿 설정

<Application.Resources>

  <LinearGradientBrush x:Key="GrayBlueGradientBrush" 
    StartPoint="0,0" EndPoint="1,1">
    <GradientStop Color="DarkGray" Offset="0" />
    <GradientStop Color="#CCCCFF" Offset="0.5" />
    <GradientStop Color="DarkGray" Offset="1" />
  </LinearGradientBrush>

  <Style TargetType="{x:Type Button}">
  <Setter Property="Background" Value="{StaticResource GrayBlueGradientBrush}" />
    <Setter Property="Width" Value="80" />
    <Setter Property="Margin" Value="10" />
    <Setter Property="Template">
      <Setter.Value>
        <!-- The button template is defined here. -->
      </Setter.Value>
    </Setter>
  </Style>

</Application.Resources>


단추 표시 변경

<Setter.Value>
  <ControlTemplate TargetType="Button">
    <Grid Width="{TemplateBinding Width}" 
     Height="{TemplateBinding Height}" ClipToBounds="True">

      <!-- Outer Rectangle with rounded corners. -->
      <Rectangle x:Name="outerRectangle" 
        HorizontalAlignment="Stretch" 
        VerticalAlignment="Stretch" 
        Stroke="{TemplateBinding Background}" 
        RadiusX="20" RadiusY="20" StrokeThickness="5" 
        Fill="Transparent" />

      <!-- Inner Rectangle with rounded corners. -->
      <Rectangle x:Name="innerRectangle" 
        HorizontalAlignment="Stretch" 
        VerticalAlignment="Stretch" Stroke="Transparent" 
        StrokeThickness="20" 
        Fill="{TemplateBinding Background}" 
        RadiusX="20" RadiusY="20"   />

      <!-- Present Content (text) of the button. -->
      <DockPanel Name="myContentPresenterDockPanel">
        <ContentPresenter x:Name="myContentPresenter" Margin="20" 
          Content="{TemplateBinding  Content}" 
          TextBlock.Foreground="Black" />
      </DockPanel>
    </Grid>
  </ControlTemplate>
</Setter.Value>


템플릿에 투명 효과 추가

<Application.Resources>
  <GradientStopCollection x:Key="MyGlassGradientStopsResource">
    <GradientStop Color="WhiteSmoke" Offset="0.2" />
    <GradientStop Color="Transparent" Offset="0.4" />
    <GradientStop Color="WhiteSmoke" Offset="0.5" />
    <GradientStop Color="Transparent" Offset="0.75" />
    <GradientStop Color="WhiteSmoke" Offset="0.9" />
    <GradientStop Color="Transparent" Offset="1" />
  </GradientStopCollection>

  <LinearGradientBrush x:Key="MyGlassBrushResource" 
   StartPoint="0,0" EndPoint="1,1" Opacity="0.75" 
   GradientStops="{StaticResource MyGlassGradientStopsResource}" />
<!-- Styles and other resources below here. -->


<Setter.Value>
  <ControlTemplate TargetType="{x:Type Button}">
    <Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"
ClipToBounds="True">

    <!-- Outer Rectangle with rounded corners. -->
    <Rectangle x:Name="outerRectangle" HorizontalAlignment="Stretch" 
      VerticalAlignment="Stretch" Stroke="{TemplateBinding Background}" 
      RadiusX="20" RadiusY="20" StrokeThickness="5" Fill="Transparent" />

    <!-- Inner Rectangle with rounded corners. -->
    <Rectangle x:Name="innerRectangle" HorizontalAlignment="Stretch" 
      VerticalAlignment="Stretch" Stroke="Transparent" StrokeThickness="20" 
      Fill="{TemplateBinding Background}" RadiusX="20" RadiusY="20" />

    <!-- Glass Rectangle -->
    <Rectangle x:Name="glassCube" HorizontalAlignment="Stretch"
      VerticalAlignment="Stretch"
      StrokeThickness="2" RadiusX="10" RadiusY="10" Opacity="0"
      Fill="{StaticResource MyGlassBrushResource}"
      RenderTransformOrigin="0.5,0.5">
      <Rectangle.Stroke>
        <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
          <LinearGradientBrush.GradientStops>
            <GradientStop Offset="0.0" Color="LightBlue" />
            <GradientStop Offset="1.0" Color="Gray" />
          </LinearGradientBrush.GradientStops>
        </LinearGradientBrush>
      </Rectangle.Stroke>

      <!-- These transforms have no effect as they are declared here. 
           The reason the transforms are included is to be targets 
           for animation (see later). -->
      <Rectangle.RenderTransform>
        <TransformGroup>
          <ScaleTransform />
          <RotateTransform />
        </TransformGroup>
      </Rectangle.RenderTransform>

      <!-- A BevelBitmapEffect is applied to give the button a 
           "Beveled" look. -->
      <Rectangle.BitmapEffect>
        <BevelBitmapEffect />
      </Rectangle.BitmapEffect>
    </Rectangle>

    <!-- Present Text of the button. -->
    <DockPanel Name="myContentPresenterDockPanel">
      <ContentPresenter x:Name="myContentPresenter" Margin="20" 
        Content="{TemplateBinding  Content}" TextBlock.Foreground="Black" />
    </DockPanel>
  </Grid>
</ControlTemplate>
</Setter.Value>


단추 대화형 작업 만들기


템플릿 트리거 추가

<Setter.Value>
  <ControlTemplate TargetType="{x:Type Button}">
    <Grid Width="{TemplateBinding Width}" 
      Height="{TemplateBinding Height}" ClipToBounds="True">

      <!-- Outer Rectangle with rounded corners. -->
      <Rectangle x:Name="outerRectangle" HorizontalAlignment="Stretch" 
      VerticalAlignment="Stretch" Stroke="{TemplateBinding Background}" 
      RadiusX="20" RadiusY="20" StrokeThickness="5" Fill="Transparent" />

      <!-- Inner Rectangle with rounded corners. -->
      <Rectangle x:Name="innerRectangle" HorizontalAlignment="Stretch" 
        VerticalAlignment="Stretch" Stroke="Transparent" 
        StrokeThickness="20" 
        Fill="{TemplateBinding Background}" RadiusX="20" RadiusY="20" 
      />

      <!-- Glass Rectangle -->
      <Rectangle x:Name="glassCube" HorizontalAlignment="Stretch"
        VerticalAlignment="Stretch"
        StrokeThickness="2" RadiusX="10" RadiusY="10" Opacity="0"
        Fill="{StaticResource MyGlassBrushResource}"
        RenderTransformOrigin="0.5,0.5">
        <Rectangle.Stroke>
          <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
            <LinearGradientBrush.GradientStops>
              <GradientStop Offset="0.0" Color="LightBlue" />
              <GradientStop Offset="1.0" Color="Gray" />
            </LinearGradientBrush.GradientStops>
          </LinearGradientBrush>
        </Rectangle.Stroke>

        <!-- These transforms have no effect as they 
             are declared here. 
             The reason the transforms are included is to be targets 
             for animation (see later). -->
        <Rectangle.RenderTransform>
          <TransformGroup>
            <ScaleTransform />
            <RotateTransform />
          </TransformGroup>
        </Rectangle.RenderTransform>

          <!-- A BevelBitmapEffect is applied to give the button a 
               "Beveled" look. -->
        <Rectangle.BitmapEffect>
          <BevelBitmapEffect />
        </Rectangle.BitmapEffect>
      </Rectangle>

      <!-- Present Text of the button. -->
      <DockPanel Name="myContentPresenterDockPanel">
        <ContentPresenter x:Name="myContentPresenter" Margin="20" 
          Content="{TemplateBinding  Content}" TextBlock.Foreground="Black" />
      </DockPanel>
    </Grid>

    <ControlTemplate.Triggers>
      <!-- Set action triggers for the buttons and define
           what the button does in response to those triggers. -->
    </ControlTemplate.Triggers>
  </ControlTemplate>
</Setter.Value>


속성 트리거 추가

<ControlTemplate.Triggers>

  <!-- Set properties when mouse pointer is over the button. -->
  <Trigger Property="IsMouseOver" Value="True">

    <!-- Below are three property settings that occur when the 
         condition is met (user mouses over button).  -->
    <!-- Change the color of the outer rectangle when user 
         mouses over it. -->
    <Setter Property ="Rectangle.Stroke" TargetName="outerRectangle"
      Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />

    <!-- Sets the glass opacity to 1, therefore, the 
         glass "appears" when user mouses over it. -->
    <Setter Property="Rectangle.Opacity" Value="1" TargetName="glassCube" />

    <!-- Makes the text slightly blurry as though you 
         were looking at it through blurry glass. -->
    <Setter Property="ContentPresenter.BitmapEffect" 
      TargetName="myContentPresenter">
      <Setter.Value>
        <BlurBitmapEffect Radius="1" />
      </Setter.Value>
    </Setter>
  </Trigger>

<ControlTemplate.Triggers/>


포커스 트리거 추가

<ControlTemplate.Triggers>

  <!-- Set properties when mouse pointer is over the button. -->
  <Trigger Property="IsMouseOver" Value="True">

    <!-- Below are three property settings that occur when the 
         condition is met (user mouses over button).  -->
    <!-- Change the color of the outer rectangle when user          mouses over it. -->
    <Setter Property ="Rectangle.Stroke" TargetName="outerRectangle"
      Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />

    <!-- Sets the glass opacity to 1, therefore, the          glass "appears" when user mouses over it. -->
    <Setter Property="Rectangle.Opacity" Value="1"       TargetName="glassCube" />

    <!-- Makes the text slightly blurry as though you were          looking at it through blurry glass. -->
    <Setter Property="ContentPresenter.BitmapEffect"       TargetName="myContentPresenter">
      <Setter.Value>
        <BlurBitmapEffect Radius="1" />
      </Setter.Value>
    </Setter>
  </Trigger>
  <!-- Set properties when button has focus. -->
  <Trigger Property="IsFocused" Value="true">
    <Setter Property="Rectangle.Opacity" Value="1"       TargetName="glassCube" />
    <Setter Property="Rectangle.Stroke" TargetName="outerRectangle"
      Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
    <Setter Property="Rectangle.Opacity" Value="1" TargetName="glassCube" />
  </Trigger>

</ControlTemplate.Triggers>


MouseEnter 및 MouseLeave 에 대한 애니메이션 추가

<!-- Animations that start when mouse enters and leaves button. -->
<EventTrigger RoutedEvent="Mouse.MouseEnter">
  <EventTrigger.Actions>
    <BeginStoryboard Name="mouseEnterBeginStoryboard">
      <Storyboard>

      <!-- This animation makes the glass rectangle shrink in the X direction. -->
        <DoubleAnimation Storyboard.TargetName="glassCube" 
          Storyboard.TargetProperty=
          "(Rectangle.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
          By="-0.1" Duration="0:0:0.5" />

        <!-- This animation makes the glass rectangle shrink in the Y direction. -->
        <DoubleAnimation
        Storyboard.TargetName="glassCube" 
          Storyboard.TargetProperty=
          "(Rectangle.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" 
          By="-0.1" Duration="0:0:0.5" />
      </Storyboard>
    </BeginStoryboard>
  </EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
  <EventTrigger.Actions>

    <!-- Stopping the storyboard sets all animated properties back to default. -->
    <StopStoryboard BeginStoryboardName="mouseEnterBeginStoryboard" />
  </EventTrigger.Actions>
</EventTrigger>


단추를 클릭할 때를 위한 애니메이션 추가

<!-- Animation fires when button is clicked, causing glass to spin.  -->
<EventTrigger RoutedEvent="Button.Click">
  <EventTrigger.Actions>
    <BeginStoryboard>
      <Storyboard>
        <DoubleAnimation Storyboard.TargetName="glassCube" 
          Storyboard.TargetProperty=
          "(Rectangle.RenderTransform).(TransformGroup.Children)[1].(RotateTransform.Angle)" 
          By="360" Duration="0:0:0.5" />
      </Storyboard>
    </BeginStoryboard>
  </EventTrigger.Actions>
</EventTrigger>


요약

1. 이 연습에서는 다음 연습을 수행했습니다.

1) Style의 대상을 개체 형식(Button)으로 지정했습니다.

2) Style을 사용하여 전체 응용 프로그램에서 단추의 기본 속성을 제어했습니다.

3) Style setter의 속성 값으로 사용할 그라데이션과 같은 리소스를 만들었습니다.

4) 단추에 템플릿을 적용하여 전체 응용 프로그램에서 단추 모양을 사용자 지정했습니다.

5) MouseEnter, MouseLeave 및 Click과 같은 사용자 작업에 응답하는 애니메이션 효과가 포함된 단추의 동작을 사용자 지정했습니다.






응용 프로그램 개발

https://msdn.microsoft.com/ko-kr/library/bb613549(v=vs.110).aspx

1. WPF(Windows Presentation Foundation)은 다음과 같은 종류의 응용 프로그램을 개발하는 데 사용할 수 있는 프레젠테이션 프레임워크입니다.

1) 독립 실행형 응용 프로그램(클라이언트 컴퓨터에 설치해서 운영하는 실행 어셈블리로 구성된 전형적인 창 응용 프로그램)

2) XAML browser applications (XBAPs)(탐색 페이지로 이루어져 있고 이 페이지가 Microsoft Internet Explorer 또는 Mozilla Firefox 등의 웹 브라우저를 통해 호스팅되는 실행 어셈블리로 구성된 응용 프로그램)

3) 사용자 지정 컨트롤 라이브러리(재사용 가능한 컨트롤이 들어 있는 비실행 어셈블리)

4) 클래스 라이브러리(재사용 가능한 클래스가 들어 있는 비실행 어셈블리)


참고

1. Windows 서비스에서 WPF 형식을 사용하지 않는 것이 좋습니다.

2. Windows 서비스에서 이러한 기능을 사용하려고 하면 기능이 예상대로 작동하지 않을 수 있습니다.


2. 이러한 응용 프로그램 집합을 빌드하기 위해 WPF는 서비스 호스트를 구현합니다.

3. 이 항목에서는 이러한 서비스에 대한 개요와 더 자세한 정보를 찾을 수 있는 링크를 제공합니다.


응용 프로그램 관리

1. 실행 가능한 WPF 응용 프로그램에는 일반적으로 다음과 같은 핵심 기능 집합이 필요합니다.

1) 진입점 메서드와 시스템 및 입력 메시지를 수신하는 Windows 메시지 루프 만들기를 비롯한 공통 응용 프로그램 인프라 만들기 및 관리

2) 응용 프로그램의 수명 추적 및 상호 작용

3) 명령줄 매개 변수 검색 및 처리

4) 응용 프로그램 범위에 속한 속성 및 UI 리소스 공유

5) 처리되지 않은 예외 검색 및 처리

6) 종료 코드 반환

7) 독립 실행형 응용 프로그램에서 창 관리

8) XAML browser applications (XBAPs)와 탐색 창 및 프레임이 있는 독립 실행형 응용 프로그램에서 탐색 추적

2. 이러한 기능은 응용 프로그램 정의를 사용하여 응용 프로그램에 추가하는 Application 클래스로 구현됩니다.

3. 자세한 내용은 응용 프로그램 관리 개요를 참조하십시오.


WPF 응용 프로그램 리소스, 콘텐츠 및 데이터 파일

1. WPF에서는 리소스, 콘텐츠 및 데이터를 비롯한 세 가지 종류의 비실행 데이터 파일에 대한 지원으로 포함 리소스에 대한 Microsoft .NET Framework의 핵심 지원을 확장합니다.

2. 자세한 내용은 WPF 응용 프로그램 리소스, 콘텐츠 및 데이터 파일을 참조하십시오.

3. WPF 비실행 데이터 파일에 대한 지원에서 중요한 구성 요소는 고유한 URI를 사용하여 데이터 파일을 식별하고 로드하는 기능입니다.

4. 자세한 내용은 WPF의 Pack URI를 참조하십시오.


창 및 대화 상자

1. 사용자는 창을 통해 WPF 독립 실행형 응용 프로그램과 상호 작용합니다.

2. 창의 용도는 응용 프로그램 콘텐츠를 호스팅하고, 대개 사용자가 콘텐츠와 상호 작용할 수 있게 만드는 응용 프로그램 기능을 노출하는 것입니다.

3. WPF에서 창은 다음을 지원하는 Window 클래스로 캡슐화됩니다.

1) 창 만들기 및 표시

2) 소유자/소유된 창 관계 설정

3) 창 모양 구성(예: 크기, 위치, 아이콘, 제목 표시줄 텍스트, 테두리)

4) 창의 수명 추적 및 상호 작용

4. 자세한 내용은 WPF 창 개요를 참조하십시오.

5. Window는 대화 상자라고 하는 특수한 유형의 창을 만드는 기능을 지원합니다.

6. 모달 및 모덜리스 유형의 대화 상자를 모두 만들 수 있습니다.

7. 사용 편의를 높이고 응용 프로그램 간의 재사용 및 일관성 있는 사용자 환경을 제공하기 위해 WPF에서는 세 가지 공용 Windows 대화 상자인 OpenFileDialog, SaveFileDialog 및 PrintDialog를 노출합니다.

8. 메시지 상자는 사용자에게 중요한 텍스트 정보를 표시하고 간단한 예/아니요/확인/취소 질문을 하는 데 사용되는 특수한 유형의 대화 상자입니다.

9. MessageBox 클래스를 사용하여 메시지 상자를 만들고 표시할 수 있습니다.

10. 자세한 내용은 대화 상자 개요를 참조하십시오.


탐색

1. WPF는 페이지(Page)와 하이퍼링크(Hyperlink)를 사용하는 웹 스타일의 탐색을 지원합니다.

2. 이러한 탐색 기능은 다음을 비롯한 다양한 방식으로 구현할 수 있습니다.

1) 웹 브라우저에서 호스팅되는 독립 실행형 페이지

2) 웹 브라우저에서 호스팅되는 XBAP로 컴파일되는 페이지

3) 독립 실행형 응용 프로그램으로 컴파일되고 탐색 창에서 호스팅되는 페이지(NavigationWindow)

4) 독립 실행형 페이지 또는 XBAP나 독립 실행형 응용 프로그램으로 컴파일되는 페이지에서 호스팅될 수 있는 프레임(Frame)을 통해 호스팅되는 페이지

3. WPF에서는 효과적인 탐색을 위해 다음을 구현합니다.

1) Frame, NavigationWindow 및 응용 프로그램 간 탐색을 지원하는 XBAP에서 사용되는 탐색 요청을 처리하기 위한 공유 탐색 엔진인 NavigationService

2) 탐색을 초기화하는 탐색 메서드

3) 탐색 수명을 추적하고 상호 작용하는 탐색 이벤트

4) 검사 및 조작이 가능한 저널을 사용한 후방 및 전방 탐색 기억

4. 자세한 내용은 탐색 개요를 참조하십시오.

5. WPF에서는 구조적 탐색이라고 하는 특수한 유형의 탐색도 지원합니다.

6. 구조적 탐색을 사용하면 호출 함수와 일관성을 유지하는 구조적이며 예측 가능한 방식으로 데이터를 반환하는 하나 이상의 페이지를 호출할 수 있습니다.

7. 이 기능은 PageFunction<T> 클래스에 따라 달라집니다.

8. 이 클래스에 대해서는 구조적 탐색 개요에서 자세히 설명합니다.

9. 탐색 토폴로지 개요에서 설명하는 것처럼 복잡한 탐색 토폴로지를 간단하게 생성하기 위해서도 PageFunction<T>이 사용됩니다.


호스팅

1. XBAP는 Microsoft Internet Explorer 또는 Firefox에서 호스팅될 수 있습니다.

2. 각 호스팅 모델에는 WPF 응용 프로그램 호스팅 항목에 설명되어 있는 고유한 고려 사항과 제약 조건 집합이 있습니다.


빌드 및 배포

1. 명령줄 컴파일러를 사용하면 명령 프롬프트에서 간단한 WPF 응용 프로그램을 빌드할 수 있지만 WPF에서는 Microsoft Visual Studio를 통합하여 개발 및 빌드 프로세스를 단순화하는 추가적인 지원을 제공합니다.

2. 자세한 내용은 WPF 응용 프로그램 만들기(WPF)를 참조하십시오.

3. 빌드하는 응용 프로그램의 형식에 따라 하나 이상의 배포 옵션을 선택하여 사용할 수 있습니다.

4. 자세한 내용은 WPF 응용 프로그램 배포(WPF)를 참조하십시오.



제목

설명

응용 프로그램 관리 개요

응용 프로그램 수명, 창, 응용 프로그램 리소스 및 탐색에 대한 관리를 비롯하여 Application 클래스에 대해 간략히 설명합니다.

WPF 응용 프로그램의 창

Window 클래스 및 대화 상자 사용 방법을 비롯하여 응용 프로그램에서 창을 관리하는 방법에 대한 정보를 제공합니다.

탐색 개요

응용 프로그램의 페이지 간 탐색 관리에 대해 간략히 설명합니다.

WPF 응용 프로그램 호스팅

XAML browser applications (XBAPs)를 간략하게 설명합니다.

WPF 응용 프로그램 빌드 및 배포

WPF 응용 프로그램을 만들고 배포하는 방법에 대해 설명합니다.

Visual Studio 2015에서의 WPF 소개

WPF의 주요 기능을 설명합니다.

연습: WPF 시작

페이지 탐색, 레이아웃, 컨트롤, 이미지, 스타일 및 바인딩을 사용하여 WPF 응용 프로그램을 만드는 방법을 보여 주는 연습을 제공합니다.




응용 프로그램 관리 개요









'프로그래밍 > WPF' 카테고리의 다른 글

WPF 고급 - 입력 (Input)  (0) 2016.10.15
ObservableCollection<T>, INotifyPropertyChanged Interface  (0) 2016.10.15
WPF 고급 - 아키텍처, XAML  (0) 2016.09.23
WPF - Application Development  (1) 2016.09.08
Data Binding (WPF)  (0) 2016.09.04
:
Posted by 지훈2
2016. 8. 25. 15:39

파일 시스템 및 레지스트리 프로그래밍/C#2016. 8. 25. 15:39

https://msdn.microsoft.com/ko-kr/library/2kzb96fk.aspx


방법: 디렉터리 트리 반복


1. "디렉터리 트리 반복"이란 깊이에 관계없이 지정된 루트 폴더 아래에 있는 각 중첩 하위 디렉터리에서 각 파일에 액세스한다는 의미입니다.

2. 이때 각 파일을 반드시 열어야 하는 것은 아닙니다.

3. 파일이나 하위 디렉터리의 이름만 string으로 검색하거나 System.IO.FileInfo 또는 System.IO.DirectoryInfo 개체의 형태로 추가 정보를 검색할 수 있습니다.


참고

Windows에서 "디렉터리"와 "폴더"라는 용어는 같은 의미로 사용됩니다. 대부분의 설명서와 사용자 인터페이스 텍스트에서는 "폴더"라는 용어가 사용되지만 .NET Framework 클래스 라이브러리에서는 "디렉터리"라는 용어가 사용됩니다.


4. 지정된 루트 아래에 있는 모든 디렉터리에 대한 액세스 권한이 있는 경우가 가장 간단하며, 이 경우에는 System.IO.SearchOption.AllDirectories 플래그를 사용할 수 있습니다.

5. 이 플래그는 지정된 패턴과 일치하는 모든 중첩 하위 디렉터리를 반환합니다.

6. 다음 예제에서는 이 플래그를 사용하는 방법을 보여 줍니다.


root.GetDirectories("*.*", System.IO.SearchOption.AllDirectories);


7. 이 방식의 단점은 지정된 루트 아래에 있는 하위 디렉터리 중 하나가 DirectoryNotFoundException 또는 UnauthorizedAccessException을 발생시키면 전체 메서드가 실패하고 디렉터리가 반환되지 않는다는 것입니다.

8. 이것은 GetFiles 메서드를 사용할 경우에도 마찬가지입니다.

9. 특정 하위 폴더에서 이러한 예외를 처리해야 한다면 다음 예제에서 볼 수 있는 것처럼 디렉터리 트리를 수동으로 탐색해야 합니다.

10. 디렉터리 트리를 수동으로 탐색할 때 하위 디렉터리를 먼저(전위 탐색) 처리하거나 파일을 먼저(후위 탐색) 처리할 수 있습니다.

11. 전위 탐색을 수행할 경우 폴더 자체에 들어 있는 파일을 반복하기 전에 먼저 현재 폴더 아래에 있는 전체 트리를 탐색합니다.

12. 이 문서의 뒷부분에 있는 예제에서는 후위 탐색을 수행하지만 전위 탐색을 수행하도록 수정하는 것은 간단합니다.

13. 다른 옵션은 재귀를 사용할지 스택 기반 탐색을 사용할지 결정하는 것입니다.

14. 이 문서의 뒷부분에 있는 예제에서는 두 방식을 모두 보여 줍니다.

15. 파일과 폴더에 대한 다양한 작업을 수행해야 한다면 단일 대리자를 통해 호출할 수 있는 별도의 함수로 작업을 리팩터링하여 이 예제를 모듈화할 수 있습니다.


참고

1. NTFS 파일 시스템은 연결 지점, 기호화된 링크 및 하드 링크의 형태로 재분석 지점을 포함할 수 있습니다.

2. GetFiles 및 GetDirectories 등의 .NET Framework 메서드는 재분석 지점 아래에 있는 하위 디렉터리를 반환하지 않습니다.

3. 이 동작은 두 재분석 지점이 상호 참조하는 경우 무한 루프에 빠지지 않도록 보호합니다.

4. 일반적으로 재분석 지점으로 작업할 때에는 실수로 파일을 수정하거나 삭제하지 않도록 특히 주의해야 합니다.

5. 재분석 지점에 대한 정밀한 제어가 필요한 경우에는 적절한 Win32 파일 시스템 메서드를 직접 호출하는 플랫폼 호출이나 네이티브 코드를 사용하십시오.


예제

1. 다음 예제에서는 재귀를 사용하여 디렉터리 트리를 탐색하는 방법을 보여 줍니다.

2. 재귀는 적절한 방식이기는 하지만 디렉터리 트리의 규모가 크고 복잡하게 중첩되어 있는 경우 스택 오버플로 예외를 발생시킬 위험이 있습니다.

3. 처리되는 특정한 예외와 각 파일이나 폴더에 수행되는 특정 작업은 예제로만 제공됩니다.

4. 따라서 해당 요구 사항에 맞게 이 코드를 수정해야 합니다. 자세한 내용은 코드의 주석을 참조하십시오.


public class RecursiveFileSearch
{
    static System.Collections.Specialized.StringCollection log = new System.Collections.Specialized.StringCollection();

    static void Main()
    {
        // Start with drives if you have to search the entire computer.
        string[] drives = System.Environment.GetLogicalDrives();

        foreach (string dr in drives)
        {
            System.IO.DriveInfo di = new System.IO.DriveInfo(dr);

            // Here we skip the drive if it is not ready to be read. This
            // is not necessarily the appropriate action in all scenarios.
            if (!di.IsReady)
            {
                Console.WriteLine("The drive {0} could not be read", di.Name);
                continue;
            }
            System.IO.DirectoryInfo rootDir = di.RootDirectory;
            WalkDirectoryTree(rootDir);
        }

        // Write out all the files that could not be processed.
        Console.WriteLine("Files with restricted access:");
        foreach (string s in log)
        {
            Console.WriteLine(s);
        }
        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key");
        Console.ReadKey();
    }

    static void WalkDirectoryTree(System.IO.DirectoryInfo root)
    {
        System.IO.FileInfo[] files = null;
        System.IO.DirectoryInfo[] subDirs = null;

        // First, process all the files directly under this folder
        try
        {
            files = root.GetFiles("*.*");
        }
        // This is thrown if even one of the files requires permissions greater
        // than the application provides.
        catch (UnauthorizedAccessException e)
        {
            // This code just writes out the message and continues to recurse.
            // You may decide to do something different here. For example, you
            // can try to elevate your privileges and access the file again.
            log.Add(e.Message);
        }

        catch (System.IO.DirectoryNotFoundException e)
        {
            Console.WriteLine(e.Message);
        }

        if (files != null)
        {
            foreach (System.IO.FileInfo fi in files)
            {
                // In this example, we only access the existing FileInfo object. If we
                // want to open, delete or modify the file, then
                // a try-catch block is required here to handle the case
                // where the file has been deleted since the call to TraverseTree().
                Console.WriteLine(fi.FullName);
            }

            // Now find all the subdirectories under this directory.
            subDirs = root.GetDirectories();

            foreach (System.IO.DirectoryInfo dirInfo in subDirs)
            {
                // Resursive call for each subdirectory.
                WalkDirectoryTree(dirInfo);
            }
        }            
    }
}


예제

1. 다음 예제에서는 재귀를 사용하지 않고 디렉터리 트리에서 파일 및 폴더를 반복하는 방법을 보여 줍니다.

2. 이 방법에서는 LIFO(후입선출) 스택인 제네릭 Stack<T> 컬렉션 형식을 사용합니다.

3. 처리되는 특정한 예외와 각 파일이나 폴더에 수행되는 특정 작업은 예제로만 제공됩니다.

4. 따라서 해당 요구 사항에 맞게 이 코드를 수정해야 합니다.

5. 자세한 내용은 코드의 주석을 참조하십시오.


public class StackBasedIteration
{
    static void Main(string[] args)
    {
        // Specify the starting folder on the command line, or in 
        // Visual Studio in the Project > Properties > Debug pane.
        TraverseTree(args[0]);

        Console.WriteLine("Press any key");
        Console.ReadKey();
    }

    public static void TraverseTree(string root)
    {
        // Data structure to hold names of subfolders to be
        // examined for files.
        Stack<string> dirs = new Stack<string>(20);

        if (!System.IO.Directory.Exists(root))
        {
            throw new ArgumentException();
        }
        dirs.Push(root);

        while (dirs.Count > 0)
        {
            string currentDir = dirs.Pop();
            string[] subDirs;
            try
            {
                subDirs = System.IO.Directory.GetDirectories(currentDir);
            }
            // An UnauthorizedAccessException exception will be thrown if we do not have
            // discovery permission on a folder or file. It may or may not be acceptable 
            // to ignore the exception and continue enumerating the remaining files and 
            // folders. It is also possible (but unlikely) that a DirectoryNotFound exception 
            // will be raised. This will happen if currentDir has been deleted by
            // another application or thread after our call to Directory.Exists. The 
            // choice of which exceptions to catch depends entirely on the specific task 
            // you are intending to perform and also on how much you know with certainty 
            // about the systems on which this code will run.
            catch (UnauthorizedAccessException e)
            {                    
                Console.WriteLine(e.Message);
                continue;
            }
            catch (System.IO.DirectoryNotFoundException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }

            string[] files = null;
            try
            {
                files = System.IO.Directory.GetFiles(currentDir);
            }

            catch (UnauthorizedAccessException e)
            {

                Console.WriteLine(e.Message);
                continue;
            }

            catch (System.IO.DirectoryNotFoundException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            // Perform the required action on each file here.
            // Modify this block to perform your required task.
            foreach (string file in files)
            {
                try
                {
                    // Perform whatever action is required in your scenario.
                    System.IO.FileInfo fi = new System.IO.FileInfo(file);
                    Console.WriteLine("{0}: {1}, {2}", fi.Name, fi.Length, fi.CreationTime);
                }
                catch (System.IO.FileNotFoundException e)
                {
                    // If file was deleted by a separate application
                    //  or thread since the call to TraverseTree()
                    // then just continue.
                    Console.WriteLine(e.Message);
                    continue;
                }
            }

            // Push the subdirectories onto the stack for traversal.
            // This could also be done before handing the files.
            foreach (string str in subDirs)
                dirs.Push(str);
        }
    }
}


6. 응용 프로그램에 폴더를 열 수 있는 권한이 있는지 확인하기 위해 모든 폴더를 테스트하는 작업은 시간이 너무 많이 걸립니다.

7. 따라서 이 코드 예제에서는 작업의 해당 부분을 try/catch 블록으로 묶기만 했습니다.

8. 폴더에 대한 액세스가 거부된 경우 권한을 상승시키고 다시 액세스할 수 있도록 catch 블록을 수정할 수 있습니다.

9. 일반적으로 응용 프로그램을 알 수 없는 상태로 두지 않고 처리할 수 있는 예외만 catch합니다.

10. 디렉터리 트리의 내용을 메모리나 디스크에 저장해야 하는 경우 각 파일의 FullName 속성(string 형식)만 저장하는 것이 좋습니다.

11. 그런 다음 필요에 따라 이 문자열을 사용하여 새 FileInfo 또는 DirectoryInfo 개체를 만들거나 추가적인 처리가 필요한 파일을 열 수 있습니다.


강력한 프로그래밍

1. 강력한 파일 반복 코드에서는 파일 시스템의 여러 가지 복잡한 특성을 고려해야 합니다.

2. 자세한 내용은 NTFS Technical Reference를 참조하십시오.




방법: 파일, 폴더 및 드라이브에 대한 정보 가져오기


1. .NET Framework에서 다음과 같은 클래스를 사용하여 파일 시스템 정보에 액세스할 수 있습니다.

1) System.IO.FileInfo

2) System.IO.DirectoryInfo

3) System.IO.DriveInfo

4) System.IO.Directory

5) System.IO.File

2. FileInfo 및 DirectoryInfo 클래스는 파일 또는 디렉터리를 나타내며 NTFS 파일 시스템이 지원하는 많은 파일 특성을 노출하는 속성을 포함합니다.

3. 또한 파일 및 폴더 열기, 닫기, 이동, 삭제를 위한 메서드도 포함합니다.

4. 다음과 같이 생성자에 파일, 폴더 또는 드라이브 이름을 나타내는 문자열을 전달하여 이러한 클래스의 인스턴스를 만들 수 있습니다.


System.IO.DriveInfo di = new System.IO.DriveInfo(@"C:\");


5. DirectoryInfo.GetDirectories, DirectoryInfo.GetFiles 및 DriveInfo.RootDirectory를 호출하여 파일, 폴더 또는 드라이브 이름을 얻을 수도 있습니다.

6. System.IO.Directory 및 System.IO.File 클래스는 디렉터리 및 파일에 대한 정보를 검색하는 static 메서드를 제공합니다.


예제

1. 다음 예제에서는 파일 및 폴더 정보에 액세스하는 여러 가지 방법을 보여 줍니다.


class FileSysInfo
{
    static void Main()
    {
        // You can also use System.Environment.GetLogicalDrives to
        // obtain names of all logical drives on the computer.
        System.IO.DriveInfo di = new System.IO.DriveInfo(@"C:\");
        Console.WriteLine(di.TotalFreeSpace);
        Console.WriteLine(di.VolumeLabel);

        // Get the root directory and print out some information about it.
        System.IO.DirectoryInfo dirInfo = di.RootDirectory;
        Console.WriteLine(dirInfo.Attributes.ToString());

        // Get the files in the directory and print out some information about them.
        System.IO.FileInfo[] fileNames = dirInfo.GetFiles("*.*");


        foreach (System.IO.FileInfo fi in fileNames)
        {
            Console.WriteLine("{0}: {1}: {2}", fi.Name, fi.LastAccessTime, fi.Length);
        }

        // Get the subdirectories directly that is under the root.
        // See "How to: Iterate Through a Directory Tree" for an example of how to
        // iterate through an entire tree.
        System.IO.DirectoryInfo[] dirInfos = dirInfo.GetDirectories("*.*");

        foreach (System.IO.DirectoryInfo d in dirInfos)
        {
            Console.WriteLine(d.Name);
        }

        // The Directory and File classes provide several static methods
        // for accessing files and directories.

        // Get the current application directory.
        string currentDirName = System.IO.Directory.GetCurrentDirectory();
        Console.WriteLine(currentDirName);           

        // Get an array of file names as strings rather than FileInfo objects.
        // Use this method when storage space is an issue, and when you might
        // hold on to the file name reference for a while before you try to access
        // the file.
        string[] files = System.IO.Directory.GetFiles(currentDirName, "*.txt");

        foreach (string s in files)
        {
            // Create the FileInfo object only when needed to ensure
            // the information is as current as possible.
            System.IO.FileInfo fi = null;
            try
            {
                 fi = new System.IO.FileInfo(s);
            }
            catch (System.IO.FileNotFoundException e)
            {
                // To inform the user and continue is
                // sufficient for this demonstration.
                // Your application may require different behavior.
                Console.WriteLine(e.Message);
                continue;
            }
            Console.WriteLine("{0} : {1}",fi.Name, fi.Directory);
        }

        // Change the directory. In this case, first check to see
        // whether it already exists, and create it if it does not.
        // If this is not appropriate for your application, you can
        // handle the System.IO.IOException that will be raised if the
        // directory cannot be found.
        if (!System.IO.Directory.Exists(@"C:\Users\Public\TestFolder\"))
        {
            System.IO.Directory.CreateDirectory(@"C:\Users\Public\TestFolder\");
        }

        System.IO.Directory.SetCurrentDirectory(@"C:\Users\Public\TestFolder\");

        currentDirName = System.IO.Directory.GetCurrentDirectory();
        Console.WriteLine(currentDirName);

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}


강력한 프로그래밍

1. 사용자가 지정한 경로 문자열을 처리할 때 다음과 같은 예외 상황을 처리해야 합니다.

1) 파일 이름의 형식이 잘못된 경우. 예를 들어 파일 이름에 잘못된 문자가 들어 있거나 공백이 있을 수 있습니다.

2) 경로 이름이 null인 경우

3) 파일 이름이 시스템에 정의된 최대 길이보다 긴 경우

4) 파일 이름에 콜론(:)이 있는 경우

2. 지정된 파일을 읽을 수 있는 충분한 권한이 응용 프로그램에 없으면 경로의 존재 여부와 상관없이 Exists 메서드에서 false를 반환합니다.

3. 이때 메서드는 예외를 throw하지 않습니다.



방법: 파일 또는 폴더 만들기


1. 프로그램으로 컴퓨터에 폴더를 만들고, 하위 폴더를 만들고, 하위 폴더에 특정 파일을 만든 다음, 해당 파일에 데이터를 쓸 수 있습니다.


public class CreateFileOrFolder
{
    static void Main()
    {
        // Specify a name for your top-level folder.
        string folderName = @"c:\Top-Level Folder";

        // To create a string that specifies the path to a subfolder under your 
        // top-level folder, add a name for the subfolder to folderName.
        string pathString = System.IO.Path.Combine(folderName, "SubFolder");

        // You can write out the path name directly instead of using the Combine
        // method. Combine just makes the process easier.
        string pathString2 = @"c:\Top-Level Folder\SubFolder2";

        // You can extend the depth of your path if you want to.
        //pathString = System.IO.Path.Combine(pathString, "SubSubFolder");

        // Create the subfolder. You can verify in File Explorer that you have this
        // structure in the C: drive.
        //    Local Disk (C:)
        //        Top-Level Folder
        //            SubFolder
        System.IO.Directory.CreateDirectory(pathString);

        // Create a file name for the file you want to create. 
        string fileName = System.IO.Path.GetRandomFileName();

        // This example uses a random string for the name, but you also can specify
        // a particular name.
        //string fileName = "MyNewFile.txt";

        // Use Combine again to add the file name to the path.
        pathString = System.IO.Path.Combine(pathString, fileName);

        // Verify the path that you have constructed.
        Console.WriteLine("Path to my file: {0}\n", pathString);

        // Check that the file doesn't already exist. If it doesn't exist, create
        // the file and write integers 0 - 99 to it.
        // DANGER: System.IO.File.Create will overwrite the file if it already exists.
        // This could happen even with random file names, although it is unlikely.
        if (!System.IO.File.Exists(pathString))
        {
            using (System.IO.FileStream fs = System.IO.File.Create(pathString))
            {
                for (byte i = 0; i < 100; i++)
                {
                    fs.WriteByte(i);
                }
            }
        }
        else
        {
            Console.WriteLine("File \"{0}\" already exists.", fileName);
            return;
        }

        // Read and display the data from your file.
        try
        {
            byte[] readBuffer = System.IO.File.ReadAllBytes(pathString);
            foreach (byte b in readBuffer)
            {
                Console.Write(b + " ");
            }
            Console.WriteLine();
        }
        catch (System.IO.IOException e)
        {
            Console.WriteLine(e.Message);
        }

        // Keep the console window open in debug mode.
        System.Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();
    }
    // Sample output:

    // Path to my file: c:\Top-Level Folder\SubFolder\ttxvauxe.vv0

    //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
    //30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
    // 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 8
    //3 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
}


2. 폴더가 이미 있을 경우 CreateDirectory는 아무 작업도 수행하지 않으며 예외가 throw되지 않습니다.

3. 그러나 File.Create이 기존 파일을 새 파일로 바꿉니다.

4. 예제는 기존 파일이 대체되지 않도록 if-else 문을 사용합니다.

5. 예제를 다음과 같이 변경하여 특정 이름을 가진 파일이 이미 있는지 여부를 기준으로 다른 결과를 지정할 수 있습니다.

6. 이러한 파일이 없으면 코드가 파일을 하나 만듭니다.

7. 이러한 파일이 있으면 코드가 파일에 데이터를 추가합니다.

1) non-random 파일 이름을 지정합니다.


// Comment out the following line.
//string fileName = System.IO.Path.GetRandomFileName();

// Replace that line with the following assignment.
string fileName = "MyNewFile.txt";


2) if-else 문을 다음 코드의 using 문으로 바꿉니다.


using (System.IO.FileStream fs = new System.IO.FileStream(pathString, FileMode.Append)) 
{
    for (byte i = 0; i < 100; i++)
    {
        fs.WriteByte(i);
    }
}


8. 데이터가 파일에 추가될 때마다 확인하려면 예제를 여러 번 실행합니다.

9. 사용자가 시도할 수 있는 더 많은 FileMode 값은 FileMode을 참조하십시오.

10. 다음 조건에서 예외가 발생할 수 있습니다.

1) 폴더 이름의 형식이 잘못된 경우. 예를 들어, 파일 이름에 잘못된 문자가 포함되어 있거나 파일 이름이 공백인 경우(ArgumentException 클래스) Path 클래스를 사용하여 유효한 경로 이름을 만듭니다.

2) 만들 폴더의 부모 폴더가 읽기 전용인 경우(IOException 클래스)

3) 폴더 이름이 null인 경우(ArgumentNullException 클래스)

4) 폴더 이름이 너무 긴 경우(PathTooLongException 클래스)

5) 폴더 이름이 콜론 ":"인 경우(PathTooLongException 클래스)


.NET Framework 보안

1. 부분 신뢰 상황에서는 SecurityException 클래스의 인스턴스가 throw될 수 있습니다.

2. 폴더를 만들 권한이 없는 경우에는 예제에서 UnauthorizedAccessException 클래스의 인스턴스가 throw됩니다.




파일 및 폴더 복사, 삭제 및 이동


1. 다음 예제에서는 System.IO 네임스페이스의 System.IO.File, System.IO.Directory, System.IO.FileInfo 및 System.IO.DirectoryInfo 클래스를 사용하여 파일 및 폴더를 동기화된 방식으로 복사, 이동 및 삭제하는 방법을 보여 줍니다.

2. 이러한 예제에서는 진행률 표시줄이나 다른 사용자 인터페이스는 제공하지 않습니다.

3. 표준 진행률 대화 상자를 제공하려면 방법: 파일 작업에 대한 진행률 대화 상자 제공(C# 프로그래밍 가이드)을 참조하십시오.

4. System.IO.FileSystemWatcher를 사용하면 여러 파일을 처리할 때 진행률을 계산할 수 있는 이벤트를 제공할 수 있습니다.

5. 또 다른 방법은 Windows 셸에서 파일 관련 메서드를 호출하는 플랫폼 호출을 사용하는 것입니다.

6. 이러한 파일 작업을 비동기적으로 수행하는 방법에 대한 자세한 내용은 비동기 파일 I/O를 참조하십시오.


예제

1. 다음 예제에서는 파일 및 디렉터리를 복사하는 방법을 보여 줍니다.


// Simple synchronous file copy operations with no user interface.
// To run this sample, first create the following directories and files:
// C:\Users\Public\TestFolder
// C:\Users\Public\TestFolder\test.txt
// C:\Users\Public\TestFolder\SubDir\test.txt
public class SimpleFileCopy
{
    static void Main()
    {
        string fileName = "test.txt";
        string sourcePath = @"C:\Users\Public\TestFolder";
        string targetPath =  @"C:\Users\Public\TestFolder\SubDir";

        // Use Path class to manipulate file and directory paths.
        string sourceFile = System.IO.Path.Combine(sourcePath, fileName);
        string destFile = System.IO.Path.Combine(targetPath, fileName);

        // To copy a folder's contents to a new location:
        // Create a new target folder, if necessary.
        if (!System.IO.Directory.Exists(targetPath))
        {
            System.IO.Directory.CreateDirectory(targetPath);
        }

        // To copy a file to another location and 
        // overwrite the destination file if it already exists.
        System.IO.File.Copy(sourceFile, destFile, true);

        // To copy all the files in one directory to another directory.
        // Get the files in the source folder. (To recursively iterate through
        // all subfolders under the current directory, see
        // "How to: Iterate Through a Directory Tree.")
        // Note: Check for target path was performed previously
        //       in this code example.
        if (System.IO.Directory.Exists(sourcePath))
        {
            string[] files = System.IO.Directory.GetFiles(sourcePath);

            // Copy the files and overwrite destination files if they already exist.
            foreach (string s in files)
            {
                // Use static Path methods to extract only the file name from the path.
                fileName = System.IO.Path.GetFileName(s);
                destFile = System.IO.Path.Combine(targetPath, fileName);
                System.IO.File.Copy(s, destFile, true);
            }
        }
        else
        {
            Console.WriteLine("Source path does not exist!");
        }

        // Keep console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}


예제

1. 다음 예제에서는 파일 및 디렉터리를 이동하는 방법을 보여 줍니다.


// Simple synchronous file move operations with no user interface.
public class SimpleFileMove
{
    static void Main()
    {
        string sourceFile = @"C:\Users\Public\public\test.txt";
        string destinationFile = @"C:\Users\Public\private\test.txt";

        // To move a file or folder to a new location:
        System.IO.File.Move(sourceFile, destinationFile);

        // To move an entire directory. To programmatically modify or combine
        // path strings, use the System.IO.Path class.
        System.IO.Directory.Move(@"C:\Users\Public\public\test\", @"C:\Users\Public\private");
    }
}


예제

1. 다음 예제에서는 파일 및 디렉터리를 삭제하는 방법을 보여 줍니다.


// Simple synchronous file deletion operations with no user interface.
// To run this sample, create the following files on your drive:
// C:\Users\Public\DeleteTest\test1.txt
// C:\Users\Public\DeleteTest\test2.txt
// C:\Users\Public\DeleteTest\SubDir\test2.txt

public class SimpleFileDelete
{
    static void Main()
    {
        // Delete a file by using File class static method...
        if(System.IO.File.Exists(@"C:\Users\Public\DeleteTest\test.txt"))
        {
            // Use a try block to catch IOExceptions, to
            // handle the case of the file already being
            // opened by another process.
            try
            {
                System.IO.File.Delete(@"C:\Users\Public\DeleteTest\test.txt");
            }
            catch (System.IO.IOException e)
            {
                Console.WriteLine(e.Message);
                return;
            }
        }

        // ...or by using FileInfo instance method.
        System.IO.FileInfo fi = new System.IO.FileInfo(@"C:\Users\Public\DeleteTest\test2.txt");
        try
        {
            fi.Delete();
        }
        catch (System.IO.IOException e)
        {
            Console.WriteLine(e.Message);
        }

        // Delete a directory. Must be writable or empty.
        try
        {
            System.IO.Directory.Delete(@"C:\Users\Public\DeleteTest");
        }
        catch (System.IO.IOException e)
        {
            Console.WriteLine(e.Message);
        }
        // Delete a directory and all subdirectories with Directory static method...
        if(System.IO.Directory.Exists(@"C:\Users\Public\DeleteTest"))
        {
            try
            {
                System.IO.Directory.Delete(@"C:\Users\Public\DeleteTest", true);
            }

            catch (System.IO.IOException e)
            {
                Console.WriteLine(e.Message);
            }
        }

        // ...or with DirectoryInfo instance method.
        System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(@"C:\Users\Public\public");
        // Delete this dir and all subdirs.
        try
        {
            di.Delete(true);
        }
        catch (System.IO.IOException e)
        {
            Console.WriteLine(e.Message);
        }

    }
}




방법: 파일 작업에 대한 진행률 대화 상자 제공


1. Microsoft.VisualBasic 네임스페이스에서 CopyFile(String, String, UIOption) 메서드를 사용하면 Windows에서 파일 작업에 대한 진행률을 표시하는 표준 대화 상자를 제공할 수 있습니다.


참고

1. 일부 Visual Studio 사용자 인터페이스 요소의 경우 다음 지침에 설명된 것과 다른 이름 또는 위치가 시스템에 표시될 수 있습니다.

2. 이러한 요소는 사용하는 Visual Studio 버전 및 설정에 따라 결정됩니다.

3. 자세한 내용은 Visual Studio IDE 개인 설정을 참조하십시오.


Visual Studio에서 참조를 추가하려면

1. 메뉴 모음에서 프로젝트, 참조 추가를 선택합니다.

2. 참조 관리자 대화 상자가 나타납니다.

3. 어셈블리 영역에서 프레임워크가 아직 선택되어 있지 않으면 프레임워크를 선택합니다.

4. 이름 목록에서, Microsoft.VisualBasic 확인란을 선택하고 나서, 확인 단추를 선택하면 대화 상자가 닫힙니다.


예제

1. 다음 코드에서는 sourcePath에서 지정하는 디렉터리를 destinationPath에서 지정하는 디렉터리로 복사합니다.

2. 이 코드에서는 또한 작업이 끝날 때까지 남은 추정 시간을 보여 주는 표준 대화 상자도 제공합니다.


// The following using directive requires a project reference to Microsoft.VisualBasic.
using Microsoft.VisualBasic.FileIO;

class FileProgress
{
    static void Main()
    {
        // Specify the path to a folder that you want to copy. If the folder is small, 
        // you won't have time to see the progress dialog box.
        string sourcePath = @"C:\Windows\symbols\";
        // Choose a destination for the copied files.
        string destinationPath = @"C:\TestFolder";

        FileSystem.CopyDirectory(sourcePath, destinationPath,
            UIOption.AllDialogs);
    }
}




방법: 텍스트 파일에 쓰기


1. 다음 코드 예제에서는 파일에 텍스트를 쓰는 여러 가지 방법을 보여 줍니다.

2. 처음 두 예제에서는 System.IO.File 클래스에서 정적 편의 메서드를 사용하여 IEnumerable<string>의 각 요소와 문자열을 텍스트 파일에 씁니다.

3. 예제 3에서는 파일에 쓸 때 각 줄을 개별적으로 처리해야 하는 경우 파일에 텍스트를 추가하는 방법을 보여 줍니다.

4. 예제 1-3에서는 파일의 기존 내용을 모두 덮어쓰지만 예제 4에서는 기존 파일에 텍스트를 추가하는 방법을 보여 줍니다.

5. 이 네 예제에서는 모두 파일에 문자열 리터럴을 쓰지만 대개는 Format 메서드를 사용합니다.

6. 이 메서드는 필드에서 값을 오른쪽 또는 왼쪽 맞춤으로 정렬하고 안쪽 여백을 포함하거나 포함하지 않는 등 다양한 형식의 값을 쓰기 위한 많은 컨트롤을 포함합니다.

7. C# 문자열 보간 기능을 사용할 수도 있습니다.


class WriteTextFile
{
    static void Main()
    {

        // These examples assume a "C:\Users\Public\TestFolder" folder on your machine.
        // You can modify the path if necessary.


        // Example #1: Write an array of strings to a file.
        // Create a string array that consists of three lines.
        string[] lines = { "First line", "Second line", "Third line" };
        // WriteAllLines creates a file, writes a collection of strings to the file,
        // and then closes the file.  You do NOT need to call Flush() or Close().
        System.IO.File.WriteAllLines(@"C:\Users\Public\TestFolder\WriteLines.txt", lines);


        // Example #2: Write one string to a text file.
        string text = "A class is the most powerful data type in C#. Like a structure, " +
                       "a class defines the data and behavior of the data type. ";
        // WriteAllText creates a file, writes the specified string to the file,
        // and then closes the file.    You do NOT need to call Flush() or Close().
        System.IO.File.WriteAllText(@"C:\Users\Public\TestFolder\WriteText.txt", text);

        // Example #3: Write only some strings in an array to a file.
        // The using statement automatically flushes AND CLOSES the stream and calls 
        // IDisposable.Dispose on the stream object.
        // NOTE: do not use FileStream for text files because it writes bytes, but StreamWriter
        // encodes the output as text.
        using (System.IO.StreamWriter file = 
            new System.IO.StreamWriter(@"C:\Users\Public\TestFolder\WriteLines2.txt"))
        {
            foreach (string line in lines)
            {
                // If the line doesn't contain the word 'Second', write the line to the file.
                if (!line.Contains("Second"))
                {
                    file.WriteLine(line);
                }
            }
        }

        // Example #4: Append new text to an existing file.
        // The using statement automatically flushes AND CLOSES the stream and calls 
        // IDisposable.Dispose on the stream object.
        using (System.IO.StreamWriter file = 
            new System.IO.StreamWriter(@"C:\Users\Public\TestFolder\WriteLines2.txt", true))
        {
            file.WriteLine("Fourth line");
        }
    }
}
 //Output (to WriteLines.txt):
 //   First line
 //   Second line
 //   Third line

 //Output (to WriteText.txt):
 //   A class is the most powerful data type in C#. Like a structure, a class defines the data and behavior of the data type.

 //Output to WriteLines2.txt after Example #3:
 //   First line
 //   Third line

 //Output to WriteLines2.txt after Example #4:
 //   First line
 //   Third line
 //   Fourth line


강력한 프로그래밍

1. 다음 조건에서 예외가 발생합니다.

1) 파일이 있지만 읽기 전용인 경우

2) 경로 이름이 너무 긴 경우

3) 디스크가 꽉 찬 경우




방법: 텍스트 파일에서 읽기


1. 정적 메서드를 사용 하 여이 예제 텍스트 파일의 내용을 읽어 ReadAllText 및 ReadAllLines 에서 System.IO.File 클래스입니다.

2. StreamReader을 사용하는 예제를 보려면 방법: 텍스트 파일을 한 번에 한 줄씩 읽기(Visual C#)을 참조하십시오.


참고

이 예제에서 사용 되는 파일은 방법: 텍스트 파일에 쓰기(C# 프로그래밍 가이드)에서 만든 파일입니다.


예제

class ReadFromFile
{
    static void Main()
    {
        // The files used in this example are created in the topic
        // How to: Write to a Text File. You can change the path and
        // file name to substitute text files of your own.

        // Example #1
        // Read the file as one string.
        string text = System.IO.File.ReadAllText(@"C:\Users\Public\TestFolder\WriteText.txt");

        // Display the file contents to the console. Variable text is a string.
        System.Console.WriteLine("Contents of WriteText.txt = {0}", text);

        // Example #2
        // Read each line of the file into a string array. Each element
        // of the array is one line of the file.
        string[] lines = System.IO.File.ReadAllLines(@"C:\Users\Public\TestFolder\WriteLines2.txt");

        // Display the file contents by using a foreach loop.
        System.Console.WriteLine("Contents of WriteLines2.txt = ");
        foreach (string line in lines)
        {
            // Use a tab to indent each line of the file.
            Console.WriteLine("\t" + line);
        }

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();
    }
}




방법: 텍스트 파일을 한 번에 한 줄씩 읽기


1. 이 예제에서는 StreamReader 클래스의 ReadLine 메서드를 사용하여 텍스트 파일의 내용을 한 번에 한 줄씩 문자열로 읽어 들입니다.

2. 각 텍스트 줄은 line 문자열에 저장되고 화면에 표시됩니다.


예제

int counter = 0;
string line;

// Read the file and display it line by line.
System.IO.StreamReader file = 
    new System.IO.StreamReader(@"c:\test.txt");
while((line = file.ReadLine()) != null)
{
    System.Console.WriteLine (line);
    counter++;
}

file.Close();
System.Console.WriteLine("There were {0} lines.", counter);
// Suspend the screen.
System.Console.ReadLine();




방법: 레지스트리에 키 만들기


1. 이 예제에서는 현재 사용자의 레지스트리에 있는 "Names" 키 아래에 "Name"과 "Isabella" 값 쌍을 추가합니다.


Microsoft.Win32.RegistryKey key;
key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey("Names");
key.SetValue("Name", "Isabella");
key.Close();


코드 컴파일

1. 코드를 복사한 다음 콘솔 응용 프로그램의 Main 메서드에 붙여넣습니다.

2. Names 매개 변수를 레지스트리의 HKEY_CURRENT_USER 노드 바로 아래에 있는 키 이름으로 바꿉니다.

3. Name 매개 변수를 Names 노드 바로 아래에 있는 값의 이름으로 바꿉니다.

강력한 프로그래밍

1. 키를 넣을 적합한 위치를 찾으려면 레지스트리 구조를 살펴 봅니다.

2. 예를 들어, 현재 사용자의 Software 키를 열고 회사 이름을 갖는 키를 만들 수 있습니다.

3. 그런 다음 해당 레지스트리 값을 회사 키에 추가하면 됩니다.

4. 다음 조건에서 예외가 발생합니다.

1) 키 이름이 null인 경우

2) 사용자에게 레지스트리 키를 만들 수 있는 권한이 없는 경우

3) 키 이름이 255자 제한을 초과하는 경우

4) 키가 닫힌 경우

5) 레지스트리 키가 읽기 전용인 경우

.NET Framework 보안

1. 데이터를 로컬 컴퓨터(Microsoft.Win32.Registry.LocalMachine)에 쓰는 것보다 사용자 폴더(Microsoft.Win32.Registry.CurrentUser)에 쓰는 것이 더 안전합니다.

2. 레지스트리 값을 만들 때는 해당 값이 이미 존재하는 경우 어떻게 처리할 것인지 결정해야 합니다.

3. 악의적인 프로세스가 이미 해당 값을 만들어 액세스하고 있을 수도 있습니다.

4. 레지스트리 값에 입력한 데이터는 다른 프로세스에서도 사용할 수 있습니다.

5. 이를 방지하려면 Overload:Microsoft.Win32.RegistryKey.GetValue 메서드를 사용합니다.

6. 키가 아직 없으면 이 메서드에서 null을 반환합니다.

7. 레지스트리 키가 ACL(액세스 제어 목록)에 의해 보호되는 경우에도 레지스트리에 암호 등의 비밀을 일반 텍스트로 저장하면 보안상 위험합니다.













'프로그래밍 > C#' 카테고리의 다른 글

C# 코딩 규칙  (0) 2016.08.28
예외 및 예외 처리  (0) 2016.08.26
형식 참조 테이블  (0) 2016.08.23
클래스 및 구조체  (0) 2016.08.05
인터페이스, 이벤트, 인덱서  (0) 2016.08.04
:
Posted by 지훈2