성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <br /> <div style='font-family: 맑은 고딕, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>WPF 데이터 바인딩 시의 예외 처리 방법</div><br /> <br /> 예전에, .NET 응용 프로그램에서 예외 처리를 하는 방법에 관해 정리해놓았지요. ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > .NET 예외 처리 정리 ; <a target='_tab' href='/2/0/316'>http://www.sysnet.pe.kr/2/0/316</a> WPF - 전역 예외 처리 ; <a target='_tab' href='/2/0/614'>http://www.sysnet.pe.kr/2/0/614</a> </pre> <br /> WPF로 오면서는 유독 First-chance Exception을 구분하는 것이 더 중요해졌습니다. 일례로 아래와 같은 경우들이 모두 "First-chance exception"을 모르면 문제를 해결하는데 헤멜 수가 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > 예외 처리를 방해하는 WPF Modal 대화창 ; <a target='_tab' href='/2/0/619'>http://www.sysnet.pe.kr/2/0/619</a> WPF - XamlParseException 대응 방법 ; <a target='_tab' href='/2/0/622'>http://www.sysnet.pe.kr/2/0/622</a> </pre> <br /> 다시 한번 강조하지만, "First-chance Exception"에 대해서 아직도 모르시는 분들은 부디 이번 기회에 꼭 알고 넘어가시기 바랍니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > First-Chance Exception ; <a target='_tab' href='/2/0/510'>http://www.sysnet.pe.kr/2/0/510</a> </pre> <br /> <hr style='width: 50%' /><br /> <br /> WPF에서, 예외 처리에 관해 어려움을 겪는 경우가 하나 더 있는데요. 아래의 코드를 보면서 설명해 보겠습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > public partial class Window1 : Window, INotifyPropertyChanged { string name2; public string Name2 { get { return this.name2; } set { this.name2 = value; OnPropertyChanged("Name2"); throw new <b style='color: Blue;'>ApplicationException</b>("TEST"); } } private void Window_Loaded(object sender, RoutedEventArgs e) { <b style='color: Blue;'>this.Name2 = "TEST";</b> } } </pre> <br /> 보통 위와 같은 상황에서, Visual Studio는 아래와 같이 정상적으로 디버그 지점을 잘 잡아냅니다.<br /> <br /> [그림 1: ApplicationException 예외]<br /> <img alt='not_catch_databind_exception_1.png' src='/SysWebRes/bbs/not_catch_databind_exception_1.png' /><br /> <br /> 하지만, 명시적으로 사용한 this.Name2 = "TEST" 코드를 삭제하고, 대신에 Name2 속성을 데이터바인딩으로 연결하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > <TextBox Height="30" Margin="16,40,124,0" Text="{<b style='color: Blue;'>Binding Path=Name2</b>}" /> </pre> <br /> 이제는 더 이상 Visual Studio IDE에서 예외를 잡아내지 못합니다. 단지 "Output" 창에 다음과 같은 식으로 오류 로그가 출력될 뿐입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > A first chance exception of type '<b style='color: Blue;'>System.ApplicationException</b>' occurred in WpfApplication1.exe A first chance exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll System.Windows.Data Error: 8 : Cannot save value from target back to source. BindingExpression:Path=Name2; DataItem='Window1' (Name=''); target element is 'TextBox' (Name='textBox1'); target property is 'Text' (type 'String') TargetInvocationException:'System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ApplicationException: TEST at WpfApplication1.Window1.<b style='color: Blue;'>set_Name2</b>(String value) in D:\Settings\desktop\binding_exception\WpfApplication1\WpfApplication1\Window1.xaml.cs:line 31 --- End of inner exception stack trace --- at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner) at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture) at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object[] index) at MS.Internal.Data.PropertyPathWorker.SetValue(Object item, Object value) at MS.Internal.Data.ClrBindingWorker.UpdateValue(Object value) at System.Windows.Data.BindingExpression.UpdateSource(Object value)' </pre> <br /> 개인적으로 아쉬운 부분이 바로 위와 같이 데이터 바인딩 구문에서 예외를 먹어버리는 현상입니다. 아쉽긴 해도, WPF의 Validation 정책을 아시는 분들은 이런 식의 동작이 "By design"이라고 수긍이 되는 면이 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > WPF Sample Series - Handling and Reporting WPF Data Binding Validation Errors and Exceptions ; <a target='_tab' href='http://karlshifflett.wordpress.com/2008/04/03/wpf-sample-series-handling-and-reporting-wpf-data-binding-validation-errors-and-exceptions/'>http://karlshifflett.wordpress.com/2008/04/03/wpf-sample-series-handling-and-reporting-wpf-data-binding-validation-errors-and-exceptions/</a> </pre> <br /> 그러하니, 유효성 검사에서 자연스럽게 처리될 예외이므로 응용 프로그램 종료로 이어지는 예외 상황을 만들지 않도록 데이터 바인딩 과정에서 try/catch로 예외를 미리 처리하게 된 것입니다. 재미있는 점이 있다면, 마이크로소프트는 DataBinding에 오류가 발생하는 것을 알 수 있도록 그나마 세심하게 배려했다는 정도!<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > How can I debug WPF bindings? ; <a target='_tab' href='http://www.beacosta.com/blog/?p=52'>http://www.beacosta.com/blog/?p=52</a> </pre> <br /> 위의 글에 보면, 데이터 바인딩 오류에 대해 "Trace"로 오류 로그를 남기는 방법과 PresentationTraceSources.TraceLevel을 이용한 방법을 소개해 주고 있습니다.<br /> <br /> 그래도... 이런 거에 만족할 수는 없지요? ^^ 어떻게 해서든지 저는 공용 속성의 set 접근자에서 발생하는 오류를 잡아내야 겠습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 단서를 찾을 수 있는 곳은 Validation을 처리하는 코드일 것 같습니다.<br /> <br /> <a target='_tab' href='http://karlshifflett.wordpress.com/2008/04/03/wpf-sample-series-handling-and-reporting-wpf-data-binding-validation-errors-and-exceptions/'>WPF Sample Series - Handling and Reporting WPF Data Binding Validation Errors and Exceptions</a> 글에 보면, ExceptionValidationErrorHandler 코드를 볼 수 있는데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > void ExceptionValidationErrorHandler(object sender, RoutedEventArgs e) { System.Windows.Controls.ValidationErrorEventArgs arg = e as System.Windows.Controls.ValidationErrorEventArgs; ; } </pre> <br /> 해답은 바로 위의 arg 인자에서 제공되는 Error 속성에 있습니다. 보통 ExceptionValidationErrorHandler가 실행되는 경우는 다음과 같은 2가지 경우입니다.<br /> <br /> <ul> <li>위에서 설명한 대로 set 접근자에서 오류가 발생한 경우, 또는 타입이 달라서 예외가 발생한 경우</li> <li>IDataErrorInfo를 구현한 개체가 해당 속성의 값이 유효하지 않다고 하는 경우</li> </ul> <br /> 이 2가지를 구분하려면 arg.Error.RuleInError의 타입으로 검사하면 됩니다.<br /> <br /> <ul> <li>(arg.Error.RuleInError is ExceptionValidationRule) == true: 첫 번째 경우</li> <li>(arg.Error.RuleInError is DataErrorValidationRule) == true: 두 번째 경우</li> </ul> <br /> 이런 것을 반영해 보면 다음과 같은 식으로 코드를 만들면 될 것 같습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > void ExceptionValidationErrorHandler(object sender, RoutedEventArgs e) { System.Windows.Controls.ValidationErrorEventArgs arg = e as System.Windows.Controls.ValidationErrorEventArgs; if (arg.Error.Exception != null && arg.Error.RuleInError is <b style='color: Blue;'>ExceptionValidationRule</b>) { if (<b style='color: Blue;'>arg.Error.Exception is System.FormatException</b>) { // 대개의 경우 발생할 수 있는 ExceptionValidationRule } else { // 그 외의 예외는 의도적이지 않은 예외 <b style='color: Blue;'>throw arg.Error.Exception.InnerException</b>; } } } </pre> <br /> 이렇게 되면, 타입이 일치하지 않아 발생하는 예외는 그대로 Validation 검사로 진행하도록 하고, 그 이외의 상황에서는 throw를 해서 개발자로 하여금 set 접근자에서 예외가 발생했음을 알 수 있도록 해줍니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 그나마 예외 상황을 잡아보긴 했지만 아직 해결되지 않은 문제가 있습니다. ExceptionValidationErrorHandler 단계에서는 스택이 이미 풀린 상태이기 때문에 정확히 오류가 발생하는 곳에 코드를 위치시킬 방법이 없습니다. 할 수 없이, 예외가 발생했다는 정도만을 정확하게 인식하고 "throw arg.Error.Exception.InnerException"에서 확인할 수 있는 예외를 디버그 예외 상자에 등록하거나, 아니면 여전히 Output 창의 "First-chance Exception"을 확인해서 디버그 예외 상자에 등록해 두는 식으로 접근해야 합니다.<br /> <br /> 게다가... 또 한 가지 아쉬운 것은.<br /> <br /> Validation 처리 과정으로 넘어오지 않은 예외에 대해서는 여전히 잡을 방법이 없습니다. 예를 들어, 데이터바인딩에는 "Name2"라는 속성명인데, 실제로는 그러한 속성이 없는 경우에는 ExceptionValidationErrorHandler까지 진입하지도 않습니다. 어쩔 수 없이 "<a target='_tab' href='http://www.beacosta.com/blog/?p=52'>How can I debug WPF bindings?</a>"에서 설명한 방식으로 데이터바인딩 예외를 추적하는 방법을 따라야 합니다.<br /> <br /> <a target='_tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=475&boardid=331301885'>관련 예제 코드는 첨부 파일</a>에 올려놓았습니다.<br /> <br /><br /><hr /><span style='color: Maroon'>[이 토픽에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1486
(왼쪽의 숫자를 입력해야 합니다.)