[C#/WINUI3/.NET6] ListView 클래스 : 필터 처리하기
■ ListView 클래스에서 필터 처리하는 방법을 보여준다. ▶ NativeHelper.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 |
using System.Runtime.InteropServices; namespace TestProject { /// <summary> /// 네이티브 헬퍼 /// </summary> public class NativeHelper { //////////////////////////////////////////////////////////////////////////////////////////////////// Import ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 현재 패키지 ID 구하기 - GetCurrentPackageId(bufferLength, buffer) /// <summary> /// 현재 패키지 ID 구하기 /// </summary> /// <param name="bufferLength">버퍼 길이</param> /// <param name="buffer">버퍼</param> /// <returns>처리 결과</returns> [DllImport("api-ms-win-appmodel-runtime-l1-1-1", SetLastError = true)] [return : MarshalAs(UnmanagedType.U4)] private static extern uint GetCurrentPackageId(ref int bufferLength, out byte buffer); #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Public #region Field /// <summary> /// ERROR_SUCCESS /// </summary> public const int ERROR_SUCCESS = 0; /// <summary> /// ERROR_INSUFFICIENT_BUFFER /// </summary> public const int ERROR_INSUFFICIENT_BUFFER = 122; /// <summary> /// APPMODEL_ERROR_NO_PACKAGE /// </summary> public const int APPMODEL_ERROR_NO_PACKAGE = 15700; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region 애플리케이션 패키지 여부 - IsAppPackaged /// <summary> /// 애플리케이션 패키지 여부 /// </summary> public static bool IsAppPackaged { get { int bufferSize = 0; uint lastError = GetCurrentPackageId(ref bufferSize, out _); bool isPackaged = true; if(lastError == APPMODEL_ERROR_NO_PACKAGE) { isPackaged = false; } return isPackaged; } } #endregion } } |
▶ FileLoader.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 |
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Threading.Tasks; using Windows.Storage; namespace TestProject { /// <summary> /// 파일 로더 /// </summary> public class FileLoader { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region 텍스트 로드하기 - LoadText(relativeFilePath) /// <summary> /// 텍스트 로드하기 /// </summary> /// <param name="relativeFilePath">상대적인 파일 경로</param> /// <returns>텍스트</returns> public static async Task<string> LoadText(string relativeFilePath) { StorageFile storageFile = null; if(!NativeHelper.IsAppPackaged) { string entryAssemblyFilePath = Assembly.GetEntryAssembly().Location; string entryAssemblyDirectorPath = Path.GetDirectoryName(entryAssemblyFilePath); string filePath = Path.Combine(entryAssemblyDirectorPath, relativeFilePath); string finalFilePath = Path.GetFullPath(filePath); storageFile = await StorageFile.GetFileFromPathAsync(finalFilePath); } else { Uri sourceURI = new Uri($"ms-appx:///{relativeFilePath}"); storageFile = await StorageFile.GetFileFromApplicationUriAsync(sourceURI); } return await FileIO.ReadTextAsync(storageFile); } #endregion #region 라인 리스트 로드하기 - LoadLineList(relativeFilePath) /// <summary> /// 라인 리스트 로드하기 /// </summary> /// <param name="relativeFilePath">상대적인 파일 경로</param> /// <returns>라인 리스트</returns> public static async Task<IList<string>> LoadLineList(string relativeFilePath) { string text = await LoadText(relativeFilePath); return text.Split(Environment.NewLine).ToList(); } #endregion } } |
▶ 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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
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 //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 문자열 구하기 - ToString() /// <summary> /// 문자열 구하기 /// </summary> /// <returns></returns> public override string ToString() { return $"Group {Key}"; } #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 |
using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; 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 연락처 컬렉션 구하기 (비동기) - GetContactCollectionAsync() /// <summary> /// 연락처 컬렉션 구하기 (비동기) /// </summary> /// <returns>연락처 컬렉션 태스크</returns> public async static Task<ObservableCollection<Contact>> GetContactCollectionAsync() { IList<string> lineList = await FileLoader.LoadLineList("DATA/Contacts.txt"); ObservableCollection<Contact> contactCollection = new ObservableCollection<Contact>(); for(int i = 0; i < lineList.Count - 2; i += 3) { contactCollection.Add(new Contact(lineList[i], lineList[i + 1], lineList[i + 2])); } return contactCollection; } #endregion #region 그룹 연락처 컬렉션 구하기 (비동기) - GetGroupedContactCollectionAsync() /// <summary> /// 그룹 연락처 컬렉션 구하기 (비동기) /// </summary> /// <returns>그룹 연락처 컬렉션 태스크</returns> public static async Task<ObservableCollection<GroupInfoList>> GetGroupedContactCollectionAsync() { var query = from item in await GetContactCollectionAsync() group item by item.LastName.Substring(0, 1).ToUpper() into g orderby g.Key select new GroupInfoList(g) { Key = g.Key }; return new ObservableCollection<GroupInfoList>(query); } #endregion #region 문자열 구하기 - ToString() /// <summary> /// 문자열 구하기 /// </summary> /// <returns>문자열</returns> public override string ToString() { return Name; } #endregion } } |
▶ MainWindow.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 |
<?xml version="1.0" encoding="utf-8"?> <Window x:Class="TestProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:TestProject" Title="TestProject"> <Grid Name="grid" Margin="10"> <Grid.Resources> <Style x:Key="TextBlockStyleKey" TargetType="TextBlock"> <Setter Property="LineStackingStrategy" Value="MaxHeight" /> <Setter Property="TextTrimming" Value="CharacterEllipsis" /> <Setter Property="TextWrapping" Value="Wrap" /> <Setter Property="TextLineBounds" Value="Full" /> <Setter Property="FontFamily" Value="XamlAutoFontFamily" /> <Setter Property="FontSize" Value="14" /> <Setter Property="FontWeight" Value="SemiBold" /> </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 x:Name="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 TextBlockStyleKey}" Margin="10 5 0 0" x:Phase="1" Text="{x:Bind Name}" /> <TextBlock Grid.Row="1" Grid.Column="1" Style="{ThemeResource BodyTextBlockStyle}" Margin="10 0 0 5" x:Phase="2" Text="{x:Bind Company}" /> </Grid> </DataTemplate> </Grid.Resources> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="10" /> <ColumnDefinition Width="200" /> </Grid.ColumnDefinitions> <ListView x:Name="listView" Grid.Column="0" ItemTemplate="{StaticResource ListViewDataTemplateKey}" BorderThickness="1" BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}" SelectionMode="Single" ShowsScrollingPlaceholders="True" /> <StackPanel Grid.Column="2"> <TextBlock Style="{ThemeResource TextBlockStyleKey}">Filter by...</TextBlock> <TextBox Name="firstNameFilterTextBox" HorizontalAlignment="Stretch" Margin="0 10 0 0" Header="First name" /> <TextBox Name="lastNameFilterTextBox" HorizontalAlignment="Stretch" Margin="0 10 0 0" Header="Last name" /> <TextBox Name="companyFilterTextBox" HorizontalAlignment="Stretch" Margin="0 10 0 0" Header="Company" /> </StackPanel> </Grid> </Window> |