-
원하는 동작
DataTemplate 내부에 만들어 둔 Popup.Combobox에 ItemsSource가 Ancestor를 잘 찾아가서 바인딩되길 원합니다. -
시도한 방법
RelativeSource AncestorType, AncestorLevel을 전부 지정해줬습니다. -
문제점
goodWorkListview부분은 DataTemplate 내부에서 직접 템플릿을 구현하였습니다. local:PlaceData 데이터가 들어올 경우 DataTemplate이 동작하여 Combobox가 원하는 정상 동작을 하게됩니다.
notGoodWorkListView 부분은 역시 DataTemplate을 사용하고 있지만, 다르게 접근하고 있습니다.
local:PlaceData 데이터가 들어올 경우 단순히 토글 버튼만 표시됩니다.
토글 버튼을 누를 경우 Popup이 활성화되며 Tag에 넣어둔 내용물이 표현되도록 만들었습니다.
여기서 문제를 하나 발견했습니다.
Combobox의 ItemsSource를 찾지 못하고있습니다.
VisualStudio에서 프로젝트 빌드 후 시작하여 토글버튼을 누르면 Combobox가 비어있는것을 확인할 수 있습니다.
이 상태에서 Combobox의 ItemsSource 코드를 지웠다가 다시 적으면 그때부턴 잘 동작하게 됩니다. -
의심가는 부분
notGoodListView의 내부에서 DataTemplate을 설정한 후 다시 한번 Tag에 집어넣게 되면서 DataContext가 꼬인게 아닐까 의심이 가지만 어떻게 접근, 수정을 해야하는지 잘 모르겠습니다.
MainWindow.xaml 입니다.
<Window Name="myTestWindow" x:Class="RelativeSourceErrorTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:RelativeSourceErrorTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
</Window.Resources>
<Grid DataContext="{Binding ElementName=myTestWindow}">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ListView Name="goodWorkListView" ItemsSource="{Binding PlaceDatas}">
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type local:PlaceData}">
<Grid Width="200">
<Grid.Resources>
<Style TargetType="Border">
<Setter Property="Margin" Value="2"/>
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="BorderThickness" Value="1"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="40"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0">
<TextBlock Text="{Binding Width}"/>
</Border>
<Border Grid.Column="1">
<TextBlock Text="{Binding Height}"/>
</Border>
<Border Grid.Column="2">
<ComboBox ItemsSource="{Binding PositionSource, RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}}"
SelectedItem="{Binding Position}" HorizontalContentAlignment="Center"/>
</Border>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView Name="notGoodWorkListView" Grid.Column="1" ItemsSource="{Binding PlaceDatas}">
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type local:PlaceData}">
<Grid Width="200">
<ToggleButton Content="Item">
<ToggleButton.Tag>
<Grid Width="200" Background="#888888" Margin="5 2">
<Grid.Resources>
<Style TargetType="Border">
<Setter Property="Margin" Value="2"/>
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="BorderThickness" Value="1"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="40"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0">
<TextBlock Text="{Binding Width}"/>
</Border>
<Border Grid.Column="1">
<TextBlock Text="{Binding Height}"/>
</Border>
<Border Grid.Column="2">
<ComboBox ItemsSource="{Binding PositionSource, RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}, AncestorLevel=1}}"
SelectedItem="{Binding Position}" HorizontalContentAlignment="Center"/>
</Border>
</Grid>
</ToggleButton.Tag>
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Background="{TemplateBinding Background}">
<Grid>
<TextBlock Text="{TemplateBinding Content}" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="10" TextAlignment="Center"/>
<Popup Placement="Bottom" AllowsTransparency="true" IsOpen="{Binding IsChecked , RelativeSource={RelativeSource TemplatedParent}}">
<Border>
<ContentPresenter Content="{TemplateBinding Tag}" />
</Border>
</Popup>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Pink"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="Gray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ToggleButton.Style>
</ToggleButton>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
MainWindow.xaml.cs입니다.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
namespace RelativeSourceErrorTest
{
/// <summary>
/// MainWindow.xaml에 대한 상호 작용 논리
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
#region Events
public event PropertyChangedEventHandler PropertyChanged;
public bool Set<T>(ref T field, T value, [CallerMemberName] string propertyName = "")
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
field = value;
RaiseOnPropertyChanged(propertyName);
return true;
}
private void RaiseOnPropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
#endregion
private Array positionSource;
private ObservableCollection<PlaceData> placeDatas;
public Array PositionSource { get => positionSource; set => Set(ref positionSource, value); }
public ObservableCollection<PlaceData> PlaceDatas { get => placeDatas; set => Set(ref placeDatas, value); }
public MainWindow()
{
PositionSource = Enum.GetValues(typeof(PositionConstants));
InitializeComponent();
PlaceDatas = new ObservableCollection<PlaceData>();
for (int i = 0; i < 10; i++)
{
var pos = PositionConstants.Top;
if (i > 3 && i < 6)
{
pos = PositionConstants.Mid;
}
else if (i >= 6)
{
pos = PositionConstants.Bottom;
}
PlaceDatas.Add(new PlaceData(pos, i));
}
}
}
public enum PositionConstants
{
Top,
Mid,
Bottom
}
public class PlaceData : INotifyPropertyChanged
{
#region Events
public event PropertyChangedEventHandler PropertyChanged;
public bool Set<T>(ref T field, T value, [CallerMemberName] string propertyName = "")
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
field = value;
RaiseOnPropertyChanged(propertyName);
return true;
}
private void RaiseOnPropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
#endregion
private PositionConstants position;
public PositionConstants Position { get => position; set => Set(ref position, value); }
public int Width { get; set; }
public int Height { get; set; }
public PlaceData(PositionConstants position, int i)
{
Position = position;
Width = i;
Height = i;
}
}
}