[문의]WPF Class 별로 바인딩 되었을 때 다른 View 시현

안녕하세요.

WPF에서 클래스 별로 다른 View를 보여주고 싶어서 문의드립니다.

클래스별로 갖고 있는 Property가 달라서 별도의 UserControl로 빼 놓았습니다.

이를 DataGrid에서 해당 아이템에 마우스를 올렸을 때 툴팁으로 각 해당하는 UserControl로 팝업 뷰를 만들어보려고 합니다.

즉, PersonClass Type의 데이터이면 UCPersonPropertyView(UserControl)로 툴팁해서 보여주고,
CarClass Type의 데이터이면 UCCarPropertyView로 툴팁을 보여줍니다.

사실 툴팁은 활용을 위한 예이고, 각 타입별로 어떻게 다르게 View에서 표현이 가능한지 보고 싶어서 문의드립니다.

DemoViewModel에서 DataGrid 시현되는 예제를 만들어 놨습니다.

확인해보시고, 가능한 방향이 있으면 안내 부탁드립니다.

감사합니다.

예제 파일 다운로드

3 Likes

먼저 예제 파일을 살펴보지 않는 상태에서 답변을 드리는 점 이해 바랍니다.

ContentControlContentTemplateSelector 속성을 이용해 원하는 목적을 달성할 수 있을 것으로 보이는데요?

3 Likes

@dimohy 님이 힌트를 주신대로 DataTemplateSelector를 쓰시면 될듯합니다.
GridDataTemplateSelector .cs 클래스 하나 만들었습니다.
바뀐 부분만 올려드립니다.

namespace Wpf.ClassType.View.Test.UI
{
    public class GridDataTemplateSelector : DataTemplateSelector
    {
        public DataTemplate CarTemplate { get; set; }
        public DataTemplate PersonTemplate { get; set; }

        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            if (item is ItemViewModel itemViewModel)
            {
                if (itemViewModel.Item is CarClass)
                {
                    return CarTemplate;
                }
                else if (itemViewModel.Item is PersonClass)
                {
                    return PersonTemplate;
                }
            }

            return null;
        }
    }
}

DataView.xaml

<UserControl x:Class="Wpf.ClassType.View.Test.UI.Views.DemoView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Wpf.ClassType.View.Test.UI.Views"
			 xmlns:ctrl="clr-namespace:Wpf.ClassType.View.Test.UI.Views.Controls" 
             xmlns:local1="clr-namespace:Wpf.ClassType.View.Test.UI"
             Background="SlateBlue"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>
        <DataTemplate x:Key="CarTemplate">
            <Grid>
                <TextBlock Text="{Binding Item.Id}">
                    <TextBlock.Style>
                        <Style TargetType="TextBlock" >
                            <Setter Property="FontWeight" Value="Bold"/>
                        </Style>
                    </TextBlock.Style>
                    <TextBlock.ToolTip>
                        <StackPanel Orientation="Vertical">
                            <TextBlock Text="{Binding Item.CarName}"/>
                            <TextBlock Text="{Binding Item.Engine}"/>
                            <TextBlock Text="{Binding Item.Brand}"/>
                            <TextBlock Text="{Binding Item.CarType}"/>
                        </StackPanel>
                    </TextBlock.ToolTip>
                </TextBlock>
            </Grid>
        </DataTemplate>

        <DataTemplate x:Key="PersonTemplate">
            <Grid>
                <TextBlock Text="{Binding Item.Id}">
                    <TextBlock.Style>
                        <Style TargetType="TextBlock" >
                            <Setter Property="FontWeight" Value="Bold"/>
                        </Style>
                    </TextBlock.Style>
                    <TextBlock.ToolTip>
                        <StackPanel Orientation="Vertical">
                            <TextBlock Text="{Binding Item.PersonName}"/>
                            <TextBlock Text="{Binding Item.Age}"/>
                            <TextBlock Text="{Binding Item.Gender}"/>
                        </StackPanel>
                    </TextBlock.ToolTip>
                </TextBlock>
            </Grid>
        </DataTemplate>

        <local1:GridDataTemplateSelector x:Key="GridDataTemplateSelector"
                                         CarTemplate="{StaticResource CarTemplate}"
                                         PersonTemplate="{StaticResource PersonTemplate}"/>
    </UserControl.Resources>
    
    <Grid>
		<Grid.ColumnDefinitions>
			<ColumnDefinition Width="10"/>
			<ColumnDefinition Width="*"/>
			<ColumnDefinition Width="10"/>
		</Grid.ColumnDefinitions>
		<Grid.RowDefinitions>
			<RowDefinition Height="20"/>
			<RowDefinition Height="*"/>
			<RowDefinition Height="20"/>
		</Grid.RowDefinitions>

		<DataGrid 
			Grid.Row="1"
			Grid.Column="1"
			CanUserAddRows="False"
			AutoGenerateColumns="False"
            IsSynchronizedWithCurrentItem="True"
            ItemsSource="{Binding Items}">
			<DataGrid.Columns>
				<DataGridTextColumn Header="Id"
									Binding="{Binding Path=Id}"/>
                <DataGridTemplateColumn Header="Item"
                                        CellTemplateSelector="{StaticResource GridDataTemplateSelector}"/>
            </DataGrid.Columns>
		</DataGrid>
	</Grid>
</UserControl>

1
2

4 Likes

@WPF 세심하신 예제 소스코드에 감탄하고 갑니다. :smile:

image

지금 구현해주신 부분에서 정말 간단하게 추가해 본다면 요렇게 해볼 수 도 있겠습니다.



1. ContentContent 안에 PropertyView 바인딩

<TextBlock.ToolTip>
	<Grid>
		<!-- 어떻게 설정해야 Tooltip에서 클래스 타입별 UserControl을 설정해서
		팝업을 할 수 있을까?-->
        <ContentControl Content="{Binding Item.PropertyView}"/>
    </Grid>
</TextBlock.ToolTip>

2. BaseClass.cs에 PropertyView 속성 추가

public UserControl PropertyView { get; protected set; }

3. 각각의 PropertyView 유저컨트롤 인스턴스 생성 및 데이터 생성자에 할당

protected override Task OnActivateAsync(CancellationToken cancellationToken)
{
    // PropertyView 생성
    UCCarPropertyView carPropertyView = new UCCarPropertyView();
    UCPersonPropertyView personPropertyView = new UCPersonPropertyView();

    Items = new ObservableCollection<ItemViewModel>();
    // 객체마다 각각 생성자에 보내주기~ 
    Items.Add(new ItemViewModel(1, new CarClass(11, "소나타", 4, "현대", "승용차", carPropertyView)));
    Items.Add(new ItemViewModel(2, new CarClass(12, "싼타페", 4, "현대", "SUV", carPropertyView)));
    Items.Add(new ItemViewModel(3, new CarClass(13, "쏘렌토", 4, "현대", "SUV", carPropertyView)));
    Items.Add(new ItemViewModel(4, new CarClass(14, "GV80", 6, "현대", "SUV", carPropertyView)));
    Items.Add(new ItemViewModel(5, new PersonClass(16, "홍길동", 20, "남성", personPropertyView)));
    Items.Add(new ItemViewModel(6, new PersonClass(17, "홍길순", 25, "여성", personPropertyView)));
    Items.Add(new ItemViewModel(7, new PersonClass(18, "고길동", 30, "남성", personPropertyView)));
    Items.Add(new ItemViewModel(8, new PersonClass(19, "고길순", 28, "여성", personPropertyView)));

    return base.OnActivateAsync(cancellationToken);
}

각 모델 생성자에서도 PropertyView에 할당하기

public CarClass(int id, string name, int engine, string brand, string carType, UserControl propertyView)
    : base(id)
{
    CarName = name;
    Engine = engine;
    Brand = brand;
    CarType = carType;

    // 여기 또는 base 에서 할당
    // PersonClass에서도 동일하게~
    PropertyView = propertyView;
}

결과

타입 A 프로퍼티 창

image

타입 B 프로퍼티 창

image

4 Likes

감사합니다. 외부에 있다보니 이제 확인했네요.
잘 참조하겠습니다.

1 Like

감사합니다!!
자세한 설명감사합니다.

1 Like

좋은 조언 감사합니다!

1 Like

감사합니다 해결책으로 너무 훌륭합니다!

1 Like