사용자 도구

사이트 도구


sdk:wpf:리소스와_데이터바인딩

차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

양쪽 이전 판이전 판
다음 판
이전 판
sdk:wpf:리소스와_데이터바인딩 [2017/07/07 18:35] – [DataBinding 디버깅] kieunssdk:wpf:리소스와_데이터바인딩 [2024/04/23 22:44] (현재) – 바깥 편집 127.0.0.1
줄 1: 줄 1:
 +====== 리소스 ======
 +
 +리소스 : 이미지,폰트,오디오,비디오,문자열테이블 
 +
 +이런 리소스를 패키지화(?)해서 쓸 수 있도록 지원해준다.
 +
 +리소스는 바이너리, 로지컬 두 방식이 있다.
 +
 +===== 바이너리 리소스 =====
 +
 +비트맵 같은 일반적인 것부터 컴파일된 xaml도 리소스로 저장 가능.
 +
 +  * 어셈블리 내부에 저장
 +  * 느슨한 파일 형태(?)로 사용한다. 컴파일할때나 런타임으로 이용 가능.
 +
 +추가 : 프로젝트에 파일을 추가하고 '속성'에서 적합한 빌드작업(빌드액션)을 선택하면 된다.
 +
 +  * Resource : 위성어셈블리(?)나 일반 어셈블리에 포함
 +  * Content : 느슨한파일(?)로 남겨두고 AssemblyAssociatedContentFile 에 파일 경로와 이름을 저장
 +    * 그니까.. 위치만 기록하고 파일 리소스는 바깥에 둔다는 이야기(?)
 +
 +바이너리 리소스에 접근
 +
 +  * URI를 통해 xaml이나 코드에서 리소스 접근 가능
 +  * 'Source' 프로퍼티 써서 파일명 적으면 알아서 찾는데..
 +  * 해당 리소스가 없어도 일단 동작은 한다. (예: 이미지 같은거)
 +
 +다른 어셈블리에 있는 리소스 접근
 +
 +  어셈블리참조;컴포넌트/리소스명(AssemblyReference;Component/ResourceName)
 +
 +라는 규칙이 있다.
 +
 +  * 어셈블리명 \\ ( MyDll;component/images/logo.jpg )
 +  * 어셈블리명;v버젼번호 \\ ( MyDll;v1.35;component/images/logo.jpg )
 +  * 어셈블리명;공용키토큰 \\ ( MyDll;dlc642a7f5bd61912;component;component/images/logo.jpg )
 +  * 어셈블리명;v버젼번호;공용키토큰 \\ ( MyDll;v1.35;dlc642a7f5bd61912;component;component/images/logo.jpg )
 +
 +사이트 원점에서 리소스 접근하기
 +
 +  * 용어를 왜 이렇게 복잡하게 쓰는가? 설치된 기준 폴더나 url.
 +  * 설치한 폴더를 기준폴더 , 사이트 원점이라고 부른다.
 +  * 웹에서 실행하는 경우 기본 Url
 +
 +표시방법
 +
 +  * siteOfOrigin : 사이트 원점 키워드
 +
 +<code>
 +pack://siteOfOrigin:,,,/
 +</code>
 +
 +
 +코드에서 리소스 접근
 +
 +  * xaml 방식의 URI 쓸 수 없고 사이트원점을 URL 등의 전체 경로를 명시
 +
 +<code csharp>
 +Image img = new Image();
 +img.Source = new BitmapImage(new Uri("pack://application:,,,/logo.jpg"))
 +</code>
 +
 +지역화
 +
 +지원 언어(컬쳐)만큼 위성 어셈블리로 분리. 
 +
 +LocBaml 을 이용하면 지역화할 문자열 작업을 간편하게 가능.
 +
 +
 +
 +===== 로지컬 리소스 =====
 +
 +프로그래밍 코드에서 만들고 사용할 수 있는 리소스. 동적으로 데이터가 추가/삭제되는 데이터 타입의 리소스를 가리키는 듯.
 +
 +  * Resource 프로퍼티에 닷넷 객체를 저장하고, 여러 자식 엘리먼트 사이에 공유.
 +  * FrameworkElement, FrameworkContentElement 에서 파생되는 클래스( 대부분의 컨트롤 UI )가 Resource 프로퍼티를 갖고 있으니 대부분 클래스에서 로지컬 리소스 이용 가능.
 +
 +하드코딩하는 예제
 +<code xml>
 +<!-- 귀찮아서 아직 안적음 -->
 +</code>
 +
 +Window.Resouce 에 브러쉬 리소스를 세팅해 놓고 사용하는 방식
 +<code xml>
 +<!-- 귀찮아서 아직 안적음 -->
 +</code>
 +
 +====리소스로 정의한 것====
 +  * SolidColorBrush
 +  * LinearGradientBrush
 +  * Image
 +
 +잠시, 리소스로 사용할 수 있는 것들의 부모 클래스
 +
 +  * System.Windows.Freezable : [[https://msdn.microsoft.com/ko-kr/library/system.windows.freezable(v=vs.110).aspx|링크]]
 +    * System.Windows.Media.Animation.Animatable : [[https://msdn.microsoft.com/ko-kr/library/system.windows.media.animation.animatable(v=vs.110).aspx|링크]]
 +      * System.Windows.Media.Brush : [[https://msdn.microsoft.com/ko-kr/library/system.windows.media.brush(v=vs.110).aspx|링크]]
 +
 +====리소스 룩업(찾기)====
 +
 +StaticResource 마크업 확장식은 리소스 딕셔너리 (위에서는 Window.Resource 부분)에서 아이템을 가리키는 키(x:Key 로 설정한)를 파라미터로 받는다.
 +
 +어느 리소스 딕셔너리에든 있기만 하다면 x:Key로 접근 가능하다. 리소스 딕셔너리느는 상위 부모 엘리먼트 또는 애플리케이션 수준의 것도 있을 수 있다.
 +
 +검색 단계
 +  - 현재의 엘리먼트 리소스 딕셔너리 Resources 컬렉션. (없으면 다음 단계)
 +  - 부모의 것에서 찾기, 반복, 루트 엘리먼트까지 검색 (없으면 다음 단계)
 +  - Application 의 Resources 에서 검색 (없으면 다음 단계)
 +  - 시스템에서 검색 (없으면 다음 단계)
 +  - 이래도 없으면 InvalidOperationException 발생
 +
 +====스태틱vs다이나믹 리소스====
 +
 +키워드
 +  * StaticResource
 +  * DynamicResource
 +
 +스태틱 리소스는 선언된 후에 사용할 수 있다. 다이나믹은 그런 제한은 없다.
 +
 +<code xml>
 +<Window 
 +  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 +  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 +  Title="SimpleWindow" Background='{DynamicResource backgroundBrush}'>
 +<!--
 +  DynamicResource 가 위에서 사용 되어도 에러는 없다.
 +  아래 리소스 정의 하는 부분에 backgroundBrush 를 추가해서 사용하게끔 한다.
 +-->
 +  <Window.Resources>
 +    <SolidColorBrush x:Key='backgroundBrush'>Yellow</SolidColorBrush>
 +    <SolidColorBrush x:Key='borderBrush'>Red</SolidColorBrush>
 +  </Window.Resources>
 +  ...
 +</Window>
 +</code>
 +
 +=== 리소스 분리해서 별개 파일로 나누기 ===
 +
 +ResourceDictionary 클래스의 MergedDictionaries 프로퍼티를 써서 다른 파일의 리소스를 자신의 컬렉션으로 (리소스로) 합칠 수 있다. 코드보면 이해하기 쉬움.
 +
 +<code xml>
 +<Window.Resources>
 +  <ResourceDictionary>
 +    <ResourceDictionary.MergedDictionaries>
 +      <ResourceDictionary Source='file1.xaml'/>
 +      <ResourceDictionary Source='file2.xaml'/>
 +    </ResourceDictionary.MergedDictionaries>
 +  </ResourceDictionary>
 +</Window.Resources>
 +</code>
 +
 +개별 파일은 ResourceDictionary를 루트 엘리먼트로 써야 한다.
 +예, file1.xaml
 +
 +<code xml>
 +<ResourceDictionary
 +  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 +  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 +  <Image x:Key="logo" Source="logo.jpg"/>
 +</ResourceDictionary>
 +</code>
 +
 +  * 머지된 것들 중, 중복되는게 있으면 마지막 것으로 설정 된다.
 +
 +=== 공유 없는 리소스 ===
 +
 +  * x:Shared = 'True' or 'False'
 +
 +'False' 설정이면 StaticResource 로 한 섹션에 여러번 적용해도 다른 개체로 인식되어 에러가 나지 않는다.
 +
 +<code xml>
 +<Window.Resources>
 +  <Image x:Key="logo" x:Shared='False' Source="logo.jpg"/>
 +</ResourceDictionary>
 +...
 +<StaticResource ResourceKey='logo'/>
 +<StaticResource ResourceKey='logo'/>
 +<StaticResource ResourceKey='logo'/>
 +<StaticResource ResourceKey='logo'/>
 +...
 +</code>
 +
 +=== 프로그래밍 코드에서 리소스 정의하고 적용하기 ===
 +
 +정의는 간단
 +
 +<code csharp>
 +window.Resources.Add("backgroundBrush", new SolidColorBrush("Yellow"));
 +</code>
 +
 +적용(사용)
 +
 +**Case Static**
 +
 +<code xml>
 +<Button
 +    Background='{StaticResource backgroundBrush}'
 +    BroderBrush='{StaticResource borderBrush}'/>
 +</code>
 +
 +이걸 코드로 쓰려면,
 +
 +<code csharp>
 +Button _btn = new Button();
 +_btn.Background = (Brush)_btn.FindResource("backgroundBrush");
 +_btn.BorderBrush = (Brush)_btn.FindReosurce("borderBrush");
 +</code>
 +
 +  * FindResource 는 못찾으면 예외 날림
 +  * TryFindResource 는 못찾으면 널 반환
 +
 +**Case Dynamic**
 +
 +<code xml>
 +<Button
 +    Background='{DynamicResource backgroundBrush}'
 +    BroderBrush='{DynamicResource borderBrush}'/>
 +</code>
 +
 +<code csharp>
 +Button _btn = new Button();
 +_btn.SetResourceReference(Button.BackgroundProperty, "backgroundBrush");
 +_btn.SetResourceReference(Button.BorderBrushProperty, "borderBrush");
 +</code>
 +
 +====== 데이터 바인딩 ======
 +
 +Data binding, Template, trigger
 +
 +System.Windows.Data.Binding 클래스가 핵심. 두개의 프로퍼티를 이용해서 둘 사이에 연결된 채널을 유지한다.
 +
 +===== 코드로 바인딩 사용 =====
 +
 +한개의 텍스트 블록과 트리뷰가 있는 화면에서,
 +
 +<code xml>
 +<TextBlock x:Name='currentFolder' Text='TextBlock'/>
 +</code>
 +
 +트리뷰 아이템을 선택할때마다, 텍스트블록에 메시지를 갱신한다면.
 +
 +<code csharp>
 +private void DummyTreeView_SelectedItemChanged(
 +    object sender,
 +    RoutedPropertyChangedEventArgs<object> e)
 +{
 +    currentFolder.Text = DummyTreeView.SelectedItem.ToString();
 +}
 +</code>
 +
 +
 +바인딩 하기
 +
 +<code csharp>
 +SetBinding()
 +BindingOperations.SetBinding( _TARGET_, _TARGET_PROP_, binding );
 +</code>
 +
 +바인딩 제거
 +
 +<code csharp>
 +BindingOperations.ClearBinding( _TARGET_, _TARGET_PROP_ );
 +// 한개 이상
 +BindingOperations.ClearAllBindings(..)
 +</code>
 +  
 +===== xaml 바인딩 =====
 +
 +Binding 선언으로 사용할 수 있는 마크업 확장식이 있다. \\
 +타겟 프로퍼티에 바인딩 인스턴스를 추가하고 프로퍼티처러 사용할 수 있다.
 +
 +<code xml>
 +<TextBlock x:Name='currentFolder' DockPanel.Dock='Top' 
 +           Text='{Binding ElementName=treeView, Path=SelectedItem.Header}'
 +           Background='AliceBlue' FontSize='16'/>
 +<!-- 
 +SelectedItem.Header 일지 SelectedItem 일지는 트리뷰 설정 상태에 따라
 +-->
 +</code>
 +
 +Path 프로퍼티는 생략 될 수 있다.
 +
 +<code xml>
 +<TextBlock x:Name='currentFolder' DockPanel.Dock='Top' 
 +           Text='{Binding SelectedItem ElementName=treeView}'
 +           Background='AliceBlue' FontSize='16'/>
 +</code>
 +
 +데이터 바인딩은 수동으로 하니씩 처리하는 것보다, 소스와 타겟 프로퍼티의 연결을 프로그래밍 코드를 통해 쉽게(?) 표현할 수 있다.
 +
 +Source 프로퍼티 대신 ElementName 프로퍼티를 사용하는데, ElementName이 더 단순한다. \\ 
 +Source를 쓰려면 대상 객체가 ResourceDictionary 에 리소스로 정의 되어 있어야 한다. ([[sdk:wpf:리소스와_데이터바인딩#리소스|리소스]]StaticResource 참조)
 +
 +<code xml>
 +<TextBlock x:Name='currentFolder' DockPanel.Dock='Top' 
 +           Text='{Binding Source={StaticResource treeView} Path=SelectedItem}'
 +           Background='AliceBlue' FontSize='16'/>
 +</code>
 +
 +
 +==== RelativeSource 바인딩 ====
 +
 +Path 프로퍼티 이외에, 자신과 타켓 엘리먼트의 관계를 통해서 바인딩하는 방법이 있다. 이때 쓰는 것이 **RelativeSource **
 +
 +  * 소스 엘리먼트와 타겟 엘리먼트가 같은 경우
 +
 +일단 넘어가고 다시 정리하자.
 +
 +==== 단순 프로퍼티와 바인딩 ====
 +
 +데이터가 표시되는 타겟과 소스 프로퍼티를 동기적으로 유지하려면,
 +
 +  * PropertyChanged 이벤트를 정의하고 있는 System.ComponentModel.INotifyPropertyChanged 인터페이스를 구현한다.
 +  * XXX_Changed 이벤트를 구현해야 한다. XXX 는 값이 변하는 프로퍼티의 이름이다.
 +
 +첫번째 방법이 권장되는 방법.
 +
 +특정 항목(예를 들면 사진을(photo)가리는 photos)의 컬렉션을 가진 컨트롤이 INotifyPropertyChanged 인터페이스를 구현하도록 수정하면 PropertyChanged 이벤트 발생시
 +
 +  * Add, Remove, Clear, Insert 
 +
 +같은 동작에 대응해서 처리할 수 있다.
 +
 +  ObservableCollection 클래스
 +
 +이 코드를 작성할때 필요한 콜렉션 클래스.
 +
 +<code csharp>
 +// Photo 라는 속성의 아이템 컬렉션의 일반적인 선언
 +public class Photos : Collection<Photo> { /* ... */ }
 +
 +// INotifyPropertyChagned 와 연동 되는 컬렉션 
 +public class Photos : ObservableCollection<Photo> { /* ... */ }
 +</code>
 +
 +**주의**
 +
 +  * 소스프로퍼티 : 닷넷 객체라면 모두. 대신 단순 필드가 아니라 실제 프로퍼티여야 한다. 위의 경우, Photo 프로퍼티 형식으로 내부 데이터가 선언되어 있어야 한다.
 +  * 타겟프로퍼티 : 의존형이어야 한다.(?)
 +
 +==== 객체 전체와 바인딩 ====
 +
 +객체 전체와 바인딩 하는 것은.. Path를 사용하지 않고 객체를 소스로 사용한다.
 +
 +<code xml>
 +<Label x:Name='numItemsLabel' Content='{Binding Source={StaticResource photos}}'/>
 +</code>
 +
 +  * photos 는 Collection 또는 ObservableCollection 컬렉션 개체
 +  * UIElement 에서 상속된 객체가 아니라서 ToString() 메소드로 반환된 문자열로만 렌더링 된다.
 +
 +
 +주의 : UIElement 전체와 바인딩 할때는
 +
 +  * 뭘까? InvalidOperationException 예외?<code xml>
 +<Label x:Name="one" Content='{Binding ElementName=two}'/>
 +<Label x:Name='two' Content='TEXT'/>
 +<!-- 'Content' 속성은 시각적 요소에 바인딩된 데이터일 수 없습니다. -->
 +</code>
 +  * 해결하려면, 컨텐츠 프로퍼티를 다른 것 (Text)로 변경하면 예외를 피해간다.<code xml>
 +<TextBlock x:Name="one" Text='{Binding ElementName=two}'/>
 +<Label x:Name='two' Content='TEXT'/>
 +<!-- 예외를 피해간다. -->
 +</code>
 +  * Label.Content 는 Object 타입이라 형변환이 발생되지 않고
 +  * TextBlock.Text는 ToString() 로 변환이 발생 되며 <code>
 +System.Windows.Controls.Label:text 라는 문자열로 치환된다.
 +</code>
 +  * Text를 온전하게 출력하려면 프로퍼티를 Path로 정확하기 가리켜야 한다.<code xml>
 +<TextBlock x:Name="one" Text='{Binding ElementName=two, Path=Content}'/>
 +<Label x:Name='two' Content='TEXT'/>
 +<!-- 예외를 피해간다. -->
 +</code>
 +
 +
 +==== 컬렉션에 바인딩 ====
 +
 +초기바인딩
 +
 +
 +ListBox 사용하는 경우, ListBox.Items 는 의존 프로퍼티가 아니어서 쓸 수 없다. 대신, ItemsSource 를 사용. \\
 +이 프로퍼티는 IEnumerable 타입이라 컬렉션 객체를 소스로 사용할 수 있다.
 +
 +<code xml>
 +<ListBox x:Name='pictureBox' 
 +         ItemsSource='{Binding Source={StaticResource photos}}'/>
 +</code>
 +
 +소스 컬렉션의 엘리먼트 변화(추가,제거) 때문에 타겟 프로퍼티 (뷰 반영)가 갱신되어야 한다면
 +
 +  * INotifyCollectionChanged 인터페이스 구현이 필요.
 +  * 하지만, **ObservableCollection**에 \\ INotifyCollectionChanged 와 INotifyCollectionChanged 인터페이스 구현 되어 있으니
 +  * 이걸 쓰면 된다.
 +
 +표시 방법의 개선
 +
 +
 +
 +
 +
 +
 +====== 데이터 바인딩 : 재정리 ======
 +
 +글만 읽고서는 알기 어렵다. 여러 케이스를 테스트 해보면서 코드 작성 방법을 익혀야 할듯.
 +
 +** 다른 엘리먼트의 텍스트(프로퍼티)를 읽어 오기 **
 +
 +<code xml>
 +<TextBox x:Name="TargetFolderPath" VerticalContentAlignment="Center" Text="Enter ..."/>
 +
 +<!-- 엘리먼트 TargetFolderPath 의 Text 프로퍼티 값을 그대로 반영한다 -->
 +<TextBox x:Name="CopyTargetFolderPath" VerticalContentAlignment="Center" 
 +         Text="{Binding ElementName=TargetFolderPath, Path=Text}"/>
 +</code>
 +
 +
 +** Source를 사용해서 소스와 대상의 바인딩 **
 +
 +<code xml>
 +<TextBlock x:Name='currentFolder' DockPanel.Dock='Top' 
 +           Text='{Binding Source={StaticResource treeView} Path=SelectedItem}'
 +           Background='AliceBlue' FontSize='16'/>
 +</code>
 +
 +  * 브러시 같은 리소스는 알겠다.
 +  * 다른 컨트롤 같은 엘리먼트는 어떻게 리소스로 정의하지?
 +    * 하지 못하는 것 같다. [[sdk:wpf:리소스와_데이터바인딩#컨트롤을 리소스로 정의한 다음 사용하는 예제]]
 +
 +
 +===== DataContext : 데이터를 전달 하는 방법 =====
 +
 +  DataContext
 +
 +모든 WPF 컨트롤은 FrameWorkElement 로부터 상속된다. 이 클래스에는 **DataContext** 가 포함되어 있다.
 +DataContext 에 클래스 형식의 데이터를 바인딩 소스로 설정할 수 있다.
 +
 +간단한 예로,
 +
 +극단적으로 MainWindow 를 통째로 바인딩 소스로 넘겼다. 윈도우에 대한 프로퍼티를 사용할 수 있게 된다.
 +
 +<code csharp>
 +public partial class MainWindow : Window
 +{
 +    // 극단적으로 MainWindow 를 통째로 바인딩 소스로 넘겼다. 윈도우에 대한 프로퍼티를 사용할 수 있게 된다.
 +    public MainWindow() {
 +        InitializeComponent();
 +        this.DataContext = this;
 +    }
 +    // ...
 +}
 +</code>
 +
 +===== ValueConverts : 데이터를 전달 하는 방법 =====
 +
 +타입이 다른 두개의 프로퍼티를 바인딩 하는 경우, 값의 컨버팅 할 필요가 있다. ( 에러가 나거나 원하는 값이 안나오거나 )
 +
 +  이럴 때 ValueConverter 사용. xaml 키워드 'Converter'
 +
 +코드로 작성 해야 하며, **IValueConverter** 인터페이스를 상속 받는 클래스를 만들어야 한다.
 +
 +예제로, 불 값을 **Visibility** 프로퍼티로 컨버팅 하는 경우를 본다. bool 값을 **Visible** , **Collapsed** , **Hidden** 으로 변경한다.
 +
 +<code xml>
 +<StackPanel>
 +  <StackPanel.Resources>
 +    <!-- 클래스 이름이 xaml 키로 사용 되었다. -->
 +    <!-- x:Name이 아닌 것에 유의(확인 필요!) -->
 +    <BooleanToVisibilityConverter x:Key="boolToVis" />
 +  </StackPanel.Resources>
 +  
 +  <CheckBox x:Name="chkShowDetails" Content="Show Details" />
 +  <StackPanel x:Name="detailsPanel" 
 +              Visibility="{Binding IsChecked, ElementName=chkShowDetails, 
 +                          Converter={StaticResource boolToVis}}">
 +  </StackPanel>
 +</StackPanel>
 +</code>
 +
 +<code csharp>
 +public class BooleanToVisibilityConverter : IValueConverter
 +{
 +    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
 +        if (value is Boolean) {
 +            return ((bool)value) ? Visibility.Visible : Visibility.Collapsed;
 +        } 
 +        return value;
 +    }
 + 
 +    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
 +        throw new NotImplementedException();
 +    }
 +
 +</code>
 +
 +===== Binding 다음에 나올 수 있는 키워드 =====
 +
 +%%{Binding%%
 +
 +  * ElementName
 +  * Source
 +    * 조건 : 대상 객체가 ResourceDictionary 에 정의 되어 있어야 한다.
 +    * StaticResource or DynamicResource
 +    * 엘리먼트를 어떻게 리소스로 정의하지?
 +
 + 
 +===== 컨트롤을 리소스로 정의한 다음 사용하는 예제 =====
 +
 +<code xml>
 +<Window.Resources>
 +   <ControlTemplate x:Key="Ampel" TargetType="ContentControl">
 +      <Canvas>
 +         <Rectangle Fill="Black" HorizontalAlignment="Left" Height="52" Stroke="Black" VerticalAlignment="Top" Width="50"/>
 +         <Ellipse x:Name="RedGreen" 
 +                  Fill="{Binding Path=Tag, RelativeSource={RelativeSource TemplatedParent}}" 
 +                  HorizontalAlignment="Left" Height="27" Margin="11,12,0,0" Stroke="Black" 
 +                  VerticalAlignment="Top" Width="28" RenderTransformOrigin="0.214,0.256"/>
 +      </Canvas>
 +   </ControlTemplate>
 +</Window.Resources >
 +<ContentControl Template="{StaticResource Ampel}" Tag="Red"></ContentControl>
 +<ContentControl Template="{StaticResource Ampel}" Tag="Green"></ContentControl>
 +<ContentControl Template="{StaticResource Ampel}" Tag="Blue"></ContentControl>
 +</code>
 +
 +====== DataBinding 디버깅 ======
 +
 +  * 문서 : [[https://wpftutorial.net/DebugDataBinding.html|Debug Databinding Issues in WPF]]
 +
 +문법 검사로 발견하지 못한 에러의 경우
 +
 +  * 문법상 오류는 없지만, 없는 오브젝트를 가리키는 등의 오류 발생시 : Trace Output 으로 찾아본다.
 +  * 값이 생각대로 나오지 않았을 경우. : DebugConverter 로 해결 시도.
 +
 +===== TRACE 메시지 출력 =====
 +
 +<code xml>
 +<Window x:Class="DebugDataBinding.Window1"
 +        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 +        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 +  <StackPanel x:Name="stack">
 +    <TextBlock Text="{Binding ElementName=stack, Path=InvalidPath}" />
 +  </StackPanel>
 +</Window>
 +</code>
 +
 +  * 'InvalidPath' 라는 프로퍼티가 없다. 없는 프로퍼티를 쓰는 에러.
 +
 +출력창에 잘못된 프로퍼티라는 에러 메시지가 뜬다. (뜨나? 다른 예제로 해보니 뜬다.)
 +
 +<code>
 +System.Windows.Data Error: 39 : BindingExpression path error: 'InvalidPath' property not found on 'object' ''StackPanel' (Name='stack')'. BindingExpression:Path=InvalidPath; DataItem='StackPanel' (Name='stack'); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
 +</code>
 +
 +==== trace level 조정 ====
 +
 +  xmal에서 하는 것은 잘 안됐고. 코드로 조정하는게 확실하게 되었다.
 +
 +  * 닷넷 3.5 이상
 +  * None, Low, Medium, High 로 설정 가능.
 +
 +<code xml>
 +<Window x:Class="DebugDataBinding.Window1"
 +    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 +    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 +    xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase">
 + 
 +  <StackPanel x:Name="stack">
 +    <TextBlock Text="{Binding ElementName=stack, Path=InvalidPath, 
 +                     diag:PresentationTraceSources.TraceLevel=High}" />
 +  </StackPanel>
 +</Window>
 +</code>
 +
 +코드로 조정하는 경우
 +
 +<code csharp>
 +PresentationTraceSources.DataBindingSource.Listeners.Add(new ConsoleTraceListener()); 
 +PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.All;
 +</code>
 +
 +
 +===== ValueConverter 를 사용한 브레이크 포인트 설정 =====
 +
 +그닥 쓸모가..
 +
 +IValueConverter 에서 상속되는 디버그용 클래스를 작성 <sup>아래 예시처럼</sup>
 +
 +<code csharp>
 +/// <summary>
 +/// This converter does nothing except breaking the
 +/// debugger into the convert method
 +/// </summary>
 +public class DatabindingDebugConverter : IValueConverter
 +{
 +    public object Convert(object value, Type targetType, 
 +        object parameter, CultureInfo culture)
 +    {
 +        Debugger.Break();
 +        return value;
 +    }
 + 
 +    public object ConvertBack(object value, Type targetType, 
 +        object parameter, CultureInfo culture)
 +    {
 +        Debugger.Break();
 +        return value;
 +    }
 +
 +</code>
 +
 +xaml 코드에서 브레이크 포인트를 설정할 곳에 추가한다.
 +
 +  * DatabindingDebugConverter 가 클래스거나 그 상위 클래스가 %%xmlns:local%%로 추가 되어야 있어야 한다.
 +
 +DatabindingDebugConverter 클래스가 TestAPP 라는 네임스페이스에 포함되어 있는 것으로 가정.
 +
 +  * 사용할 네임스페이스 : %% xmlns:local="clr-namespace:TestAPP" %%
 +  * 실제 사용하는 클래스 : %% <local:DatabindingDebugConverter x:Key="debugConverter" /> %%
 +
 +<code xml>
 +<Window x:Class="TestAPP.MainWindow"
 +        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 +        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 +        xmlns:local="clr-namespace:TestAPP"
 +        Title="Window1" Height="300" Width="300">
 + 
 +    <Window.Resources>
 +        <local:DatabindingDebugConverter x:Key="debugConverter" />
 +    </Window.Resources>
 + 
 +    <StackPanel x:Name="stack">
 +        <TextBlock Text="{Binding ElementName=stack, Path=ActualWidth, 
 +                          Converter={StaticResource debugConverter}}" />
 +    </StackPanel>
 +</Window>
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +