RelativeSource와 함께 WPF 바인딩을 어떻게 사용합니까?


답변:


783

객체의 다른 속성에 바인딩하려는 경우 :

{Binding Path=PathToProperty, RelativeSource={RelativeSource Self}}

조상에 재산을 얻으려면 :

{Binding Path=PathToProperty,
    RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}

템플릿 부모에서 속성을 얻으려면 ControlTemplate에서 양방향 바인딩을 수행 할 수 있습니다.

{Binding Path=PathToProperty, RelativeSource={RelativeSource TemplatedParent}}

또는 더 짧습니다 (OneWay 바인딩에서만 작동 함).

{TemplateBinding Path=PathToProperty}

15
이 "{Binding Path = PathToProperty, RelativeSource = {RelativeSource AncestorType = {x : Type typeOfAncestor}}}"의 경우 "AncestorType"앞에 "Mode = FindAncestor"가 있어야합니다.
EdwardM의

1
어떤 기술? WPF에서는을 지정할 때 유추됩니다 AncestorType.
Abe Heidebrecht

2
@EdwardM에 동의합니다. FindAncestor전에를 생략하면 AncestorType"RelativeSource가 FindAncestor 모드에 있지 않습니다"라는 오류가 발생합니다. (VS2013, 커뮤니티 버전)
kmote

1
@kmote, 이것은 .net 3.0부터 나에게 도움이되었으며 kaxaml 에서이 방식으로 작동하는지 다시 한 번 확인했습니다 ... 다시, 어떤 기술을 사용하고 있습니까? XAML 프로세서는 WPF / Silverlight / UWP마다 다르므로 기술마다 결과가 다를 수 있습니다. VS 커뮤니티에 대해서도 언급 했으므로 IDE 경고 일지 모르지만 런타임에 작동합니까?
Abe Heidebrecht

6
RelativeSource의 DataContext에서 속성에 바인딩하려면 명시 적으로 지정해야합니다 {Binding Path=DataContext.SomeProperty, RelativeSource=.... DataTemplate 내에서 부모의 DataContext에 바인딩하려고 할 때 초보자에게는 다소 예기치 않은 일이었습니다.
DrEsperanto

133
Binding RelativeSource={
    RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemType}
}
...

의 기본 속성 RelativeSource은 IS Mode속성입니다. MSDN에서 제공하는 유효한 값의 전체 세트는 다음과 같습니다 .

  • PreviousData 표시되는 데이터 항목 목록에서 이전 데이터 항목 (데이터 항목이 포함 된 컨트롤이 아님)을 바인딩 할 수 있습니다.

  • TemplatedParent 템플릿 (데이터 바인딩 된 요소가있는)이 적용되는 요소를 나타냅니다. 이는 TemplateBindingExtension 설정과 유사하며 바인딩이 템플리트 내에있는 경우에만 적용 가능합니다.

  • 자체 바인딩을 설정하는 요소를 참조하고 해당 요소의 한 속성을 같은 요소의 다른 속성에 바인딩 할 수 있습니다.

  • FindAncestor 데이터 바인딩 된 요소의 부모 체인에있는 조상을 나타냅니다. 이를 사용하여 특정 유형의 조상 또는 해당 서브 클래스에 바인딩 할 수 있습니다. AncestorType 및 / 또는 AncestorLevel을 지정하려는 경우 사용하는 모드입니다.


128

다음은 MVVM 아키텍처와 관련하여보다 시각적 인 설명입니다.

여기에 이미지 설명을 입력하십시오


19
내가 뭘 놓 쳤니? 간단하고 명확한 그래픽을 어떻게 고려할 수 있습니까? 1 : 왼쪽 의미의 상자는 오른쪽 상자와 관련이 없습니다 (ViewModel 내에 .cs 파일이 왜 있습니까?) 2 :이 DataContext 화살표는 무엇을 가리 킵니까? 3 : Message 속성이 ViewModel1에없는 이유는 무엇입니까? 가장 중요한 5 : TextBlock에 이미 동일한 DataContext가있는 경우 Window의 DataContext에 도달하기 위해 RelativeSource 바인딩이 필요한 이유는 무엇입니까? 나는 여기에 뭔가가 빠져있어서 너무 멍청 하거나이 그래픽이 모든 사람들이 생각하는 것처럼 간단하고 명확하지 않습니다! 계몽하십시오
Markus Hütter

2
@ MarkusHütter 다이어그램에는 그룹에 중첩 된 뷰와 해당 ViewModel이 표시됩니다. View1의 DataContext는 ViewModel1이지만 BaseViewModel의 속성에 바인딩하려고합니다. BaseViewModel은 BaseView (Window)의 DataContext이므로 Window 인 첫 번째 상위 컨테이너를 찾고 DataContext를 가져 와서 수행 할 수 있습니다.
mcargille

6
@MatthewCargille 나는 아주 잘 무엇을 알고 가정 내 말이되지 않았 음을 의미하는 것으로. 그러나 XAML과 MVVM을 잘 모르는 사람의 입장에 서면 이것이 간단하고 명확 하지 않다는 것을 알게 될 것 입니다.
Markus Hütter

1
나는 @ MarkusHütter에 동의해야한다. 그런데 왼쪽의 바인딩은 다음과 같이 간단 할 수있다. {Binding Message}(조금 더 간단하다 ...)
florien

@florien 적어도 내 유스 케이스에는 그렇게 생각하지 않습니다. MainWindow의 DataContext (내 viewmodel 클래스)를 참조하여 드롭 다운 메뉴 (데이터베이스에서로드)에 대한 옵션 목록을 가져와야하는 DataTemplate이 있습니다. DataTemplate은 데이터베이스에서도로드되는 모델 객체에 바인딩되어 있지만 선택한 옵션에만 액세스 할 수 있습니다. Path=DataContext.Message바인딩이 작동 하도록 명시 적으로 설정 해야했습니다. 너비 / 높이 / 등에 상대 바인딩을 수행 할 수 있다는 점에서 이치에 맞습니다. 통제의.
DrEsperanto

47

Bechir Bejaoui는 그의 기사 에서 WPF의 RelativeSources 사용 사례를 공개합니다 .

RelativeSource는 특정 객체의 속성을 객체 자체의 다른 속성에 바인딩하려고 할 때, 특정 객체의 속성을 상대 부모 중 하나에 바인딩하려고 할 때 특히 바인딩 케이스에 사용되는 태그 확장입니다. 사용자 지정 컨트롤 개발 및 일련의 바운드 데이터 차등을 사용하는 경우 종속성 속성 값을 XAML에 바인딩 할 때 이러한 모든 상황은 상대 소스 모드로 표시됩니다. 모든 사례를 하나씩 공개하겠습니다.

  1. 모드 자체 :

높이가 항상 너비와 같기를 원하는 사각형 인이 경우를 상상해보십시오. 우리는 요소 이름을 사용 하여이 작업을 수행 할 수 있습니다

<Rectangle Fill="Red" Name="rectangle" 
                Height="100" Stroke="Black" 
                Canvas.Top="100" Canvas.Left="100"
                Width="{Binding ElementName=rectangle,
                Path=Height}"/>

그러나이 경우 바인딩 객체의 이름, 즉 사각형을 표시해야합니다. RelativeSource를 사용하여 동일한 목적에 다르게 도달 할 수 있습니다

<Rectangle Fill="Red" Height="100" 
               Stroke="Black" 
               Width="{Binding RelativeSource={RelativeSource Self},
               Path=Height}"/>

이 경우 바인딩 객체의 이름을 언급 할 의무가 없으며 높이가 변경 될 때마다 너비는 항상 높이와 같습니다.

너비를 높이의 절반으로 매개 변수화하려면 바인딩 태그 확장에 변환기를 추가하여이 작업을 수행 할 수 있습니다. 다른 경우를 상상해 봅시다.

 <TextBlock Width="{Binding RelativeSource={RelativeSource Self},
               Path=Parent.ActualWidth}"/>

위의 경우는 주어진 요소의 주어진 속성을 직접 부모의 속성 중 하나에 묶는 데 사용됩니다.이 요소에는 Parent라는 속성이 있습니다. 이것은 다른 상대 소스 모드 인 FindAncestor 모드로 연결됩니다.

  1. 모드 찾기

이 경우 주어진 요소의 속성은 부모 중 하나 인 Corse에 연결됩니다. 위의 경우와의 주요 차이점은 속성을 연결하는 계층 구조에서 상위 유형과 상위 순위를 결정하는 것은 사용자의 책임입니다. 그건 그렇고이 XAML 조각으로 놀아보십시오.

<Canvas Name="Parent0">
    <Border Name="Parent1"
             Width="{Binding RelativeSource={RelativeSource Self},
             Path=Parent.ActualWidth}"
             Height="{Binding RelativeSource={RelativeSource Self},
             Path=Parent.ActualHeight}">
        <Canvas Name="Parent2">
            <Border Name="Parent3"
            Width="{Binding RelativeSource={RelativeSource Self},
           Path=Parent.ActualWidth}"
           Height="{Binding RelativeSource={RelativeSource Self},
              Path=Parent.ActualHeight}">
               <Canvas Name="Parent4">
               <TextBlock FontSize="16" 
               Margin="5" Text="Display the name of the ancestor"/>
               <TextBlock FontSize="16" 
                 Margin="50" 
            Text="{Binding RelativeSource={RelativeSource  
                       FindAncestor,
                       AncestorType={x:Type Border}, 
                       AncestorLevel=2},Path=Name}" 
                       Width="200"/>
                </Canvas>
            </Border>
        </Canvas>
     </Border>
   </Canvas>

위 상황은 일련의 테두리 안에 포함 된 두 개의 TextBlock 요소와 계층 적 부모를 나타내는 캔버스 요소입니다. 두 번째 TextBlock은 상대 소스 수준에서 주어진 부모의 이름을 표시합니다.

따라서 AncestorLevel = 2를 AncestorLevel = 1로 변경하고 어떻게되는지보십시오. 그런 다음 조상의 유형을 AncestorType = Border에서 AncestorType = Canvas로 변경하고 어떻게되는지보십시오.

표시되는 텍스트는 조상 유형 및 레벨에 따라 변경됩니다. 그러면 조상 수준이 조상 유형에 적합하지 않으면 어떻게됩니까? 좋은 질문입니다. 물어 보려고한다는 것을 알고 있습니다. 응답은 예외가 발생하지 않으며 TextBlock 수준에 아무것도 표시되지 않습니다.

  1. TemplatedParent

이 모드에서는 지정된 ControlTemplate 속성을 ControlTemplate이 적용된 컨트롤의 속성에 연결할 수 있습니다. 여기에 문제를 잘 이해하려면 다음 예가 있습니다.

<Window.Resources>
<ControlTemplate x:Key="template">
        <Canvas>
            <Canvas.RenderTransform>
                <RotateTransform Angle="20"/>
                </Canvas.RenderTransform>
            <Ellipse Height="100" Width="150" 
                 Fill="{Binding 
            RelativeSource={RelativeSource TemplatedParent},
            Path=Background}">

              </Ellipse>
            <ContentPresenter Margin="35" 
                  Content="{Binding RelativeSource={RelativeSource  
                  TemplatedParent},Path=Content}"/>
        </Canvas>
    </ControlTemplate>
</Window.Resources>
    <Canvas Name="Parent0">
    <Button   Margin="50" 
              Template="{StaticResource template}" Height="0" 
              Canvas.Left="0" Canvas.Top="0" Width="0">
        <TextBlock FontSize="22">Click me</TextBlock>
    </Button>
 </Canvas>

주어진 컨트롤의 속성을 컨트롤 템플릿에 적용하려면 TemplatedParent 모드를 사용할 수 있습니다. 이 태그 확장과 비슷한 것이 있는데, 첫 번째 것의 일종 인 TemplateBinding 인 TemplateBinding이지만, 첫 번째 런타임 직후에 평가되는 TemplatedParent와 대조적으로 컴파일 타임에 TemplateBinding이 평가됩니다. 아래 그림에서 알 수 있듯이 배경과 내용은 단추 내에서 컨트롤 템플릿에 적용됩니다.


저에게 아주 좋은 예는 Find Ancestor를 사용하여 parent 데이터 컨텍스트의 명령에 연결했습니다 ListView. 부모는 그 ListView아래에 2 단계 더 있습니다. 이 날 각의 이후의 각 VM에 데이터를 전달 방지 도움 ListViewDataTemplate
갈렙 W.

34

WPF RelativeSource바인딩 properties에서 다음을 설정하기 위해 3 을 노출합니다 .

1. 모드 : 다음과 같은 enum네 가지 값을 가질 수 있습니다.

ㅏ. PreviousData ( value=0) : 의 이전 값을property바인딩 된값에 할당합니다

비. TemplatedParent ( value=1) :templates 컨트롤을 정의 할 때 사용되며의 값 / 속성에 바인딩하려고합니다control.

예를 들어, 다음을 정의하십시오 ControlTemplate.

  <ControlTemplate>
        <CheckBox IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
 </ControlTemplate>

씨. 자기 ( value=2) : 우리가에서 바인딩 할 때self또는property자기의.

예를 들면 다음checkbox같습니다.CommandParameterCommand 켜기 를 설정하는 동안CheckBox

<CheckBox ...... CommandParameter="{Binding RelativeSource={RelativeSource Self},Path=IsChecked}" />

디. FindAncestor ( value=3) : 부모로부터 바인딩 할 때control 에서Visual Tree.

예를 들어 바인딩 checkbox에서 records만약grid , 경우는 header checkbox체크

<CheckBox IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid}}, Path=DataContext.IsHeaderChecked, Mode=TwoWay}" />

2. 조상 유형 : mode가 FindAncestor어떤 조상 유형을 정의 할 때

RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid}}

3. 조상 레벨 : mode가 FindAncestor조상 레벨 인 경우 (에 동일한 유형의 상위가 두 개있는 경우 visual tree)

RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid, AncestorLevel=1}}

위의 모든 사용 사례는 RelativeSource binding .

참조 링크는 다음과 같습니다 .


2
.. 이것은 나를 위해 일했다 : <DataGridCheckBoxColumn Header = "Paid"Width = "35"Binding = "{Binding RelativeSource = {RelativeSource Mode = FindAncestor, AncestorType = {x : Type Window}}, Path = DataContext.SelectedBuyer.IsPaid , Mode = OneWay} "/> 여기서 부모 창의 selectedbuyer에 바인딩하려고
Michael K

21

TemplatedParent를 잊지 마십시오 :

<Binding RelativeSource="{RelativeSource TemplatedParent}"/>

또는

{Binding RelativeSource={RelativeSource TemplatedParent}}


16

RelativeSource를보다 쉽게 ​​사용할 수 있도록하는 등 WPF의 바인딩 구문을 단순화하는 라이브러리를 만들었습니다. 여기 몇 가지 예가 있어요. 전에:

{Binding Path=PathToProperty, RelativeSource={RelativeSource Self}}
{Binding Path=PathToProperty, RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}
{Binding Path=PathToProperty, RelativeSource={RelativeSource TemplatedParent}}
{Binding Path=Text, ElementName=MyTextBox}

후:

{BindTo PathToProperty}
{BindTo Ancestor.typeOfAncestor.PathToProperty}
{BindTo Template.PathToProperty}
{BindTo #MyTextBox.Text}

다음은 메소드 바인딩이 단순화 된 방법의 예입니다. 전에:

// C# code
private ICommand _saveCommand;
public ICommand SaveCommand {
 get {
  if (_saveCommand == null) {
   _saveCommand = new RelayCommand(x => this.SaveObject());
  }
  return _saveCommand;
 }
}

private void SaveObject() {
 // do something
}

// XAML
{Binding Path=SaveCommand}

후:

// C# code
private void SaveObject() {
 // do something
}

// XAML
{BindTo SaveObject()}

여기에서 라이브러리를 찾을 수 있습니다 : http://www.simplygoodcode.com/2012/08/simpler-wpf-binding.html

'BEFORE'예제에서 필자 RelayCommand가 마지막으로 확인한 WPF의 기본 부분이 아닌 코드를 사용하여 코드가 이미 최적화 된 메소드 바인딩에 사용한다는 점에 유의하십시오 . 그렇지 않으면 'BEFORE'예제가 더 길었을 것입니다.


2
이러한 종류의 연습은 XAML의 약점을 보여줍니다. 방법이 너무 복잡합니다.
dudeNumber4

16

유용한 비트 및 조각 :

코드에서 주로 수행하는 방법은 다음과 같습니다.

Binding b = new Binding();
b.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, this.GetType(), 1);
b.Path = new PropertyPath("MyElementThatNeedsBinding");
MyLabel.SetBinding(ContentProperty, b);

나는 이것을 코드 숨김의 바인딩 상대 소스에서 크게 복사했습니다. .

또한 MSDN 페이지는 예제가있는 한 꽤 좋습니다. RelativeSource Class


5
WPF에 대한 모호한 기억은 코드에서 바인딩을하는 것이 일반적으로 최선의 방법은 아니라는 것입니다.
Nathan Cooper

12

방금 Silverlight에서 부모 요소의 DataContext에 액세스하기위한 다른 솔루션 을 게시했습니다 . 사용합니다 Binding ElementName.


10

모든 대답을 읽지는 않았지만 버튼의 상대 소스 명령 바인딩의 경우이 정보를 추가하고 싶습니다.

로 상대 소스를 사용하는 Mode=FindAncestor경우 바인딩은 다음과 같아야합니다.

Command="{Binding Path=DataContext.CommandProperty, RelativeSource={...}}"

경로에 DataContext를 추가하지 않으면 실행시 속성을 검색 할 수 없습니다.


9

이것은 빈 데이터 그리드에서 나를 위해 일한이 패턴의 사용 예입니다.

<Style.Triggers>
    <DataTrigger Binding="{Binding Items.Count, RelativeSource={RelativeSource Self}}" Value="0">
        <Setter Property="Background">
            <Setter.Value>
                <VisualBrush Stretch="None">
                    <VisualBrush.Visual>
                        <TextBlock Text="We did't find any matching records for your search..." FontSize="16" FontWeight="SemiBold" Foreground="LightCoral"/>
                    </VisualBrush.Visual>
                </VisualBrush>
            </Setter.Value>
        </Setter>
    </DataTrigger>
</Style.Triggers>

6

요소가 비주얼 트리의 일부가 아닌 경우 RelativeSource는 작동하지 않습니다.

이 경우 Thomas Levesque가 개척 한 다른 기술을 시도해야합니다.

그는 블로그에서 [WPF] 아래에 솔루션을 가지고 있습니다. 있습니다. 그리고 그것은 절대적으로 훌륭하게 작동합니다!

그의 블로그가 다운되지 않았을 경우, 부록 A에는 그의 기사의 사본이 포함되어 있습니다 .

여기에 의견을 말하지 말고 그의 블로그 게시물에 직접 의견을 말하십시오 .

부록 A : 블로그 게시물의 거울

WPF의 DataContext 속성은 할당 한 요소의 모든 자식에 의해 자동으로 상속되므로 매우 편리합니다. 따라서 바인딩하려는 각 요소에 다시 설정할 필요가 없습니다. 그러나 경우에 따라 DataContext에 액세스 할 수 없습니다. 시각적 또는 논리적 트리의 일부가 아닌 요소에 대해 발생합니다. 그런 다음 해당 요소에 속성을 바인딩하는 것은 매우 어려울 수 있습니다…

간단한 예를 들어 설명하겠습니다. DataGrid에 제품 목록을 표시하려고합니다. 그리드에서 ViewModel에 의해 노출 된 ShowPrice 속성 값을 기반으로 Price 열을 표시하거나 숨길 수 있기를 원합니다. 확실한 접근 방식은 열의 가시성을 ShowPrice 속성에 바인딩하는 것입니다.

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                Visibility="{Binding ShowPrice,
                Converter={StaticResource visibilityConverter}}"/>

불행히도 ShowPrice의 값을 변경해도 아무런 효과가 없으며 열이 항상 표시됩니다. 왜 그렇습니까? Visual Studio에서 출력 창을 보면 다음 줄을 볼 수 있습니다.

System.Windows.Data 오류 : 2 : 대상 요소에 대한 관리 FrameworkElement 또는 FrameworkContentElement를 찾을 수 없습니다. BindingExpression : 경로 = 쇼 가격; DataItem = null; 대상 요소는 'DataGridTextColumn'(HashCode = 32685253)입니다. 대상 속성은 'Visibility'(유형 'Visibility')입니다.

메시지는 다소 비밀 스럽지만 실제로는 그 의미가 매우 간단합니다. WPF는 열이 DataGrid의 시각적 또는 논리 트리에 속하지 않기 때문에 DataContext를 가져 오는 데 사용할 FrameworkElement를 알지 못합니다.

예를 들어 RelativeSource를 DataGrid 자체로 설정하여 원하는 결과를 얻도록 바인딩을 조정할 수 있습니다.

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                Visibility="{Binding DataContext.ShowPrice,
                Converter={StaticResource visibilityConverter},
                RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}}"/>

또는 ShowPrice에 바인딩 된 CheckBox를 추가하고 요소 이름을 지정하여 열 가시성을 IsChecked 속성에 바인딩 할 수 있습니다.

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                Visibility="{Binding IsChecked,
                Converter={StaticResource visibilityConverter},
                ElementName=chkShowPrice}"/>

그러나이 해결 방법 중 어느 것도 효과가없는 것 같습니다. 항상 같은 결과를 얻습니다.

이 시점에서 유일하게 실행 가능한 접근 방식은 코드 숨김에서 열 가시성을 변경하는 것 같습니다. MVVM 패턴을 사용할 때 일반적으로 피하는 것이 좋습니다 ... 그러나 적어도 그렇게 빨리 포기하지는 않을 것입니다. 고려해야 할 다른 옵션이 있지만 😉

우리의 문제에 대한 해결책은 실제로 매우 간단하며 Freezable 클래스를 활용합니다. 이 클래스의 기본 목적은 수정 가능하고 읽기 전용 상태 인 객체를 정의하는 것이지만, 우리의 흥미로운 기능은 시각적 또는 논리적 트리에 있지 않은 경우에도 Freezable 객체가 DataContext를 상속 할 수 있다는 것입니다. 이 동작을 가능하게하는 정확한 메커니즘을 모르지만 바인딩 작업을 위해이를 활용할 것입니다.

아이디어는 Freezable을 상속하고 데이터 종속성 속성을 선언하는 클래스를 작성하는 것입니다.

public class BindingProxy : Freezable
{
    #region Overrides of Freezable

    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }

    #endregion

    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}

그런 다음 DataGrid의 리소스에서이 클래스의 인스턴스를 선언하고 Data 속성을 현재 DataContext에 바인딩 할 수 있습니다.

<DataGrid.Resources>
    <local:BindingProxy x:Key="proxy" Data="{Binding}" />
</DataGrid.Resources>

마지막 단계는이 BindingProxy 객체 (StaticResource로 쉽게 액세스 가능)를 바인딩 소스로 지정하는 것입니다.

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                Visibility="{Binding Data.ShowPrice,
                Converter={StaticResource visibilityConverter},
                Source={StaticResource proxy}}"/>

경로는 이제 BindingProxy 객체를 기준으로하기 때문에 바인딩 경로는“Data”로 시작됩니다.

이제 바인딩이 올바르게 작동하고 ShowPrice 속성에 따라 열이 올바르게 표시되거나 숨겨집니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.