XAML SelectDialog

Date: 2023-05-12
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Data;

namespace Plugin.Views.Controls
{
    public interface ISelectDialogOption
    { 
        object Key { get; }
        string Label { get; set; }
        object Value { get; }
    }

    public class SelectDialogOption<TKey, TValue> : ISelectDialogOption
    {
        public SelectDialogOption(TKey key, string label, TValue value)
        {
            Key = key;
            Label = label;
            Value = value;
        }

        public TKey Key { get; set; }
        public string Label { get; set; }
        public TValue Value { get; set; }
        object ISelectDialogOption.Key => Key;
        object ISelectDialogOption.Value => Label;
    }
    public partial class SelectDialog : Window
    {
        public SelectDialog(string question, string title)
        {
            InitializeComponent();
            Loaded += new RoutedEventHandler(SelectDialog_Loaded);
            txtQuestion.Text = question;
            Title = title;
        }

        private CollectionView ListView => (CollectionView)CollectionViewSource.GetDefaultView(lvDetails?.ItemsSource);

        public void InitOptions<TKey, TValue>(IEnumerable<SelectDialogOption<TKey, TValue>> options, TKey defaultValue = default(TKey)) where TKey : class
        {
            lvDetails.ItemsSource = options;
            ListView.Filter = CustomFilter;
            var selectedItem = options.FirstOrDefault(x => x.Key == defaultValue);
            if (selectedItem?.Key != null)
                lvDetails.SelectedItem = selectedItem;
        }

        private bool CustomFilter(object item)
        {
            if (string.IsNullOrEmpty(txtFilter.Text)) return true;
            if (item is ISelectDialogOption option)
                return Search(GetSearchWords(txtFilter.Text), option.Label);
            return false;
        }

        public static bool Search(List<string> words, string label) => words.All(x => label.IndexOf(x, StringComparison.OrdinalIgnoreCase) >= 0);
        public static List<string> GetSearchWords(string text) => text.Trim().Split(' ').Select(x => x.Trim()).Where(x => !string.IsNullOrWhiteSpace(x)).ToList();

        public static TValue ShowSelectDialog<TKey, TValue>(string question, string title, IEnumerable<SelectDialogOption<TKey, TValue>> options, TKey defaultValue = default(TKey)) where TKey : class
        {
            var inst = new SelectDialog(question, title);
            inst.InitOptions(options, defaultValue);
            inst.ShowDialog();
            if (inst.DialogResult == true && inst.SelectedItem is SelectDialogOption<TKey, TValue> kv)
                return kv.Value;
            return default;
        }

        private void BtnOk_Click(object sender, RoutedEventArgs e)
        {
            if (SelectedItem == null) return;
            DialogResult = true;
            Close();
        }

        public object SelectedItem => lvDetails.SelectedItem;
        void SelectDialog_Loaded(object sender, RoutedEventArgs e) => txtFilter.Focus();
        private void BtnCancel_Click(object sender, RoutedEventArgs e) => Close();
        private void txtFilter_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) => ListView.Refresh();
    }
}
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    x:Class="Plugin.Views.Controls.SelectDialog"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    WindowStartupLocation="CenterScreen" 
    SizeToContent="WidthAndHeight"
    MinWidth="400"
    MinHeight="100"
    WindowStyle="SingleBorderWindow"
    ResizeMode="CanMinimize">
    <StackPanel Margin="5">
        <TextBlock Name="txtQuestion" Margin="5"/>
        <TextBox DockPanel.Dock="Top" Margin="0,0,0,10" Name="txtFilter" TextChanged="txtFilter_TextChanged"  />
        <ListView Name="lvDetails" Height="200">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header=" " Width="400" DisplayMemberBinding="{Binding Label}" />
                </GridView>
            </ListView.View>
        </ListView>
        <StackPanel Orientation="Horizontal" Margin="5" HorizontalAlignment="Right">
            <Button Content="_OK" IsDefault="True" Margin="5" Name="BtnOk" Click="BtnOk_Click" />
            <Button Content="_Cancel" IsCancel="True" Margin="5" Name="BtnCancel" Click="BtnCancel_Click" />
        </StackPanel>
    </StackPanel>
</Window>

Example:

var options = lookup.InventoryItems.Select(x => new SelectDialogOption<string, CommonInvItemClient>(x.Item, $"{x.GTIN} {x.Name} ({x.Item})", x)).OrderBy(x => x.Label);
var invItem = SelectDialog.ShowSelectDialog("Zoek artikel (of GTIN) en selecteer om aan de orderregel te koppelen", "Artikel matchen", options);
if (invItem == null) return;
var invItemGTIN = invItem.GTIN ?? invItem.EAN;
74720cookie-checkXAML SelectDialog