Custom input bar
This commit is contained in:
parent
d404cf2ca3
commit
a51aa6958b
184
FileSystemSuggestions.cs
Normal file
184
FileSystemSuggestions.cs
Normal file
@ -0,0 +1,184 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace HashCalculator.GUI
|
||||
{
|
||||
internal class FileSystemSuggestions
|
||||
{
|
||||
private static readonly Dictionary<string, InputEntryType> Mapping = new Dictionary<string, InputEntryType>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ ".big", InputEntryType.BigFile },
|
||||
{ ".xml", InputEntryType.XmlFile },
|
||||
{ ".w3x", InputEntryType.XmlFile },
|
||||
{ ".manifest", InputEntryType.ManifestFile },
|
||||
};
|
||||
|
||||
private Search _search = new Search();
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1031")]
|
||||
public IEnumerable<InputEntry> ProvideFileSystemSuggestions(string? path)
|
||||
{
|
||||
var empty = Enumerable.Empty<InputEntry>();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(path) || path == null)
|
||||
{
|
||||
return empty;
|
||||
}
|
||||
|
||||
path = Environment.ExpandEnvironmentVariables(path);
|
||||
|
||||
_search.Update(path);
|
||||
|
||||
if (!_search.IsValidPath)
|
||||
{
|
||||
return empty;
|
||||
}
|
||||
|
||||
var currentFiles = empty;
|
||||
string? fileName;
|
||||
string? currentFullPath;
|
||||
try
|
||||
{
|
||||
currentFullPath = Path.GetFullPath(path);
|
||||
fileName = Path.GetFileName(path);
|
||||
if (File.Exists(currentFullPath))
|
||||
{
|
||||
|
||||
var type = CheckExtension(currentFullPath);
|
||||
if (type.HasValue)
|
||||
{
|
||||
currentFiles.Append(new InputEntry(type.Value, path, currentFullPath));
|
||||
}
|
||||
currentFiles.Append(new InputEntry(InputEntryType.BinaryFile, path, currentFullPath));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return empty;
|
||||
}
|
||||
|
||||
var directories = from directory in _search.AllDirectories
|
||||
where directory.Name.StartsWith(fileName, StringComparison.OrdinalIgnoreCase)
|
||||
select new InputEntry(InputEntryType.Path, _search.GetInputStyleName(directory), directory.FullName);
|
||||
|
||||
var otherFiles = from file in _search.AllFiles
|
||||
where file.Name.StartsWith(fileName, StringComparison.OrdinalIgnoreCase)
|
||||
where file.FullName != currentFullPath
|
||||
select file;
|
||||
|
||||
var supportedFiles = empty;
|
||||
try
|
||||
{
|
||||
supportedFiles = from file in otherFiles
|
||||
let type = CheckExtension(file.Extension)
|
||||
where type.HasValue
|
||||
select new InputEntry(type.Value, _search.GetInputStyleName(file), file.FullName);
|
||||
}
|
||||
catch { }
|
||||
|
||||
var binaryFiles = empty;
|
||||
try
|
||||
{
|
||||
binaryFiles = from file in otherFiles
|
||||
select new InputEntry(InputEntryType.BinaryFile, _search.GetInputStyleName(file), file.FullName);
|
||||
}
|
||||
catch { }
|
||||
|
||||
return currentFiles.Concat(supportedFiles).Concat(directories).Concat(binaryFiles);
|
||||
}
|
||||
|
||||
private static InputEntryType? CheckExtension(string path)
|
||||
{
|
||||
if (Mapping.TryGetValue(path, out var type))
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Search
|
||||
{
|
||||
private string? _inputBaseDirectory;
|
||||
public bool IsValidPath => _inputBaseDirectory != null;
|
||||
public IEnumerable<DirectoryInfo> AllDirectories { get; private set; }
|
||||
public IEnumerable<FileInfo> AllFiles { get; private set; }
|
||||
|
||||
public Search()
|
||||
{
|
||||
AllDirectories = Array.Empty<DirectoryInfo>();
|
||||
AllFiles = Array.Empty<FileInfo>();
|
||||
}
|
||||
|
||||
public string GetInputStyleName(FileSystemInfo entry)
|
||||
{
|
||||
if (_inputBaseDirectory == null)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return Path.Combine(_inputBaseDirectory, entry.Name);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1031")]
|
||||
public void Update(string path)
|
||||
{
|
||||
string? newBaseDirectory = null;
|
||||
try
|
||||
{
|
||||
newBaseDirectory = Path.GetDirectoryName(path);
|
||||
var rootDirectory = Path.GetPathRoot(path);
|
||||
if(string.IsNullOrEmpty(newBaseDirectory) && !string.IsNullOrEmpty(rootDirectory))
|
||||
{
|
||||
var last = rootDirectory.LastOrDefault();
|
||||
if (last != Path.DirectorySeparatorChar && last != Path.AltDirectorySeparatorChar)
|
||||
{
|
||||
rootDirectory += Path.DirectorySeparatorChar;
|
||||
}
|
||||
newBaseDirectory = rootDirectory;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
_inputBaseDirectory = null;
|
||||
}
|
||||
|
||||
if (newBaseDirectory == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (newBaseDirectory == _inputBaseDirectory)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_inputBaseDirectory = newBaseDirectory;
|
||||
Update();
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1031")]
|
||||
private void Update()
|
||||
{
|
||||
AllDirectories = Enumerable.Empty<DirectoryInfo>();
|
||||
AllFiles = Enumerable.Empty<FileInfo>();
|
||||
try
|
||||
{
|
||||
var actualPath = _inputBaseDirectory!.Length == 0
|
||||
? "."
|
||||
: _inputBaseDirectory;
|
||||
var directory = new DirectoryInfo(actualPath);
|
||||
if (directory.Exists)
|
||||
{
|
||||
AllDirectories = directory.EnumerateDirectories();
|
||||
AllFiles = directory.EnumerateFiles();
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
}
|
@ -2,14 +2,25 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net461</TargetFramework>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<RootNamespace>HashCalculator.GUI</RootNamespace>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWPF>true</UseWPF>
|
||||
<Platforms>AnyCPU;x86</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DotNetKit.Wpf.AutoCompleteComboBox" Version="1.2.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="TechnologyAssembler.Core">
|
||||
<HintPath>TechnologyAssembler.Core.dll</HintPath>
|
||||
<Private>true</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</Project>
|
115
InputBar.xaml
Normal file
115
InputBar.xaml
Normal file
@ -0,0 +1,115 @@
|
||||
<UserControl
|
||||
x:Class="HashCalculator.GUI.InputBar"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:HashCalculator.GUI"
|
||||
mc:Ignorable="d"
|
||||
x:ClassModifier="internal"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="100" d:DesignWidth="800"
|
||||
>
|
||||
<UserControl.Resources>
|
||||
<local:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
<Style
|
||||
x:Key="BlankListBoxContainerStyle"
|
||||
TargetType="{x:Type ListBoxItem}"
|
||||
>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ListBoxItem">
|
||||
<Border
|
||||
Name="Border"
|
||||
Padding="3, 2"
|
||||
SnapsToDevicePixels="true"
|
||||
>
|
||||
<ContentPresenter />
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger
|
||||
Property="IsSelected"
|
||||
Value="true"
|
||||
>
|
||||
<Setter
|
||||
TargetName="Border"
|
||||
Property="Background"
|
||||
Value="DarkSlateGray"
|
||||
/>
|
||||
<Setter
|
||||
Property="Foreground"
|
||||
Value="White"
|
||||
/>
|
||||
</Trigger>
|
||||
<Trigger
|
||||
Property="IsMouseOver"
|
||||
Value="true"
|
||||
>
|
||||
<Setter
|
||||
TargetName="Border"
|
||||
Property="Background"
|
||||
Value="DarkSlateGray"
|
||||
/>
|
||||
<Setter
|
||||
Property="Foreground"
|
||||
Value="White"
|
||||
/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<!--TextChanged="OnTextChanged"-->
|
||||
<Grid>
|
||||
<TextBox
|
||||
x:Name="TextBox"
|
||||
Text="{Binding Path=Text,
|
||||
RelativeSource={RelativeSource AncestorType=local:InputBar},
|
||||
UpdateSourceTrigger=PropertyChanged}"
|
||||
PreviewKeyDown="OnPreviewKeyDown"
|
||||
Padding="2, 0"
|
||||
VerticalContentAlignment="Center"
|
||||
TextChanged="OnTextChanged"
|
||||
LostFocus="OnLostFocus"
|
||||
/>
|
||||
<TextBlock
|
||||
Text="{Binding Path=HintText,
|
||||
RelativeSource={RelativeSource AncestorType=local:InputBar}}"
|
||||
IsHitTestVisible="False"
|
||||
Visibility="{Binding ElementName=TextBox, Path=Text, Converter={StaticResource NullToVisibilityConverter}}"
|
||||
Padding="5, 0"
|
||||
VerticalAlignment="Center"
|
||||
/>
|
||||
</Grid>
|
||||
<Popup
|
||||
x:Name="DropDown"
|
||||
StaysOpen="False"
|
||||
MaxHeight="400"
|
||||
Width="{Binding ElementName=TextBox, Path=ActualWidth}"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Auto"
|
||||
>
|
||||
<ListBox
|
||||
x:Name="ListBox"
|
||||
ItemContainerStyle="{StaticResource ResourceKey=BlankListBoxContainerStyle}"
|
||||
ItemsSource="{Binding Path=Collection,
|
||||
RelativeSource={RelativeSource AncestorType=local:InputBar}}"
|
||||
SelectionMode="Single"
|
||||
SelectionChanged="OnSelectionChanged"
|
||||
VirtualizingPanel.IsVirtualizing="True"
|
||||
VirtualizingPanel.VirtualizationMode="Recycling"
|
||||
>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock Text="{Binding Text}" FontWeight="Bold"></TextBlock>
|
||||
<TextBlock Text="{Binding Type}"></TextBlock>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Popup>
|
||||
</Grid>
|
||||
</UserControl>
|
150
InputBar.xaml.cs
Normal file
150
InputBar.xaml.cs
Normal file
@ -0,0 +1,150 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace HashCalculator.GUI
|
||||
{
|
||||
/// <summary>
|
||||
/// InputBar.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
[SuppressMessage("Microsoft.Performance", "CA1812")]
|
||||
internal partial class InputBar : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty HintTextProperty =
|
||||
DependencyProperty.Register(nameof(HintText), typeof(string), typeof(InputBar), new FrameworkPropertyMetadata
|
||||
{
|
||||
BindsTwoWayByDefault = true,
|
||||
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
|
||||
});
|
||||
public string? HintText
|
||||
{
|
||||
get => GetValue(HintTextProperty) as string;
|
||||
set => SetValue(HintTextProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextProperty =
|
||||
DependencyProperty.Register(nameof(Text), typeof(string), typeof(InputBar), new FrameworkPropertyMetadata
|
||||
{
|
||||
BindsTwoWayByDefault = true,
|
||||
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
|
||||
});
|
||||
public string? Text
|
||||
{
|
||||
get => GetValue(TextProperty) as string;
|
||||
set => SetValue(TextProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CollectionProperty =
|
||||
DependencyProperty.Register(nameof(Collection), typeof(IEnumerable<InputEntry>), typeof(InputBar), new FrameworkPropertyMetadata
|
||||
{
|
||||
BindsTwoWayByDefault = true,
|
||||
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
|
||||
CoerceValueCallback = (d, baseObject) =>
|
||||
{
|
||||
var value = baseObject as IEnumerable<InputEntry>;
|
||||
if (value?.Count() > 100)
|
||||
{
|
||||
value = value
|
||||
.Take(99)
|
||||
.Append(new InputEntry(InputEntryType.Path, $"Other {value.Count() - 50} items...", string.Empty));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
});
|
||||
public IEnumerable<InputEntry>? Collection
|
||||
{
|
||||
get => GetValue(CollectionProperty) as IEnumerable<InputEntry>;
|
||||
set => SetValue(CollectionProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectedItemProperty =
|
||||
DependencyProperty.Register(nameof(SelectedItem), typeof(InputEntry), typeof(InputBar), new FrameworkPropertyMetadata
|
||||
{
|
||||
BindsTwoWayByDefault = true,
|
||||
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
|
||||
});
|
||||
public InputEntry? SelectedItem
|
||||
{
|
||||
get => GetValue(SelectedItemProperty) as InputEntry;
|
||||
set => SetValue(SelectedItemProperty, value);
|
||||
}
|
||||
|
||||
public event TextChangedEventHandler? TextChanged;
|
||||
|
||||
public InputBar()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void OnPreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
switch (e.Key)
|
||||
{
|
||||
case Key.Down:
|
||||
ListBox.SelectedIndex = NormalizeIndex(ListBox.SelectedIndex + 1);
|
||||
ListBox.ScrollIntoView(ListBox.SelectedItem);
|
||||
DropDown.IsOpen = true;
|
||||
break;
|
||||
case Key.Up:
|
||||
ListBox.SelectedIndex = NormalizeIndex(ListBox.SelectedIndex - 1);
|
||||
ListBox.ScrollIntoView(ListBox.SelectedItem);
|
||||
break;
|
||||
case Key.Escape:
|
||||
case Key.Enter:
|
||||
DropDown.IsOpen = false;
|
||||
break;
|
||||
default:
|
||||
DropDown.IsOpen = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
SelectedItem = (InputEntry)ListBox.SelectedItem;
|
||||
if (SelectedItem != null)
|
||||
{
|
||||
Text = SelectedItem.ToString();
|
||||
TextBox.Select(Text.Length, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (Text != SelectedItem?.ToString())
|
||||
{
|
||||
TextChanged?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLostFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DropDown.IsOpen = false;
|
||||
}
|
||||
|
||||
private int NormalizeIndex(int rawIndex)
|
||||
{
|
||||
if (Collection == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return Math.Min(Math.Max(rawIndex, -1), Collection.Count() - 1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
39
InputEntry.cs
Normal file
39
InputEntry.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TechnologyAssembler.Core.IO;
|
||||
|
||||
namespace HashCalculator.GUI
|
||||
{
|
||||
internal enum InputEntryType
|
||||
{
|
||||
Text,
|
||||
BigFile,
|
||||
ManifestFile,
|
||||
XmlFile,
|
||||
BinaryFile,
|
||||
Path,
|
||||
}
|
||||
|
||||
internal sealed class InputEntry
|
||||
{
|
||||
public InputEntryType Type { get; }
|
||||
public string Value { get; }
|
||||
public string Text { get; }
|
||||
|
||||
public InputEntry(InputEntryType type, string text, string value)
|
||||
{
|
||||
Type = type;
|
||||
Text = text;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Text;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -3,10 +3,12 @@
|
||||
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:dotNetKitControls="clr-namespace:DotNetKit.Windows.Controls;assembly=DotNetKit.Wpf.AutoCompleteComboBox"
|
||||
xmlns:l="clr-namespace:HashCalculator.GUI"
|
||||
mc:Ignorable="d"
|
||||
Title="Sage FastHash 哈希计算器" Height="600" Width="600">
|
||||
<Window.Resources>
|
||||
<l:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
</Window.Resources>
|
||||
<Grid Margin="10, 10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
@ -18,36 +20,35 @@
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="92"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<dotNetKitControls:AutoCompleteComboBox
|
||||
SelectedValuePath="Id"
|
||||
TextSearch.TextPath="Name"
|
||||
Text="输入任意字符串来计算它的哈希值,也可以输入big/manifest/xml文件的路径"
|
||||
ItemsSource="{Binding Items}"
|
||||
SelectedItem="{Binding SelectedItem}"
|
||||
SelectedValue="{Binding SelectedValue}"
|
||||
Grid.Column="0" Margin="0"
|
||||
/>
|
||||
<Grid>
|
||||
<!--<l:InputBox
|
||||
HintText="Select some big file"
|
||||
Collection="{Binding Items}"
|
||||
TextChanged="OnTextChanged"
|
||||
>
|
||||
</l:InputBox>-->
|
||||
<l:InputBar
|
||||
HintText="Select some big file"
|
||||
Text="{Binding Text}"
|
||||
Collection="{Binding Items}"
|
||||
TextChanged="OnTextChanged"
|
||||
/>
|
||||
</Grid>
|
||||
<Button x:Name="button" Content="浏览文件"
|
||||
Grid.Column="1" Margin="0"
|
||||
/>
|
||||
</Grid>
|
||||
<dotNetKitControls:AutoCompleteComboBox
|
||||
SelectedValuePath="Id"
|
||||
TextSearch.TextPath="Name"
|
||||
Text="输入big文件里包含的manifest文件的路径"
|
||||
ItemsSource="{Binding Items}"
|
||||
<l:InputBar
|
||||
HintText="输入big文件里包含的manifest文件的路径"
|
||||
Collection="{Binding Items}"
|
||||
SelectedItem="{Binding SelectedItem}"
|
||||
SelectedValue="{Binding SelectedValue}"
|
||||
Margin="0,10,0,0"
|
||||
Height="25" VerticalAlignment="Top"
|
||||
/>
|
||||
<dotNetKitControls:AutoCompleteComboBox
|
||||
SelectedValuePath="Id"
|
||||
TextSearch.TextPath="Name"
|
||||
Text="过滤Asset ID(可选)"
|
||||
ItemsSource="{Binding Items}"
|
||||
<l:InputBar
|
||||
HintText="过滤Asset ID(可选)"
|
||||
Collection="{Binding Items}"
|
||||
SelectedItem="{Binding SelectedItem}"
|
||||
SelectedValue="{Binding SelectedValue}"
|
||||
Margin="0,10,0,0"
|
||||
Height="25" VerticalAlignment="Top"
|
||||
/>
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
@ -23,19 +23,40 @@ namespace HashCalculator.GUI
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
private readonly FileSystemSuggestions _suggestions = new FileSystemSuggestions();
|
||||
private readonly ViewModel _model = new ViewModel();
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = new ViewModel();
|
||||
DataContext = _model;
|
||||
}
|
||||
|
||||
private void OnTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (sender is InputBar)
|
||||
{
|
||||
var inputValue = _model.Text;
|
||||
if(inputValue != null)
|
||||
{
|
||||
_model.Items = _suggestions.ProvideFileSystemSuggestions(inputValue)
|
||||
.Prepend(new InputEntry(InputEntryType.Text, inputValue, inputValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ViewModel : INotifyPropertyChanged
|
||||
internal class ViewModel : INotifyPropertyChanged
|
||||
{
|
||||
#region INotifyPropertyChanged
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
private void Notify(string name)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Updating {name}");
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
||||
}
|
||||
|
||||
private void SetField<X>(ref X field, X value, [CallerMemberName] string? propertyName = null)
|
||||
{
|
||||
if (propertyName == null)
|
||||
@ -50,104 +71,37 @@ namespace HashCalculator.GUI
|
||||
|
||||
field = value;
|
||||
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
Notify(propertyName);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public IReadOnlyList<Person> Items
|
||||
private IEnumerable<InputEntry>? _items;
|
||||
public IEnumerable<InputEntry>? Items
|
||||
{
|
||||
get { return PersonModule.All; }
|
||||
get => _items;
|
||||
set => SetField(ref _items, value);
|
||||
}
|
||||
|
||||
Person selectedItem;
|
||||
public Person SelectedItem
|
||||
private InputEntry? selectedItem;
|
||||
public InputEntry? SelectedItem
|
||||
{
|
||||
get { return selectedItem; }
|
||||
set { SetField(ref selectedItem, value); }
|
||||
}
|
||||
|
||||
long? selectedValue;
|
||||
public long? SelectedValue
|
||||
private string? selectedValue;
|
||||
public string? SelectedValue
|
||||
{
|
||||
get { return selectedValue; }
|
||||
set { SetField(ref selectedValue, value); }
|
||||
}
|
||||
}
|
||||
|
||||
internal enum InputEntryType
|
||||
{
|
||||
Text,
|
||||
SupportedFilePath,
|
||||
BinaryFilePath,
|
||||
Path,
|
||||
}
|
||||
|
||||
internal sealed class InputEntry
|
||||
{
|
||||
public InputEntryType Type { get; }
|
||||
public string Value { get; }
|
||||
|
||||
public InputEntry(InputEntryType type, string value)
|
||||
private string? _text;
|
||||
public string? Text
|
||||
{
|
||||
Type = type;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public static List<InputEntry> CreateSuggestion(string value)
|
||||
{
|
||||
var list = new List<InputEntry>();
|
||||
try
|
||||
{
|
||||
var path = new FileInfo(value);
|
||||
path.Directory.GetFiles()
|
||||
}
|
||||
catch { }
|
||||
|
||||
}
|
||||
|
||||
public static bool IsSupportedFile(string value)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static IEnumerable<InputEntry> ProvideFileSystemSuggestions(string path)
|
||||
{
|
||||
var empty = Enumerable.Empty<InputEntry>();
|
||||
var list = empty;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
return list;
|
||||
}
|
||||
|
||||
var directories = empty;
|
||||
try
|
||||
{
|
||||
var directoryInfo = new DirectoryInfo(path);
|
||||
if (directoryInfo.Exists)
|
||||
{
|
||||
directories = directoryInfo.GetDirectories()
|
||||
.Select(info => new InputEntry(InputEntryType.Path, info.FullName));
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
var files = empty;
|
||||
try
|
||||
{
|
||||
var fileInfo = new FileInfo(path);
|
||||
if (fileInfo.Exists)
|
||||
{
|
||||
files = files.Concat()
|
||||
}
|
||||
if (fileInfo.Directory.Exists)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//fileInfo.Directory.get
|
||||
}
|
||||
catch { }
|
||||
get { return _text; }
|
||||
set { SetField(ref _text, value); }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
22
NullToVisibilityConverter.cs
Normal file
22
NullToVisibilityConverter.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace HashCalculator.GUI
|
||||
{
|
||||
[ValueConversion(typeof(string), typeof(Visibility))]
|
||||
public class NullToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var text = value as string;
|
||||
return string.IsNullOrEmpty(text) ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,14 @@
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Navigation;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace HashCalculator.GUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Opens <see cref="Hyperlink.NavigateUri"/> in a default system browser
|
||||
/// </summary>
|
||||
[SuppressMessage("Microsoft.Performance", "CA1812")]
|
||||
internal sealed class ShellLink : Hyperlink
|
||||
{
|
||||
public ShellLink()
|
||||
|
BIN
TechnologyAssembler.Core.dll
Normal file
BIN
TechnologyAssembler.Core.dll
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user