반응형

최근에 프로젝트를 진행하면서 ListView Control을 하며 어려웠던 부분을 정리하였습니다.

 

👉 기본 환경

- Language: C#, xaml

- IDE: Visual Basic 2022

- Framework: .NET 8.0


✍️ 최근에 Button 클릭 영역으로 몇 시간 헤매어 내용을 간략히 적어봅니다.

 

View1

1
2
3
4
5
6
7
8
9
10
<!--// Selected Image //-->
<Image Grid.Row="0" Source="{Binding SelectedImageSource}">
    <b:Interaction.Triggers>
        <b:EventTrigger EventName="MouseLeftButtonUp">
            <b:InvokeCommandAction Command="{Binding EnlargeImageCommand}"
                                   CommandParameter="{Binding ElementName=window}"
                                   />
        </b:EventTrigger>
    </b:Interaction.Triggers>
</Image>

 

이미지를 클릭했을 때, 확대된 이미지를 팝업창으로 띄우려고 합니다.

 

크게 이용했던 방법이

  * Popup 태그

  * Window

였는데, Viewer를 띄우는 부모창의 위치에 따라 확대되는 이미지의 위치가 변합니다.

 

Popup 태그는 위치 컨트롤이 쉽지 않아 결국 Window로 결정하였습니다.

 

ViewModel1

1
2
3
4
5
6
7
8
9
10
11
12
13
public RelayCommand EnlargeImageCommand => null ?? new RelayCommand(EnlargeImageEvent);
 
private void EnlargeImageEvent(object obj)
{
    Window window = obj as Window;
 
    WindowImageViewer windowImageViewer = new WindowImageViewer();
    windowImageViewer.DataContext = new ViewModelImageViewer(SelectedImageSource);
    windowImageViewer.Width = 300;
    windowImageViewer.Height = 330;
    windowImageViewer.Owner = window;
    windowImageViewer.ShowDialog();
}

 

간단하게 만들어보기 위해서 Width와 Height는 모두 상수로 설정해서 사실 WindowImageViewer에서 설정이 가능합니다.

 

하지만, 프로젝트에서는 Viewer Window를 띄우는 부모창의 Width와 Height를 이용했습니다.

당시에 DataContext에 해당 값을 넘겨주고, Window에서 Width, Height를 Binding 했는데,

동작 순서의 문제인지(Window Show → Binding Width, Height) Width, Height 바인딩이 되지 않았습니다.

 

그래서 처음부터 Window를 열 때 Width, Height를 설정하고 시작했습니다.

 

또한, 부모창의 중앙에 위치하기 위해 Owner 설정을 했고, 이를 위해서 CommandParameter를 View에서 추가했습니다.

 

View2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<Window WindowStyle="None" ResizeMode="NoResize" 
        AllowsTransparency="True" Background="Transparent"
        Name="window" WindowStartupLocation="CenterOwner"
        >
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Button Height="30"
                VerticalAlignment="Center" HorizontalAlignment="Right"
                BorderThickness="0"
                Background="Transparent"
                Command="{Binding CloseWindowCommand}" CommandParameter="{Binding ElementName=window}"
                >
            <Image Source="pack://application:,,,/Resources/IconClose.png"
                   RenderOptions.BitmapScalingMode="HighQuality"
                   />
        </Button>
        <Image Grid.Row="1" 
               Source="{Binding SelectedImageSource}"/>
    </Grid>
</Window>
 

 

Viewer Window는 다른 창들과 TitleBar가 없고 크기조절을 못하도록 막아두었습니다.

 

이미지를 제외하고 모두 투명한 상태에서 X 버튼을 클릭하면 확대된 이미지 뷰어가 닫히는 것을 그린 Window입니다.

 

사실, 지금 코드에서는 버튼이 네모 영역에서 잘 동작하지만 프로젝트에서는 이미지 구간을 제외하고 버튼 클릭 이벤트가 동작하지 않았습니다.

그것을 해결하기 위해 열심히 찾아본 결과 문제는 Background에 있음을 알게 되었습니다.

 

* Background

  * Transparent: 배경을 투명하게 만드는 요소

  * #00FFFFFF: 배경을 FFFFFF(흰색)으로 하되 투명도를 최대(00 - 완전 투명)로 설정

 

Background에 색상을 지정하면 그 버튼 영역이 인식되기 때문에 Transparent로 인식 안되던 버튼 공간이 인식이 됩니다.

 

 

 

😮 오늘의 깨달음: Background, 오늘부터는 8자리다!

 

반응형

'C# > WPF' 카테고리의 다른 글

[WPF] MaterialDesignTheme 적용  (0) 2024.04.13
[WPF] WebView2와 동영상  (0) 2024.04.13
[WPF] MVVM Scroll 동작 구현  (0) 2024.03.31
[WPF] ListView와 SelectedItem 초기화  (0) 2024.03.31
[WPF] Converter와 Visibility  (0) 2024.03.18
반응형

최근에 프로젝트를 진행하면서 ListView Control을 하며 어려웠던 부분을 정리하였습니다.

 

👉 기본 환경

- Language: C#, xaml

- IDE: Visual Basic 2022

- Framework: .NET 8.0


Scroll 처리를 버튼으로 만든 것..

제가 구현했던 동작 중 난이도 최상..!

 

✍️ ListView에 이미지를 클릭할 때, 스크롤이 이동하면서 선택된 이미지가 중앙에 오는 동작입니다.

 

 

View

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<Window>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="30"/>
        </Grid.RowDefinitions>
 
        <!--// Window //-->
        <Grid Grid.Row="0">
            
        </Grid>
        
        <!--// Image //-->
        <Grid Grid.Row="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="100"/>
            </Grid.RowDefinitions>
            
            <!--// Selected Image //-->
            <Image Grid.Row="0" Source="{Binding SelectedImageSource}"/>
            
            <!--// Image List //-->
            <ListView Name="listViewImageSources" 
                      Grid.Row="1"
                      ItemsSource="{Binding ImageSources}"
                      SelectedValue="{Binding SelectedImageSource, Mode=TwoWay}"
                      SelectedIndex="{Binding SelectedImageSourceIndex, Mode=TwoWay}"
                      ScrollViewer.VerticalScrollBarVisibility="Disabled"
                      ScrollViewer.HorizontalScrollBarVisibility="Hidden"
                      >
                <b:Interaction.Triggers>
                    <b:EventTrigger EventName="MouseLeftButtonUp">
                        <b:InvokeCommandAction Command="{Binding ScrollImageCommand}"
                                               CommandParameter="{Binding ElementName=listViewImageSources}"
                                               />
                    </b:EventTrigger>
                </b:Interaction.Triggers>
                <ListView.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal"
                                    HorizontalAlignment="Center"
                                    />
                    </ItemsPanelTemplate>
                </ListView.ItemsPanel>
 
                <ListView.ItemContainerStyle>
                    <Style TargetType="ListViewItem">
                        <Setter Property="Width" Value="75"/>
                        <Setter Property="Height" Value="75"/>
                    </Style>
                </ListView.ItemContainerStyle>
                
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <Image Source="{Binding .}" Stretch="Fill"/>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </Grid>
        
        <!--// Etc.. //-->
        <Grid Grid.Row="2">
            
        </Grid>
    </Grid>
</Window>
 

 

ListView

  * SelectedValue와 SelectedIndex를 모두 설정한 이유는 

    * SelectedValue: Image Source를 바인딩하기 위함이고,

    * SelectedIndex: Scroll 위치 계산에 사용하기 위함입니다.

  * ScrollViewer는 Hidden 처리하고 동작을 Select 이벤트에 넘겼습니다.

  * InvokeCommand: Nuget Behaviors 설치했습니다.

    * 보통 Click 이벤트 구현은 xaml.cs로 넘어가게 되는데, MVVM 패턴을 유지하기 위함입니다.

 

ViewModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
namespace ScrollButton.ViewModels
{
    public class ViewModelMain : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler? PropertyChanged;
 
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(thisnew PropertyChangedEventArgs(propertyName));
        }
 
        #endregion
 
        #region Properties
        private ImageSource _selectedImageSource;
 
        public ImageSource SelectedImageSource
        {
            get { return _selectedImageSource; }
           set 
{
_selectedImageSource = value; 
OnPropertyChange(nameof(SelectedImageSource));
}
        }
 
        private int _SelectedImageSourceIndex;
 
        public int SelectedImageSourceIndex
        {
            get { return _SelectedImageSourceIndex; }
            set { _SelectedImageSourceIndex = value; }
        }
 
        private ObservableCollection<ImageSource> _imageSources = new ObservableCollection<ImageSource>();
 
        public ObservableCollection<ImageSource> ImageSources
        {
            get { return _imageSources; }
            set { _imageSources = value; }
        }
        #endregion
 
 
 
        #region Commands
        public RelayCommand ScrollImageCommand => null ?? new RelayCommand(ScrollImageEvent);
        #endregion
 
 
 
        #region Constructors
        public ViewModelMain()
        {
            ImageSources = new ObservableCollection<ImageSource>
            {
                new BitmapImage(new Uri("pack://application:,,,/Resources/number0.png"))
                , new BitmapImage(new Uri("pack://application:,,,/Resources/number1.png"))
                , new BitmapImage(new Uri("pack://application:,,,/Resources/number2.png"))
                , new BitmapImage(new Uri("pack://application:,,,/Resources/number3.png"))
                , new BitmapImage(new Uri("pack://application:,,,/Resources/number4.png"))
                , new BitmapImage(new Uri("pack://application:,,,/Resources/number5.png"))
                , new BitmapImage(new Uri("pack://application:,,,/Resources/number6.png"))
                , new BitmapImage(new Uri("pack://application:,,,/Resources/number7.png"))
                , new BitmapImage(new Uri("pack://application:,,,/Resources/number8.png"))
                , new BitmapImage(new Uri("pack://application:,,,/Resources/number9.png"))
            };
 
            SelectedImageSource = ImageSources[0];
        }
        #endregion
 
 
 
        #region Methods
        private void ScrollImageEvent(object obj)
        {
            if (obj is ListView listView)
            {
                var scrollViewer = FindScrollViewer(listView);
 
                if (scrollViewer != null)
                {
                    int middlePositionIndex = 2// 중앙에 위치시키고자 하는 인덱스
                    double newHorizontalOffset = SelectedImageSourceIndex - middlePositionIndex;
 
                    scrollViewer.ScrollToHorizontalOffset(newHorizontalOffset);
                    scrollViewer.UpdateLayout();
                }
            }
        }
 
        private ScrollViewer FindScrollViewer(DependencyObject dependencyObject)
        {
            if (dependencyObject is ScrollViewer)
            {
                return dependencyObject as ScrollViewer;
            }
 
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
            {
                var child = VisualTreeHelper.GetChild(dependencyObject, i);
                var scrollViewerInListView = FindScrollViewer(child);
                if (scrollViewerInListView != null)
                {
                    return scrollViewerInListView;
                }
            }
 
            return null;
        }
 
        #endregion
    }
}
 
 
 

 

🚨  문제가 ScrollViewer를 어떻게 얻어오냐..였습니다.

View와 ViewModel이 독립적이어야한다고 했지만, 도저히 방도가 생각나지 않아 CommandParameter로 ListView를 넘기고 ListView 하위에 있는 ScrollViewer를 찾아서 반환하는 형식으로 진행했습니다.

 

 

 

😮 오늘의 깨달음: Web의 Scroll Event Control과 프로그램의 Scroll Event Control은 다르다..!

반응형

'C# > WPF' 카테고리의 다른 글

[WPF] WebView2와 동영상  (0) 2024.04.13
[WPF] Button 클릭 영역과 Background  (0) 2024.04.06
[WPF] ListView와 SelectedItem 초기화  (0) 2024.03.31
[WPF] Converter와 Visibility  (0) 2024.03.18
[WPF] ResourceDictionary  (0) 2024.03.18
반응형

최근에 프로젝트를 진행하면서 ListView Control을 하며 어려웠던 부분을 정리하였습니다.

 

👉 기본 환경

- Language: C#, xaml

- IDE: Visual Basic 2022

- Framework: .NET 8.0


사내 프로젝트도 어느덧 막바지를 향해 가고 있습니다.

 

설계팀으로부터 테스트 결과를 받았습니다.

Click 이벤트 컨트롤이 잘 되지 않아 해결을 하고, 그 해결은 또 다른 문제를 불러오게 되는데..

의 굴레에서 빠져나온 이야기를 짧게 정리해보고자 합니다✍️.

 

상황:

  1. ListView에서 Item을 클릭했을 때, 데이터를 로드하고,

  2. DataContext로 연결한 ViewModel에 로드된 데이터를 넘겨주면서

  3. Window를 여는 것이었습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
private void ClickItemEvent()
{
    // 생략
    
    if(SelectedItem != null && SelectedItem.Title != null)
    {
        LoadDataModel(SelectedItem);
        
        WindowDetails windowDetails = new WindowDetails();
        windowDetails.DataContext = new ViewModelDetails(SelectedDataModel);
        windowDetails.ShowDialog();
    }
}

 

문제:

기존에 ClickItemEvent가 1번이라도 발생해서 SelectedItem이 설정되면,

더블클릭을 통한 창 최대/최소 시에 ListView가 클릭된 것처럼 windowDetails 창이 열렸습니다.

 

SelectedItem이 null값일 때, window가 열리지 않도록 유효성 검사를 조건으로도 해결할 수 없는 문제였기에 다른 해결책이 필요했습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void ClickAddinItemEvent()
{
    // 생략
    
    if(SelectedItem != null && SelectedItem.Title != null)
    {
        LoadDataModel(SelectedItem);
        
        WindowDetails windowDetails = new WindowDetails();
        windowDetails.DataContext = new ViewModelDetails(SelectedDataModel);
        windowDetails.ShowDialog();
 
        // Initialize Data
        SelectedItem = new ItemModel();
    }
}

 

해결1:

새로운 ItemModel()로 초기화

→ 부정확한 click 이벤트에 대해서는 windowDetails가 열리지 않음

🚨 그러나, 같은 SelectedItem을 클릭했을 때,  windowDetails가 열리지 않음

 

🤓 이유:

ListView의 총 3개의 ListViewItem이 있다고 가정했을 때,

  * ItemA

  * ItemB

  * ItemC

ItemA에 대한 SelectedItem의 참조값이 0001 일 때, 새로운 인스턴스로 초기화하며 종료했으므로 0002로 변경

  * ItemA: 0001 → 0002

  * ItemB: 0003

  * ItemC: 0004

 

새로운 Item인 B나 C를 선택했을 때는 참조값이 변경되면서 변화를 인식하지만,

동일한 Item인 A를 클릭했을 때는 이미 빈 참조값인 0002로 초기화되었기 때문에 변화를 인식하지 못함

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void ClickAddinItemEvent()
{
    // 생략
    
    if(SelectedItem != null && SelectedItem.Title != null)
    {
        LoadDataModel(SelectedItem);
        
        WindowDetails windowDetails = new WindowDetails();
        windowDetails.DataContext = new ViewModelDetails(SelectedDataModel);
        windowDetails.ShowDialog();
 
        // Initialize Data
        SelectedItem = null;
    }
}

해결2:

null로 초기화

→ 참조값이 없어지므로 동일한 Item을 클릭해도 SelectedItem의 변화가 인식됨

 

 

 

✍️ 값 초기화를 null로 하지 않기 위해 새로운 인스턴스를 사용헀는데, 오히려 동작인식이 되지 않아 새로운 문제가 발생했었습니다. 이에 대해 오히려 WPF의 동작원리를 조금 더 깊게 알게 된 것 같아 뿌듯했습니다🤗.

 

반응형

'C# > WPF' 카테고리의 다른 글

[WPF] Button 클릭 영역과 Background  (0) 2024.04.06
[WPF] MVVM Scroll 동작 구현  (0) 2024.03.31
[WPF] Converter와 Visibility  (0) 2024.03.18
[WPF] ResourceDictionary  (0) 2024.03.18
[WPF] Popup Control  (1) 2024.03.17
반응형

최근에 프로젝트를 진행하면서 ListView Control을 하며 어려웠던 부분을 정리하였습니다.

 

👉 기본 환경

- Language: C#, xaml

- IDE: Visual Basic 2022


bool 타입의 값으로 Visibility를 컨트롤 하는 일이 많았습니다.

 

이번 기회에 사용한 Converter를 정리🗂️해 봅니다.

 

BooleanToVisibleConverter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class BooleanToVisibleConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        bool val = (bool)value;
        if (val)
        {
            return System.Windows.Visibility.Visible;
        }
        else
        {
            return System.Windows.Visibility.Collapsed;
        }
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

 

NegativeBooleanConverter

1
2
3
4
5
6
7
8
9
10
11
public class NegativeBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return !((bool)value);
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

 

ChainConverter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ChainConverter : IValueConverter
{
    public IValueConverter Converter1 { get; set; }
    public IValueConverter Converter2 { get; set; }
 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        object convertedValue = Converter1.Convert(value, targetType, parameter, culture);
        return Converter2.Convert(convertedValue, targetType, parameter, culture);
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

 

Window / UserControl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<Window>
    <Window.Resources>
        <ResourceDictionary>
            <converter:BooleanToVisibleConveter x:Key="boolVisibleInverter"/>
            <converter:NegativeBooleanConverter x:Key="negativeBoolInverter"/>
            <converter:ChainConverter x:Key="negativeBoolVisibleInverter"
                                      Converter1="{StaticResource negativeBoolInverter}"
                                      Converter2="{StaticResource boolVisibleInverter}" />
        </ResourceDictionary>
    </Window.Resources>
    <Grid>
        <StackPanel>
            <TextBlock Text="If the value is true, this TextBlock will be Visible"
                       Visibility="{Binding TrueValue, Converter={StaticResource boolVisibleInverter}}" />
            <TextBlock Text="If the value is false, this TextBlock will be Visible"
                       Visibility="{Binding FalseValue, Converter={StaticResource negativeBoolVisibleInverter}}" />
        </StackPanel>
        <Grid Background="#000000" Opacity="0.5" 
              Visibility="{Binding TrueValue, Converter={StaticResource boolVisibleInverter}}">
        </Grid>
    </Grid>
</Window>

 

⭐ Converter와 Visibility를 통해서 Dim 처리를 구현할 수 있음

    * Dim 처리: 웹페이지에서 팝업을 띄울때 배경으로부터 팝업화면을 강조하기 위해 넣는 반투명 음영 영역

    (여기서는 18행의 Grid가 Dim 역할을 수행)

 

 

 

📚 참고 자료

 

WPF: how to use 2 converters in 1 binding?

I have a control that I want to show/hide, depending on the value of a boolean. I have a NegatedBooleanConverter (switches true to false and vice versa) and I need to run this converter first. I h...

stackoverflow.com

 

반응형

'C# > WPF' 카테고리의 다른 글

[WPF] MVVM Scroll 동작 구현  (0) 2024.03.31
[WPF] ListView와 SelectedItem 초기화  (0) 2024.03.31
[WPF] ResourceDictionary  (0) 2024.03.18
[WPF] Popup Control  (1) 2024.03.17
[WPF] 검색과 정렬  (0) 2024.03.10
반응형

최근에 프로젝트를 진행하면서 ListView Control을 하며 어려웠던 부분을 정리하였습니다.

 

👉 기본 환경

- Language: C#, xaml

- IDE: Visual Basic 2022


Style을 ResourceDictionary에 선언해두고 필요한 파일에서만 적용하고 싶었는데, 

Resource의 key를 설정하는 부분에서 반나절 넘게 해멨습니다.

 

코드를 정리하고나니, 두 줄뿐이었지만 잊기 전에 다시 기록해둡니다.

 

ResourceDictionary

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<ResourceDictionary>
    <SolidColorBrush x:Key="PrimaryColor" Color="#FF0000"/>
    <Style x:Key="ScrollBarTrackThumb" TargetType="{x:Type Thumb}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Thumb}">
                    <Grid x:Name="Grid">
                        <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                                   Width="Auto" Height="Auto"
                                   Fill="Transparent" />
                        <Border x:Name="CornerScrollBarRectangle"
                                CornerRadius="5"
                                HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                                Width="Auto" Height="Auto"
                                Margin="0,1,0,1"
                                Background="{TemplateBinding Background}" />
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="Tag" Value="Horizontal">
                            <Setter TargetName="CornerScrollBarRectangle" Property="Width" Value="Auto" />
                            <Setter TargetName="CornerScrollBarRectangle" Property="Height" Value="6" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

 

Window / UserControl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<UserControl>
    <UserControl.Resources>
        <ResourceDictionary>
            <converter:BooleanToVisibleConverter x:Key="boolVisibleInverter"/>
            <RosourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="../Styles/CustomStyle.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>
    
    <!-- 생략 -->
 
    <!-- 암시적 스타일: TargetType="{x:Type Thumb}"에 따라 ScrollViewer에 Style 적용 -->
    <ScrollViewer>
        <!-- 명시적 스타일: ResourceDictionary 선언된 Key값 선언 -->
        <Grid Background="{StaticResource PrimaryColor}"></Grid>
    </ScrollViewer>
</UserControl>

 

* ResourceDictionary
    * 일반적으로 x:Key 없이 Resources 또는 ResourceDictionary.MergedDictionaries 내에서 직접 사용
    * 만일, 리소스 구별이 필요할 경우 x:Key 값을 설정해야 함
* ResourceDictionary.MergedDictionaries
    * 리소스를 전역적으로 적용할 목적으로 사용되므로 x:Key가 필요하지 않음
    * 여러 리소스 사전을 하나로 합치는 것이 목적

        → 각 리소스 사전 자체에 대한 키를 설정하는 것이 아니라, 그 안에 포함된 개별 리소스에 x:Key를 설정
        * ResourceDictionary로 연결하면, 개별 요소에서 key값을 통해 Style에 접근 가능

 

반응형

'C# > WPF' 카테고리의 다른 글

[WPF] ListView와 SelectedItem 초기화  (0) 2024.03.31
[WPF] Converter와 Visibility  (0) 2024.03.18
[WPF] Popup Control  (1) 2024.03.17
[WPF] 검색과 정렬  (0) 2024.03.10
[WPF] ComboBox와 SelectedItem  (0) 2024.03.10