MVVM 패턴 TabControl과 TabItem DataContext 분리

public partial class A: Grid
{
public A()
{
InitializeComponent();
DataContext = new MainViewModel();
}
public class MainViewModel
{
public B G1VM { get; set; } = new B();
public C G2VM { get; set; } = new C();
}
}

ViewModel

    static public ObservableCollection<Table> datagrid{ get; set; } = new ObservableCollection<Table>();   

public C()
{
datagrid.Add(new Table{
Name= “Hello”
};
}

다음과 같이 MVVM 구조에서 총 3개의 View Model의 DataContext를 설정하였습니다.

  <TabControl   DataContext="{Binding G1VM}">

그렇게 한 뒤에 TabControl에 G1VM을 Binding한 뒤에,

<TabItem Header=“Tmp”
DataGrid ItemsSource=“{Binding datagrid, UpdateSourceTrigger=PropertyChanged}” DataContext =“{Binding G2VM}”

<DataGrid.Columns>
<DataGridTemplateColumn Header=“TmpName”
<DataGridTemplateColumn.CellTemplate
<DataTemplate
<TextBox Text=“{Binding Name}”
</DataTemplate
</DataGridTemplateColumn.CellTemplate
</DataGridTemplateColumn
</DataGrid.Columns>
다음과 같이 TabItem 내부의 DataGrid만 G2VM으로 바인딩을 진행하고 싶습니다.
하지만 DataGrid가 이미 G1VM으로 바인딩이 돼버리는데, 이 부분을 어떻게 해결할 수 있을까요?
datagrid는 ObservableCollection 자료형입니다.

3개의 좋아요

@미니뀨 안녕하세요 :smile:

Binding RelativeSource를 사용하시면 됩니다.

<TabControl DataContext="{Binding G1VM}">
    <TabItem Header="TMP">
        <DataGrid ItemsSource="{Binding datagrid}" DataContext="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.G1VM}"/>
    </TabItem>
</TabControl>

저도 정말 자주 사용하는 부분 중에 하나에요.
특히 CommandParameter를 사용할 때 자주 상위 객체의 DataContext에 접근하기 떄문에요~

그리고 제가 정리해놓은 Binding 관련 내용도 한번 참고해보시길 바랍니다.
여기

1개의 좋아요

음 이상하게 해결이 되지 않네요 ㅠㅠ… 제가 datagrid를 Static 변수로 설정했는데 이게 영향이 있는 걸까요?

1개의 좋아요

@미니뀨 혹시 본문에 소스코드를 좀더 보완해주실 수 있으실까요?

그리고 datagrid ObservableCollection<T>는 G2VM 클래스 안에 public get; set; 형태로 있어야 합니다.

public class G2VM
{
    public ObservableCollection<T> datagrid { get; set; }
}

해보시고 혹시 필요하시면 간단한 샘플 만들어 드릴께요. :smile:

1개의 좋아요

소스코드를 조금 더 보완했는데 충분하실 지 모르겠네요 ㅠㅠ

코드가 이상하게 닫으면 보이지 않아 가독성이 떨어집니다… 죄송합니다.

Class B는 DataGrid를 제외한 나머지에 대한 ViewModel이며, Class C는 DataGrid 용의 ViewModel입니다.

1개의 좋아요

괜찮습니다. :smile:
Markdown을 배워보시면 질문하실 때 소스코드나 가독성을 훨씬 키우실 수 있어요. 여기


샘플 소스코드 만들어드렸으니 한번 확인해보시길 바랍니다.

샘플코드 여기


아래는 샘플 이미지입니다.

image

<Grid Background="{Binding GridBackground}">
	<TabControl DataContext="{Binding G1VM}" Background="{Binding TabControlBackground}">
		<TabItem Header="Tab Item 1">
			<DataGrid ItemsSource="{Binding Users}" DataContext="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.G2VM}"/>
		</TabItem>
	</TabControl>
</Grid>
3개의 좋아요

도와주셔서 감사합니다 ㅠㅠ 덕분에 문제가 풀렸습니다 복받으세요!!!

2개의 좋아요

Binding는 DataContext의 상대적 경로를 따르는 것으로 알고 있습니다.

예를 들어 Grid에 DataContext 바인딩 했으면 Grid 내부에 있는 아이템은 Grid와 연결된 바인딩 데이터로부터 아이템을 찾는 것으로 알고 있습니다.

<Grid DataContext="{Binding SomeGridVM}">
   <TabControl DataContext="{이곳은 SomeGridVM 영향을 받습니다}"/>
</Grid>

이를 해소하기 위해서는 작업하는 코드의 기존에 사용하던 VM을 찾아줘야 하는데
그 방법이 @jamesnet214 님께서 알려주신 방법입니다.

또 다른 방법으로는 G1VMParent 속성을 추가하는 것 입니다.
이 방식을 사용하면 RelativeSource를 사용하지 않고 기존 VM에 접근할 수 있습니다.

<TabControl DataContext="{Binding G1VM}">
    <TabItem Header="TMP">
        <DataGrid ItemsSource="{Binding datagrid}" DataContext="{Binding Parent.G2VM}"/>
    </TabItem>
</TabControl>
3개의 좋아요

@level120 감사합니다 :smile:

저도 유용하게 사용할 수 있을 것 같습니다!

1개의 좋아요