■ ListView 엘리먼트의 DragItemsStarting/DragEnter/DragOver/Drop 이벤트를 사용하는 방법을 보여준다.
▶ GroupInfoList.cs
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 |
using System.Collections.Generic; namespace TestProject { /// <summary> /// 그룹 정보 리스트 /// </summary> public class GroupInfoList : List<object> { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 키 - Key /// <summary> /// 키 /// </summary> public object Key { get; set; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - GroupInfoList(itemEnumerable) /// <summary> /// 생성자 /// </summary> /// <param name="itemEnumerable">항목 열거 가능형</param> public GroupInfoList(IEnumerable<object> itemEnumerable) : base(itemEnumerable) { } #endregion } } |
▶ Contact.cs
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 120 121 122 123 124 125 126 127 128 129 130 |
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using Windows.Storage; namespace TestProject { /// <summary> /// 연락 /// </summary> public class Contact { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 이름 - FirstName /// <summary> /// 이름 /// </summary> public string FirstName { get; private set; } #endregion #region 성 - LastName /// <summary> /// 성 /// </summary> public string LastName { get; private set; } #endregion #region 회사 - Company /// <summary> /// 회사 /// </summary> public string Company { get; private set; } #endregion #region 성명 - Name /// <summary> /// 성명 /// </summary> public string Name => FirstName + " " + LastName; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - Contact(firstName, lastName, company) /// <summary> /// 생성자 /// </summary> /// <param name="firstName">이름</param> /// <param name="lastName">성</param> /// <param name="company">회사</param> public Contact(string firstName, string lastName, string company) { FirstName = firstName; LastName = lastName; Company = company; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region 컬렉션 구하기 (비동기) - GetCollectionAsync() /// <summary> /// 컬렉션 구하기 (비동기) /// </summary> /// <returns>컬렉션</returns> public static async Task<ObservableCollection<Contact>> GetCollectionAsync() { StorageFile storageFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///DATA/Contacts.txt")); IList<string> lineList = await FileIO.ReadLinesAsync(storageFile); ObservableCollection<Contact> collection = new ObservableCollection<Contact>(); for(int i = 0; i < lineList.Count; i += 3) { collection.Add(new Contact(lineList[i], lineList[i + 1], lineList[i + 2])); } return collection; } #endregion #region 그룹 컬렉션 구하기 (비동기) - GetGroupCollectionAsync() /// <summary> /// 그룹 컬렉션 구하기 (비동기) /// </summary> /// <returns>그룹 컬렉션</returns> public static async Task<ObservableCollection<GroupInfoList>> GetGroupCollectionAsync() { IEnumerable<GroupInfoList> query = from item in await GetCollectionAsync() group item by item.LastName.Substring(0, 1).ToUpper() into itemGroup orderby itemGroup.Key select new GroupInfoList(itemGroup) { Key = itemGroup.Key }; return new ObservableCollection<GroupInfoList>(query); } #endregion #region 문자열 구하기 - ToString() /// <summary> /// 문자열 구하기 /// </summary> /// <returns>문자열</returns> public override string ToString() { return Name; } #endregion } } |
▶ MainPage.xaml
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 |
<Page x:Class="TestProject.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:TestProject" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" FontFamily="나눔고딕코딩" FontSize="16"> <Page.Resources> <Style x:Key="BaseTextBlockStyleKey" TargetType="TextBlock"> <Setter Property="LineStackingStrategy" Value="MaxHeight" /> <Setter Property="TextLineBounds" Value="Full" /> <Setter Property="TextTrimming" Value="None" /> <Setter Property="TextWrapping" Value="Wrap" /> <Setter Property="FontFamily" Value="XamlAutoFontFamily" /> <Setter Property="FontWeight" Value="SemiBold" /> <Setter Property="FontSize" Value="14" /> </Style> <DataTemplate x:Key="ListViewDataTemplateKey" x:DataType="local:Contact"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Ellipse Grid.Row="0" Grid.RowSpan="2" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5" Width ="32" Height="32" Fill="{ThemeResource SystemControlBackgroundBaseMediumBrush}" /> <TextBlock Grid.Row="0" Grid.Column="1" Style="{ThemeResource BaseTextBlockStyleKey}" Margin="10 5 0 0" x:Phase="1" Text="{x:Bind Name}" /> <TextBlock Grid.Row="1" Grid.Column="1" Style="{ThemeResource BaseTextBlockStyleKey}" Margin="10 0 0 5" x:Phase="2" Text="{x:Bind Company}" /> </Grid> </DataTemplate> </Page.Resources> <Grid> <Grid HorizontalAlignment="Center" VerticalAlignment="Center"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="30" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <ListView Name="listView1" Grid.Column="0" ItemTemplate="{StaticResource ListViewDataTemplateKey}" Width="300" Height="400" BorderThickness="1" BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}" AllowDrop="True" CanDragItems="True" CanReorderItems="True" SelectionMode="Single" DragItemsStarting="listView1_DragItemsStarting" DragOver="listView1_DragOver" Drop="listView_Drop" /> <ListView Name="listView2" Grid.Column="2" ItemTemplate="{StaticResource ListViewDataTemplateKey}" Width="300" Height="400" BorderThickness="1" BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}" AllowDrop="True" CanDragItems="True" CanReorderItems="True" SelectionMode="Single" DragItemsStarting="listView2_DragItemsStarting" DragEnter="listView2_DragEnter" DragOver="listView2_DragOver" Drop="listView_Drop" /> </Grid> </Grid> </Page> |
▶ MainPage.xaml.cs
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 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
using System; using System.Collections.ObjectModel; using System.Text; using Windows.ApplicationModel.DataTransfer; using Windows.Foundation; using Windows.Graphics.Display; using Windows.UI.ViewManagement; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; namespace TestProject { /// <summary> /// 메인 페이지 /// </summary> public sealed partial class MainPage : Page { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region Field /// <summary> /// 소스 컬렉션 1 /// </summary> private ObservableCollection<Contact> sourceCollection1 = new ObservableCollection<Contact>(); /// <summary> /// 소스 컬렉션 2 /// </summary> private ObservableCollection<Contact> sourceCollection2 = new ObservableCollection<Contact>(); #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainPage() /// <summary> /// 생성자 /// </summary> public MainPage() { InitializeComponent(); #region 윈도우 크기를 설정한다. double width = 800d; double height = 600d; double dpi = (double)DisplayInformation.GetForCurrentView().LogicalDpi; ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize; Size windowSize = new Size(width * 96d / dpi, height * 96d / dpi); ApplicationView.PreferredLaunchViewSize = windowSize; Window.Current.Activate(); ApplicationView.GetForCurrentView().TryResizeView(windowSize); #endregion #region 윈도우 제목을 설정한다. ApplicationView.GetForCurrentView().Title = "ListView 엘리먼트 : DragItemsStarting/DragEnter/DragOver/Drop 이벤트 사용하기"; #endregion } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 탐색되는 경우 처리하기 - OnNavigatedTo(e) /// <summary> /// 탐색되는 경우 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override async void OnNavigatedTo(NavigationEventArgs e) { this.sourceCollection1 = await Contact.GetCollectionAsync(); this.listView1.ItemsSource = this.sourceCollection1; this.sourceCollection2.Add(new Contact("John" , "Doe" , "ABC Printers" )); this.sourceCollection2.Add(new Contact("Jane" , "Doe" , "XYZ Refrigerators" )); this.sourceCollection2.Add(new Contact("Santa", "Claus", "North Pole Toy Factory Inc.")); this.listView2.ItemsSource = this.sourceCollection2; } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private #region 리스트 뷰 1 항목 드래그 시작시 처리하기 - listView1_DragItemsStarting(sender, e) /// <summary> /// 리스트 뷰 1 항목 드래그 시작시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void listView1_DragItemsStarting(object sender, DragItemsStartingEventArgs e) { StringBuilder stringBuilder = new StringBuilder(); foreach(Contact item in e.Items) { if(stringBuilder.Length > 0) { stringBuilder.AppendLine(); } if(item.ToString() != null) { stringBuilder.Append($"{item.ToString()} {item.Company}"); } } e.Data.SetText(stringBuilder.ToString()); e.Data.RequestedOperation = DataPackageOperation.Move; } #endregion #region 리스트 뷰 1 드래그 OVER 처리하기 - listView1_DragOver(sender, e) /// <summary> /// 리스트 뷰 1 드래그 OVER 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void listView1_DragOver(object sender, DragEventArgs e) { e.AcceptedOperation = DataPackageOperation.Move; } #endregion #region 리스트 뷰 2 항목 드래그 시작시 처리하기 - listView2_DragItemsStarting(sender, e) /// <summary> /// 리스트 뷰 2 항목 드래그 시작시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void listView2_DragItemsStarting(object sender, DragItemsStartingEventArgs e) { if(e.Items.Count == 1) { Contact contact = (Contact)e.Items[0]; e.Data.SetText($"{contact.FirstName} {contact.LastName} {contact.Company}"); e.Data.RequestedOperation = DataPackageOperation.Move; } } #endregion #region 리스트 뷰 2 드래그 진입시 처리하기 - listView2_DragEnter(sender, e) /// <summary> /// 리스트 뷰 2 드래그 진입시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void listView2_DragEnter(object sender, DragEventArgs e) { e.DragUIOverride.IsGlyphVisible = false; } #endregion #region 리스트 뷰 2 드래그 OVER 처리하기 - listView2_DragOver(sender, e) /// <summary> /// 리스트 뷰 2 드래그 OVER 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void listView2_DragOver(object sender, DragEventArgs e) { e.AcceptedOperation = DataPackageOperation.Move; } #endregion #region 리스트 뷰 DROP 처리하기 - listView_Drop(sender, e) /// <summary> /// 리스트 뷰 DROP 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private async void listView_Drop(object sender, DragEventArgs e) { ListView listView = sender as ListView; if(e.DataView.Contains(StandardDataFormats.Text)) { DragOperationDeferral dragOperationDeferral = e.GetDeferral(); string sourceValueList = await e.DataView.GetTextAsync(); string[] sourceValueArry = sourceValueList.Split('\n'); foreach(string sourceValue in sourceValueArry) { string[] sourceValueItemArray = sourceValue.Split(" ", 3); Contact sourceContact = new Contact(sourceValueItemArray[0], sourceValueItemArray[1], sourceValueItemArray[2]); Point pos = e.GetPosition(listView.ItemsPanelRoot); ListViewItem sampleItem; if(listView.Name == "listView1") { sampleItem = (ListViewItem)this.listView2.ContainerFromIndex(0); } else { sampleItem = (ListViewItem)this.listView1.ContainerFromIndex(0); } double itemHeight = sampleItem.ActualHeight + sampleItem.Margin.Top + sampleItem.Margin.Bottom; int index = Math.Min(listView.Items.Count - 1, (int)(pos.Y / itemHeight)); ListViewItem targetItem = (ListViewItem)listView.ContainerFromIndex(index); Point positionInItem = e.GetPosition(targetItem); if(positionInItem.Y > itemHeight / 2) { index++; } index = Math.Min(listView.Items.Count, index); if(listView.Name == "listView1") { this.sourceCollection1.Insert(index, sourceContact); foreach(Contact contact in this.listView2.Items) { if(contact.FirstName == sourceContact.FirstName && contact.LastName == sourceContact.LastName && contact.Company == sourceContact.Company) { this.sourceCollection2.Remove(contact); break; } } } else if(listView.Name == "listView2") { this.sourceCollection2.Insert(index, sourceContact); foreach(Contact contact in this.listView1.Items) { if(contact.FirstName == sourceContact.FirstName && contact.LastName == sourceContact.LastName && contact.Company == sourceContact.Company) { this.sourceCollection1.Remove(contact); break; } } } } e.AcceptedOperation = DataPackageOperation.Move; dragOperationDeferral.Complete(); } } #endregion } } |