diff --git a/.gitignore b/.gitignore
index 940794e6..3432f1fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -286,3 +286,6 @@ __pycache__/
*.btm.cs
*.odx.cs
*.xsd.cs
+
+# directory of local nuget package builds
+packageBuilds/
diff --git a/LICENSE b/LICENSE
index 6db15b21..927f52c3 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2017-2018 Philipp Spiegel
+Copyright (c) 2017-2020 Philipp Spiegel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/MaterialDesignExtensions.sln b/MaterialDesignExtensions.sln
index 58660b8b..8178ea17 100644
--- a/MaterialDesignExtensions.sln
+++ b/MaterialDesignExtensions.sln
@@ -1,32 +1,56 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27130.2026
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29613.14
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaterialDesignExtensions", "MaterialDesignExtensions\MaterialDesignExtensions.csproj", "{809632DA-5EB8-4EE8-AD71-57239701550C}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MaterialDesignExtensions", "MaterialDesignExtensions\MaterialDesignExtensions.csproj", "{809632DA-5EB8-4EE8-AD71-57239701550C}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaterialDesignExtensionsDemo", "MaterialDesignExtensionsDemo\MaterialDesignExtensionsDemo.csproj", "{279D7E62-1206-4928-890E-00F51CD0181C}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MaterialDesignExtensionsDemo", "MaterialDesignExtensionsDemo\MaterialDesignExtensionsDemo.csproj", "{279D7E62-1206-4928-890E-00F51CD0181C}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaterialDesignExtensionsTests", "MaterialDesignExtensionsTests\MaterialDesignExtensionsTests.csproj", "{DCF16057-4955-48F1-BD0E-28D671DF59B0}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MaterialDesignExtensionsTests", "MaterialDesignExtensionsTests\MaterialDesignExtensionsTests.csproj", "{DCF16057-4955-48F1-BD0E-28D671DF59B0}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MaterialDesignExtensionsBuildUtility", "MaterialDesignExtensionsBuildUtility\MaterialDesignExtensionsBuildUtility.csproj", "{2E40D411-CE99-489E-A1E4-9F28A1399CA1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ DebugLongPath|Any CPU = DebugLongPath|Any CPU
Release|Any CPU = Release|Any CPU
+ ReleaseLongPath|Any CPU = ReleaseLongPath|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{809632DA-5EB8-4EE8-AD71-57239701550C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{809632DA-5EB8-4EE8-AD71-57239701550C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {809632DA-5EB8-4EE8-AD71-57239701550C}.DebugLongPath|Any CPU.ActiveCfg = Debug|Any CPU
+ {809632DA-5EB8-4EE8-AD71-57239701550C}.DebugLongPath|Any CPU.Build.0 = Debug|Any CPU
{809632DA-5EB8-4EE8-AD71-57239701550C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{809632DA-5EB8-4EE8-AD71-57239701550C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {809632DA-5EB8-4EE8-AD71-57239701550C}.ReleaseLongPath|Any CPU.ActiveCfg = Release|Any CPU
+ {809632DA-5EB8-4EE8-AD71-57239701550C}.ReleaseLongPath|Any CPU.Build.0 = Release|Any CPU
{279D7E62-1206-4928-890E-00F51CD0181C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{279D7E62-1206-4928-890E-00F51CD0181C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {279D7E62-1206-4928-890E-00F51CD0181C}.DebugLongPath|Any CPU.ActiveCfg = Debug|Any CPU
+ {279D7E62-1206-4928-890E-00F51CD0181C}.DebugLongPath|Any CPU.Build.0 = Debug|Any CPU
{279D7E62-1206-4928-890E-00F51CD0181C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{279D7E62-1206-4928-890E-00F51CD0181C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {279D7E62-1206-4928-890E-00F51CD0181C}.ReleaseLongPath|Any CPU.ActiveCfg = Release|Any CPU
+ {279D7E62-1206-4928-890E-00F51CD0181C}.ReleaseLongPath|Any CPU.Build.0 = Release|Any CPU
{DCF16057-4955-48F1-BD0E-28D671DF59B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DCF16057-4955-48F1-BD0E-28D671DF59B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DCF16057-4955-48F1-BD0E-28D671DF59B0}.DebugLongPath|Any CPU.ActiveCfg = Debug|Any CPU
+ {DCF16057-4955-48F1-BD0E-28D671DF59B0}.DebugLongPath|Any CPU.Build.0 = Debug|Any CPU
{DCF16057-4955-48F1-BD0E-28D671DF59B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DCF16057-4955-48F1-BD0E-28D671DF59B0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DCF16057-4955-48F1-BD0E-28D671DF59B0}.ReleaseLongPath|Any CPU.ActiveCfg = Release|Any CPU
+ {DCF16057-4955-48F1-BD0E-28D671DF59B0}.ReleaseLongPath|Any CPU.Build.0 = Release|Any CPU
+ {2E40D411-CE99-489E-A1E4-9F28A1399CA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2E40D411-CE99-489E-A1E4-9F28A1399CA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2E40D411-CE99-489E-A1E4-9F28A1399CA1}.DebugLongPath|Any CPU.ActiveCfg = Debug|Any CPU
+ {2E40D411-CE99-489E-A1E4-9F28A1399CA1}.DebugLongPath|Any CPU.Build.0 = Debug|Any CPU
+ {2E40D411-CE99-489E-A1E4-9F28A1399CA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2E40D411-CE99-489E-A1E4-9F28A1399CA1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2E40D411-CE99-489E-A1E4-9F28A1399CA1}.ReleaseLongPath|Any CPU.ActiveCfg = Debug|Any CPU
+ {2E40D411-CE99-489E-A1E4-9F28A1399CA1}.ReleaseLongPath|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/MaterialDesignExtensions/Commands/Internal/AutocompleteCommands.cs b/MaterialDesignExtensions/Commands/Internal/AutocompleteCommands.cs
new file mode 100644
index 00000000..824b15c3
--- /dev/null
+++ b/MaterialDesignExtensions/Commands/Internal/AutocompleteCommands.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace MaterialDesignExtensions.Commands.Internal
+{
+ ///
+ /// Class containing commands used by the for internal use only.
+ ///
+ public class AutocompleteCommands
+ {
+ // abstract class with private constructor to prevent object initialization
+ private AutocompleteCommands() { }
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand SelectAutocompleteItemCommand = new RoutedCommand();
+ }
+}
diff --git a/MaterialDesignExtensions/Commands/Internal/FileSystemControlCommands.cs b/MaterialDesignExtensions/Commands/Internal/FileSystemControlCommands.cs
new file mode 100644
index 00000000..f18d0124
--- /dev/null
+++ b/MaterialDesignExtensions/Commands/Internal/FileSystemControlCommands.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace MaterialDesignExtensions.Commands.Internal
+{
+ ///
+ /// Class containing commands used by the file system controls for internal use only.
+ ///
+ public abstract class FileSystemControlCommands
+ {
+ // abstract class with private constructor to prevent object initialization
+ private FileSystemControlCommands() { }
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand CreateNewDirectoryCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand CancelCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand CancelNewDirectoryCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand FileSystemEntryDoubleClickCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand OpenSelectionDrawerCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand OpenSpecialDirectoriesDrawerCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand SelectDirectoryCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand SelectDirectoryItemCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand SelectFileCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand SelectFileSystemEntryCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand SelectMultipleDirectoriesCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand SelectMultipleFilesCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand ShowCreateNewDirectoryCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand ShowInfoCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand SwitchPathPartsAsButtonsCommand = new RoutedCommand();
+ }
+}
diff --git a/MaterialDesignExtensions/Commands/Internal/OversizedNumberSpinnerCommands.cs b/MaterialDesignExtensions/Commands/Internal/OversizedNumberSpinnerCommands.cs
new file mode 100644
index 00000000..a3fdfb2f
--- /dev/null
+++ b/MaterialDesignExtensions/Commands/Internal/OversizedNumberSpinnerCommands.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace MaterialDesignExtensions.Commands.Internal
+{
+ ///
+ /// Class containing commands used by the for internal use only.
+ ///
+ public class OversizedNumberSpinnerCommands
+ {
+ // abstract class with private constructor to prevent object initialization
+ private OversizedNumberSpinnerCommands() { }
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand EditValueCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand MinusCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand PlusCommand = new RoutedCommand();
+ }
+}
diff --git a/MaterialDesignExtensions/Commands/Internal/SearchControlCommands.cs b/MaterialDesignExtensions/Commands/Internal/SearchControlCommands.cs
new file mode 100644
index 00000000..50c5458a
--- /dev/null
+++ b/MaterialDesignExtensions/Commands/Internal/SearchControlCommands.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace MaterialDesignExtensions.Commands.Internal
+{
+ ///
+ /// Class containing commands used by the search controls for internal use only.
+ ///
+ public class SearchControlCommands
+ {
+
+ // abstract class with private constructor to prevent object initialization
+ private SearchControlCommands() { }
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand SelectSearchSuggestionCommand = new RoutedCommand();
+ }
+}
diff --git a/MaterialDesignExtensions/Commands/Internal/SideNavigationCommands.cs b/MaterialDesignExtensions/Commands/Internal/SideNavigationCommands.cs
new file mode 100644
index 00000000..dff382a6
--- /dev/null
+++ b/MaterialDesignExtensions/Commands/Internal/SideNavigationCommands.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace MaterialDesignExtensions.Commands.Internal
+{
+ ///
+ /// Class containing commands used by the for internal use only.
+ ///
+ public class SideNavigationCommands
+ {
+ // abstract class with private constructor to prevent object initialization
+ private SideNavigationCommands() { }
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand SelectNavigationItemCommand = new RoutedCommand();
+ }
+}
diff --git a/MaterialDesignExtensions/Commands/Internal/StepperCommands.cs b/MaterialDesignExtensions/Commands/Internal/StepperCommands.cs
new file mode 100644
index 00000000..6d35e478
--- /dev/null
+++ b/MaterialDesignExtensions/Commands/Internal/StepperCommands.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace MaterialDesignExtensions.Commands.Internal
+{
+ ///
+ /// Class containing commands used by the for internal use only.
+ ///
+ public class StepperCommands
+ {
+ // abstract class with private constructor to prevent object initialization
+ private StepperCommands() { }
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand BackCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand CancelCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand ContinueCommand = new RoutedCommand();
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand StepSelectedCommand = new RoutedCommand();
+ }
+}
diff --git a/MaterialDesignExtensions/Commands/Internal/TextBoxSuggestionsCommands.cs b/MaterialDesignExtensions/Commands/Internal/TextBoxSuggestionsCommands.cs
new file mode 100644
index 00000000..65f096bc
--- /dev/null
+++ b/MaterialDesignExtensions/Commands/Internal/TextBoxSuggestionsCommands.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace MaterialDesignExtensions.Commands.Internal
+{
+ ///
+ /// Class containing commands used by the for internal use only.
+ ///
+ public class TextBoxSuggestionsCommands
+ {
+ // abstract class with private constructor to prevent object initialization
+ private TextBoxSuggestionsCommands() { }
+
+ ///
+ /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ ///
+ public static readonly RoutedCommand SelectSuggestionItemCommand = new RoutedCommand();
+ }
+}
diff --git a/MaterialDesignExtensions/Controllers/AutocompleteController.cs b/MaterialDesignExtensions/Controllers/AutocompleteController.cs
index 5ea03b73..4a0ac091 100644
--- a/MaterialDesignExtensions/Controllers/AutocompleteController.cs
+++ b/MaterialDesignExtensions/Controllers/AutocompleteController.cs
@@ -9,6 +9,9 @@
namespace MaterialDesignExtensions.Controllers
{
+ ///
+ /// The controller with the technical logic for autocomplete controls.
+ ///
public class AutocompleteController
{
private readonly object m_lockObject = new object();
@@ -77,44 +80,45 @@ public AutocompleteController()
}
///
- /// Starts a new task for the autocomplete and propagates the result via the event.
+ /// Starts a new task for the autocomplete and propagates the result via the event.
/// This method does some technical stuff and delegates the actual search to the .
///
/// The term to search for
public void Search(string searchTerm)
{
- string id = Guid.NewGuid().ToString();
-
- IAutocompleteSource autocompleteSource = null;
-
- lock (m_lockObject)
+ Task.Run(async () =>
{
- autocompleteSource = m_autocompleteSource;
+ string id = Guid.NewGuid().ToString();
+
+ IAutocompleteSource autocompleteSource = null;
- // no source, no search
- if (autocompleteSource == null)
+ lock (m_lockObject)
{
- return;
+ autocompleteSource = m_autocompleteSource;
+
+ // no source, no search
+ if (autocompleteSource == null)
+ {
+ return;
+ }
+
+ LastId = id;
}
- LastId = id;
- }
+ await Task.Delay(SearchDelay).ConfigureAwait(false);
- Task.Delay(SearchDelay)
- .ContinueWith((prevTask) =>
+ // search only if there was no other request during the delay
+ if (DoSearchWithId(id))
{
- // search only if there was no other request during the delay
+ IEnumerable items = autocompleteSource.Search(searchTerm);
+
+ // a final check if this result will not be replaced by another active search
if (DoSearchWithId(id))
{
- IEnumerable items = autocompleteSource.Search(searchTerm);
-
- // a final check if this result will not be replaced by another active search
- if (DoSearchWithId(id))
- {
- AutocompleteItemsChanged?.Invoke(this, new AutocompleteItemsChangedEventArgs(items));
- }
+ AutocompleteItemsChanged?.Invoke(this, new AutocompleteItemsChangedEventArgs(items));
}
- });
+ }
+ });
}
private bool DoSearchWithId(string id)
diff --git a/MaterialDesignExtensions/Controllers/BitmapImageHelper.cs b/MaterialDesignExtensions/Controllers/BitmapImageHelper.cs
index ba70f722..06a8b8f1 100644
--- a/MaterialDesignExtensions/Controllers/BitmapImageHelper.cs
+++ b/MaterialDesignExtensions/Controllers/BitmapImageHelper.cs
@@ -50,50 +50,71 @@ public static BitmapImage LoadImage(string imageFilename, int targetWidth = 40,
try
{
- using (BufferedStream fileStream = new BufferedStream(new FileStream(imageFilename, FileMode.Open), BufferSize))
+ using (MemoryStream imageMemoryStream = new MemoryStream())
{
- BitmapDecoder bitmapDecoder = BitmapDecoder.Create(fileStream, BitmapCreateOptions.DelayCreation, BitmapCacheOption.Default);
- int width = bitmapDecoder.Frames[0].PixelWidth;
- int height = bitmapDecoder.Frames[0].PixelHeight;
-
- fileStream.Position = 0;
+ using (BufferedStream fileStream = new BufferedStream(new FileStream(imageFilename, FileMode.Open), BufferSize))
+ {
+ fileStream.CopyTo(imageMemoryStream);
+ }
- image = new BitmapImage();
- image.BeginInit();
+ return GetAsBitmapImage(imageMemoryStream, targetWidth, targetHeight, useCache, key);
+ }
+ }
+ catch (Exception exc)
+ {
+ if (exc is IOException || exc is UnauthorizedAccessException || exc is PathTooLongException || exc is NotSupportedException)
+ {
+ return null;
+ }
+ else
+ {
+ throw;
+ }
+ }
+ }
- double targetRatio = ((double)targetWidth) / targetHeight;
- double ratio = ((double)width) / height;
+ ///
+ /// Loads the image from the file with the specified width and height keeping its ratio.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task LoadImageAsync(string imageFilename, int targetWidth = 40, int targetHeight = 40, bool useCache = false)
+ {
+ string key = GetKey(imageFilename, targetWidth, targetHeight);
- if (targetRatio > ratio)
- {
- image.DecodePixelWidth = targetWidth;
- }
- else
- {
- image.DecodePixelHeight = targetHeight;
- }
+ BitmapImage image = null;
- image.CacheOption = BitmapCacheOption.OnLoad;
- image.StreamSource = fileStream;
+ if (useCache)
+ {
+ lock (m_staticLockObject)
+ {
+ Cache.TryGetValue(key, out image);
+ }
- image.EndInit();
- image.StreamSource = null;
- image.Freeze();
+ if (image != null)
+ {
+ return image;
+ }
+ }
- if (useCache)
+ try
+ {
+ using (MemoryStream imageMemoryStream = new MemoryStream())
+ {
+ using (BufferedStream fileStream = new BufferedStream(new FileStream(imageFilename, FileMode.Open), BufferSize))
{
- lock (m_staticLockObject)
- {
- Cache[key] = image;
- }
+ await fileStream.CopyToAsync(imageMemoryStream).ConfigureAwait(false);
}
- return image;
+ return GetAsBitmapImage(imageMemoryStream, targetWidth, targetHeight, useCache, key);
}
}
catch (Exception exc)
{
- if (exc is IOException || exc is UnauthorizedAccessException || exc is PathTooLongException)
+ if (exc is IOException || exc is UnauthorizedAccessException || exc is PathTooLongException || exc is NotSupportedException)
{
return null;
}
@@ -109,6 +130,52 @@ private static string GetKey(string imageFilename, int targetWidth, int targetHe
return string.Format("{0}_{1}_file://{2}", targetWidth, targetHeight, imageFilename);
}
+ private static BitmapImage GetAsBitmapImage(MemoryStream imageMemoryStream, int targetWidth, int targetHeight, bool useCache, string key)
+ {
+ imageMemoryStream.Position = 0;
+
+ BitmapDecoder bitmapDecoder = BitmapDecoder.Create(imageMemoryStream, BitmapCreateOptions.DelayCreation, BitmapCacheOption.Default);
+ int width = bitmapDecoder.Frames[0].PixelWidth;
+ int height = bitmapDecoder.Frames[0].PixelHeight;
+
+ imageMemoryStream.Position = 0;
+
+ BitmapImage image = new BitmapImage();
+ image.BeginInit();
+
+ double targetRatio = ((double)targetWidth) / targetHeight;
+ double ratio = ((double)width) / height;
+
+ if (targetRatio > ratio)
+ {
+ image.DecodePixelWidth = targetWidth;
+ }
+ else
+ {
+ image.DecodePixelHeight = targetHeight;
+ }
+
+ image.CacheOption = BitmapCacheOption.OnLoad;
+ image.StreamSource = imageMemoryStream;
+
+ image.EndInit();
+ image.StreamSource = null;
+ image.Freeze();
+
+ if (useCache)
+ {
+ lock (m_staticLockObject)
+ {
+ Cache[key] = image;
+ }
+ }
+
+ return image;
+ }
+
+ ///
+ /// Clears the cache of loaded images.
+ ///
public static void ClearCache()
{
lock (m_staticLockObject)
diff --git a/MaterialDesignExtensions/Controllers/FileControlHelper.cs b/MaterialDesignExtensions/Controllers/FileControlHelper.cs
new file mode 100644
index 00000000..58ac85ff
--- /dev/null
+++ b/MaterialDesignExtensions/Controllers/FileControlHelper.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+
+using MaterialDesignExtensions.Model;
+
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using DirectoryInfo = Pri.LongPath.DirectoryInfo;
+using FileInfo = Pri.LongPath.FileInfo;
+using FileSystemInfo = Pri.LongPath.FileSystemInfo;
+#endif
+
+namespace MaterialDesignExtensions.Controllers
+{
+ ///
+ /// Helper class for file system controls with general code for reuse.
+ ///
+ public abstract class FileControlHelper
+ {
+ private FileControlHelper() { }
+
+ ///
+ /// Updates the visibility of the ComboBox with the filter options.
+ ///
+ ///
+ public static void UpdateFileFiltersVisibility(ComboBox fileFiltersComboBox)
+ {
+ if (fileFiltersComboBox != null
+ && fileFiltersComboBox.ItemsSource != null
+ && fileFiltersComboBox.ItemsSource.GetEnumerator().MoveNext())
+ {
+ fileFiltersComboBox.Visibility = Visibility.Visible;
+ }
+ else
+ {
+ fileFiltersComboBox.Visibility = Visibility.Collapsed;
+ }
+ }
+
+ ///
+ /// Builds a list with the items of a directory.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IEnumerable GetFileSystemEntryItems(List directoriesAndFiles, FileSystemController controller, bool groupFoldersAndFiles, Func isSelectedFunc)
+ {
+ if (directoriesAndFiles == null || !directoriesAndFiles.Any())
+ {
+ return new ArrayList(0);
+ }
+
+ int numberOfItems = directoriesAndFiles.Count;
+
+ if (groupFoldersAndFiles)
+ {
+ numberOfItems = numberOfItems + 2;
+ }
+
+ ArrayList items = new ArrayList(numberOfItems);
+
+ for (int i = 0; i < directoriesAndFiles.Count; i++)
+ {
+ FileSystemInfo item = directoriesAndFiles[i];
+
+ if (item is DirectoryInfo directoryInfo)
+ {
+ if (groupFoldersAndFiles && i == 0)
+ {
+ items.Add(new FileSystemEntriesGroupHeader() { Header = Localization.Strings.Folders, ShowSeparator = false });
+ }
+
+ bool isSelected = directoryInfo.FullName == controller.CurrentDirectory?.FullName;
+
+ items.Add(new DirectoryInfoItem() { IsSelected = isSelected, Value = directoryInfo });
+ }
+ else if (item is FileInfo fileInfo)
+ {
+ if (groupFoldersAndFiles)
+ {
+ if (i == 0)
+ {
+ items.Add(new FileSystemEntriesGroupHeader() { Header = Localization.Strings.Files, ShowSeparator = false });
+ }
+ else if (directoriesAndFiles[i - 1] is DirectoryInfo)
+ {
+ items.Add(new FileSystemEntriesGroupHeader() { Header = Localization.Strings.Files, ShowSeparator = true });
+ }
+ }
+
+ items.Add(new FileInfoItem() { IsSelected = isSelectedFunc(fileInfo), Value = fileInfo });
+ }
+ }
+
+ return items;
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Controllers/FileFilterHelper.cs b/MaterialDesignExtensions/Controllers/FileFilterHelper.cs
index 8195f8a2..feaecacf 100644
--- a/MaterialDesignExtensions/Controllers/FileFilterHelper.cs
+++ b/MaterialDesignExtensions/Controllers/FileFilterHelper.cs
@@ -150,5 +150,26 @@ public static string ConvertFileFiltersToString(IEnumerable fileFil
return sb.ToString();
}
+
+ ///
+ /// Extracts the file extensions out of the file filter.
+ ///
+ ///
+ ///
+ public static IEnumerable GetFileExtensionsFromFilter(IFileFilter fileFilter)
+ {
+ if (fileFilter == null)
+ {
+ return null;
+ }
+
+ string[] split = fileFilter.Filters.Split(';');
+
+ return fileFilter.Filters.Split(';')
+ .Select(filterStr => filterStr.Trim())
+ .Where(filterStr => filterStr.Length > 1 && filterStr.Contains(".") && !filterStr.EndsWith("."))
+ .Select(filterStr => filterStr.Substring(filterStr.LastIndexOf(".") + 1).Replace("*", string.Empty))
+ .Where(fileExtension => !string.IsNullOrWhiteSpace(fileExtension));
+ }
}
}
diff --git a/MaterialDesignExtensions/Controllers/FileNameHelper.cs b/MaterialDesignExtensions/Controllers/FileNameHelper.cs
new file mode 100644
index 00000000..041fc42a
--- /dev/null
+++ b/MaterialDesignExtensions/Controllers/FileNameHelper.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MaterialDesignExtensions.Controllers
+{
+ ///
+ /// Helper class for operations on file names.
+ ///
+ public abstract class FileNameHelper
+ {
+ private static readonly ISet NotAllowedChars = new HashSet() { '<', '>', ':', '"', '/', '\\', '|', '?', '*' };
+
+ // abstract class with private constructor to prevent object initialization
+ private FileNameHelper() { }
+
+ ///
+ /// Checks the specified file name if it is OK for the operation system.
+ ///
+ /// The file name to check
+ /// boolean indication if teh file name is OK or not
+ public static bool CheckFileName(string fileName)
+ {
+ // see https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file#file-and-directory-names for file name constraints
+
+ if (string.IsNullOrWhiteSpace(fileName))
+ {
+ return false;
+ }
+
+ for (int i = 0; i < fileName.Length; i++)
+ {
+ char c = fileName[i];
+ ISet NotAllowedChars = new HashSet() { '<', '>', ':', '"', '/', '\\', '|', '?', '*' };
+
+ if (NotAllowedChars.Contains(c) || ((int)c) <= 31)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Controllers/FileSystemController.cs b/MaterialDesignExtensions/Controllers/FileSystemController.cs
index 82172ca4..67d62eca 100644
--- a/MaterialDesignExtensions/Controllers/FileSystemController.cs
+++ b/MaterialDesignExtensions/Controllers/FileSystemController.cs
@@ -11,6 +11,13 @@
using MaterialDesignExtensions.Model;
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using FileSystemInfo = Pri.LongPath.FileSystemInfo;
+using DirectoryInfo = Pri.LongPath.DirectoryInfo;
+using FileInfo = Pri.LongPath.FileInfo;
+#endif
+
namespace MaterialDesignExtensions.Controllers
{
///
@@ -33,6 +40,10 @@ public class FileSystemController : INotifyPropertyChanged
private bool m_showSystemFilesAndDirectories;
private IList m_fileFilters;
private IFileFilter m_fileFilterToApply;
+ private bool m_forceFileExtensionOfFileFilter;
+
+ private HashSet m_selectedDirectories;
+ private HashSet m_selectedFiles;
///
/// The current directory shown in the control.
@@ -179,7 +190,7 @@ public List Drives
if (driveInfo.DriveType == DriveType.CDRom)
{
- icon = PackIconKind.Disk;
+ icon = PackIconKind.Disc;
}
else if (driveInfo.DriveType == DriveType.Removable)
{
@@ -197,7 +208,16 @@ public List Drives
label = label.Substring(0, label.Length - 1);
}
- string volumeLabel = driveInfo.IsReady ? driveInfo.VolumeLabel : null;
+ string volumeLabel = null;
+
+ try
+ {
+ volumeLabel = driveInfo.IsReady ? driveInfo.VolumeLabel : null;
+ }
+ catch (Exception)
+ {
+ return new SpecialDrive { Info = driveInfo, Icon = icon };
+ }
if (string.IsNullOrWhiteSpace(volumeLabel) && driveInfo.DriveType == DriveType.Fixed)
{
@@ -278,6 +298,49 @@ public IFileFilter FileFilterToApply
}
}
+ ///
+ /// Forces the possible file extension of the selected file filter for new filenames.
+ ///
+ public bool ForceFileExtensionOfFileFilter
+ {
+ get
+ {
+ return m_forceFileExtensionOfFileFilter;
+ }
+
+ set
+ {
+ if (m_forceFileExtensionOfFileFilter != value)
+ {
+ m_forceFileExtensionOfFileFilter = value;
+
+ OnPropertyChanged(nameof(ForceFileExtensionOfFileFilter));
+ }
+ }
+ }
+
+ ///
+ /// The selected directories for multiple selection controls.
+ ///
+ public HashSet SelectedDirectories
+ {
+ get
+ {
+ return m_selectedDirectories;
+ }
+ }
+
+ ///
+ /// The selected files for multiple selection controls.
+ ///
+ public HashSet SelectedFiles
+ {
+ get
+ {
+ return m_selectedFiles;
+ }
+ }
+
///
/// The special directories (e.g. music directory) of the user.
///
@@ -315,7 +378,7 @@ public bool ShowHiddenFilesAndDirectories
set
{
- if (!m_showHiddenFilesAndDirectories != value)
+ if (m_showHiddenFilesAndDirectories != value)
{
m_showHiddenFilesAndDirectories = value;
@@ -360,6 +423,10 @@ public FileSystemController()
m_showSystemFilesAndDirectories = false;
m_fileFilters = null;
m_fileFilterToApply = null;
+ m_forceFileExtensionOfFileFilter = false;
+
+ m_selectedDirectories = new HashSet();
+ m_selectedFiles = new HashSet();
}
///
@@ -437,6 +504,74 @@ bool ShowFileSystemInfo(FileSystemInfo fileSystemInfo)
UpdateCurrentDirectoryPathParts();
}
+ ///
+ /// Selects (not yetselected) or removes (already selected so remove it) a directory for the multiple selection feature.
+ ///
+ ///
+ public void SelectOrRemoveDirectoryForMultipleSelection(string directory)
+ {
+ SelectOrRemoveDirectoryForMultipleSelection(new DirectoryInfo(directory));
+ }
+
+ ///
+ /// Selects (not yetselected) or removes (already selected so remove it) a directory for the multiple selection feature.
+ ///
+ ///
+ public void SelectOrRemoveDirectoryForMultipleSelection(DirectoryInfo directory)
+ {
+ IEnumerable sameDirectories = m_selectedDirectories
+ .Where(directoryInfo => directoryInfo.FullName.ToLower() == directory.FullName.ToLower())
+ .ToList();
+
+ if (sameDirectories.Any())
+ {
+ foreach (DirectoryInfo sameDirectory in sameDirectories)
+ {
+ m_selectedDirectories.Remove(sameDirectory);
+ }
+ }
+ else
+ {
+ m_selectedDirectories.Add(directory);
+ }
+
+ OnPropertyChanged(nameof(SelectedDirectories));
+ }
+
+ ///
+ /// Selects (not yet selected) or removes (already selected so remove it) a file for the multiple selection feature.
+ ///
+ ///
+ public void SelectOrRemoveFileForMultipleSelection(string file)
+ {
+ SelectOrRemoveFileForMultipleSelection(new FileInfo(file));
+ }
+
+ ///
+ /// Selects (not yet selected) or removes (already selected so remove it) a file for the multiple selection feature.
+ ///
+ ///
+ public void SelectOrRemoveFileForMultipleSelection(FileInfo file)
+ {
+ IEnumerable sameFiles = m_selectedFiles
+ .Where(fileInfo => fileInfo.FullName.ToLower() == file.FullName.ToLower())
+ .ToList();
+
+ if (sameFiles.Any())
+ {
+ foreach (FileInfo sameFile in sameFiles)
+ {
+ m_selectedFiles.Remove(sameFile);
+ }
+ }
+ else
+ {
+ m_selectedFiles.Add(file);
+ }
+
+ OnPropertyChanged(nameof(SelectedFiles));
+ }
+
///
/// Selects a file.
///
@@ -484,7 +619,7 @@ private void UpdateCurrentDirectoryPathParts()
currentDirectoryPathParts.Add(directoryInfo);
directoryInfo = directoryInfo.Parent;
}
-
+
currentDirectoryPathParts.Sort((directoryInfo1, directoryInfo2) => directoryInfo1.FullName.CompareTo(directoryInfo2.FullName));
}
@@ -546,6 +681,85 @@ public void SetFileFilter(IList fileFilters, IFileFilter fileFilter
}
}
+ ///
+ /// Creates a new directory with the specified name.
+ ///
+ /// The name of the new directory
+ public void CreateNewDirectory(string newDirectoryName)
+ {
+ if (string.IsNullOrWhiteSpace(newDirectoryName))
+ {
+ throw new ArgumentException(Localization.Strings.TheDirectoryNameMustNotBeEmpty);
+ }
+
+ if (!FileNameHelper.CheckFileName(newDirectoryName))
+ {
+ throw new ArgumentException(Localization.Strings.TheDirectoryNameIsInvalid);
+ }
+
+ string fullDirectoryName = CurrentDirectory.FullName + @"\" + newDirectoryName;
+ DirectoryInfo newDirectory = new DirectoryInfo(fullDirectoryName);
+
+ if (newDirectory.Exists)
+ {
+ throw new ArgumentException(string.Format(Localization.Strings.TheDirectoryXAlreadyExists, newDirectoryName));
+ }
+
+ // create directory and select it
+ newDirectory.Create();
+
+ // important: create a new DirectoryInfo instance, because the Exists property will not be updated by the Create() method
+ SelectDirectory(new DirectoryInfo(fullDirectoryName));
+ }
+
+ ///
+ /// Builds a full filename for the specified filename inside the current directory.
+ ///
+ /// The filename to append to the current directory
+ ///
+ public string BuildFullFileNameForInCurrentDirectory(string newFilename)
+ {
+ string filename = null;
+
+ if (!string.IsNullOrWhiteSpace(newFilename) && m_currentDirectory != null)
+ {
+ string directory = m_currentDirectory.FullName;
+
+ if (directory != null && !directory.EndsWith(@"\") && !directory.EndsWith("/"))
+ {
+ directory = $@"{directory}\";
+ }
+
+ filename = directory + newFilename.Trim();
+
+ // ensure that the full filename has a file extension out of the selected file filter
+ if (m_forceFileExtensionOfFileFilter && m_fileFilterToApply != null && !m_fileFilterToApply.IsMatch(filename))
+ {
+ IEnumerable fileExtensions = FileFilterHelper.GetFileExtensionsFromFilter(m_fileFilterToApply);
+
+ if (fileExtensions != null && fileExtensions.Any())
+ {
+ fileExtensions = fileExtensions.Select(fileExtension => fileExtension.ToLower());
+ string lowerCaseFilename = filename.ToLower();
+
+ bool hasWrongFileExtension = !fileExtensions.Any(fileExtension => lowerCaseFilename.EndsWith($".{fileExtension}"));
+
+ if (hasWrongFileExtension)
+ {
+ if (!filename.EndsWith("."))
+ {
+ filename = $"{filename}.";
+ }
+
+ filename = filename + fileExtensions.First();
+ }
+ }
+ }
+ }
+
+ return filename;
+ }
+
private bool AreObjectsEqual(object o1, object o2)
{
if (o1 == o2)
diff --git a/MaterialDesignExtensions/Controllers/StepperController.cs b/MaterialDesignExtensions/Controllers/StepperController.cs
index 82963290..e6a73a61 100644
--- a/MaterialDesignExtensions/Controllers/StepperController.cs
+++ b/MaterialDesignExtensions/Controllers/StepperController.cs
@@ -196,7 +196,7 @@ public void InitSteps(IStep[] steps)
}
}
- private int GetActiveStepIndex()
+ internal int GetActiveStepIndex()
{
if (m_stepViewModels != null)
{
diff --git a/MaterialDesignExtensions/Controls/AlertDialog.cs b/MaterialDesignExtensions/Controls/AlertDialog.cs
new file mode 100644
index 00000000..5e905bbf
--- /dev/null
+++ b/MaterialDesignExtensions/Controls/AlertDialog.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+using MaterialDesignThemes.Wpf;
+
+namespace MaterialDesignExtensions.Controls
+{
+ ///
+ /// An alert dialog to show a title and message with an OK button only.
+ ///
+ public class AlertDialog : MessageDialog
+ {
+ static AlertDialog()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(AlertDialog), new FrameworkPropertyMetadata(typeof(AlertDialog)));
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ public AlertDialog() : base() { }
+
+ ///
+ /// Shows a new .
+ ///
+ /// The name of the
+ /// The arguments for the dialog initialization
+ ///
+ public static async Task ShowDialogAsync(string dialogHostName, AlertDialogArguments args)
+ {
+ AlertDialog dialog = InitDialog(args);
+
+ await DialogHost.Show(dialog, dialogHostName, args.OpenedHandler, args.ClosingHandler);
+ }
+
+ ///
+ /// Shows a new .
+ ///
+ /// The
+ /// The arguments for the dialog initialization
+ ///
+ public static async Task ShowDialogAsync(DialogHost dialogHost, AlertDialogArguments args)
+ {
+ AlertDialog dialog = InitDialog(args);
+
+ await dialogHost.ShowDialog(dialog, args.OpenedHandler, args.ClosingHandler);
+ }
+
+ private static AlertDialog InitDialog(AlertDialogArguments args)
+ {
+ AlertDialog dialog = new AlertDialog
+ {
+ Title = args.Title,
+ Message = args.Message,
+ CustomContent = args.CustomContent,
+ CustomContentTemplate = args.CustomContentTemplate
+ };
+
+ if (!string.IsNullOrWhiteSpace(args.OkButtonLabel))
+ {
+ dialog.OkButtonLabel = args.OkButtonLabel;
+ }
+
+ return dialog;
+ }
+ }
+
+ ///
+ /// The arguments for an alert dialog.
+ ///
+ public class AlertDialogArguments : MessageDialogArguments
+ {
+ ///
+ /// Creates a new .
+ ///
+ public AlertDialogArguments() : base() { }
+ }
+}
diff --git a/MaterialDesignExtensions/Controls/AppBar.cs b/MaterialDesignExtensions/Controls/AppBar.cs
index d510f30a..c53b09fa 100644
--- a/MaterialDesignExtensions/Controls/AppBar.cs
+++ b/MaterialDesignExtensions/Controls/AppBar.cs
@@ -16,7 +16,7 @@ namespace MaterialDesignExtensions.Controls
/// A custom control implementing the concept of the app bar (https://material.io/design/components/app-bars-top.html#usage).
/// It provides an optional toggle button for a navigation drawer, an icon, a title and a content area (to add toolbar buttons for example).
///
- [ContentProperty(nameof(Children))]
+ [ContentProperty(nameof(ContentAreaContent))]
public class AppBar : Control
{
private const string BackButtonName = "backButton";
@@ -133,24 +133,46 @@ public ICommand BackCommand
}
///
- /// The items for the content area (toolbar buttons for example).
+ /// The content for the content area (toolbar buttons for example).
///
- public static readonly DependencyPropertyKey ChildrenProperty = DependencyProperty.RegisterReadOnly(
- nameof(Children), typeof(IList), typeof(AppBar), new UIPropertyMetadata(null, null));
+ public static readonly DependencyProperty ContentAreaContentProperty = DependencyProperty.Register(
+ nameof(ContentAreaContent), typeof(object), typeof(AppBar), new UIPropertyMetadata(null, null));
///
- /// The items for the content area (toolbar buttons for example).
+ /// The content for the content area (toolbar buttons for example).
///
- public IList Children
+ public object ContentAreaContent
{
get
{
- return (IList)GetValue(ChildrenProperty.DependencyProperty);
+ return GetValue(ContentAreaContentProperty);
}
set
{
- SetValue(ChildrenProperty, value);
+ SetValue(ContentAreaContentProperty, value);
+ }
+ }
+
+ ///
+ /// The data template for the content area.
+ ///
+ public static readonly DependencyProperty ContentAreaContentTemplateProperty = DependencyProperty.Register(
+ nameof(ContentAreaContentTemplate), typeof(DataTemplate), typeof(AppBar), new UIPropertyMetadata(null, null));
+
+ ///
+ /// The data template for the content area.
+ ///
+ public object ContentAreaContentTemplate
+ {
+ get
+ {
+ return GetValue(ContentAreaContentTemplateProperty);
+ }
+
+ set
+ {
+ SetValue(ContentAreaContentTemplateProperty, value);
}
}
@@ -344,8 +366,6 @@ public AppBar()
: base()
{
m_backButton = null;
-
- Children = new ObservableCollection();
}
public override void OnApplyTemplate()
diff --git a/MaterialDesignExtensions/Controls/Autocomplete.cs b/MaterialDesignExtensions/Controls/Autocomplete.cs
index 00a4c4ae..6065afe4 100644
--- a/MaterialDesignExtensions/Controls/Autocomplete.cs
+++ b/MaterialDesignExtensions/Controls/Autocomplete.cs
@@ -9,6 +9,7 @@
using System.Windows.Input;
using System.Windows.Controls.Primitives;
+using MaterialDesignExtensions.Commands.Internal;
using MaterialDesignExtensions.Controllers;
using MaterialDesignExtensions.Model;
@@ -24,11 +25,6 @@ public class Autocomplete : ControlWithAutocompletePopup
private static readonly string ClearButtonName = "clearButton";
private static readonly string SearchTextBoxName = "searchTextBox";
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand SelectAutocompleteItemCommand = new RoutedCommand();
-
///
/// An event raised by changing the selected item.
///
@@ -272,7 +268,7 @@ public Autocomplete()
m_autocompleteController = new AutocompleteController() { AutocompleteSource = AutocompleteSource };
- CommandBindings.Add(new CommandBinding(SelectAutocompleteItemCommand, SelectAutocompleteItemCommandHandler));
+ CommandBindings.Add(new CommandBinding(AutocompleteCommands.SelectAutocompleteItemCommand, SelectAutocompleteItemCommandHandler));
}
public override void OnApplyTemplate()
@@ -363,8 +359,7 @@ private void SearchTextBoxKeyUpHandler(object sender, KeyEventArgs args)
private void ClearClickHandler(object sender, RoutedEventArgs args)
{
- SelectedItem = null;
- SearchTerm = null;
+ ClearSelection();
m_searchTextBox.Focus();
}
@@ -442,14 +437,17 @@ private void SelectAutocompleteItemCommandHandler(object sender, ExecutedRoutedE
SelectedItem = args.Parameter;
}
- public void AutocompleteSourceItemsChangedHandler(object sender, AutocompleteSourceItemsChangedEventArgs args)
+ private void AutocompleteSourceItemsChangedHandler(object sender, AutocompleteSourceItemsChangedEventArgs args)
{
- if (m_searchTextBox != null && m_searchTextBox.IsKeyboardFocused)
+ Dispatcher.Invoke(() =>
{
- m_autocompleteController?.Search(SearchTerm);
+ if (m_searchTextBox != null && m_searchTextBox.IsKeyboardFocused)
+ {
+ m_autocompleteController?.Search(SearchTerm);
- UpdateClearButtonVisibility();
- }
+ UpdateClearButtonVisibility();
+ }
+ });
}
private void AutocompleteItemsChangedHandler(object sender, AutocompleteItemsChangedEventArgs args)
@@ -489,6 +487,15 @@ private void UpdateClearButtonVisibility()
}
}
}
+
+ ///
+ /// Clears the selection.
+ ///
+ public void ClearSelection()
+ {
+ SelectedItem = null;
+ SearchTerm = null;
+ }
}
///
diff --git a/MaterialDesignExtensions/Controls/AutocompletePopup.cs b/MaterialDesignExtensions/Controls/AutocompletePopup.cs
index 7c803e23..2b399f73 100644
--- a/MaterialDesignExtensions/Controls/AutocompletePopup.cs
+++ b/MaterialDesignExtensions/Controls/AutocompletePopup.cs
@@ -10,10 +10,16 @@
namespace MaterialDesignExtensions.Controls
{
+ ///
+ /// Another implementation of to add a better behavior while moving or resizing the window.
+ ///
public class AutocompletePopup : Popup
{
private Window m_window;
+ ///
+ /// Creates a new .
+ ///
public AutocompletePopup()
: base()
{
diff --git a/MaterialDesignExtensions/Controls/BaseFileControl.cs b/MaterialDesignExtensions/Controls/BaseFileControl.cs
index 51e5dd91..81c0b064 100644
--- a/MaterialDesignExtensions/Controls/BaseFileControl.cs
+++ b/MaterialDesignExtensions/Controls/BaseFileControl.cs
@@ -10,10 +10,18 @@
using System.Windows.Controls;
using System.Windows.Input;
+using MaterialDesignExtensions.Commands.Internal;
using MaterialDesignExtensions.Controllers;
using MaterialDesignExtensions.Converters;
using MaterialDesignExtensions.Model;
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using FileSystemInfo = Pri.LongPath.FileSystemInfo;
+using DirectoryInfo = Pri.LongPath.DirectoryInfo;
+using FileInfo = Pri.LongPath.FileInfo;
+#endif
+
namespace MaterialDesignExtensions.Controls
{
///
@@ -21,12 +29,10 @@ namespace MaterialDesignExtensions.Controls
///
public abstract class BaseFileControl : FileSystemControl
{
- protected const string FileFiltersComboBoxName = "fileFiltersComboBox";
-
///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ /// The name of the combo box inside the template.
///
- public static readonly RoutedCommand SelectFileCommand = new RoutedCommand();
+ protected const string FileFiltersComboBoxName = "fileFiltersComboBox";
///
/// An event raised by selecting a file.
@@ -56,7 +62,7 @@ public event RoutedEventHandler FileSelected
public static readonly DependencyProperty ClearCacheOnUnloadProperty = DependencyProperty.Register(
nameof(ClearCacheOnUnload),
typeof(bool),
- typeof(FileSystemControl),
+ typeof(BaseFileControl),
new PropertyMetadata(true));
///
@@ -101,13 +107,13 @@ public string CurrentFile
}
///
- /// An command called by by selecting a file.
+ /// An command called by selecting a file.
///
public static readonly DependencyProperty FileSelectedCommandProperty = DependencyProperty.Register(
nameof(FileSelectedCommand), typeof(ICommand), typeof(BaseFileControl), new PropertyMetadata(null, null));
///
- /// An command called by by selecting a file.
+ /// An command called by selecting a file.
///
public ICommand FileSelectedCommand
{
@@ -204,12 +210,16 @@ public bool GroupFoldersAndFiles
protected ComboBox m_fileFiltersComboBox;
+ ///
+ /// Creates a new .
+ ///
public BaseFileControl()
: base()
{
m_fileFiltersComboBox = null;
- CommandBindings.Add(new CommandBinding(SelectFileCommand, SelectFileCommandHandler));
+ CommandBindings.Add(new CommandBinding(FileSystemControlCommands.SelectFileCommand, SelectFileCommandHandler));
+ CommandBindings.Add(new CommandBinding(FileSystemControlCommands.FileSystemEntryDoubleClickCommand, FileDoubleClickCommandHandler));
}
public override void OnApplyTemplate()
@@ -224,12 +234,29 @@ public override void OnApplyTemplate()
protected override void UnloadedHandler(object sender, RoutedEventArgs args)
{
- BitmapImageHelper.ClearCache();
+ if (ClearCacheOnUnload)
+ {
+ BitmapImageHelper.ClearCache();
+ }
base.UnloadedHandler(sender, args);
}
+ protected override void SelectFileSystemEntryCommandHandler(object sender, ExecutedRoutedEventArgs args)
+ {
+ SelectFileSystemEntry(args.Parameter as FileSystemInfo);
+
+ Keyboard.Focus(this);
+ }
+
+ protected abstract void SelectFileSystemEntry(FileSystemInfo fileSystemInfo);
+
protected virtual void SelectFileCommandHandler(object sender, ExecutedRoutedEventArgs args)
+ {
+ SelectFile();
+ }
+
+ protected virtual void SelectFile()
{
try
{
@@ -247,6 +274,22 @@ protected virtual void SelectFileCommandHandler(object sender, ExecutedRoutedEve
}
}
+ protected virtual void FileDoubleClickCommandHandler(object sender, ExecutedRoutedEventArgs args)
+ {
+ try
+ {
+ if (args.Parameter is FileInfo fileInfo)
+ {
+ SelectFileSystemEntry(fileInfo);
+ SelectFile();
+ }
+ }
+ catch (PathTooLongException)
+ {
+ SnackbarMessageQueue.Enqueue(Localization.Strings.LongPathsAreNotSupported);
+ }
+ }
+
private static void CurrentFileChangedHandler(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
(obj as BaseFileControl)?.CurrentFileChangedHandler(args.NewValue as string);
@@ -353,70 +396,17 @@ protected override IEnumerable GetFileSystemEntryItems()
protected IEnumerable GetFileSystemEntryItems(List directoriesAndFiles)
{
- if (directoriesAndFiles == null || !directoriesAndFiles.Any())
- {
- return new ArrayList(0);
- }
-
- int numberOfItems = directoriesAndFiles.Count;
-
- if (GroupFoldersAndFiles)
- {
- numberOfItems = numberOfItems + 2;
- }
-
- ArrayList items = new ArrayList(numberOfItems);
-
- for (int i = 0; i < directoriesAndFiles.Count; i++)
- {
- FileSystemInfo item = directoriesAndFiles[i];
-
- if (item is DirectoryInfo directoryInfo)
- {
- if (GroupFoldersAndFiles && i == 0)
- {
- items.Add(new FileSystemEntriesGroupHeader() { Header = Localization.Strings.Folders, ShowSeparator = false });
- }
-
- bool isSelected = directoryInfo.FullName == m_controller.CurrentDirectory?.FullName;
-
- items.Add(new DirectoryInfoItem() { IsSelected = isSelected, Value = directoryInfo });
- }
- else if (item is FileInfo fileInfo)
- {
- if (GroupFoldersAndFiles)
- {
- if (i == 0)
- {
- items.Add(new FileSystemEntriesGroupHeader() { Header = Localization.Strings.Files, ShowSeparator = false });
- }
- else if (directoriesAndFiles[i - 1] is DirectoryInfo)
- {
- items.Add(new FileSystemEntriesGroupHeader() { Header = Localization.Strings.Files, ShowSeparator = true });
- }
- }
-
- bool isSelected = fileInfo.FullName == m_controller.CurrentFileFullName;
-
- items.Add(new FileInfoItem() { IsSelected = isSelected, Value = fileInfo });
- }
- }
-
- return items;
+ return FileControlHelper.GetFileSystemEntryItems(
+ directoriesAndFiles,
+ m_controller,
+ GroupFoldersAndFiles,
+ fileInfo => fileInfo.FullName == m_controller.CurrentFileFullName
+ );
}
protected void UpdateFileFiltersVisibility()
{
- if (m_fileFiltersComboBox != null
- && m_fileFiltersComboBox.ItemsSource != null
- && m_fileFiltersComboBox.ItemsSource.GetEnumerator().MoveNext())
- {
- m_fileFiltersComboBox.Visibility = Visibility.Visible;
- }
- else
- {
- m_fileFiltersComboBox.Visibility = Visibility.Collapsed;
- }
+ FileControlHelper.UpdateFileFiltersVisibility(m_fileFiltersComboBox);
}
}
@@ -426,7 +416,7 @@ protected void UpdateFileFiltersVisibility()
public class FileSelectedEventArgs : RoutedEventArgs
{
///
- /// The selected file as
+ /// The selected file as .
///
public FileInfo FileInfo { get; private set; }
diff --git a/MaterialDesignExtensions/Controls/BaseFileDialog.cs b/MaterialDesignExtensions/Controls/BaseFileDialog.cs
index 03ad50c3..21f91f7f 100644
--- a/MaterialDesignExtensions/Controls/BaseFileDialog.cs
+++ b/MaterialDesignExtensions/Controls/BaseFileDialog.cs
@@ -7,11 +7,14 @@
using System.Threading.Tasks;
using System.Windows;
-using MaterialDesignThemes.Wpf;
-
using MaterialDesignExtensions.Converters;
using MaterialDesignExtensions.Model;
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using FileInfo = Pri.LongPath.FileInfo;
+#endif
+
namespace MaterialDesignExtensions.Controls
{
///
@@ -176,6 +179,17 @@ public FileDialogArguments()
Filters = null;
FilterIndex = 0;
}
+
+ ///
+ /// Copy constructor
+ ///
+ ///
+ public FileDialogArguments(FileDialogArguments args)
+ : base(args)
+ {
+ Filters = args.Filters;
+ FilterIndex = args.FilterIndex;
+ }
}
///
diff --git a/MaterialDesignExtensions/Controls/BusyOverlay.cs b/MaterialDesignExtensions/Controls/BusyOverlay.cs
new file mode 100644
index 00000000..955d9402
--- /dev/null
+++ b/MaterialDesignExtensions/Controls/BusyOverlay.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace MaterialDesignExtensions.Controls
+{
+ ///
+ /// A control for displaying some kind of progress indication over the complete user interface while a long running operation is in progress.
+ ///
+ public class BusyOverlay : ContentControl
+ {
+ ///
+ /// True, to switch the control into busy state and make it visible in the UI's foreground.
+ ///
+ public static readonly DependencyProperty IsBusyProperty = DependencyProperty.Register(
+ nameof(IsBusy), typeof(bool), typeof(BusyOverlay), new PropertyMetadata(false));
+
+ ///
+ /// True, to switch the control into busy state and make it visible in the UI's foreground.
+ ///
+ public bool IsBusy
+ {
+ get
+ {
+ return (bool)GetValue(IsBusyProperty);
+ }
+
+ set
+ {
+ SetValue(IsBusyProperty, value);
+ }
+ }
+
+ ///
+ /// The progress in percentage of the operation causing the busy state.
+ ///
+ public static readonly DependencyProperty ProgressProperty = DependencyProperty.Register(
+ nameof(Progress), typeof(int), typeof(BusyOverlay), new PropertyMetadata(0));
+
+ ///
+ /// The progress in percentage of the operation causing the busy state.
+ ///
+ public int Progress
+ {
+ get
+ {
+ return (int)GetValue(ProgressProperty);
+ }
+
+ set
+ {
+ SetValue(ProgressProperty, value);
+ }
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ public BusyOverlay() : base() { }
+ }
+}
diff --git a/MaterialDesignExtensions/Controls/ConfirmationDialog.cs b/MaterialDesignExtensions/Controls/ConfirmationDialog.cs
new file mode 100644
index 00000000..796557c6
--- /dev/null
+++ b/MaterialDesignExtensions/Controls/ConfirmationDialog.cs
@@ -0,0 +1,196 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+
+using MaterialDesignThemes.Wpf;
+
+namespace MaterialDesignExtensions.Controls
+{
+ ///
+ /// A confirmation dialog to show a title and message with an OK and a cancel button.
+ ///
+ public class ConfirmationDialog : MessageDialog
+ {
+ private static readonly string CancelButtonName = "cancelButton";
+
+ ///
+ /// The label of the cancel button.
+ ///
+ public static readonly DependencyProperty CancelButtonLabelProperty = DependencyProperty.Register(
+ nameof(CancelButtonLabel), typeof(string), typeof(ConfirmationDialog));
+
+ ///
+ /// The label of the cancel button.
+ ///
+ public string CancelButtonLabel
+ {
+ get
+ {
+ return (string)GetValue(CancelButtonLabelProperty);
+ }
+
+ set
+ {
+ SetValue(CancelButtonLabelProperty, value);
+ }
+ }
+
+ ///
+ /// True to stack the OK and cancel buttons instead of showing them side by side.
+ ///
+ public static readonly DependencyProperty StackedButtonsProperty = DependencyProperty.Register(
+ nameof(StackedButtons), typeof(bool), typeof(ConfirmationDialog));
+
+ ///
+ /// True to stack the OK and cancel buttons instead of showing them side by side.
+ ///
+ public bool StackedButtons
+ {
+ get
+ {
+ return (bool)GetValue(StackedButtonsProperty);
+ }
+
+ set
+ {
+ SetValue(StackedButtonsProperty, value);
+ }
+ }
+
+ private Button m_cancelButton;
+
+ static ConfirmationDialog()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(ConfirmationDialog), new FrameworkPropertyMetadata(typeof(ConfirmationDialog)));
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ public ConfirmationDialog()
+ : base()
+ {
+ m_cancelButton = null;
+ }
+
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ if (m_cancelButton != null)
+ {
+ m_cancelButton.Click -= CancelButtonClickHandler;
+ }
+
+ m_cancelButton = Template.FindName(CancelButtonName, this) as Button;
+ }
+
+ protected override void LoadedHandler(object sender, RoutedEventArgs args)
+ {
+ base.LoadedHandler(sender, args);
+
+ m_cancelButton.Click += CancelButtonClickHandler;
+ }
+
+ protected override void UnloadedHandler(object sender, RoutedEventArgs args)
+ {
+ base.UnloadedHandler(sender, args);
+
+ m_cancelButton.Click -= CancelButtonClickHandler;
+ }
+
+ protected override void OkButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ DialogHost.CloseDialogCommand.Execute(true, GetDialogHost());
+ }
+
+ private void CancelButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ DialogHost.CloseDialogCommand.Execute(false, GetDialogHost());
+ }
+
+ ///
+ /// Shows a new .
+ ///
+ /// The name of the
+ /// The arguments for the dialog initialization
+ ///
+ public static async Task ShowDialogAsync(string dialogHostName, ConfirmationDialogArguments args)
+ {
+ ConfirmationDialog dialog = InitDialog(args);
+
+ object result = await DialogHost.Show(dialog, dialogHostName, args.OpenedHandler, args.ClosingHandler);
+
+ return (bool)result;
+ }
+
+ ///
+ /// Shows a new .
+ ///
+ /// The
+ /// The arguments for the dialog initialization
+ ///
+ public static async Task ShowDialogAsync(DialogHost dialogHost, ConfirmationDialogArguments args)
+ {
+ ConfirmationDialog dialog = InitDialog(args);
+
+ object result = await dialogHost.ShowDialog(dialog, args.OpenedHandler, args.ClosingHandler);
+
+ return (bool)result;
+ }
+
+ private static ConfirmationDialog InitDialog(ConfirmationDialogArguments args)
+ {
+ ConfirmationDialog dialog = new ConfirmationDialog
+ {
+ Title = args.Title,
+ Message = args.Message,
+ StackedButtons = args.StackedButtons,
+ CustomContent = args.CustomContent,
+ CustomContentTemplate = args.CustomContentTemplate
+ };
+
+ if (!string.IsNullOrWhiteSpace(args.OkButtonLabel))
+ {
+ dialog.OkButtonLabel = args.OkButtonLabel;
+ }
+
+ if (!string.IsNullOrWhiteSpace(args.CancelButtonLabel))
+ {
+ dialog.CancelButtonLabel = args.CancelButtonLabel;
+ }
+
+ return dialog;
+ }
+ }
+
+ ///
+ /// The arguments for a confirmation dialog.
+ ///
+ public class ConfirmationDialogArguments : MessageDialogArguments
+ {
+ ///
+ /// The label of the cancel button.
+ ///
+ public string CancelButtonLabel { get; set; }
+
+ ///
+ /// True to stack the OK and cancel buttons instead of showing them side by side.
+ ///
+ public bool StackedButtons { get; set; }
+
+ ///
+ /// Creates a new .
+ ///
+ public ConfirmationDialogArguments()
+ : base()
+ {
+ CancelButtonLabel = null;
+ StackedButtons = false;
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Controls/ControlWithAutocompletePopup.cs b/MaterialDesignExtensions/Controls/ControlWithAutocompletePopup.cs
index 5c9e3992..e858c9d6 100644
--- a/MaterialDesignExtensions/Controls/ControlWithAutocompletePopup.cs
+++ b/MaterialDesignExtensions/Controls/ControlWithAutocompletePopup.cs
@@ -19,7 +19,7 @@ public abstract class ControlWithAutocompletePopup : Control
protected AutocompletePopup m_popup;
///
- /// Creates a new ControlWithPopup.
+ /// Creates a new .
///
public ControlWithAutocompletePopup()
: base()
diff --git a/MaterialDesignExtensions/Controls/FileSystemControl.cs b/MaterialDesignExtensions/Controls/FileSystemControl.cs
index 3a9d19ce..f8e6c8e0 100644
--- a/MaterialDesignExtensions/Controls/FileSystemControl.cs
+++ b/MaterialDesignExtensions/Controls/FileSystemControl.cs
@@ -13,9 +13,16 @@
using MaterialDesignThemes.Wpf;
+using MaterialDesignExtensions.Commands.Internal;
using MaterialDesignExtensions.Controllers;
using MaterialDesignExtensions.Model;
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using FileSystemInfo = Pri.LongPath.FileSystemInfo;
+using DirectoryInfo = Pri.LongPath.DirectoryInfo;
+#endif
+
namespace MaterialDesignExtensions.Controls
{
///
@@ -26,34 +33,10 @@ public abstract class FileSystemControl : Control
protected const string DrawerHostName = "drawerHost";
protected const string PathPartsScrollViewerName = "pathPartsScrollViewer";
protected const string PathPartsItemsControlName = "pathPartsItemsControl";
+ protected const string CurrentDirectoryTextBoxName = "currentDirectoryTextBox";
protected const string FileSystemEntryItemsControlName = "fileSystemEntryItemsControl";
protected const string EmptyDirectoryTextBlockName = "emptyDirectoryTextBlock";
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand OpenSpecialDirectoriesDrawerCommand = new RoutedCommand();
-
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand SelectDirectoryItemCommand = new RoutedCommand();
-
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand SelectFileSystemEntryCommand = new RoutedCommand();
-
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand ShowInfoCommand = new RoutedCommand();
-
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand CancelCommand = new RoutedCommand();
-
///
/// An event raised by canceling the operation.
///
@@ -87,6 +70,31 @@ public FileSystemController Controller
}
}
+ ///
+ /// Enables the feature to create new directories.
+ ///
+ public static readonly DependencyProperty CreateNewDirectoryEnabledProperty = DependencyProperty.Register(
+ nameof(CreateNewDirectoryEnabled),
+ typeof(bool),
+ typeof(FileSystemControl),
+ new PropertyMetadata(false));
+
+ ///
+ /// Enables the feature to create new directories. Notice: It does not have any effects for .
+ ///
+ public bool CreateNewDirectoryEnabled
+ {
+ get
+ {
+ return (bool)GetValue(CreateNewDirectoryEnabledProperty);
+ }
+
+ set
+ {
+ SetValue(CreateNewDirectoryEnabledProperty, value);
+ }
+ }
+
///
/// The current directory of the control.
///
@@ -170,6 +178,56 @@ ScrollViewer FindItemsScrollViewer(ItemsControl itemsControl)
}
}
+ ///
+ /// The name for the new directory.
+ ///
+ public static readonly DependencyProperty NewDirectoryNameProperty = DependencyProperty.Register(
+ nameof(NewDirectoryName),
+ typeof(string),
+ typeof(FileSystemControl),
+ new PropertyMetadata(null));
+
+ ///
+ /// The name for the new directory.
+ ///
+ public string NewDirectoryName
+ {
+ get
+ {
+ return (string)GetValue(NewDirectoryNameProperty);
+ }
+
+ set
+ {
+ SetValue(NewDirectoryNameProperty, value);
+ }
+ }
+
+ ///
+ /// Show the current directory path with a short cut button for each part in the path, instead of a text box.
+ ///
+ public static readonly DependencyProperty PathPartsAsButtonsProperty = DependencyProperty.Register(
+ nameof(PathPartsAsButtons),
+ typeof(bool),
+ typeof(FileSystemControl),
+ new PropertyMetadata(true));
+
+ ///
+ /// Show the current directory path with a short cut button for each part in the path, instead of a text box.
+ ///
+ public bool PathPartsAsButtons
+ {
+ get
+ {
+ return (bool)GetValue(PathPartsAsButtonsProperty);
+ }
+
+ set
+ {
+ SetValue(PathPartsAsButtonsProperty, value);
+ }
+ }
+
///
/// Shows or hides hidden directories and files.
///
@@ -245,12 +303,38 @@ protected set
}
}
+ ///
+ /// Enable switching between a text box and the buttons for each sub directory of the current directory's path.
+ ///
+ public static readonly DependencyProperty SwitchPathPartsAsButtonsEnabledProperty = DependencyProperty.Register(
+ nameof(SwitchPathPartsAsButtonsEnabled),
+ typeof(bool),
+ typeof(FileSystemControl),
+ new PropertyMetadata(false));
+
+ ///
+ /// Enable switching between a text box and the buttons for each sub directory of the current directory's path.
+ ///
+ public bool SwitchPathPartsAsButtonsEnabled
+ {
+ get
+ {
+ return (bool)GetValue(SwitchPathPartsAsButtonsEnabledProperty);
+ }
+
+ set
+ {
+ SetValue(SwitchPathPartsAsButtonsEnabledProperty, value);
+ }
+ }
+
protected FileSystemController m_controller;
protected ScrollViewer m_pathPartsScrollViewer;
protected ItemsControl m_pathPartsItemsControl;
+ protected TextBox m_currentDirectoryTextBox;
// use an ItemsControl instead of a ListBox, because the ListBox raises several selection changed events without an explicit user input
- // another advantage; non selectable items such as headers can be added
+ // another advantage: non selectable items such as headers can be added
protected ItemsControl m_fileSystemEntryItemsControl;
// private to force the usage of the lazy getter, because it only works after applying the template
private ScrollViewer m_fileSystemEntryItemsScrollViewer;
@@ -261,20 +345,30 @@ static FileSystemControl()
DefaultStyleKeyProperty.OverrideMetadata(typeof(FileSystemControl), new FrameworkPropertyMetadata(typeof(FileSystemControl)));
}
+ ///
+ /// Creates a new .
+ ///
public FileSystemControl()
: base()
{
m_controller = new FileSystemController();
m_controller.SelectDirectory(CurrentDirectory);
- CommandBindings.Add(new CommandBinding(OpenSpecialDirectoriesDrawerCommand, OpenSpecialDirectoriesDrawerCommandHandler));
- CommandBindings.Add(new CommandBinding(SelectDirectoryItemCommand, SelectDirectoryItemCommandHandler));
- CommandBindings.Add(new CommandBinding(SelectFileSystemEntryCommand, SelectFileSystemEntryCommandHandler));
- CommandBindings.Add(new CommandBinding(ShowInfoCommand, ShowInfoCommandHandler));
- CommandBindings.Add(new CommandBinding(CancelCommand, CancelCommandHandler));
+ CommandBindings.Add(new CommandBinding(FileSystemControlCommands.OpenSpecialDirectoriesDrawerCommand, OpenSpecialDirectoriesDrawerCommandHandler));
+ CommandBindings.Add(new CommandBinding(FileSystemControlCommands.SwitchPathPartsAsButtonsCommand, SwitchPathPartsAsButtonsHandler));
+ CommandBindings.Add(new CommandBinding(FileSystemControlCommands.SelectDirectoryItemCommand, SelectDirectoryItemCommandHandler));
+ CommandBindings.Add(new CommandBinding(FileSystemControlCommands.SelectFileSystemEntryCommand, SelectFileSystemEntryCommandHandler));
+ CommandBindings.Add(new CommandBinding(FileSystemControlCommands.ShowInfoCommand, ShowInfoCommandHandler));
+ CommandBindings.Add(new CommandBinding(FileSystemControlCommands.CancelCommand, CancelCommandHandler));
+ CommandBindings.Add(new CommandBinding(FileSystemControlCommands.ShowCreateNewDirectoryCommand, ShowCreateNewDirectoryCommandHandler));
+ CommandBindings.Add(new CommandBinding(FileSystemControlCommands.CancelNewDirectoryCommand, CancelNewDirectoryCommandHandler));
+ CommandBindings.Add(new CommandBinding(FileSystemControlCommands.CreateNewDirectoryCommand, CreateNewDirectoryCommandHandler));
+
+ InputBindings.Add(new KeyBinding(FileSystemControlCommands.CancelCommand, new KeyGesture(Key.Escape)));
m_pathPartsScrollViewer = null;
m_pathPartsItemsControl = null;
+ m_currentDirectoryTextBox = null;
m_fileSystemEntryItemsScrollViewer = null;
m_fileSystemEntryItemsControl = null;
@@ -291,6 +385,9 @@ public override void OnApplyTemplate()
m_pathPartsItemsControl = Template.FindName(PathPartsItemsControlName, this) as ItemsControl;
m_pathPartsItemsControl.ItemsSource = m_controller.CurrentDirectoryPathParts;
+ m_currentDirectoryTextBox = Template.FindName(CurrentDirectoryTextBoxName, this) as TextBox;
+ m_currentDirectoryTextBox.Text = CurrentDirectory;
+
m_fileSystemEntryItemsControl = Template.FindName(FileSystemEntryItemsControlName, this) as ItemsControl;
m_fileSystemEntryItemsControl.ItemsSource = GetFileSystemEntryItems();
@@ -302,11 +399,24 @@ public override void OnApplyTemplate()
protected virtual void LoadedHandler(object sender, RoutedEventArgs args)
{
m_controller.PropertyChanged += ControllerPropertyChangedHandler;
+
+ if (m_currentDirectoryTextBox != null)
+ {
+ m_currentDirectoryTextBox.KeyDown += CurrentDirectoryTextBoxKeyDownHandler;
+ }
+
+ // not sure if the control should get keyboard focus on loading
+ //Keyboard.Focus(this);
}
protected virtual void UnloadedHandler(object sender, RoutedEventArgs args)
{
m_controller.PropertyChanged -= ControllerPropertyChangedHandler;
+
+ if (m_currentDirectoryTextBox != null)
+ {
+ m_currentDirectoryTextBox.KeyDown -= CurrentDirectoryTextBoxKeyDownHandler;
+ }
}
protected void OpenSpecialDirectoriesDrawerCommandHandler(object sender, ExecutedRoutedEventArgs args)
@@ -315,6 +425,28 @@ protected void OpenSpecialDirectoriesDrawerCommandHandler(object sender, Execute
drawerHost.IsTopDrawerOpen = true;
}
+ protected void SwitchPathPartsAsButtonsHandler(object sender, ExecutedRoutedEventArgs args)
+ {
+ PathPartsAsButtons = !PathPartsAsButtons;
+ }
+
+ private void CurrentDirectoryTextBoxKeyDownHandler(object sender, KeyEventArgs args)
+ {
+ if (sender == m_currentDirectoryTextBox && args.Key == Key.Enter)
+ {
+ string directory = m_currentDirectoryTextBox.Text
+ .Replace("\n", string.Empty)
+ .Replace("\r", string.Empty)
+ .Replace("\r", string.Empty)
+ .Trim();
+
+ if (!string.IsNullOrWhiteSpace(directory))
+ {
+ CurrentDirectory = directory;
+ }
+ }
+ }
+
protected void SelectDirectoryItemCommandHandler(object sender, ExecutedRoutedEventArgs args)
{
if (args.Parameter != null)
@@ -339,6 +471,8 @@ protected void SelectDirectoryItemCommandHandler(object sender, ExecutedRoutedEv
drawerHost.IsTopDrawerOpen = false;
}
}
+
+ Keyboard.Focus(this);
}
protected virtual void SelectFileSystemEntryCommandHandler(object sender, ExecutedRoutedEventArgs args)
@@ -350,6 +484,8 @@ protected virtual void SelectFileSystemEntryCommandHandler(object sender, Execut
CurrentDirectory = directoryInfo.FullName;
}
}
+
+ Keyboard.Focus(this);
}
protected void ShowInfoCommandHandler(object sender, ExecutedRoutedEventArgs args)
@@ -366,6 +502,43 @@ protected void CancelCommandHandler(object sender, ExecutedRoutedEventArgs args)
RaiseEvent(eventArgs);
}
+ protected void ShowCreateNewDirectoryCommandHandler(object sender, ExecutedRoutedEventArgs args)
+ {
+ NewDirectoryName = null;
+
+ DrawerHost drawerHost = ((DrawerHost)Template.FindName(DrawerHostName, this));
+ drawerHost.IsBottomDrawerOpen = true;
+ }
+
+ protected void CancelNewDirectoryCommandHandler(object sender, ExecutedRoutedEventArgs args)
+ {
+ DrawerHost drawerHost = ((DrawerHost)Template.FindName(DrawerHostName, this));
+
+ if (drawerHost.IsBottomDrawerOpen)
+ {
+ drawerHost.IsBottomDrawerOpen = false;
+ }
+ }
+
+ protected void CreateNewDirectoryCommandHandler(object sender, ExecutedRoutedEventArgs args)
+ {
+ try
+ {
+ m_controller.CreateNewDirectory(NewDirectoryName);
+
+ DrawerHost drawerHost = ((DrawerHost)Template.FindName(DrawerHostName, this));
+
+ if (drawerHost.IsBottomDrawerOpen)
+ {
+ drawerHost.IsBottomDrawerOpen = false;
+ }
+ }
+ catch (Exception exc)
+ {
+ SnackbarMessageQueue.Enqueue(exc.Message);
+ }
+ }
+
protected static void CurrentDirectoryChangedHandler(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
(obj as FileSystemControl)?.CurrentDirectoryChangedHandler(args.NewValue as string);
@@ -376,6 +549,11 @@ protected virtual void CurrentDirectoryChangedHandler(string newCurrentDirectory
try
{
m_controller.SelectDirectory(newCurrentDirectory);
+
+ if (m_currentDirectoryTextBox != null)
+ {
+ m_currentDirectoryTextBox.Text = newCurrentDirectory;
+ }
}
catch (PathTooLongException)
{
@@ -425,7 +603,7 @@ protected virtual void ControllerPropertyChangedHandler(object sender, PropertyC
}
}
- protected void UpdateSelection()
+ protected virtual void UpdateSelection()
{
IEnumerable items = m_fileSystemEntryItemsControl?.ItemsSource;
diff --git a/MaterialDesignExtensions/Controls/FileSystemDialog.cs b/MaterialDesignExtensions/Controls/FileSystemDialog.cs
index ddccc6bb..2dec4283 100644
--- a/MaterialDesignExtensions/Controls/FileSystemDialog.cs
+++ b/MaterialDesignExtensions/Controls/FileSystemDialog.cs
@@ -16,6 +16,31 @@ namespace MaterialDesignExtensions.Controls
///
public abstract class FileSystemDialog : Control
{
+ ///
+ /// Enables the feature to create new directories.
+ ///
+ public static readonly DependencyProperty CreateNewDirectoryEnabledProperty = DependencyProperty.Register(
+ nameof(CreateNewDirectoryEnabled),
+ typeof(bool),
+ typeof(FileSystemDialog),
+ new PropertyMetadata(false));
+
+ ///
+ /// Enables the feature to create new directories. Notice: It does not have any effects for .
+ ///
+ public bool CreateNewDirectoryEnabled
+ {
+ get
+ {
+ return (bool)GetValue(CreateNewDirectoryEnabledProperty);
+ }
+
+ set
+ {
+ SetValue(CreateNewDirectoryEnabledProperty, value);
+ }
+ }
+
///
/// The current directory of the dialog.
///
@@ -41,6 +66,31 @@ public string CurrentDirectory
}
}
+ ///
+ /// Show the current directory path with a short cut button for each part in the path, instead of a text box.
+ ///
+ public static readonly DependencyProperty PathPartsAsButtonsProperty = DependencyProperty.Register(
+ nameof(PathPartsAsButtons),
+ typeof(bool),
+ typeof(FileSystemDialog),
+ new PropertyMetadata(true));
+
+ ///
+ /// Show the current directory path with a short cut button for each part in the path, instead of a text box.
+ ///
+ public bool PathPartsAsButtons
+ {
+ get
+ {
+ return (bool)GetValue(PathPartsAsButtonsProperty);
+ }
+
+ set
+ {
+ SetValue(PathPartsAsButtonsProperty, value);
+ }
+ }
+
///
/// Shows or hides hidden directories and files.
///
@@ -91,6 +141,31 @@ public bool ShowSystemFilesAndDirectories
}
}
+ ///
+ /// Enable switching between a text box and the buttons for each sub directory of the current directory's path.
+ ///
+ public static readonly DependencyProperty SwitchPathPartsAsButtonsEnabledProperty = DependencyProperty.Register(
+ nameof(SwitchPathPartsAsButtonsEnabled),
+ typeof(bool),
+ typeof(FileSystemDialog),
+ new PropertyMetadata(false));
+
+ ///
+ /// Enable switching between a text box and the buttons for each sub directory of the current directory's path.
+ ///
+ public bool SwitchPathPartsAsButtonsEnabled
+ {
+ get
+ {
+ return (bool)GetValue(SwitchPathPartsAsButtonsEnabledProperty);
+ }
+
+ set
+ {
+ SetValue(SwitchPathPartsAsButtonsEnabledProperty, value);
+ }
+ }
+
static FileSystemDialog()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(FileSystemDialog), new FrameworkPropertyMetadata(typeof(FileSystemDialog)));
@@ -115,7 +190,9 @@ protected DialogHost GetDialogHost()
protected static void InitDialog(FileSystemDialog dialog, double? width, double? height,
string currentDirectory,
- bool showHiddenFilesAndDirectories, bool showSystemFilesAndDirectories)
+ bool showHiddenFilesAndDirectories, bool showSystemFilesAndDirectories,
+ bool createNewDirectoryEnabled = false,
+ bool switchPathPartsAsButtonsEnabled = false, bool pathPartsAsButtons = true)
{
if (width != null)
{
@@ -132,8 +209,11 @@ protected static void InitDialog(FileSystemDialog dialog, double? width, double?
dialog.CurrentDirectory = currentDirectory;
}
+ dialog.CreateNewDirectoryEnabled = createNewDirectoryEnabled;
dialog.ShowHiddenFilesAndDirectories = showHiddenFilesAndDirectories;
dialog.ShowSystemFilesAndDirectories = showSystemFilesAndDirectories;
+ dialog.SwitchPathPartsAsButtonsEnabled = switchPathPartsAsButtonsEnabled;
+ dialog.PathPartsAsButtons = pathPartsAsButtons;
}
}
@@ -148,7 +228,7 @@ public abstract class FileSystemDialogArguments
public double? Width { get; set; }
///
- /// The fixed heigth of the dialog (nullable).
+ /// The fixed height of the dialog (nullable).
///
public double? Height { get; set; }
@@ -157,6 +237,16 @@ public abstract class FileSystemDialogArguments
///
public string CurrentDirectory { get; set; }
+ ///
+ /// Enables the feature to create new directories. Notice: It does not have any effects for .
+ ///
+ public bool CreateNewDirectoryEnabled { get; set; }
+
+ ///
+ /// Show the current directory path with a short cut button for each part in the path, instead of a text box.
+ ///
+ public bool PathPartsAsButtons { get; set; }
+
///
/// Shows or hides hidden directories and files.
///
@@ -167,6 +257,11 @@ public abstract class FileSystemDialogArguments
///
public bool ShowSystemFilesAndDirectories { get; set; }
+ ///
+ /// Enable switching between a text box and the buttons for each sub directory of the current directory's path.
+ ///
+ public bool SwitchPathPartsAsButtonsEnabled { get; set; }
+
///
/// Callback after openening the dialog.
///
@@ -185,11 +280,30 @@ public FileSystemDialogArguments()
Width = null;
Height = null;
CurrentDirectory = null;
+ CreateNewDirectoryEnabled = false;
ShowHiddenFilesAndDirectories = false;
ShowSystemFilesAndDirectories = false;
+ SwitchPathPartsAsButtonsEnabled = false;
+ PathPartsAsButtons = true;
OpenedHandler = null;
ClosingHandler = null;
}
+
+ ///
+ /// Copy constructor
+ ///
+ ///
+ public FileSystemDialogArguments(FileSystemDialogArguments args)
+ {
+ Width = args.Width;
+ Height = args.Height;
+ CurrentDirectory = args.CurrentDirectory;
+ CreateNewDirectoryEnabled = args.CreateNewDirectoryEnabled;
+ ShowHiddenFilesAndDirectories = args.ShowHiddenFilesAndDirectories;
+ ShowSystemFilesAndDirectories = args.ShowSystemFilesAndDirectories;
+ OpenedHandler = args.OpenedHandler;
+ ClosingHandler = args.ClosingHandler;
+ }
}
///
@@ -202,6 +316,17 @@ public abstract class FileSystemDialogResult
///
public bool Canceled { get; protected set; }
+ ///
+ /// true, if the dialog was confirmed
+ ///
+ public bool Confirmed
+ {
+ get
+ {
+ return !Canceled;
+ }
+ }
+
///
/// Creates a new .
///
diff --git a/MaterialDesignExtensions/Controls/IStepper.cs b/MaterialDesignExtensions/Controls/IStepper.cs
index 0f963b00..f23bf6c0 100644
--- a/MaterialDesignExtensions/Controls/IStepper.cs
+++ b/MaterialDesignExtensions/Controls/IStepper.cs
@@ -6,6 +6,7 @@
using System.Windows;
using System.Windows.Input;
+using MaterialDesignExtensions.Controllers;
using MaterialDesignExtensions.Model;
namespace MaterialDesignExtensions.Controls
@@ -56,6 +57,16 @@ public interface IStepper
///
ICommand ContinueNavigationCommand { get; set; }
+ ///
+ /// Gets the controller for this .
+ ///
+ StepperController Controller { get; }
+
+ ///
+ /// An alternative icon template done steps.
+ ///
+ DataTemplate DoneIconTemplate { get; set; }
+
///
/// Enables the linear mode by disabling the buttons of the header.
/// The navigation must be accomplished by using the navigation commands.
@@ -71,5 +82,10 @@ public interface IStepper
/// A command called by navigating to an arbitrary in a non-linear stepper.
///
ICommand StepNavigationCommand { get; set; }
+
+ ///
+ /// An alternative icon template to indicate validation errors.
+ ///
+ DataTemplate ValidationErrorIconTemplate { get; set; }
}
}
diff --git a/MaterialDesignExtensions/Controls/InputDialog.cs b/MaterialDesignExtensions/Controls/InputDialog.cs
new file mode 100644
index 00000000..4b2b34df
--- /dev/null
+++ b/MaterialDesignExtensions/Controls/InputDialog.cs
@@ -0,0 +1,156 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+using MaterialDesignThemes.Wpf;
+
+namespace MaterialDesignExtensions.Controls
+{
+ public class InputDialog : ConfirmationDialog
+ {
+ ///
+ /// A handler called for validation right before confirming the dialog.
+ ///
+ public static readonly DependencyProperty ValidationHandlerProperty = DependencyProperty.Register(
+ nameof(ValidationHandler), typeof(InputDialogValidationEventHandler), typeof(InputDialog));
+
+ ///
+ /// A handler called for validation right before confirming the dialog.
+ ///
+ public InputDialogValidationEventHandler ValidationHandler
+ {
+ get
+ {
+ return (InputDialogValidationEventHandler)GetValue(ValidationHandlerProperty);
+ }
+
+ set
+ {
+ SetValue(ValidationHandlerProperty, value);
+ }
+ }
+
+ static InputDialog()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(InputDialog), new FrameworkPropertyMetadata(typeof(InputDialog)));
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ public InputDialog() : base() { }
+
+ protected override void OkButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ InputDialogValidationEventArgs validationArgs = new InputDialogValidationEventArgs { CancelConfirmation = false };
+
+ ValidationHandler?.Invoke(this, validationArgs);
+
+ if (!validationArgs.CancelConfirmation)
+ {
+ DialogHost.CloseDialogCommand.Execute(true, GetDialogHost());
+ }
+ }
+
+ ///
+ /// Shows a new .
+ ///
+ /// The name of the
+ /// The arguments for the dialog initialization
+ ///
+ public static async Task ShowDialogAsync(string dialogHostName, InputDialogArguments args)
+ {
+ InputDialog dialog = InitDialog(args);
+
+ object result = await DialogHost.Show(dialog, dialogHostName, args.OpenedHandler, args.ClosingHandler);
+
+ return (bool)result;
+ }
+
+ ///
+ /// Shows a new .
+ ///
+ /// The
+ /// The arguments for the dialog initialization
+ ///
+ public static async Task ShowDialogAsync(DialogHost dialogHost, InputDialogArguments args)
+ {
+ InputDialog dialog = InitDialog(args);
+
+ object result = await dialogHost.ShowDialog(dialog, args.OpenedHandler, args.ClosingHandler);
+
+ return (bool)result;
+ }
+
+ private static InputDialog InitDialog(InputDialogArguments args)
+ {
+ InputDialog dialog = new InputDialog
+ {
+ Title = args.Title,
+ Message = args.Message,
+ StackedButtons = args.StackedButtons,
+ CustomContent = args.CustomContent,
+ CustomContentTemplate = args.CustomContentTemplate,
+ ValidationHandler = args.ValidationHandler
+ };
+
+ if (!string.IsNullOrWhiteSpace(args.OkButtonLabel))
+ {
+ dialog.OkButtonLabel = args.OkButtonLabel;
+ }
+
+ if (!string.IsNullOrWhiteSpace(args.CancelButtonLabel))
+ {
+ dialog.CancelButtonLabel = args.CancelButtonLabel;
+ }
+
+ return dialog;
+ }
+ }
+
+ ///
+ /// The arguments for a confirmation dialog.
+ ///
+ public class InputDialogArguments : ConfirmationDialogArguments
+ {
+ ///
+ /// A handler called for validation right before confirming the dialog.
+ ///
+ public InputDialogValidationEventHandler ValidationHandler { get; set; }
+
+ ///
+ /// Creates a new .
+ ///
+ public InputDialogArguments()
+ : base()
+ {
+ ValidationHandler = null;
+ }
+ }
+
+ ///
+ /// The arguments for the validation handler.
+ ///
+ public class InputDialogValidationEventArgs
+ {
+ public bool CancelConfirmation { get; set; }
+
+ ///
+ /// Creates a new .
+ ///
+ public InputDialogValidationEventArgs()
+ {
+ CancelConfirmation = true;
+ }
+ }
+
+ ///
+ /// The delegate for handling the input dialog validation.
+ ///
+ ///
+ ///
+ public delegate void InputDialogValidationEventHandler(object sender, InputDialogValidationEventArgs args);
+}
diff --git a/MaterialDesignExtensions/Controls/MaterialNavigationWindow.cs b/MaterialDesignExtensions/Controls/MaterialNavigationWindow.cs
new file mode 100644
index 00000000..f4e5c1c3
--- /dev/null
+++ b/MaterialDesignExtensions/Controls/MaterialNavigationWindow.cs
@@ -0,0 +1,204 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+using System.Windows.Navigation;
+
+namespace MaterialDesignExtensions.Controls
+{
+ ///
+ /// Custom navigation window class for a Material Design like styled window.
+ ///
+ public class MaterialNavigationWindow : NavigationWindow
+ {
+ private const string MinimizeButtonName = "minimizeButton";
+ private const string MaximizeRestoreButtonName = "maximizeRestoreButton";
+ private const string CloseButtonName = "closeButton";
+
+ ///
+ /// The color for the border and caption area background of the window.
+ ///
+ public static readonly DependencyProperty BorderBackgroundBrushProperty = DependencyProperty.Register(
+ nameof(BorderBackgroundBrush), typeof(Brush), typeof(MaterialNavigationWindow), new FrameworkPropertyMetadata(null, null));
+
+ ///
+ /// The color for the border and caption area background of the window.
+ ///
+ public Brush BorderBackgroundBrush
+ {
+ get
+ {
+ return (Brush)GetValue(BorderBackgroundBrushProperty);
+ }
+
+ set
+ {
+ SetValue(BorderBackgroundBrushProperty, value);
+ }
+ }
+
+ ///
+ /// The forground color for the caption area of the window.
+ ///
+ public static readonly DependencyProperty BorderForegroundBrushProperty = DependencyProperty.Register(
+ nameof(BorderForegroundBrush), typeof(Brush), typeof(MaterialNavigationWindow), new FrameworkPropertyMetadata(null, null));
+
+ ///
+ /// The forground color for the caption area of the window.
+ ///
+ public Brush BorderForegroundBrush
+ {
+ get
+ {
+ return (Brush)GetValue(BorderForegroundBrushProperty);
+ }
+
+ set
+ {
+ SetValue(BorderForegroundBrushProperty, value);
+ }
+ }
+
+ ///
+ /// Lets the content of the window fade out if the window is inactive.
+ /// The default is true (enabled).
+ ///
+ public static readonly DependencyProperty FadeContentIfInactiveProperty = DependencyProperty.Register(
+ nameof(FadeContentIfInactive), typeof(bool), typeof(MaterialNavigationWindow), new FrameworkPropertyMetadata(true));
+
+ ///
+ /// Lets the content of the window fade out if the window is inactive.
+ /// The default is true (enabled).
+ ///
+ public bool FadeContentIfInactive
+ {
+ get
+ {
+ return (bool)GetValue(FadeContentIfInactiveProperty);
+ }
+
+ set
+ {
+ SetValue(FadeContentIfInactiveProperty, value);
+ }
+ }
+
+ ///
+ /// The template for the title bar. The default shows a with the title.
+ ///
+ public static readonly DependencyProperty TitleTemplateProperty = DependencyProperty.Register(
+ nameof(TitleTemplate), typeof(DataTemplate), typeof(MaterialNavigationWindow));
+
+ ///
+ /// The template for the title bar. The default shows a with the title.
+ ///
+ public DataTemplate TitleTemplate
+ {
+ get
+ {
+ return (DataTemplate)GetValue(TitleTemplateProperty);
+ }
+
+ set
+ {
+ SetValue(TitleTemplateProperty, value);
+ }
+ }
+
+ ///
+ /// The icon inside the window's title bar.
+ ///
+ public static readonly DependencyProperty TitleBarIconProperty = DependencyProperty.Register(
+ nameof(TitleBarIcon), typeof(ImageSource), typeof(MaterialNavigationWindow), new FrameworkPropertyMetadata(null, null));
+
+ ///
+ /// The icon inside the window's title bar.
+ ///
+ public ImageSource TitleBarIcon
+ {
+ get
+ {
+ return (ImageSource)GetValue(TitleBarIconProperty);
+ }
+
+ set
+ {
+ SetValue(TitleBarIconProperty, value);
+ }
+ }
+
+ private Button m_minimizeButton;
+ private Button m_maximizeRestoreButton;
+ private Button m_closeButton;
+
+ static MaterialNavigationWindow()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(MaterialNavigationWindow), new FrameworkPropertyMetadata(typeof(MaterialNavigationWindow)));
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ public MaterialNavigationWindow() : base() { }
+
+ public override void OnApplyTemplate()
+ {
+ if (m_minimizeButton != null)
+ {
+ m_minimizeButton.Click -= MinimizeButtonClickHandler;
+ }
+
+ m_minimizeButton = GetTemplateChild(MinimizeButtonName) as Button;
+
+ if (m_minimizeButton != null)
+ {
+ m_minimizeButton.Click += MinimizeButtonClickHandler;
+ }
+
+ if (m_maximizeRestoreButton != null)
+ {
+ m_maximizeRestoreButton.Click -= MaximizeRestoreButtonClickHandler;
+ }
+
+ m_maximizeRestoreButton = GetTemplateChild(MaximizeRestoreButtonName) as Button;
+
+ if (m_maximizeRestoreButton != null)
+ {
+ m_maximizeRestoreButton.Click += MaximizeRestoreButtonClickHandler;
+ }
+
+ if (m_closeButton != null)
+ {
+ m_closeButton.Click -= CloseButtonClickHandler;
+ }
+
+ m_closeButton = GetTemplateChild(CloseButtonName) as Button;
+
+ if (m_closeButton != null)
+ {
+ m_closeButton.Click += CloseButtonClickHandler;
+ }
+
+ base.OnApplyTemplate();
+ }
+
+ private void CloseButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ Close();
+ }
+
+ private void MaximizeRestoreButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ WindowState = (WindowState == WindowState.Normal) ? WindowState.Maximized : WindowState.Normal;
+ }
+
+ private void MinimizeButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ WindowState = WindowState.Minimized;
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Controls/MaterialWindow.cs b/MaterialDesignExtensions/Controls/MaterialWindow.cs
new file mode 100644
index 00000000..bafb2b1d
--- /dev/null
+++ b/MaterialDesignExtensions/Controls/MaterialWindow.cs
@@ -0,0 +1,203 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+
+namespace MaterialDesignExtensions.Controls
+{
+ ///
+ /// Custom window class for a Material Design like styled window.
+ ///
+ public class MaterialWindow : Window
+ {
+ private const string MinimizeButtonName = "minimizeButton";
+ private const string MaximizeRestoreButtonName = "maximizeRestoreButton";
+ private const string CloseButtonName = "closeButton";
+
+ ///
+ /// The color for the border and caption area background of the window.
+ ///
+ public static readonly DependencyProperty BorderBackgroundBrushProperty = DependencyProperty.Register(
+ nameof(BorderBackgroundBrush), typeof(Brush), typeof(MaterialWindow), new FrameworkPropertyMetadata(null, null));
+
+ ///
+ /// The color for the border and caption area background of the window.
+ ///
+ public Brush BorderBackgroundBrush
+ {
+ get
+ {
+ return (Brush)GetValue(BorderBackgroundBrushProperty);
+ }
+
+ set
+ {
+ SetValue(BorderBackgroundBrushProperty, value);
+ }
+ }
+
+ ///
+ /// The forground color for the caption area of the window.
+ ///
+ public static readonly DependencyProperty BorderForegroundBrushProperty = DependencyProperty.Register(
+ nameof(BorderForegroundBrush), typeof(Brush), typeof(MaterialWindow), new FrameworkPropertyMetadata(null, null));
+
+ ///
+ /// The forground color for the caption area of the window.
+ ///
+ public Brush BorderForegroundBrush
+ {
+ get
+ {
+ return (Brush)GetValue(BorderForegroundBrushProperty);
+ }
+
+ set
+ {
+ SetValue(BorderForegroundBrushProperty, value);
+ }
+ }
+
+ ///
+ /// Lets the content of the window fade out if the window is inactive.
+ /// The default is true (enabled).
+ ///
+ public static readonly DependencyProperty FadeContentIfInactiveProperty = DependencyProperty.Register(
+ nameof(FadeContentIfInactive), typeof(bool), typeof(MaterialWindow), new FrameworkPropertyMetadata(true));
+
+ ///
+ /// Lets the content of the window fade out if the window is inactive.
+ /// The default is true (enabled).
+ ///
+ public bool FadeContentIfInactive
+ {
+ get
+ {
+ return (bool)GetValue(FadeContentIfInactiveProperty);
+ }
+
+ set
+ {
+ SetValue(FadeContentIfInactiveProperty, value);
+ }
+ }
+
+ ///
+ /// The template for the title bar. The default shows a with the title.
+ ///
+ public static readonly DependencyProperty TitleTemplateProperty = DependencyProperty.Register(
+ nameof(TitleTemplate), typeof(DataTemplate), typeof(MaterialWindow));
+
+ ///
+ /// The template for the title bar. The default shows a with the title.
+ ///
+ public DataTemplate TitleTemplate
+ {
+ get
+ {
+ return (DataTemplate)GetValue(TitleTemplateProperty);
+ }
+
+ set
+ {
+ SetValue(TitleTemplateProperty, value);
+ }
+ }
+
+ ///
+ /// The icon inside the window's title bar.
+ ///
+ public static readonly DependencyProperty TitleBarIconProperty = DependencyProperty.Register(
+ nameof(TitleBarIcon), typeof(ImageSource), typeof(MaterialWindow), new FrameworkPropertyMetadata(null, null));
+
+ ///
+ /// The icon inside the window's title bar.
+ ///
+ public ImageSource TitleBarIcon
+ {
+ get
+ {
+ return (ImageSource)GetValue(TitleBarIconProperty);
+ }
+
+ set
+ {
+ SetValue(TitleBarIconProperty, value);
+ }
+ }
+
+ private Button m_minimizeButton;
+ private Button m_maximizeRestoreButton;
+ private Button m_closeButton;
+
+ static MaterialWindow()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(MaterialWindow), new FrameworkPropertyMetadata(typeof(MaterialWindow)));
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ public MaterialWindow() : base() { }
+
+ public override void OnApplyTemplate()
+ {
+ if (m_minimizeButton != null)
+ {
+ m_minimizeButton.Click -= MinimizeButtonClickHandler;
+ }
+
+ m_minimizeButton = GetTemplateChild(MinimizeButtonName) as Button;
+
+ if (m_minimizeButton != null)
+ {
+ m_minimizeButton.Click += MinimizeButtonClickHandler;
+ }
+
+ if (m_maximizeRestoreButton != null)
+ {
+ m_maximizeRestoreButton.Click -= MaximizeRestoreButtonClickHandler;
+ }
+
+ m_maximizeRestoreButton = GetTemplateChild(MaximizeRestoreButtonName) as Button;
+
+ if (m_maximizeRestoreButton != null)
+ {
+ m_maximizeRestoreButton.Click += MaximizeRestoreButtonClickHandler;
+ }
+
+ if (m_closeButton != null)
+ {
+ m_closeButton.Click -= CloseButtonClickHandler;
+ }
+
+ m_closeButton = GetTemplateChild(CloseButtonName) as Button;
+
+ if (m_closeButton != null)
+ {
+ m_closeButton.Click += CloseButtonClickHandler;
+ }
+
+ base.OnApplyTemplate();
+ }
+
+ private void CloseButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ Close();
+ }
+
+ private void MaximizeRestoreButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ WindowState = (WindowState == WindowState.Normal) ? WindowState.Maximized : WindowState.Normal;
+ }
+
+ private void MinimizeButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ WindowState = WindowState.Minimized;
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Controls/MessageDialog.cs b/MaterialDesignExtensions/Controls/MessageDialog.cs
new file mode 100644
index 00000000..5056c3c5
--- /dev/null
+++ b/MaterialDesignExtensions/Controls/MessageDialog.cs
@@ -0,0 +1,241 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Controls;
+
+using MaterialDesignThemes.Wpf;
+
+namespace MaterialDesignExtensions.Controls
+{
+ ///
+ /// The base class for simple dialogs with a title and a message.
+ ///
+ public abstract class MessageDialog : Control
+ {
+ private static readonly string OkButtonName = "okButton";
+
+ ///
+ /// An optional custom content to show in the dialog.
+ ///
+ public static readonly DependencyProperty CustomContentProperty = DependencyProperty.Register(
+ nameof(CustomContent), typeof(object), typeof(MessageDialog));
+
+ ///
+ /// An optional custom content to show in the dialog.
+ ///
+ public object CustomContent
+ {
+ get
+ {
+ return GetValue(CustomContentProperty);
+ }
+
+ set
+ {
+ SetValue(CustomContentProperty, value);
+ }
+ }
+
+ ///
+ /// An optional for .
+ ///
+ public static readonly DependencyProperty CustomContentTemplateProperty = DependencyProperty.Register(
+ nameof(CustomContentTemplate), typeof(DataTemplate), typeof(MessageDialog));
+
+ ///
+ /// An optional for .
+ ///
+ public DataTemplate CustomContentTemplate
+ {
+ get
+ {
+ return (DataTemplate)GetValue(CustomContentTemplateProperty);
+ }
+
+ set
+ {
+ SetValue(CustomContentTemplateProperty, value);
+ }
+ }
+
+ ///
+ /// The message to display inside the dialog.
+ ///
+ public static readonly DependencyProperty MessageProperty = DependencyProperty.Register(
+ nameof(Message), typeof(string), typeof(MessageDialog));
+
+ ///
+ /// The message to display inside the dialog.
+ ///
+ public string Message
+ {
+ get
+ {
+ return (string)GetValue(MessageProperty);
+ }
+
+ set
+ {
+ SetValue(MessageProperty, value);
+ }
+ }
+
+ ///
+ /// The label of the OK button.
+ ///
+ public static readonly DependencyProperty OkButtonLabelProperty = DependencyProperty.Register(
+ nameof(OkButtonLabel), typeof(string), typeof(MessageDialog));
+
+ ///
+ /// The label of the OK button.
+ ///
+ public string OkButtonLabel
+ {
+ get
+ {
+ return (string)GetValue(OkButtonLabelProperty);
+ }
+
+ set
+ {
+ SetValue(OkButtonLabelProperty, value);
+ }
+ }
+
+ ///
+ /// The title to display inside the dialog.
+ ///
+ public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
+ nameof(Title), typeof(string), typeof(MessageDialog));
+
+ ///
+ /// The title to display inside the dialog.
+ ///
+ public string Title
+ {
+ get
+ {
+ return (string)GetValue(TitleProperty);
+ }
+
+ set
+ {
+ SetValue(TitleProperty, value);
+ }
+ }
+
+ private Button m_okButton;
+
+ static MessageDialog()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(MessageDialog), new FrameworkPropertyMetadata(typeof(MessageDialog)));
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ public MessageDialog()
+ : base()
+ {
+ m_okButton = null;
+
+ Loaded += LoadedHandler;
+ Unloaded += UnloadedHandler;
+ }
+
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ if (m_okButton != null)
+ {
+ m_okButton.Click -= OkButtonClickHandler;
+ }
+
+ m_okButton = Template.FindName(OkButtonName, this) as Button;
+ }
+
+ protected virtual void LoadedHandler(object sender, RoutedEventArgs args)
+ {
+ m_okButton.Click += OkButtonClickHandler;
+ }
+
+ protected virtual void UnloadedHandler(object sender, RoutedEventArgs args)
+ {
+ m_okButton.Click -= OkButtonClickHandler;
+ }
+
+ protected virtual void OkButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ DialogHost.CloseDialogCommand.Execute(null, GetDialogHost());
+ }
+
+ protected DialogHost GetDialogHost()
+ {
+ DependencyObject element = VisualTreeHelper.GetParent(this);
+
+ while (element != null && !(element is DialogHost))
+ {
+ element = VisualTreeHelper.GetParent(element);
+ }
+
+ return element as DialogHost;
+ }
+ }
+
+ ///
+ /// The base class for arguments of simple dialogs with a title and a message.
+ ///
+ public class MessageDialogArguments
+ {
+ ///
+ /// An optional custom content to show in the dialog.
+ ///
+ public object CustomContent { get; set; }
+
+ ///
+ /// An optional for .
+ ///
+ public DataTemplate CustomContentTemplate { get; set; }
+
+ ///
+ /// The message to display inside the dialog.
+ ///
+ public string Message { get; set; }
+
+ ///
+ /// The label of the OC button.
+ ///
+ public string OkButtonLabel { get; set; }
+
+ ///
+ /// The title to display inside the dialog.
+ ///
+ public string Title { get; set; }
+
+ ///
+ /// Callback after openening the dialog.
+ ///
+ public DialogOpenedEventHandler OpenedHandler { get; set; }
+
+ ///
+ /// Callback after closing the dialog.
+ ///
+ public DialogClosingEventHandler ClosingHandler { get; set; }
+
+ ///
+ /// Creates a new .
+ ///
+ public MessageDialogArguments()
+ {
+ Message = null;
+ Title = null;
+ OpenedHandler = null;
+ ClosingHandler = null;
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Controls/NavigationRail.cs b/MaterialDesignExtensions/Controls/NavigationRail.cs
new file mode 100644
index 00000000..63375a1d
--- /dev/null
+++ b/MaterialDesignExtensions/Controls/NavigationRail.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using MaterialDesignExtensions.Model;
+
+namespace MaterialDesignExtensions.Controls
+{
+ ///
+ /// A special version of the side navigation.
+ ///
+ public class NavigationRail : SideNavigation
+ {
+ ///
+ /// Creates a new .
+ ///
+ public NavigationRail() : base() { }
+
+ protected override void InitItems(IList values)
+ {
+ if (m_navigationItemsControl != null)
+ {
+ IList navigationItems = new List();
+
+ if (values != null)
+ {
+ foreach (object item in values)
+ {
+ if (item is FirstLevelNavigationItem navigationItem)
+ {
+ navigationItems.Add(navigationItem);
+ }
+ else
+ {
+ throw new NotSupportedException($"Not supported item type {item.GetType().FullName}");
+ }
+ }
+ }
+
+ m_navigationItemsControl.ItemsSource = navigationItems;
+
+ INavigationItem selectedItem = navigationItems.FirstOrDefault(item => item.IsSelected);
+
+ if (selectedItem != null)
+ {
+ if (SelectedItem != selectedItem)
+ {
+ SelectedItem = selectedItem;
+ }
+ }
+ else
+ {
+ SelectedItem = null;
+ }
+ }
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Controls/OpenDirectoryControl.cs b/MaterialDesignExtensions/Controls/OpenDirectoryControl.cs
index 20cf0ef0..3587db48 100644
--- a/MaterialDesignExtensions/Controls/OpenDirectoryControl.cs
+++ b/MaterialDesignExtensions/Controls/OpenDirectoryControl.cs
@@ -9,9 +9,15 @@
using System.Windows;
using System.Windows.Input;
+using MaterialDesignExtensions.Commands.Internal;
using MaterialDesignExtensions.Controllers;
using MaterialDesignExtensions.Model;
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using DirectoryInfo = Pri.LongPath.DirectoryInfo;
+#endif
+
namespace MaterialDesignExtensions.Controls
{
///
@@ -19,11 +25,6 @@ namespace MaterialDesignExtensions.Controls
///
public class OpenDirectoryControl : FileSystemControl
{
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand SelectDirectoryCommand = new RoutedCommand();
-
///
/// An event raised by selecting a directory to open.
///
@@ -47,13 +48,13 @@ public event RoutedEventHandler DirectorySelected
}
///
- /// An command called by by selecting a directory to open.
+ /// An command called by selecting a directory to open.
///
public static readonly DependencyProperty DirectorySelectedCommandProperty = DependencyProperty.Register(
nameof(DirectorySelectedCommand), typeof(ICommand), typeof(OpenDirectoryControl), new PropertyMetadata(null, null));
///
- /// An command called by by selecting a directory to open.
+ /// An command called by selecting a directory to open.
///
public ICommand DirectorySelectedCommand
{
@@ -79,7 +80,7 @@ static OpenDirectoryControl()
public OpenDirectoryControl()
: base()
{
- CommandBindings.Add(new CommandBinding(SelectDirectoryCommand, SelectDirectoryCommandHandler));
+ CommandBindings.Add(new CommandBinding(FileSystemControlCommands.SelectDirectoryCommand, SelectDirectoryCommandHandler));
}
private void SelectDirectoryCommandHandler(object sender, ExecutedRoutedEventArgs args)
@@ -131,7 +132,7 @@ protected override IEnumerable GetFileSystemEntryItems()
public class DirectorySelectedEventArgs : RoutedEventArgs
{
///
- /// The selected directory as
+ /// The selected directory as .
///
public DirectoryInfo DirectoryInfo { get; private set; }
diff --git a/MaterialDesignExtensions/Controls/OpenDirectoryDialog.cs b/MaterialDesignExtensions/Controls/OpenDirectoryDialog.cs
index 8c84e544..514eed1a 100644
--- a/MaterialDesignExtensions/Controls/OpenDirectoryDialog.cs
+++ b/MaterialDesignExtensions/Controls/OpenDirectoryDialog.cs
@@ -8,6 +8,11 @@
using MaterialDesignThemes.Wpf;
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using DirectoryInfo = Pri.LongPath.DirectoryInfo;
+#endif
+
namespace MaterialDesignExtensions.Controls
{
///
@@ -71,29 +76,6 @@ private void OpenDirectoryControlDirectorySelectedHandler(object sender, RoutedE
DialogHost.CloseDialogCommand.Execute(new OpenDirectoryDialogResult(false, (args as DirectorySelectedEventArgs)?.DirectoryInfo), GetDialogHost());
}
- ///
- /// Shows a new .
- ///
- /// The name of the
- /// The width of the dialog (optional)
- /// The heigth of the dialog (optional)
- /// The current directory to show (optional)
- /// Show or hide hidden files in the dialog (optional)
- /// Show or hide system files in the dialog (optional)
- /// Callback after openening the dialog (optional)
- /// Callback after closing the dialog (optional)
- ///
- [Obsolete("Use the overloaded method with OpenDirectoryDialogArguments instead")]
- public static async Task ShowDialogAsync(string dialogHostName, double? width = null, double? height = null,
- string currentDirectory = null,
- bool showHiddenFilesAndDirectories = false, bool showSystemFilesAndDirectories = false,
- DialogOpenedEventHandler openedHandler = null, DialogClosingEventHandler closingHandler = null)
- {
- OpenDirectoryDialog dialog = InitDialog(width, height, currentDirectory, showHiddenFilesAndDirectories, showSystemFilesAndDirectories);
-
- return await DialogHost.Show(dialog, dialogHostName, openedHandler, closingHandler) as OpenDirectoryDialogResult;
- }
-
///
/// Shows a new .
///
@@ -106,36 +88,16 @@ public static async Task ShowDialogAsync(string dialo
args.Width,
args.Height,
args.CurrentDirectory,
+ args.CreateNewDirectoryEnabled,
args.ShowHiddenFilesAndDirectories,
- args.ShowSystemFilesAndDirectories
+ args.ShowSystemFilesAndDirectories,
+ args.SwitchPathPartsAsButtonsEnabled,
+ args.PathPartsAsButtons
);
return await DialogHost.Show(dialog, dialogHostName, args.OpenedHandler, args.ClosingHandler) as OpenDirectoryDialogResult;
}
- ///
- /// Shows a new .
- ///
- /// The
- /// The width of the dialog (optional)
- /// The heigth of the dialog (optional)
- /// The current directory to show (optional)
- /// Show or hide hidden files in the dialog (optional)
- /// Show or hide system files in the dialog (optional)
- /// Callback after openening the dialog (optional)
- /// Callback after closing the dialog (optional)
- ///
- [Obsolete("Use the overloaded method with OpenDirectoryDialogArguments instead")]
- public static async Task ShowDialogAsync(DialogHost dialogHost, double? width = null, double? height = null,
- string currentDirectory = null,
- bool showHiddenFilesAndDirectories = false, bool showSystemFilesAndDirectories = false,
- DialogOpenedEventHandler openedHandler = null, DialogClosingEventHandler closingHandler = null)
- {
- OpenDirectoryDialog dialog = InitDialog(width, height, currentDirectory, showHiddenFilesAndDirectories, showSystemFilesAndDirectories);
-
- return await dialogHost.ShowDialog(dialog, openedHandler, closingHandler) as OpenDirectoryDialogResult;
- }
-
///
/// Shows a new .
///
@@ -148,8 +110,11 @@ public static async Task ShowDialogAsync(DialogHost d
args.Width,
args.Height,
args.CurrentDirectory,
+ args.CreateNewDirectoryEnabled,
args.ShowHiddenFilesAndDirectories,
- args.ShowSystemFilesAndDirectories
+ args.ShowSystemFilesAndDirectories,
+ args.SwitchPathPartsAsButtonsEnabled,
+ args.PathPartsAsButtons
);
return await dialogHost.ShowDialog(dialog, args.OpenedHandler, args.ClosingHandler) as OpenDirectoryDialogResult;
@@ -157,10 +122,12 @@ public static async Task ShowDialogAsync(DialogHost d
private static OpenDirectoryDialog InitDialog(double? width, double? height,
string currentDirectory,
- bool showHiddenFilesAndDirectories, bool showSystemFilesAndDirectories)
+ bool createNewDirectoryEnabled,
+ bool showHiddenFilesAndDirectories, bool showSystemFilesAndDirectories,
+ bool switchPathPartsAsButtonsEnabled, bool pathPartsAsButtons)
{
OpenDirectoryDialog dialog = new OpenDirectoryDialog();
- InitDialog(dialog, width, height, currentDirectory, showHiddenFilesAndDirectories, showSystemFilesAndDirectories);
+ InitDialog(dialog, width, height, currentDirectory, showHiddenFilesAndDirectories, showSystemFilesAndDirectories, createNewDirectoryEnabled, switchPathPartsAsButtonsEnabled, pathPartsAsButtons);
return dialog;
}
@@ -175,6 +142,13 @@ public class OpenDirectoryDialogArguments : FileSystemDialogArguments
/// Creates a new .
///
public OpenDirectoryDialogArguments() : base() { }
+
+ ///
+ /// Copy constructor
+ ///
+ ///
+ public OpenDirectoryDialogArguments(OpenDirectoryDialogArguments args)
+ : base(args) { }
}
///
diff --git a/MaterialDesignExtensions/Controls/OpenFileControl.cs b/MaterialDesignExtensions/Controls/OpenFileControl.cs
index 609427d9..9b20acfd 100644
--- a/MaterialDesignExtensions/Controls/OpenFileControl.cs
+++ b/MaterialDesignExtensions/Controls/OpenFileControl.cs
@@ -10,6 +10,13 @@
using System.Windows.Controls;
using System.Windows.Input;
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using DirectoryInfo = Pri.LongPath.DirectoryInfo;
+using FileInfo = Pri.LongPath.FileInfo;
+using FileSystemInfo = Pri.LongPath.FileSystemInfo;
+#endif
+
namespace MaterialDesignExtensions.Controls
{
///
@@ -39,16 +46,16 @@ protected override void CurrentFileChangedHandler(string newCurrentFile)
}
}
- protected override void SelectFileSystemEntryCommandHandler(object sender, ExecutedRoutedEventArgs args)
+ protected override void SelectFileSystemEntry(FileSystemInfo fileSystemInfo)
{
- if (args.Parameter != null)
+ if (fileSystemInfo != null)
{
- if (args.Parameter is DirectoryInfo directoryInfo)
+ if (fileSystemInfo is DirectoryInfo directoryInfo)
{
CurrentDirectory = directoryInfo.FullName;
CurrentFile = null;
}
- else if (args.Parameter is FileInfo fileInfo)
+ else if (fileSystemInfo is FileInfo fileInfo)
{
CurrentFile = fileInfo.FullName;
}
diff --git a/MaterialDesignExtensions/Controls/OpenFileDialog.cs b/MaterialDesignExtensions/Controls/OpenFileDialog.cs
index ca443511..bd6ade24 100644
--- a/MaterialDesignExtensions/Controls/OpenFileDialog.cs
+++ b/MaterialDesignExtensions/Controls/OpenFileDialog.cs
@@ -11,6 +11,11 @@
using MaterialDesignExtensions.Converters;
using MaterialDesignExtensions.Model;
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using FileInfo = Pri.LongPath.FileInfo;
+#endif
+
namespace MaterialDesignExtensions.Controls
{
///
@@ -38,29 +43,6 @@ protected override void OpenDirectoryControlFileSelectedHandler(object sender, R
DialogHost.CloseDialogCommand.Execute(new OpenFileDialogResult(false, (args as FileSelectedEventArgs)?.FileInfo), GetDialogHost());
}
- ///
- /// Shows a new .
- ///
- /// The name of the
- /// The width of the dialog (optional)
- /// The heigth of the dialog (optional)
- /// The current directory to show (optional)
- /// Show or hide hidden files in the dialog (optional)
- /// Show or hide system files in the dialog (optional)
- /// Callback after openening the dialog (optional)
- /// Callback after closing the dialog (optional)
- ///
- [Obsolete("Use the overloaded method with OpenFileDialogArguments instead")]
- public static async Task ShowDialogAsync(string dialogHostName, double? width = null, double? height = null,
- string currentDirectory = null,
- bool showHiddenFilesAndDirectories = false, bool showSystemFilesAndDirectories = false,
- DialogOpenedEventHandler openedHandler = null, DialogClosingEventHandler closingHandler = null)
- {
- OpenFileDialog dialog = InitDialog(width, height, currentDirectory, null, -1, showHiddenFilesAndDirectories, showSystemFilesAndDirectories);
-
- return await DialogHost.Show(dialog, dialogHostName, openedHandler, closingHandler) as OpenFileDialogResult;
- }
-
///
/// Shows a new .
///
@@ -76,35 +58,14 @@ public static async Task ShowDialogAsync(string dialogHost
args.Filters,
args.FilterIndex,
args.ShowHiddenFilesAndDirectories,
- args.ShowSystemFilesAndDirectories
+ args.ShowSystemFilesAndDirectories,
+ args.SwitchPathPartsAsButtonsEnabled,
+ args.PathPartsAsButtons
);
return await DialogHost.Show(dialog, dialogHostName, args.OpenedHandler, args.ClosingHandler) as OpenFileDialogResult;
}
- ///
- /// Shows a new .
- ///
- /// The
- /// The width of the dialog (optional)
- /// The heigth of the dialog (optional)
- /// The current directory to show (optional)
- /// Show or hide hidden files in the dialog (optional)
- /// Show or hide system files in the dialog (optional)
- /// Callback after openening the dialog (optional)
- /// Callback after closing the dialog (optional)
- ///
- [Obsolete("Use the overloaded method with OpenFileDialogArguments instead")]
- public static async Task ShowDialogAsync(DialogHost dialogHost, double? width = null, double? height = null,
- string currentDirectory = null,
- bool showHiddenFilesAndDirectories = false, bool showSystemFilesAndDirectories = false,
- DialogOpenedEventHandler openedHandler = null, DialogClosingEventHandler closingHandler = null)
- {
- OpenFileDialog dialog = InitDialog(width, height, currentDirectory, null, -1, showHiddenFilesAndDirectories, showSystemFilesAndDirectories);
-
- return await dialogHost.ShowDialog(dialog, openedHandler, closingHandler) as OpenFileDialogResult;
- }
-
///
/// Shows a new .
///
@@ -120,7 +81,9 @@ public static async Task ShowDialogAsync(DialogHost dialog
args.Filters,
args.FilterIndex,
args.ShowHiddenFilesAndDirectories,
- args.ShowSystemFilesAndDirectories
+ args.ShowSystemFilesAndDirectories,
+ args.SwitchPathPartsAsButtonsEnabled,
+ args.PathPartsAsButtons
);
return await dialogHost.ShowDialog(dialog, args.OpenedHandler, args.ClosingHandler) as OpenFileDialogResult;
@@ -129,10 +92,11 @@ public static async Task ShowDialogAsync(DialogHost dialog
private static OpenFileDialog InitDialog(double? width, double? height,
string currentDirectory,
string filters, int filterIndex,
- bool showHiddenFilesAndDirectories, bool showSystemFilesAndDirectories)
+ bool showHiddenFilesAndDirectories, bool showSystemFilesAndDirectories,
+ bool switchPathPartsAsButtonsEnabled, bool pathPartsAsButtons)
{
OpenFileDialog dialog = new OpenFileDialog();
- InitDialog(dialog, width, height, currentDirectory, showHiddenFilesAndDirectories, showSystemFilesAndDirectories);
+ InitDialog(dialog, width, height, currentDirectory, showHiddenFilesAndDirectories, showSystemFilesAndDirectories, switchPathPartsAsButtonsEnabled, pathPartsAsButtons);
dialog.Filters = new FileFiltersTypeConverter().ConvertFrom(null, null, filters) as IList;
dialog.FilterIndex = filterIndex;
@@ -149,6 +113,13 @@ public class OpenFileDialogArguments : FileDialogArguments
/// Creates a new .
///
public OpenFileDialogArguments() : base() { }
+
+ ///
+ /// Copy constructor
+ ///
+ ///
+ public OpenFileDialogArguments(OpenFileDialogArguments args)
+ : base(args) { }
}
///
diff --git a/MaterialDesignExtensions/Controls/OpenMultipleDirectoriesControl.cs b/MaterialDesignExtensions/Controls/OpenMultipleDirectoriesControl.cs
new file mode 100644
index 00000000..40092de0
--- /dev/null
+++ b/MaterialDesignExtensions/Controls/OpenMultipleDirectoriesControl.cs
@@ -0,0 +1,271 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+
+using MaterialDesignThemes.Wpf;
+
+using MaterialDesignExtensions.Commands.Internal;
+using MaterialDesignExtensions.Controllers;
+using MaterialDesignExtensions.Model;
+
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using DirectoryInfo = Pri.LongPath.DirectoryInfo;
+#endif
+
+namespace MaterialDesignExtensions.Controls
+{
+ ///
+ /// A control for selecting multiple directories.
+ ///
+ public class OpenMultipleDirectoriesControl : FileSystemControl
+ {
+ private const string SelectionItemsControlName = "selectionItemsControl";
+ private const string EmptySelectionTextBlockName = "emptySelectionTextBlock";
+
+ ///
+ /// An event raised by selecting directories to open.
+ ///
+ public static readonly RoutedEvent DirectoriesSelectedEvent = EventManager.RegisterRoutedEvent(
+ nameof(DirectoriesSelected), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(OpenMultipleDirectoriesControl));
+
+ ///
+ /// An event raised by selecting directories to open.
+ ///
+ public event RoutedEventHandler DirectoriesSelected
+ {
+ add
+ {
+ AddHandler(DirectoriesSelectedEvent, value);
+ }
+
+ remove
+ {
+ RemoveHandler(DirectoriesSelectedEvent, value);
+ }
+ }
+
+ ///
+ /// An command called by selecting directories to open.
+ ///
+ public static readonly DependencyProperty DirectoriesSelectedCommandProperty = DependencyProperty.Register(
+ nameof(DirectoriesSelectedCommand), typeof(ICommand), typeof(OpenMultipleDirectoriesControl), new PropertyMetadata(null, null));
+
+ ///
+ /// An command called by selecting directories to open.
+ ///
+ public ICommand DirectoriesSelectedCommand
+ {
+ get
+ {
+ return (ICommand)GetValue(DirectoriesSelectedCommandProperty);
+ }
+
+ set
+ {
+ SetValue(DirectoriesSelectedCommandProperty, value);
+ }
+ }
+
+ private ItemsControl m_selectionItemsControl;
+ private TextBlock m_emptySelectionTextBlock;
+
+ static OpenMultipleDirectoriesControl()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(OpenMultipleDirectoriesControl), new FrameworkPropertyMetadata(typeof(OpenMultipleDirectoriesControl)));
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ public OpenMultipleDirectoriesControl()
+ : base()
+ {
+
+ m_selectionItemsControl = null;
+ m_emptySelectionTextBlock = null;
+
+ CommandBindings.Add(new CommandBinding(FileSystemControlCommands.OpenSelectionDrawerCommand, OpenSelectionDrawerCommandHandler));
+ CommandBindings.Add(new CommandBinding(FileSystemControlCommands.SelectDirectoryCommand, SelectDirectoryCommandHandler));
+ CommandBindings.Add(new CommandBinding(FileSystemControlCommands.SelectMultipleDirectoriesCommand, SelectMultipleDirectoriesCommandHandler, CanExecuteSelectMultipleDirectoriesCommand));
+ }
+
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ m_selectionItemsControl = Template.FindName(SelectionItemsControlName, this) as ItemsControl;
+
+ m_emptySelectionTextBlock = Template.FindName(EmptySelectionTextBlockName, this) as TextBlock;
+
+ UpdateSelectionList();
+
+ UpdateSelectionListVisibility();
+ }
+
+ private void OpenSelectionDrawerCommandHandler(object sender, ExecutedRoutedEventArgs args)
+ {
+ DrawerHost drawerHost = (DrawerHost)Template.FindName(DrawerHostName, this);
+ drawerHost.IsRightDrawerOpen = true;
+ }
+
+ private void SelectDirectoryCommandHandler(object sender, ExecutedRoutedEventArgs args)
+ {
+ if (args.Parameter != null)
+ {
+ if (args.Parameter is DirectoryInfo directoryInfo)
+ {
+ m_controller.SelectOrRemoveDirectoryForMultipleSelection(directoryInfo);
+ }
+ }
+ }
+
+ private void SelectMultipleDirectoriesCommandHandler(object sender, ExecutedRoutedEventArgs args)
+ {
+ DirectoriesSelectedEventArgs eventArgs = new DirectoriesSelectedEventArgs(DirectoriesSelectedEvent, this, m_controller.SelectedDirectories.ToList());
+ RaiseEvent(eventArgs);
+
+ if (DirectoriesSelectedCommand != null && DirectoriesSelectedCommand.CanExecute(eventArgs.DirectoryInfoList))
+ {
+ DirectoriesSelectedCommand.Execute(eventArgs.DirectoryInfoList);
+ }
+ }
+
+ private void CanExecuteSelectMultipleDirectoriesCommand(object sender, CanExecuteRoutedEventArgs args)
+ {
+ args.CanExecute = m_controller != null && m_controller.SelectedDirectories != null && m_controller.SelectedDirectories.Any();
+ }
+
+ protected override void ControllerPropertyChangedHandler(object sender, PropertyChangedEventArgs args)
+ {
+ if (sender == m_controller)
+ {
+ if (args.PropertyName == nameof(FileSystemController.Directories))
+ {
+ m_fileSystemEntryItemsControl.ItemsSource = GetFileSystemEntryItems();
+
+ if (m_controller.Directories != null && m_controller.Directories.Any())
+ {
+ ItemsScrollViewer?.ScrollToTop();
+ }
+
+ UpdateListVisibility();
+ }
+ else if (args.PropertyName == nameof(FileSystemController.SelectedDirectories))
+ {
+ UpdateSelection();
+ UpdateSelectionList();
+
+ UpdateSelectionListVisibility();
+ }
+ }
+
+ base.ControllerPropertyChangedHandler(sender, args);
+ }
+
+ protected override IEnumerable GetFileSystemEntryItems()
+ {
+ ISet directoryNames = new HashSet(m_controller.SelectedDirectories.Select(directoryInfo => directoryInfo.FullName.ToLower()));
+
+ return m_controller.Directories
+ .Select(directory =>
+ {
+ bool isSelected = directoryNames.Contains(directory.FullName.ToLower());
+
+ return new DirectoryInfoItem() { IsSelected = isSelected, Value = directory };
+ })
+ // call ToList() to run the LINQ expression immediately, otherwise WPF will behave some kind of strange
+ .ToList();
+ }
+
+ protected override void UpdateSelection()
+ {
+ IEnumerable items = m_fileSystemEntryItemsControl?.ItemsSource;
+
+ if (items != null)
+ {
+ ISet directoryNames = new HashSet(m_controller.SelectedDirectories.Select(directoryInfo => directoryInfo.FullName.ToLower()));
+
+ foreach (object item in items)
+ {
+ if (item is DirectoryInfoItem directoryInfoItem)
+ {
+ directoryInfoItem.IsSelected = directoryNames.Contains(directoryInfoItem.Value.FullName.ToLower());
+ }
+ }
+ }
+ }
+
+ private void UpdateSelectionList()
+ {
+ m_selectionItemsControl.ItemsSource = m_controller.SelectedDirectories
+ .OrderBy(directory => directory.Name.ToLower())
+ .ThenBy(directory => directory.Parent.FullName.ToLower());
+ }
+
+ ///
+ /// Shows the list of the selected directories or hides it if it is empty. A message will be show instead of an empty list.
+ ///
+ protected void UpdateSelectionListVisibility()
+ {
+ if (m_selectionItemsControl != null
+ && m_selectionItemsControl.ItemsSource != null
+ && m_selectionItemsControl.ItemsSource.GetEnumerator().MoveNext())
+ {
+ m_selectionItemsControl.Visibility = Visibility.Visible;
+ m_emptySelectionTextBlock.Visibility = Visibility.Collapsed;
+ }
+ else
+ {
+ m_selectionItemsControl.Visibility = Visibility.Collapsed;
+ m_emptySelectionTextBlock.Visibility = Visibility.Visible;
+ }
+ }
+ }
+
+ ///
+ /// The arguments for the event.
+ ///
+ public class DirectoriesSelectedEventArgs : RoutedEventArgs
+ {
+ ///
+ /// The selected directories as .
+ ///
+ public List DirectoryInfoList { get; private set; }
+
+ ///
+ /// The selected directories as full filename string.
+ ///
+ public List Directories
+ {
+ get
+ {
+ return DirectoryInfoList
+ .Select(directoryInfo => directoryInfo.FullName)
+ .ToList();
+ }
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ ///
+ /// The source object
+ /// The list of selected directories
+ public DirectoriesSelectedEventArgs(RoutedEvent routedEvent, object source, List directoryInfoList)
+ : base(routedEvent, source)
+ {
+ DirectoryInfoList = directoryInfoList
+ .OrderBy(directoryInfo => directoryInfo.FullName.ToLower())
+ .ToList();
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Controls/OpenMultipleDirectoriesDialog.cs b/MaterialDesignExtensions/Controls/OpenMultipleDirectoriesDialog.cs
new file mode 100644
index 00000000..0ad4b7cd
--- /dev/null
+++ b/MaterialDesignExtensions/Controls/OpenMultipleDirectoriesDialog.cs
@@ -0,0 +1,186 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+using MaterialDesignThemes.Wpf;
+
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using DirectoryInfo = Pri.LongPath.DirectoryInfo;
+#endif
+
+namespace MaterialDesignExtensions.Controls
+{
+ ///
+ /// A dialog for selecting multiple directories.
+ ///
+ public class OpenMultipleDirectoriesDialog : FileSystemDialog
+ {
+ private static readonly string OpenMultipleDirectoriesControlName = "openMultipleDirectoriesControl";
+
+ private OpenMultipleDirectoriesControl m_openMultipleDirectoriesControl;
+
+ static OpenMultipleDirectoriesDialog()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(OpenMultipleDirectoriesDialog), new FrameworkPropertyMetadata(typeof(OpenMultipleDirectoriesDialog)));
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ public OpenMultipleDirectoriesDialog()
+ : base()
+ {
+ m_openMultipleDirectoriesControl = null;
+
+ Loaded += LoadedHandler;
+ Unloaded += UnloadedHandler;
+ }
+
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ if (m_openMultipleDirectoriesControl != null)
+ {
+ m_openMultipleDirectoriesControl.Cancel -= CancelHandler;
+ m_openMultipleDirectoriesControl.DirectoriesSelected -= OpenMultipleDirectoriesControlDirectoriesSelectedHandler;
+ }
+
+ m_openMultipleDirectoriesControl = Template.FindName(OpenMultipleDirectoriesControlName, this) as OpenMultipleDirectoriesControl;
+ }
+
+ private void LoadedHandler(object sender, RoutedEventArgs args)
+ {
+ m_openMultipleDirectoriesControl.Cancel += CancelHandler;
+ m_openMultipleDirectoriesControl.DirectoriesSelected += OpenMultipleDirectoriesControlDirectoriesSelectedHandler;
+ }
+
+ private void UnloadedHandler(object sender, RoutedEventArgs args)
+ {
+ m_openMultipleDirectoriesControl.Cancel -= CancelHandler;
+ m_openMultipleDirectoriesControl.DirectoriesSelected -= OpenMultipleDirectoriesControlDirectoriesSelectedHandler;
+ }
+
+ private void CancelHandler(object sender, RoutedEventArgs args)
+ {
+ DialogHost.CloseDialogCommand.Execute(new OpenMultipleDirectoriesDialogResult(true, null), GetDialogHost());
+ }
+
+ private void OpenMultipleDirectoriesControlDirectoriesSelectedHandler(object sender, RoutedEventArgs args)
+ {
+ DialogHost.CloseDialogCommand.Execute(new OpenMultipleDirectoriesDialogResult(false, (args as DirectoriesSelectedEventArgs)?.DirectoryInfoList), GetDialogHost());
+ }
+
+ ///
+ /// Shows a new .
+ ///
+ /// The name of the
+ /// The arguments for the dialog initialization
+ ///
+ public static async Task ShowDialogAsync(string dialogHostName, OpenMultipleDirectoriesDialogArguments args)
+ {
+ OpenMultipleDirectoriesDialog dialog = InitDialog(
+ args.Width,
+ args.Height,
+ args.CurrentDirectory,
+ args.CreateNewDirectoryEnabled,
+ args.ShowHiddenFilesAndDirectories,
+ args.ShowSystemFilesAndDirectories,
+ args.SwitchPathPartsAsButtonsEnabled,
+ args.PathPartsAsButtons
+ );
+
+ return await DialogHost.Show(dialog, dialogHostName, args.OpenedHandler, args.ClosingHandler) as OpenMultipleDirectoriesDialogResult;
+ }
+
+ ///
+ /// Shows a new .
+ ///
+ /// The
+ /// The arguments for the dialog initialization
+ ///
+ public static async Task ShowDialogAsync(DialogHost dialogHost, OpenMultipleDirectoriesDialogArguments args)
+ {
+ OpenMultipleDirectoriesDialog dialog = InitDialog(
+ args.Width,
+ args.Height,
+ args.CurrentDirectory,
+ args.CreateNewDirectoryEnabled,
+ args.ShowHiddenFilesAndDirectories,
+ args.ShowSystemFilesAndDirectories,
+ args.SwitchPathPartsAsButtonsEnabled,
+ args.PathPartsAsButtons
+ );
+
+ return await dialogHost.ShowDialog(dialog, args.OpenedHandler, args.ClosingHandler) as OpenMultipleDirectoriesDialogResult;
+ }
+
+ private static OpenMultipleDirectoriesDialog InitDialog(double? width, double? height,
+ string currentDirectory,
+ bool createNewDirectoryEnabled,
+ bool showHiddenFilesAndDirectories, bool showSystemFilesAndDirectories,
+ bool switchPathPartsAsButtonsEnabled, bool pathPartsAsButtons)
+ {
+ OpenMultipleDirectoriesDialog dialog = new OpenMultipleDirectoriesDialog();
+ InitDialog(dialog, width, height, currentDirectory, showHiddenFilesAndDirectories, showSystemFilesAndDirectories, createNewDirectoryEnabled, switchPathPartsAsButtonsEnabled, pathPartsAsButtons);
+
+ return dialog;
+ }
+ }
+
+ ///
+ /// Arguments to initialize an open multiple directories dialog.
+ ///
+ public class OpenMultipleDirectoriesDialogArguments : FileSystemDialogArguments
+ {
+ ///
+ /// Creates a new .
+ ///
+ public OpenMultipleDirectoriesDialogArguments() : base() { }
+ }
+
+ ///
+ /// The dialog result for .
+ ///
+ public class OpenMultipleDirectoriesDialogResult : FileSystemDialogResult
+ {
+ ///
+ /// The selected directories as .
+ ///
+ public List DirectoryInfoList { get; private set; }
+
+ ///
+ /// The selected directories as full filename string.
+ ///
+ public List Directories
+ {
+ get
+ {
+ return DirectoryInfoList
+ .Select(directoryInfo => directoryInfo.FullName)
+ .ToList();
+ }
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ /// True if the dialog was canceled
+ /// The list of selected directories
+ public OpenMultipleDirectoriesDialogResult(bool canceled, List directoryInfoList)
+ : base(canceled)
+ {
+ if (directoryInfoList != null)
+ {
+ DirectoryInfoList = directoryInfoList
+ .OrderBy(directoryInfo => directoryInfo.FullName.ToLower())
+ .ToList();
+ }
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Controls/OpenMultipleFilesControl.cs b/MaterialDesignExtensions/Controls/OpenMultipleFilesControl.cs
new file mode 100644
index 00000000..69533808
--- /dev/null
+++ b/MaterialDesignExtensions/Controls/OpenMultipleFilesControl.cs
@@ -0,0 +1,450 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+
+using MaterialDesignThemes.Wpf;
+
+using MaterialDesignExtensions.Commands.Internal;
+using MaterialDesignExtensions.Controllers;
+using MaterialDesignExtensions.Converters;
+using MaterialDesignExtensions.Model;
+
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using FileSystemInfo = Pri.LongPath.FileSystemInfo;
+using DirectoryInfo = Pri.LongPath.DirectoryInfo;
+using FileInfo = Pri.LongPath.FileInfo;
+#endif
+
+namespace MaterialDesignExtensions.Controls
+{
+ ///
+ /// A control for selecting multiple files.
+ ///
+ public class OpenMultipleFilesControl : FileSystemControl
+ {
+ private const string FileFiltersComboBoxName = "fileFiltersComboBox";
+ private const string SelectionItemsControlName = "selectionItemsControl";
+ private const string EmptySelectionTextBlockName = "emptySelectionTextBlock";
+
+ ///
+ /// An event raised by selecting files to open.
+ ///
+ public static readonly RoutedEvent FilesSelectedEvent = EventManager.RegisterRoutedEvent(
+ nameof(FilesSelected), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(OpenMultipleFilesControl));
+
+ ///
+ /// An event raised by selecting files to open.
+ ///
+ public event RoutedEventHandler FilesSelected
+ {
+ add
+ {
+ AddHandler(FilesSelectedEvent, value);
+ }
+
+ remove
+ {
+ RemoveHandler(FilesSelectedEvent, value);
+ }
+ }
+
+ ///
+ /// True, to clear the cache during unloading the control.
+ ///
+ public static readonly DependencyProperty ClearCacheOnUnloadProperty = DependencyProperty.Register(
+ nameof(ClearCacheOnUnload), typeof(bool), typeof(OpenMultipleFilesControl), new PropertyMetadata(true));
+
+ ///
+ /// True, to clear the cache during unloading the control.
+ ///
+ public bool ClearCacheOnUnload
+ {
+ get
+ {
+ return (bool)GetValue(ClearCacheOnUnloadProperty);
+ }
+
+ set
+ {
+ SetValue(ClearCacheOnUnloadProperty, value);
+ }
+ }
+
+ ///
+ /// An command called by selecting files to open.
+ ///
+ public static readonly DependencyProperty FilesSelectedCommandProperty = DependencyProperty.Register(
+ nameof(FilesSelectedCommand), typeof(ICommand), typeof(OpenMultipleFilesControl), new PropertyMetadata(null, null));
+
+ ///
+ /// An command called by selecting files to open.
+ ///
+ public ICommand FilesSelectedCommand
+ {
+ get
+ {
+ return (ICommand)GetValue(FilesSelectedCommandProperty);
+ }
+
+ set
+ {
+ SetValue(FilesSelectedCommandProperty, value);
+ }
+ }
+
+ ///
+ /// The possible file filters to select from for applying to the files inside the current directory.
+ /// Strings according to the original .NET API will be converted automatically
+ /// (see https://docs.microsoft.com/de-de/dotnet/api/microsoft.win32.filedialog.filter?view=netframework-4.7.1#Microsoft_Win32_FileDialog_Filter).
+ ///
+ public static readonly DependencyProperty FiltersProperty = DependencyProperty.Register(
+ nameof(Filters), typeof(IList), typeof(OpenMultipleFilesControl), new PropertyMetadata(null, FiltersChangedHandler));
+
+ ///
+ /// The possible file filters to select from for applying to the files inside the current directory.
+ /// Strings according to the original .NET API will be converted automatically
+ /// (see https://docs.microsoft.com/de-de/dotnet/api/microsoft.win32.filedialog.filter?view=netframework-4.7.1#Microsoft_Win32_FileDialog_Filter).
+ ///
+ [TypeConverter(typeof(FileFiltersTypeConverter))]
+ public IList Filters
+ {
+ get
+ {
+ return (IList)GetValue(FiltersProperty);
+ }
+
+ set
+ {
+ SetValue(FiltersProperty, value);
+ }
+ }
+
+ ///
+ /// The index of the file filter to apply to the files inside the current directory.
+ ///
+ public static readonly DependencyProperty FilterIndexProperty = DependencyProperty.Register(
+ nameof(FilterIndex), typeof(int), typeof(OpenMultipleFilesControl), new PropertyMetadata(0, FiltersChangedHandler));
+
+ ///
+ /// The index of the file filter to apply to the files inside the current directory.
+ ///
+ public int FilterIndex
+ {
+ get
+ {
+ return (int)GetValue(FilterIndexProperty);
+ }
+
+ set
+ {
+ SetValue(FilterIndexProperty, value);
+ }
+ }
+
+ ///
+ /// Shows folders and files as a group with a header.
+ ///
+ public static readonly DependencyProperty GroupFoldersAndFilesProperty = DependencyProperty.Register(
+ nameof(GroupFoldersAndFiles), typeof(bool), typeof(OpenMultipleFilesControl), new PropertyMetadata(true));
+
+ ///
+ /// Shows folders and files as a group with a header.
+ ///
+ public bool GroupFoldersAndFiles
+ {
+ get
+ {
+ return (bool)GetValue(GroupFoldersAndFilesProperty);
+ }
+
+ set
+ {
+ SetValue(GroupFoldersAndFilesProperty, value);
+ }
+ }
+
+ private ComboBox m_fileFiltersComboBox;
+ private ItemsControl m_selectionItemsControl;
+ private TextBlock m_emptySelectionTextBlock;
+
+ static OpenMultipleFilesControl()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(OpenMultipleFilesControl), new FrameworkPropertyMetadata(typeof(OpenMultipleFilesControl)));
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ public OpenMultipleFilesControl()
+ : base()
+ {
+ m_fileFiltersComboBox = null;
+ m_selectionItemsControl = null;
+ m_emptySelectionTextBlock = null;
+
+ CommandBindings.Add(new CommandBinding(FileSystemControlCommands.OpenSelectionDrawerCommand, OpenSelectionDrawerCommandHandler));
+ CommandBindings.Add(new CommandBinding(FileSystemControlCommands.SelectFileCommand, SelectFileCommandHandler));
+ CommandBindings.Add(new CommandBinding(FileSystemControlCommands.SelectMultipleFilesCommand, SelectMultipleFilesCommandHandler, CanExecuteSelectMultipleFilesCommand));
+ }
+
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ m_fileFiltersComboBox = Template.FindName(FileFiltersComboBoxName, this) as ComboBox;
+ m_fileFiltersComboBox.ItemsSource = Filters;
+
+ m_selectionItemsControl = Template.FindName(SelectionItemsControlName, this) as ItemsControl;
+
+ m_emptySelectionTextBlock = Template.FindName(EmptySelectionTextBlockName, this) as TextBlock;
+
+ UpdateFileFiltersVisibility();
+ UpdateSelectionList();
+
+ UpdateSelectionListVisibility();
+ }
+
+ protected override void UnloadedHandler(object sender, RoutedEventArgs args)
+ {
+ if (ClearCacheOnUnload)
+ {
+ BitmapImageHelper.ClearCache();
+ }
+
+ base.UnloadedHandler(sender, args);
+ }
+
+ private void OpenSelectionDrawerCommandHandler(object sender, ExecutedRoutedEventArgs args)
+ {
+ DrawerHost drawerHost = (DrawerHost)Template.FindName(DrawerHostName, this);
+ drawerHost.IsRightDrawerOpen = true;
+ }
+
+ private void SelectFileCommandHandler(object sender, ExecutedRoutedEventArgs args)
+ {
+ try
+ {
+ if (args.Parameter != null)
+ {
+ if (args.Parameter is FileInfo fileInfo)
+ {
+ m_controller.SelectOrRemoveFileForMultipleSelection(fileInfo);
+ }
+ }
+ }
+ catch (PathTooLongException)
+ {
+ SnackbarMessageQueue.Enqueue(Localization.Strings.LongPathsAreNotSupported);
+ }
+ }
+
+ private void SelectMultipleFilesCommandHandler(object sender, ExecutedRoutedEventArgs args)
+ {
+ FilesSelectedEventArgs eventArgs = new FilesSelectedEventArgs(FilesSelectedEvent, this, m_controller.SelectedFiles.ToList());
+ RaiseEvent(eventArgs);
+
+ if (FilesSelectedCommand != null && FilesSelectedCommand.CanExecute(eventArgs.FileInfoList))
+ {
+ FilesSelectedCommand.Execute(eventArgs.FileInfoList);
+ }
+ }
+
+ private void CanExecuteSelectMultipleFilesCommand(object sender, CanExecuteRoutedEventArgs args)
+ {
+ args.CanExecute = m_controller != null && m_controller.SelectedFiles != null && m_controller.SelectedFiles.Any();
+ }
+
+ private static void FiltersChangedHandler(DependencyObject obj, DependencyPropertyChangedEventArgs args)
+ {
+ if (args.Property == FiltersProperty)
+ {
+ (obj as OpenMultipleFilesControl)?.FileFiltersChangedHandler(args.NewValue as IList);
+ }
+ else if (args.Property == FilterIndexProperty)
+ {
+ (obj as OpenMultipleFilesControl)?.FileFiltersChangedHandler((int)args.NewValue);
+ }
+ }
+
+ private void FileFiltersChangedHandler(IList newFilters)
+ {
+ FileFiltersChangedHandler(newFilters, FilterIndex);
+ }
+
+ private void FileFiltersChangedHandler(int newFilterIndex)
+ {
+ FileFiltersChangedHandler(Filters, newFilterIndex);
+ }
+
+ private void FileFiltersChangedHandler(IList newFilters, int newFilterIndex)
+ {
+ IFileFilter fileFilter = null;
+
+ if (newFilters != null && newFilterIndex >= 0 && newFilterIndex < newFilters.Count)
+ {
+ fileFilter = newFilters[FilterIndex];
+ }
+
+ m_controller.SetFileFilter(newFilters, fileFilter);
+ }
+
+ protected override void ControllerPropertyChangedHandler(object sender, PropertyChangedEventArgs args)
+ {
+ if (sender == m_controller)
+ {
+ if (args.PropertyName == nameof(FileSystemController.DirectoriesAndFiles))
+ {
+ List items = m_controller.DirectoriesAndFiles;
+ m_fileSystemEntryItemsControl.ItemsSource = GetFileSystemEntryItems();
+
+ if (items != null && items.Any())
+ {
+ ItemsScrollViewer?.ScrollToTop();
+ }
+
+ UpdateListVisibility();
+ }
+ else if (args.PropertyName == nameof(FileSystemController.FileFilters))
+ {
+ Filters = m_controller.FileFilters;
+ m_fileFiltersComboBox.ItemsSource = m_controller.FileFilters;
+
+ UpdateFileFiltersVisibility();
+ }
+ else if (args.PropertyName == nameof(FileSystemController.FileFilterToApply))
+ {
+ int filterIndex = -1;
+
+ if (m_controller.FileFilterToApply != null && m_controller.FileFilters != null)
+ {
+ for (int i = 0; i < m_controller.FileFilters.Count && filterIndex == -1; i++)
+ {
+ if (m_controller.FileFilters[i] == m_controller.FileFilterToApply)
+ {
+ filterIndex = i;
+ }
+ }
+ }
+
+ FilterIndex = filterIndex;
+ }
+ else if (args.PropertyName == nameof(FileSystemController.SelectedFiles))
+ {
+ UpdateSelection();
+ UpdateSelectionList();
+ UpdateSelectionListVisibility();
+ }
+ }
+
+ base.ControllerPropertyChangedHandler(sender, args);
+ }
+
+ protected override IEnumerable GetFileSystemEntryItems()
+ {
+ ISet fileNames = new HashSet(m_controller.SelectedFiles.Select(fileInfo => fileInfo.FullName.ToLower()));
+
+ return FileControlHelper.GetFileSystemEntryItems(
+ m_controller.DirectoriesAndFiles,
+ m_controller,
+ GroupFoldersAndFiles,
+ fileInfo => fileNames.Contains(fileInfo.FullName.ToLower())
+ );
+ }
+
+ protected void UpdateFileFiltersVisibility()
+ {
+ FileControlHelper.UpdateFileFiltersVisibility(m_fileFiltersComboBox);
+ }
+
+ protected override void UpdateSelection()
+ {
+ IEnumerable items = m_fileSystemEntryItemsControl?.ItemsSource;
+
+ if (items != null)
+ {
+ ISet fileNames = new HashSet(m_controller.SelectedFiles.Select(fileInfo => fileInfo.FullName.ToLower()));
+
+ foreach (object item in items)
+ {
+ if (item is FileInfoItem fileInfoItem)
+ {
+ fileInfoItem.IsSelected = fileNames.Contains(fileInfoItem.Value.FullName.ToLower());
+ }
+ }
+ }
+ }
+
+ private void UpdateSelectionList()
+ {
+ m_selectionItemsControl.ItemsSource = m_controller.SelectedFiles
+ .OrderBy(file => file.Name.ToLower())
+ .ThenBy(file => file.Directory.FullName.ToLower());
+ }
+
+ ///
+ /// Shows the list of the selected directories or hides it if it is empty. A message will be show instead of an empty list.
+ ///
+ protected void UpdateSelectionListVisibility()
+ {
+ if (m_selectionItemsControl != null
+ && m_selectionItemsControl.ItemsSource != null
+ && m_selectionItemsControl.ItemsSource.GetEnumerator().MoveNext())
+ {
+ m_selectionItemsControl.Visibility = Visibility.Visible;
+ m_emptySelectionTextBlock.Visibility = Visibility.Collapsed;
+ }
+ else
+ {
+ m_selectionItemsControl.Visibility = Visibility.Collapsed;
+ m_emptySelectionTextBlock.Visibility = Visibility.Visible;
+ }
+ }
+ }
+
+ ///
+ /// The arguments for the event.
+ ///
+ public class FilesSelectedEventArgs : RoutedEventArgs
+ {
+ ///
+ /// The selected files as .
+ ///
+ public List FileInfoList { get; private set; }
+
+ ///
+ /// The selected files as full filename string.
+ ///
+ public List Files
+ {
+ get
+ {
+ return FileInfoList
+ .Select(fileInfo => fileInfo.FullName)
+ .ToList();
+ }
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ ///
+ /// The source object
+ /// The list selected files
+ public FilesSelectedEventArgs(RoutedEvent routedEvent, object source, List fileInfoList)
+ : base(routedEvent, source)
+ {
+ FileInfoList = fileInfoList
+ .OrderBy(directoryInfo => directoryInfo.FullName.ToLower())
+ .ToList();
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Controls/OpenMultipleFilesDialog.cs b/MaterialDesignExtensions/Controls/OpenMultipleFilesDialog.cs
new file mode 100644
index 00000000..efb11248
--- /dev/null
+++ b/MaterialDesignExtensions/Controls/OpenMultipleFilesDialog.cs
@@ -0,0 +1,261 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+using MaterialDesignThemes.Wpf;
+
+using MaterialDesignExtensions.Converters;
+using MaterialDesignExtensions.Model;
+
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using FileInfo = Pri.LongPath.FileInfo;
+#endif
+
+namespace MaterialDesignExtensions.Controls
+{
+ ///
+ /// A dialog for selecting multiple files.
+ ///
+ public class OpenMultipleFilesDialog : FileSystemDialog
+ {
+ private static readonly string OpenMultipleFilesControlName = "openMultipleFilesControl";
+
+ ///
+ /// The possible file filters to select from for applying to the files inside the current directory.
+ /// Strings according to the original .NET API will be converted automatically
+ /// (see https://docs.microsoft.com/de-de/dotnet/api/microsoft.win32.filedialog.filter?view=netframework-4.7.1#Microsoft_Win32_FileDialog_Filter).
+ ///
+ public static readonly DependencyProperty FiltersProperty = DependencyProperty.Register(
+ nameof(Filters), typeof(IList), typeof(OpenMultipleFilesDialog), new PropertyMetadata(null));
+
+ ///
+ /// The possible file filters to select from for applying to the files inside the current directory.
+ /// Strings according to the original .NET API will be converted automatically
+ /// (see https://docs.microsoft.com/de-de/dotnet/api/microsoft.win32.filedialog.filter?view=netframework-4.7.1#Microsoft_Win32_FileDialog_Filter).
+ ///
+ [TypeConverter(typeof(FileFiltersTypeConverter))]
+ public IList Filters
+ {
+ get
+ {
+ return (IList)GetValue(FiltersProperty);
+ }
+
+ set
+ {
+ SetValue(FiltersProperty, value);
+ }
+ }
+
+ ///
+ /// The index of the file filter to apply to the files inside the current directory.
+ ///
+ public static readonly DependencyProperty FilterIndexProperty = DependencyProperty.Register(
+ nameof(FilterIndex), typeof(int), typeof(OpenMultipleFilesDialog), new PropertyMetadata(0));
+
+ ///
+ /// The index of the file filter to apply to the files inside the current directory.
+ ///
+ public int FilterIndex
+ {
+ get
+ {
+ return (int)GetValue(FilterIndexProperty);
+ }
+
+ set
+ {
+ SetValue(FilterIndexProperty, value);
+ }
+ }
+
+ private OpenMultipleFilesControl m_openMultipleFilesControl;
+
+ static OpenMultipleFilesDialog()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(OpenMultipleFilesDialog), new FrameworkPropertyMetadata(typeof(OpenMultipleFilesDialog)));
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ public OpenMultipleFilesDialog()
+ : base()
+ {
+ m_openMultipleFilesControl = null;
+
+ Loaded += LoadedHandler;
+ Unloaded += UnloadedHandler;
+ }
+
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ if (m_openMultipleFilesControl != null)
+ {
+ m_openMultipleFilesControl.Cancel -= CancelHandler;
+ m_openMultipleFilesControl.FilesSelected -= OpenMultipleFilesControlFilesSelectedHandler;
+ }
+
+ m_openMultipleFilesControl = Template.FindName(OpenMultipleFilesControlName, this) as OpenMultipleFilesControl;
+ }
+
+ private void LoadedHandler(object sender, RoutedEventArgs args)
+ {
+ m_openMultipleFilesControl.Cancel += CancelHandler;
+ m_openMultipleFilesControl.FilesSelected += OpenMultipleFilesControlFilesSelectedHandler;
+ }
+
+ private void UnloadedHandler(object sender, RoutedEventArgs args)
+ {
+ m_openMultipleFilesControl.Cancel -= CancelHandler;
+ m_openMultipleFilesControl.FilesSelected -= OpenMultipleFilesControlFilesSelectedHandler;
+ }
+
+ private void CancelHandler(object sender, RoutedEventArgs args)
+ {
+ DialogHost.CloseDialogCommand.Execute(new OpenMultipleFilesDialogResult(true, null), GetDialogHost());
+ }
+
+ private void OpenMultipleFilesControlFilesSelectedHandler(object sender, RoutedEventArgs args)
+ {
+ DialogHost.CloseDialogCommand.Execute(new OpenMultipleFilesDialogResult(false, (args as FilesSelectedEventArgs)?.FileInfoList), GetDialogHost());
+ }
+
+ ///
+ /// Shows a new .
+ ///
+ /// The name of the
+ /// The arguments for the dialog initialization
+ ///
+ public static async Task ShowDialogAsync(string dialogHostName, OpenMultipleFilesDialogArguments args)
+ {
+ OpenMultipleFilesDialog dialog = InitDialog(
+ args.Width,
+ args.Height,
+ args.CurrentDirectory,
+ args.Filters,
+ args.FilterIndex,
+ args.ShowHiddenFilesAndDirectories,
+ args.ShowSystemFilesAndDirectories,
+ args.SwitchPathPartsAsButtonsEnabled,
+ args.PathPartsAsButtons
+ );
+
+ return await DialogHost.Show(dialog, dialogHostName, args.OpenedHandler, args.ClosingHandler) as OpenMultipleFilesDialogResult;
+ }
+
+ ///
+ /// Shows a new .
+ ///
+ /// The
+ /// The arguments for the dialog initialization
+ ///
+ public static async Task ShowDialogAsync(DialogHost dialogHost, OpenMultipleFilesDialogArguments args)
+ {
+ OpenMultipleFilesDialog dialog = InitDialog(
+ args.Width,
+ args.Height,
+ args.CurrentDirectory,
+ args.Filters,
+ args.FilterIndex,
+ args.ShowHiddenFilesAndDirectories,
+ args.ShowSystemFilesAndDirectories,
+ args.SwitchPathPartsAsButtonsEnabled,
+ args.PathPartsAsButtons
+ );
+
+ return await dialogHost.ShowDialog(dialog, args.OpenedHandler, args.ClosingHandler) as OpenMultipleFilesDialogResult;
+ }
+
+ private static OpenMultipleFilesDialog InitDialog(double? width, double? height,
+ string currentDirectory,
+ string filters, int filterIndex,
+ bool showHiddenFilesAndDirectories, bool showSystemFilesAndDirectories,
+ bool switchPathPartsAsButtonsEnabled, bool pathPartsAsButtons)
+ {
+ OpenMultipleFilesDialog dialog = new OpenMultipleFilesDialog();
+ InitDialog(dialog, width, height, currentDirectory, showHiddenFilesAndDirectories, showSystemFilesAndDirectories, switchPathPartsAsButtonsEnabled, pathPartsAsButtons);
+ dialog.Filters = new FileFiltersTypeConverter().ConvertFrom(null, null, filters) as IList;
+ dialog.FilterIndex = filterIndex;
+
+ return dialog;
+ }
+ }
+
+ ///
+ /// Arguments to initialize an open multiple files dialog.
+ ///
+ public class OpenMultipleFilesDialogArguments : FileSystemDialogArguments
+ {
+ ///
+ /// The possible file filters to select from for applying to the files inside the current directory.
+ /// Strings according to the original .NET API will be converted automatically
+ /// (see https://docs.microsoft.com/de-de/dotnet/api/microsoft.win32.filedialog.filter?view=netframework-4.7.1#Microsoft_Win32_FileDialog_Filter).
+ ///
+ public string Filters { get; set; }
+
+ ///
+ /// The index of the file filter to apply to the files inside the current directory.
+ ///
+ public int FilterIndex { get; set; }
+
+ ///
+ /// Creates a new .
+ ///
+ public OpenMultipleFilesDialogArguments()
+ : base()
+ {
+ Filters = null;
+ FilterIndex = 0;
+ }
+ }
+
+ ///
+ /// The dialog result for .
+ ///
+ public class OpenMultipleFilesDialogResult : FileSystemDialogResult
+ {
+
+ ///
+ /// The selected files as .
+ ///
+ public List FileInfoList { get; private set; }
+
+ ///
+ /// The selected files as full filename string.
+ ///
+ public List Files
+ {
+ get
+ {
+ return FileInfoList
+ .Select(fileInfo => fileInfo.FullName)
+ .ToList();
+ }
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ /// True if the dialog was canceled
+ /// The list of selected files
+ public OpenMultipleFilesDialogResult(bool canceled, List fileInfoList)
+ : base(canceled)
+ {
+ if (fileInfoList != null)
+ {
+ FileInfoList = fileInfoList
+ .OrderBy(fileInfo => fileInfo.FullName.ToLower())
+ .ToList();
+ }
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Controls/OversizedNumberSpinner.cs b/MaterialDesignExtensions/Controls/OversizedNumberSpinner.cs
index c6c9dabf..2bbe03e5 100644
--- a/MaterialDesignExtensions/Controls/OversizedNumberSpinner.cs
+++ b/MaterialDesignExtensions/Controls/OversizedNumberSpinner.cs
@@ -7,6 +7,8 @@
using System.Windows.Controls;
using System.Windows.Input;
+using MaterialDesignExtensions.Commands.Internal;
+
namespace MaterialDesignExtensions.Controls
{
///
@@ -17,23 +19,14 @@ public class OversizedNumberSpinner : Control
private const string ValueTextBoxName = "ValueTextBox";
///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand EditValueCommand = new RoutedCommand();
-
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand MinusCommand = new RoutedCommand();
-
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ /// True, if the editing mode with the textbox is active.
///
- public static readonly RoutedCommand PlusCommand = new RoutedCommand();
-
public static readonly DependencyProperty IsEditingProperty = DependencyProperty.Register(
nameof(IsEditing), typeof(bool), typeof(OversizedNumberSpinner), new PropertyMetadata(false));
+ ///
+ /// True, if the editing mode with the textbox is active.
+ ///
private bool IsEditing
{
get
@@ -47,9 +40,15 @@ private bool IsEditing
}
}
+ ///
+ /// The minimum value of the .
+ ///
public static readonly DependencyProperty MinProperty = DependencyProperty.Register(
nameof(Min), typeof(int), typeof(OversizedNumberSpinner), new PropertyMetadata(0));
+ ///
+ /// The minimum value of the .
+ ///
public int Min
{
get
@@ -63,9 +62,15 @@ public int Min
}
}
+ ///
+ /// The maximum value of the .
+ ///
public static readonly DependencyProperty MaxProperty = DependencyProperty.Register(
nameof(Max), typeof(int), typeof(OversizedNumberSpinner), new PropertyMetadata(5));
+ ///
+ /// The maximum value of the .
+ ///
public int Max
{
get
@@ -79,9 +84,15 @@ public int Max
}
}
+ ///
+ /// The current value of the .
+ ///
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
nameof(Value), typeof(int), typeof(OversizedNumberSpinner), new PropertyMetadata(1, ValuePropertyChangedCallback));
+ ///
+ /// The current value of the .
+ ///
public int Value
{
get
@@ -102,12 +113,15 @@ static OversizedNumberSpinner()
DefaultStyleKeyProperty.OverrideMetadata(typeof(OversizedNumberSpinner), new FrameworkPropertyMetadata(typeof(OversizedNumberSpinner)));
}
+ ///
+ /// Creates a new .
+ ///
public OversizedNumberSpinner()
: base()
{
- CommandBindings.Add(new CommandBinding(EditValueCommand, EditValueCommandHandler));
- CommandBindings.Add(new CommandBinding(MinusCommand, MinusCommandHandler));
- CommandBindings.Add(new CommandBinding(PlusCommand, PlusCommandHandler));
+ CommandBindings.Add(new CommandBinding(OversizedNumberSpinnerCommands.EditValueCommand, EditValueCommandHandler));
+ CommandBindings.Add(new CommandBinding(OversizedNumberSpinnerCommands.MinusCommand, MinusCommandHandler));
+ CommandBindings.Add(new CommandBinding(OversizedNumberSpinnerCommands.PlusCommand, PlusCommandHandler));
Loaded += LoadedHandler;
Unloaded += UnloadedHandler;
@@ -128,20 +142,35 @@ public override void OnApplyTemplate()
private void LoadedHandler(object sender, RoutedEventArgs args)
{
- m_valueTextBox.LostFocus += LostFocusHandler;
- m_valueTextBox.KeyUp += KeyUpHandler;
+ if (m_valueTextBox != null)
+ {
+ m_valueTextBox.LostFocus += LostFocusHandler;
+ m_valueTextBox.KeyUp += KeyUpHandler;
+ }
}
private void UnloadedHandler(object sender, RoutedEventArgs args)
{
- m_valueTextBox.LostFocus -= LostFocusHandler;
- m_valueTextBox.KeyUp -= KeyUpHandler;
+ if (m_valueTextBox != null)
+ {
+ m_valueTextBox.LostFocus -= LostFocusHandler;
+ m_valueTextBox.KeyUp -= KeyUpHandler;
+ }
}
private void EditValueCommandHandler(object sender, ExecutedRoutedEventArgs args)
{
IsEditing = true;
- m_valueTextBox.Focus();
+
+ try
+ {
+ m_valueTextBox.Focus();
+ }
+ catch (InvalidOperationException)
+ {
+ // This is a hack. The above call of Focus() will cause an exception inside MaterialDesignThemes version 2.5.0.1205.
+ // Older or newer versions of MaterialDesignThemes work as expected.
+ }
}
private void MinusCommandHandler(object sender, ExecutedRoutedEventArgs args)
diff --git a/MaterialDesignExtensions/Controls/PersistentSearch.cs b/MaterialDesignExtensions/Controls/PersistentSearch.cs
index 7fd44fcd..595074fe 100644
--- a/MaterialDesignExtensions/Controls/PersistentSearch.cs
+++ b/MaterialDesignExtensions/Controls/PersistentSearch.cs
@@ -13,6 +13,28 @@ namespace MaterialDesignExtensions.Controls
///
public class PersistentSearch : SearchBase
{
+ ///
+ /// The size of the displayed icons.
+ ///
+ public static readonly DependencyProperty IconSizeProperty = DependencyProperty.Register(
+ nameof(IconSize), typeof(int), typeof(PersistentSearch), new PropertyMetadata(24));
+
+ ///
+ /// The size of the displayed icons.
+ ///
+ public string IconSize
+ {
+ get
+ {
+ return (string)GetValue(IconSizeProperty);
+ }
+
+ set
+ {
+ SetValue(IconSizeProperty, value);
+ }
+ }
+
static PersistentSearch()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PersistentSearch), new FrameworkPropertyMetadata(typeof(PersistentSearch)));
diff --git a/MaterialDesignExtensions/Controls/SaveFileControl.cs b/MaterialDesignExtensions/Controls/SaveFileControl.cs
index 8812487e..7a2fe34c 100644
--- a/MaterialDesignExtensions/Controls/SaveFileControl.cs
+++ b/MaterialDesignExtensions/Controls/SaveFileControl.cs
@@ -11,6 +11,13 @@
using MaterialDesignExtensions.Controllers;
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using DirectoryInfo = Pri.LongPath.DirectoryInfo;
+using FileInfo = Pri.LongPath.FileInfo;
+using FileSystemInfo = Pri.LongPath.FileSystemInfo;
+#endif
+
namespace MaterialDesignExtensions.Controls
{
///
@@ -18,6 +25,8 @@ namespace MaterialDesignExtensions.Controls
///
public class SaveFileControl : BaseFileControl
{
+ private const string FilenameTextBoxName = "filenameTextBox";
+
///
/// The name of the file itself without the full path.
///
@@ -43,6 +52,33 @@ public string Filename
}
}
+ ///
+ /// Forces the possible file extension of the selected file filter for new filenames.
+ ///
+ public static readonly DependencyProperty ForceFileExtensionOfFileFilterProperty = DependencyProperty.Register(
+ nameof(ForceFileExtensionOfFileFilter),
+ typeof(bool),
+ typeof(SaveFileControl),
+ new PropertyMetadata(false, ForceFileExtensionOfFileFilterChangedHandler));
+
+ ///
+ /// Forces the possible file extension of the selected file filter for new filenames.
+ ///
+ public bool ForceFileExtensionOfFileFilter
+ {
+ get
+ {
+ return (bool)GetValue(ForceFileExtensionOfFileFilterProperty);
+ }
+
+ set
+ {
+ SetValue(ForceFileExtensionOfFileFilterProperty, value);
+ }
+ }
+
+ private TextBox m_filenameTextBox;
+
static SaveFileControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(SaveFileControl), new FrameworkPropertyMetadata(typeof(SaveFileControl)));
@@ -51,7 +87,46 @@ static SaveFileControl()
///
/// Creates a new .
///
- public SaveFileControl() : base() { }
+ public SaveFileControl()
+ : base()
+ {
+ m_filenameTextBox = null;
+ }
+
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ if (m_filenameTextBox != null)
+ {
+ m_filenameTextBox.KeyUp -= FilenameTextBoxKeyUpHandler;
+ }
+
+ m_filenameTextBox = Template.FindName(FilenameTextBoxName, this) as TextBox;
+ }
+
+ protected override void LoadedHandler(object sender, RoutedEventArgs args)
+ {
+ base.LoadedHandler(sender, args);
+
+ m_filenameTextBox.KeyUp -= FilenameTextBoxKeyUpHandler;
+ m_filenameTextBox.KeyUp += FilenameTextBoxKeyUpHandler;
+ }
+
+ protected override void UnloadedHandler(object sender, RoutedEventArgs args)
+ {
+ m_filenameTextBox.KeyUp -= FilenameTextBoxKeyUpHandler;
+
+ base.UnloadedHandler(sender, args);
+ }
+
+ private void FilenameTextBoxKeyUpHandler(object sender, KeyEventArgs args)
+ {
+ if (args.Key == Key.Enter && !string.IsNullOrWhiteSpace(CurrentFile))
+ {
+ SelectFile();
+ }
+ }
protected override void SelectFileCommandHandler(object sender, ExecutedRoutedEventArgs args)
{
@@ -82,7 +157,7 @@ protected virtual void FilenameChangedHandler(string newFilename)
{
try
{
- m_controller.SelectFile(BuildFullFilename(newFilename));
+ m_controller.SelectFile(m_controller.BuildFullFileNameForInCurrentDirectory(newFilename));
}
catch (PathTooLongException)
{
@@ -122,47 +197,36 @@ protected override void ControllerPropertyChangedHandler(object sender, Property
base.ControllerPropertyChangedHandler(sender, args);
}
- protected override void SelectFileSystemEntryCommandHandler(object sender, ExecutedRoutedEventArgs args)
+ protected override void SelectFileSystemEntry(FileSystemInfo fileSystemInfo)
{
- if (args.Parameter != null)
+ if (fileSystemInfo != null)
{
- if (args.Parameter is DirectoryInfo directoryInfo)
+ if (fileSystemInfo is DirectoryInfo directoryInfo)
{
CurrentDirectory = directoryInfo.FullName;
if (Filename != null && CurrentDirectory != null)
{
- CurrentFile = BuildFullFilename(Filename);
+ CurrentFile = m_controller.BuildFullFileNameForInCurrentDirectory(Filename);
}
else
{
CurrentFile = null;
}
}
- else if (args.Parameter is FileInfo fileInfo)
+ else if (fileSystemInfo is FileInfo fileInfo)
{
CurrentFile = fileInfo.FullName;
}
}
}
- private string BuildFullFilename(string newFilename)
+ protected static void ForceFileExtensionOfFileFilterChangedHandler(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
- string filename = null;
-
- if (!string.IsNullOrWhiteSpace(newFilename))
+ if (obj is SaveFileControl saveFileControl)
{
- string directory = CurrentDirectory;
-
- if (CurrentDirectory != null && !directory.EndsWith(@"\") && !directory.EndsWith("/"))
- {
- directory = directory + @"\";
- }
-
- filename = directory + newFilename.Trim();
+ saveFileControl.m_controller.ForceFileExtensionOfFileFilter = (bool)args.NewValue;
}
-
- return filename;
}
}
}
diff --git a/MaterialDesignExtensions/Controls/SaveFileDialog.cs b/MaterialDesignExtensions/Controls/SaveFileDialog.cs
index 1033a07c..cffb0bcc 100644
--- a/MaterialDesignExtensions/Controls/SaveFileDialog.cs
+++ b/MaterialDesignExtensions/Controls/SaveFileDialog.cs
@@ -11,6 +11,11 @@
using MaterialDesignExtensions.Converters;
using MaterialDesignExtensions.Model;
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using FileInfo = Pri.LongPath.FileInfo;
+#endif
+
namespace MaterialDesignExtensions.Controls
{
///
@@ -43,6 +48,31 @@ public string Filename
}
}
+ ///
+ /// Forces the possible file extension of the selected file filter for new filenames.
+ ///
+ public static readonly DependencyProperty ForceFileExtensionOfFileFilterProperty = DependencyProperty.Register(
+ nameof(ForceFileExtensionOfFileFilter),
+ typeof(bool),
+ typeof(SaveFileDialog),
+ new PropertyMetadata(false));
+
+ ///
+ /// Forces the possible file extension of the selected file filter for new filenames.
+ ///
+ public bool ForceFileExtensionOfFileFilter
+ {
+ get
+ {
+ return (bool)GetValue(ForceFileExtensionOfFileFilterProperty);
+ }
+
+ set
+ {
+ SetValue(ForceFileExtensionOfFileFilterProperty, value);
+ }
+ }
+
static SaveFileDialog()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(SaveFileDialog), new FrameworkPropertyMetadata(typeof(SaveFileDialog)));
@@ -63,30 +93,6 @@ protected override void OpenDirectoryControlFileSelectedHandler(object sender, R
DialogHost.CloseDialogCommand.Execute(new SaveFileDialogResult(false, (args as FileSelectedEventArgs)?.FileInfo), GetDialogHost());
}
- ///
- /// Shows a new .
- ///
- /// The name of the
- /// The width of the dialog (optional)
- /// The heigth of the dialog (optional)
- /// The current directory to show (optional)
- /// The name of the file without the full path (optional)
- /// Show or hide hidden files in the dialog (optional)
- /// Show or hide system files in the dialog (optional)
- /// Callback after openening the dialog (optional)
- /// Callback after closing the dialog (optional)
- ///
- [Obsolete("Use the overloaded method with SaveFileDialogArguments instead")]
- public static async Task ShowDialogAsync(string dialogHostName, double? width = null, double? height = null,
- string currentDirectory = null, string filename = null,
- bool showHiddenFilesAndDirectories = false, bool showSystemFilesAndDirectories = false,
- DialogOpenedEventHandler openedHandler = null, DialogClosingEventHandler closingHandler = null)
- {
- SaveFileDialog dialog = InitDialog(width, height, currentDirectory, filename, null, -1, showHiddenFilesAndDirectories, showSystemFilesAndDirectories);
-
- return await DialogHost.Show(dialog, dialogHostName, openedHandler, closingHandler) as SaveFileDialogResult;
- }
-
///
/// Shows a new .
///
@@ -102,37 +108,17 @@ public static async Task ShowDialogAsync(string dialogHost
args.Filename,
args.Filters,
args.FilterIndex,
+ args.CreateNewDirectoryEnabled,
args.ShowHiddenFilesAndDirectories,
- args.ShowSystemFilesAndDirectories
+ args.ShowSystemFilesAndDirectories,
+ args.SwitchPathPartsAsButtonsEnabled,
+ args.PathPartsAsButtons,
+ args.ForceFileExtensionOfFileFilter
);
return await DialogHost.Show(dialog, dialogHostName, args.OpenedHandler, args.ClosingHandler) as SaveFileDialogResult;
}
- ///
- /// Shows a new .
- ///
- /// The
- /// The width of the dialog (optional)
- /// The heigth of the dialog (optional)
- /// The current directory to show (optional)
- /// The name of the file without the full path (optional)
- /// Show or hide hidden files in the dialog (optional)
- /// Show or hide system files in the dialog (optional)
- /// Callback after openening the dialog (optional)
- /// Callback after closing the dialog (optional)
- ///
- [Obsolete("Use the overloaded method with SaveFileDialogArguments instead")]
- public static async Task ShowDialogAsync(DialogHost dialogHost, double? width = null, double? height = null,
- string currentDirectory = null, string filename = null,
- bool showHiddenFilesAndDirectories = false, bool showSystemFilesAndDirectories = false,
- DialogOpenedEventHandler openedHandler = null, DialogClosingEventHandler closingHandler = null)
- {
- SaveFileDialog dialog = InitDialog(width, height, currentDirectory, filename, null, -1, showHiddenFilesAndDirectories, showSystemFilesAndDirectories);
-
- return await dialogHost.ShowDialog(dialog, openedHandler, closingHandler) as SaveFileDialogResult;
- }
-
///
/// Shows a new .
///
@@ -148,8 +134,12 @@ public static async Task ShowDialogAsync(DialogHost dialog
args.Filename,
args.Filters,
args.FilterIndex,
+ args.CreateNewDirectoryEnabled,
args.ShowHiddenFilesAndDirectories,
- args.ShowSystemFilesAndDirectories
+ args.ShowSystemFilesAndDirectories,
+ args.SwitchPathPartsAsButtonsEnabled,
+ args.PathPartsAsButtons,
+ args.ForceFileExtensionOfFileFilter
);
return await dialogHost.ShowDialog(dialog, args.OpenedHandler, args.ClosingHandler) as SaveFileDialogResult;
@@ -158,11 +148,15 @@ public static async Task ShowDialogAsync(DialogHost dialog
private static SaveFileDialog InitDialog(double? width, double? height,
string currentDirectory, string filename,
string filters, int filterIndex,
- bool showHiddenFilesAndDirectories, bool showSystemFilesAndDirectories)
+ bool createNewDirectoryEnabled,
+ bool showHiddenFilesAndDirectories, bool showSystemFilesAndDirectories,
+ bool switchPathPartsAsButtonsEnabled, bool pathPartsAsButtons,
+ bool forceFileExtensionOfFileFilter)
{
SaveFileDialog dialog = new SaveFileDialog();
- InitDialog(dialog, width, height, currentDirectory, showHiddenFilesAndDirectories, showSystemFilesAndDirectories);
+ InitDialog(dialog, width, height, currentDirectory, showHiddenFilesAndDirectories, showSystemFilesAndDirectories, createNewDirectoryEnabled, switchPathPartsAsButtonsEnabled, pathPartsAsButtons);
dialog.Filename = filename;
+ dialog.ForceFileExtensionOfFileFilter = forceFileExtensionOfFileFilter;
dialog.Filters = new FileFiltersTypeConverter().ConvertFrom(null, null, filters) as IList;
dialog.FilterIndex = filterIndex;
@@ -180,10 +174,22 @@ public class SaveFileDialogArguments : FileDialogArguments
///
public string Filename { get; set; }
+ ///
+ /// Forces the possible file extension of the selected file filter for new filenames.
+ ///
+ public bool ForceFileExtensionOfFileFilter { get; set; }
+
///
/// Creates a new .
///
public SaveFileDialogArguments() : base() { }
+
+ ///
+ /// Copy constructor
+ ///
+ ///
+ public SaveFileDialogArguments(SaveFileDialogArguments args)
+ : base(args) { }
}
///
diff --git a/MaterialDesignExtensions/Controls/SearchBase.cs b/MaterialDesignExtensions/Controls/SearchBase.cs
index 830c1534..188b14e0 100644
--- a/MaterialDesignExtensions/Controls/SearchBase.cs
+++ b/MaterialDesignExtensions/Controls/SearchBase.cs
@@ -10,6 +10,7 @@
using MaterialDesignThemes.Wpf;
+using MaterialDesignExtensions.Commands.Internal;
using MaterialDesignExtensions.Controllers;
using MaterialDesignExtensions.Model;
@@ -26,11 +27,6 @@ public abstract class SearchBase : ControlWithAutocompletePopup
protected const string SearchSuggestionsPopupName = "searchSuggestionsPopup";
protected const string SearchSuggestionsItemsControlName = "searchSuggestionsItemsControl";
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand SelectSearchSuggestionCommand = new RoutedCommand();
-
///
/// An event raised by triggering a search (select a suggestion or hit enter).
///
@@ -119,6 +115,50 @@ public object SearchIcon
}
}
+ ///
+ /// The icon on the left side of the search text box that appears when the text is not empty and replaced the search icon.
+ ///
+ public static readonly DependencyProperty CancelIconProperty = DependencyProperty.Register(
+ nameof(CancelIcon), typeof(object), typeof(SearchBase), new PropertyMetadata(PackIconKind.ArrowLeft, null));
+
+ ///
+ /// The icon on the left side of the search text box that appears when the text is not empty and replaced the search icon.
+ ///
+ public object CancelIcon
+ {
+ get
+ {
+ return GetValue(CancelIconProperty);
+ }
+
+ set
+ {
+ SetValue(CancelIconProperty, value);
+ }
+ }
+
+ ///
+ /// The icon on the right side of the search text box that appears when the text is not empty.
+ ///
+ public static readonly DependencyProperty ClearIconProperty = DependencyProperty.Register(
+ nameof(ClearIcon), typeof(object), typeof(SearchBase), new PropertyMetadata(PackIconKind.Close, null));
+
+ ///
+ /// The icon on the right side of the search text box that appears when the text is not empty.
+ ///
+ public object ClearIcon
+ {
+ get
+ {
+ return GetValue(ClearIconProperty);
+ }
+
+ set
+ {
+ SetValue(ClearIconProperty, value);
+ }
+ }
+
///
/// A source for providing suggestions to search for.
///
@@ -170,6 +210,9 @@ public string SearchTerm
private SearchSuggestionsController m_searchSuggestionsController;
+ ///
+ /// Creates a new .
+ ///
public SearchBase()
: base()
{
@@ -179,7 +222,7 @@ public SearchBase()
m_searchSuggestionsController = new SearchSuggestionsController() { SearchSuggestionsSource = SearchSuggestionsSource };
- CommandBindings.Add(new CommandBinding(SelectSearchSuggestionCommand, SelectSearchSuggestionCommandHandler));
+ CommandBindings.Add(new CommandBinding(SearchControlCommands.SelectSearchSuggestionCommand, SelectSearchSuggestionCommandHandler));
Loaded += LoadedHandler;
Unloaded += UnloadedHandler;
diff --git a/MaterialDesignExtensions/Controls/SideNavigation.cs b/MaterialDesignExtensions/Controls/SideNavigation.cs
index 442eedd7..bd2dd1b3 100644
--- a/MaterialDesignExtensions/Controls/SideNavigation.cs
+++ b/MaterialDesignExtensions/Controls/SideNavigation.cs
@@ -11,22 +11,18 @@
using System.Windows.Input;
using System.Windows.Media;
+using MaterialDesignExtensions.Commands.Internal;
using MaterialDesignExtensions.Model;
namespace MaterialDesignExtensions.Controls
{
///
- /// A control to be used as side navigation or inside a navigation drawer.
+ /// A navigation control to be used as side navigation or inside a navigation drawer.
///
public class SideNavigation : Control
{
private const string NavigationItemsControlName = "navigationItemsControl";
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand SelectNavigationItemCommand = new RoutedCommand();
-
///
/// An event raised by selecting an item.
///
@@ -71,6 +67,72 @@ public event WillSelectNavigationItemEventHandler WillSelectNavigationItem
}
}
+ ///
+ /// The foreground color of the icon of not selected items.
+ ///
+ public static readonly DependencyProperty IconForegroundProperty = DependencyProperty.Register(
+ nameof(IconForeground), typeof(Brush), typeof(SideNavigation), new PropertyMetadata(null, null));
+
+ ///
+ /// The foreground color of the icon of not selected items.
+ ///
+ public Brush IconForeground
+ {
+ get
+ {
+ return (Brush)GetValue(IconForegroundProperty);
+ }
+
+ set
+ {
+ SetValue(IconForegroundProperty, value);
+ }
+ }
+
+ ///
+ /// The font size of the item labels.
+ ///
+ public static readonly DependencyProperty LabelFontSizeProperty = DependencyProperty.Register(
+ nameof(LabelFontSize), typeof(double), typeof(SideNavigation), new PropertyMetadata(14.0, null));
+
+ ///
+ /// The font size of the item labels.
+ ///
+ public double LabelFontSize
+ {
+ get
+ {
+ return (double)GetValue(LabelFontSizeProperty);
+ }
+
+ set
+ {
+ SetValue(LabelFontSizeProperty, value);
+ }
+ }
+
+ ///
+ /// The foreground color of the label of not selected items.
+ ///
+ public static readonly DependencyProperty LabelForegroundProperty = DependencyProperty.Register(
+ nameof(LabelForeground), typeof(Brush), typeof(SideNavigation), new PropertyMetadata(null, null));
+
+ ///
+ /// The foreground color of the label of not selected items.
+ ///
+ public Brush LabelForeground
+ {
+ get
+ {
+ return (Brush)GetValue(LabelForegroundProperty);
+ }
+
+ set
+ {
+ SetValue(LabelForegroundProperty, value);
+ }
+ }
+
///
/// The color of the click ripple by selecting an item.
///
@@ -94,13 +156,13 @@ public Brush NavigationItemFeedback
}
///
- /// The background color of the selected item. It will get an opacity of 15%.
+ /// The background color of the selected item.
///
public static readonly DependencyProperty SelectionBackgroundProperty = DependencyProperty.Register(
nameof(SelectionBackground), typeof(Brush), typeof(SideNavigation), new PropertyMetadata(null, null));
///
- /// The background color of the selected item. It will get an opacity of 15%.
+ /// The background color of the selected item.
///
public Brush SelectionBackground
{
@@ -115,6 +177,28 @@ public Brush SelectionBackground
}
}
+ ///
+ /// The background color opacity of the selected item.
+ ///
+ public static readonly DependencyProperty SelectionBackgroundOpacityProperty = DependencyProperty.Register(
+ nameof(SelectionBackgroundOpacity), typeof(double), typeof(SideNavigation), new PropertyMetadata(0.12, null));
+
+ ///
+ /// The background color opacity of the selected item.
+ ///
+ public double SelectionBackgroundOpacity
+ {
+ get
+ {
+ return (double)GetValue(SelectionBackgroundOpacityProperty);
+ }
+
+ set
+ {
+ SetValue(SelectionBackgroundOpacityProperty, value);
+ }
+ }
+
///
/// The corner radius of the selected item.
///
@@ -280,7 +364,7 @@ public ICommand WillSelectNavigationItemCommand
}
}
- private ItemsControl m_navigationItemsControl;
+ protected ItemsControl m_navigationItemsControl;
static SideNavigation()
{
@@ -296,7 +380,7 @@ public SideNavigation()
Loaded += LoadedHandler;
Unloaded += UnloadedHandler;
- CommandBindings.Add(new CommandBinding(SelectNavigationItemCommand, SelectNavigationItemCommandHandlerAsync));
+ CommandBindings.Add(new CommandBinding(SideNavigationCommands.SelectNavigationItemCommand, SelectNavigationItemCommandHandlerAsync));
}
public override void OnApplyTemplate()
@@ -392,26 +476,38 @@ private async void SelectNavigationItemCommandHandlerAsync(object sender, Execut
}
}
- private void InitItems(IList values)
+ protected virtual void InitItems(IList values)
{
- IList navigationItems = new List();
-
- if (values != null)
+ if (m_navigationItemsControl != null)
{
- foreach (object item in values)
+ IList navigationItems = new List();
+
+ if (values != null)
{
- if (item is INavigationItem navigationItem)
+ foreach (object item in values)
{
- navigationItems.Add(navigationItem);
+ if (item is INavigationItem navigationItem)
+ {
+ navigationItems.Add(navigationItem);
+ }
}
}
- }
- m_navigationItemsControl.ItemsSource = navigationItems;
+ m_navigationItemsControl.ItemsSource = navigationItems;
- if (SelectedItem != null && !navigationItems.Contains(SelectedItem))
- {
- SelectedItem = null;
+ INavigationItem selectedItem = navigationItems.FirstOrDefault(item => item.IsSelected);
+
+ if (selectedItem != null)
+ {
+ if (SelectedItem != selectedItem)
+ {
+ SelectedItem = selectedItem;
+ }
+ }
+ else
+ {
+ SelectedItem = null;
+ }
}
}
}
diff --git a/MaterialDesignExtensions/Controls/StepButtonBar.cs b/MaterialDesignExtensions/Controls/StepButtonBar.cs
index 65f568b9..10709510 100644
--- a/MaterialDesignExtensions/Controls/StepButtonBar.cs
+++ b/MaterialDesignExtensions/Controls/StepButtonBar.cs
@@ -8,6 +8,8 @@
using System.Windows.Input;
using System.Windows.Media;
+using MaterialDesignExtensions.Commands.Internal;
+
namespace MaterialDesignExtensions.Controls
{
///
@@ -37,6 +39,7 @@ public object Back
SetValue(BackProperty, value);
}
}
+
///
/// The interal back command of the parent stepper.
///
@@ -80,6 +83,7 @@ public object Cancel
SetValue(CancelProperty, value);
}
}
+
///
/// The interal cancel command of the parent stepper.
///
@@ -239,6 +243,9 @@ static StepButtonBar()
DefaultStyleKeyProperty.OverrideMetadata(typeof(StepButtonBar), new FrameworkPropertyMetadata(typeof(StepButtonBar)));
}
+ ///
+ /// Creates a new .
+ ///
public StepButtonBar() : base() { }
public override void OnApplyTemplate()
@@ -250,18 +257,9 @@ public override void OnApplyTemplate()
if (stepper != null)
{
- if (stepper is TabControlStepper)
- {
- BackCommand = TabControlStepper.BackCommand;
- CancelCommand = TabControlStepper.CancelCommand;
- ContinueCommand = TabControlStepper.ContinueCommand;
- }
- else
- {
- BackCommand = Stepper.BackCommand;
- CancelCommand = Stepper.CancelCommand;
- ContinueCommand = Stepper.ContinueCommand;
- }
+ BackCommand = StepperCommands.BackCommand;
+ CancelCommand = StepperCommands.CancelCommand;
+ ContinueCommand = StepperCommands.ContinueCommand;
}
base.OnApplyTemplate();
diff --git a/MaterialDesignExtensions/Controls/StepTitleHeaderControl.cs b/MaterialDesignExtensions/Controls/StepTitleHeaderControl.cs
index 5d4a631a..0ac7bc85 100644
--- a/MaterialDesignExtensions/Controls/StepTitleHeaderControl.cs
+++ b/MaterialDesignExtensions/Controls/StepTitleHeaderControl.cs
@@ -8,6 +8,9 @@
namespace MaterialDesignExtensions.Controls
{
+ ///
+ /// Control for a header of a stepper step to enable data bindings.
+ ///
public class StepTitleHeaderControl : Control
{
///
diff --git a/MaterialDesignExtensions/Controls/Stepper.cs b/MaterialDesignExtensions/Controls/Stepper.cs
index aaa69733..20a6545b 100644
--- a/MaterialDesignExtensions/Controls/Stepper.cs
+++ b/MaterialDesignExtensions/Controls/Stepper.cs
@@ -13,6 +13,7 @@
using System.Windows.Markup;
using System.Windows.Media.Animation;
+using MaterialDesignExtensions.Commands.Internal;
using MaterialDesignExtensions.Controllers;
using MaterialDesignExtensions.Model;
@@ -24,26 +25,6 @@ namespace MaterialDesignExtensions.Controls
[ContentProperty(nameof(Steps))]
public class Stepper : Control, IStepper
{
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand BackCommand = new RoutedCommand();
-
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand CancelCommand = new RoutedCommand();
-
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand ContinueCommand = new RoutedCommand();
-
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand StepSelectedCommand = new RoutedCommand();
-
///
/// An event raised by changing the active .
///
@@ -354,6 +335,28 @@ public ICommand ContinueNavigationCommand
}
}
+ ///
+ /// An alternative icon template done steps.
+ ///
+ public static readonly DependencyProperty DoneIconTemplateProperty = DependencyProperty.Register(
+ nameof(DoneIconTemplate), typeof(DataTemplate), typeof(Stepper), new PropertyMetadata(null, null));
+
+ ///
+ /// An alternative icon template done steps.
+ ///
+ public DataTemplate DoneIconTemplate
+ {
+ get
+ {
+ return (DataTemplate)GetValue(DoneIconTemplateProperty);
+ }
+
+ set
+ {
+ SetValue(DoneIconTemplateProperty, value);
+ }
+ }
+
///
/// Enables the linear mode by disabling the buttons of the header.
/// The navigation must be accomplished by using the navigation commands.
@@ -489,17 +492,31 @@ public ICommand StepValidationCommand
}
///
- /// Gets the controller for this .
+ /// An alternative icon template to indicate validation errors.
+ ///
+ public static readonly DependencyProperty ValidationErrorIconTemplateProperty = DependencyProperty.Register(
+ nameof(ValidationErrorIconTemplate), typeof(DataTemplate), typeof(Stepper), new PropertyMetadata(null, null));
+
+ ///
+ /// An alternative icon template to indicate validation errors.
///
- public StepperController Controller
+ public DataTemplate ValidationErrorIconTemplate
{
get
{
- return m_controller;
+ return (DataTemplate)GetValue(ValidationErrorIconTemplateProperty);
+ }
+
+ set
+ {
+ SetValue(ValidationErrorIconTemplateProperty, value);
}
}
- private StepperController m_controller;
+ ///
+ /// Gets the controller for this .
+ ///
+ public StepperController Controller { get; private set; }
static Stepper()
{
@@ -512,24 +529,24 @@ static Stepper()
public Stepper()
: base()
{
- m_controller = new StepperController();
+ Controller = new StepperController();
Steps = new ObservableCollection();
Loaded += LoadedHandler;
Unloaded += UnloadedHandler;
- CommandBindings.Add(new CommandBinding(BackCommand, BackHandler));
- CommandBindings.Add(new CommandBinding(CancelCommand, CancelHandler));
- CommandBindings.Add(new CommandBinding(ContinueCommand, ContinueHandler));
- CommandBindings.Add(new CommandBinding(StepSelectedCommand, StepSelectedHandler, CanExecuteStepSelectedHandler));
+ CommandBindings.Add(new CommandBinding(StepperCommands.BackCommand, BackHandler));
+ CommandBindings.Add(new CommandBinding(StepperCommands.CancelCommand, CancelHandler));
+ CommandBindings.Add(new CommandBinding(StepperCommands.ContinueCommand, ContinueHandler));
+ CommandBindings.Add(new CommandBinding(StepperCommands.StepSelectedCommand, StepSelectedHandler, CanExecuteStepSelectedHandler));
Focusable = false;
}
private void LoadedHandler(object sender, RoutedEventArgs args)
{
- m_controller.PropertyChanged += PropertyChangedHandler;
+ Controller.PropertyChanged += PropertyChangedHandler;
if (Steps is ObservableCollection steps)
{
@@ -546,7 +563,7 @@ private void LoadedHandler(object sender, RoutedEventArgs args)
private void UnloadedHandler(object sender, RoutedEventArgs args)
{
- m_controller.PropertyChanged -= PropertyChangedHandler;
+ Controller.PropertyChanged -= PropertyChangedHandler;
if (Steps is ObservableCollection steps)
{
@@ -556,7 +573,7 @@ private void UnloadedHandler(object sender, RoutedEventArgs args)
private bool ValidateActiveStep()
{
- IStep step = m_controller.ActiveStepViewModel?.Step;
+ IStep step = Controller.ActiveStepViewModel?.Step;
if (step != null)
{
@@ -584,7 +601,7 @@ private bool ValidateActiveStep()
private void RaiseNavigationCanceledByValidation()
{
- IStep step = m_controller.ActiveStepViewModel?.Step;
+ IStep step = Controller.ActiveStepViewModel?.Step;
if (step != null)
{
@@ -600,18 +617,22 @@ private void RaiseNavigationCanceledByValidation()
private void SelectStep(IStep step)
{
- if (step != null && step != m_controller.ActiveStep && !IsLinear)
+ if (step != null && step != Controller.ActiveStep && !IsLinear)
{
bool isValid = ValidateActiveStep();
- if (BlockNavigationOnValidationErrors && !isValid)
+ StepperStepViewModel activeStepViewModel = Controller.ActiveStepViewModel;
+ StepperStepViewModel nextStepViewModel = Controller.InternalSteps.FirstOrDefault(stepViewModel => stepViewModel.Step == step);
+
+ if (BlockNavigationOnValidationErrors && !isValid
+ && (nextStepViewModel == null || nextStepViewModel.Number > activeStepViewModel.Number))
{
RaiseNavigationCanceledByValidation();
return;
}
- StepperNavigationEventArgs navigationArgs = new StepperNavigationEventArgs(StepNavigationEvent, this, m_controller.ActiveStep, step, false);
+ StepperNavigationEventArgs navigationArgs = new StepperNavigationEventArgs(StepNavigationEvent, this, Controller.ActiveStep, step, false);
RaiseEvent(navigationArgs);
if (StepNavigationCommand != null && StepNavigationCommand.CanExecute(navigationArgs))
@@ -621,12 +642,12 @@ private void SelectStep(IStep step)
if (!navigationArgs.Cancel)
{
- m_controller.GotoStep(step);
+ Controller.GotoStep(step);
}
else
{
// refresh the property with the old state
- ActiveStep = m_controller.ActiveStep;
+ ActiveStep = Controller.ActiveStep;
}
}
}
@@ -681,21 +702,14 @@ private void InitSteps(IList values)
}
}
- m_controller.InitSteps(steps);
+ Controller.InitSteps(steps);
}
private void BackHandler(object sender, ExecutedRoutedEventArgs args)
{
- bool isValid = ValidateActiveStep();
-
- if (BlockNavigationOnValidationErrors && !isValid)
- {
- RaiseNavigationCanceledByValidation();
-
- return;
- }
+ ValidateActiveStep();
- StepperNavigationEventArgs navigationArgs = new StepperNavigationEventArgs(BackNavigationEvent, this, m_controller.ActiveStep, m_controller.PreviousStep, false);
+ StepperNavigationEventArgs navigationArgs = new StepperNavigationEventArgs(BackNavigationEvent, this, Controller.ActiveStep, Controller.PreviousStep, false);
RaiseEvent(navigationArgs);
if (BackNavigationCommand != null && BackNavigationCommand.CanExecute(navigationArgs))
@@ -705,7 +719,7 @@ private void BackHandler(object sender, ExecutedRoutedEventArgs args)
if (!navigationArgs.Cancel)
{
- m_controller.Back();
+ Controller.Back();
}
}
@@ -716,7 +730,7 @@ private void CancelHandler(object sender, ExecutedRoutedEventArgs args)
return;
}
- StepperNavigationEventArgs navigationArgs = new StepperNavigationEventArgs(CancelNavigationEvent, this, m_controller.ActiveStep, null, false);
+ StepperNavigationEventArgs navigationArgs = new StepperNavigationEventArgs(CancelNavigationEvent, this, Controller.ActiveStep, null, false);
RaiseEvent(navigationArgs);
if (CancelNavigationCommand != null && CancelNavigationCommand.CanExecute(navigationArgs))
@@ -736,7 +750,7 @@ private void ContinueHandler(object sender, ExecutedRoutedEventArgs args)
return;
}
- StepperNavigationEventArgs navigationArgs = new StepperNavigationEventArgs(ContinueNavigationEvent, this, m_controller.ActiveStep, m_controller.NextStep, false);
+ StepperNavigationEventArgs navigationArgs = new StepperNavigationEventArgs(ContinueNavigationEvent, this, Controller.ActiveStep, Controller.NextStep, false);
RaiseEvent(navigationArgs);
if (ContinueNavigationCommand != null && ContinueNavigationCommand.CanExecute(navigationArgs))
@@ -746,7 +760,7 @@ private void ContinueHandler(object sender, ExecutedRoutedEventArgs args)
if (!navigationArgs.Cancel)
{
- m_controller.Continue();
+ Controller.Continue();
}
}
@@ -762,15 +776,15 @@ private void StepSelectedHandler(object sender, ExecutedRoutedEventArgs args)
private void PropertyChangedHandler(object sender, PropertyChangedEventArgs args)
{
- if (sender == m_controller)
+ if (sender == Controller)
{
- if (args.PropertyName == nameof(m_controller.ActiveStep))
+ if (args.PropertyName == nameof(Controller.ActiveStep))
{
// set the property
- ActiveStep = m_controller.ActiveStep;
+ ActiveStep = Controller.ActiveStep;
// raise the event and call the command
- ActiveStepChangedEventArgs eventArgs = new ActiveStepChangedEventArgs(StepValidationEvent, this, ActiveStep);
+ ActiveStepChangedEventArgs eventArgs = new ActiveStepChangedEventArgs(ActiveStepChangedEvent, this, ActiveStep);
RaiseEvent(eventArgs);
if (ActiveStepChangedCommand != null && ActiveStepChangedCommand.CanExecute(ActiveStep))
@@ -778,8 +792,8 @@ private void PropertyChangedHandler(object sender, PropertyChangedEventArgs args
ActiveStepChangedCommand.Execute(ActiveStep);
}
}
- else if (args.PropertyName == nameof(m_controller.ActiveStepContent)
- && m_controller.ActiveStepContent != null
+ else if (args.PropertyName == nameof(Controller.ActiveStepContent)
+ && Controller.ActiveStepContent != null
&& Layout == StepperLayout.Horizontal)
{
// there is no event raised if the Content of a ContentControl changes
@@ -811,7 +825,7 @@ private void PlayHorizontalContentAnimation()
///
public void Continue()
{
- m_controller.Continue();
+ Controller.Continue();
}
///
@@ -820,7 +834,7 @@ public void Continue()
///
public void Back()
{
- m_controller.Back();
+ Controller.Back();
}
///
@@ -830,7 +844,7 @@ public void Back()
///
public void GotoStep(int index)
{
- m_controller.GotoStep(index);
+ Controller.GotoStep(index);
}
///
@@ -841,7 +855,7 @@ public void GotoStep(int index)
///
public void GotoStep(IStep step)
{
- m_controller.GotoStep(step);
+ Controller.GotoStep(step);
}
}
diff --git a/MaterialDesignExtensions/Controls/TabControlAssist.cs b/MaterialDesignExtensions/Controls/TabControlAssist.cs
new file mode 100644
index 00000000..9596b196
--- /dev/null
+++ b/MaterialDesignExtensions/Controls/TabControlAssist.cs
@@ -0,0 +1,287 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Media;
+
+namespace MaterialDesignExtensions.Controls
+{
+ ///
+ /// Contains attached properties for TabControl.
+ ///
+ public static class TabControlAssist
+ {
+ ///
+ /// The alignment of the horizontal tab headers in the TabControl.
+ ///
+ public static readonly DependencyProperty TabHeaderHorizontalAlignmentProperty = DependencyProperty.RegisterAttached(
+ "TabHeaderHorizontalAlignment",
+ typeof(HorizontalAlignment),
+ typeof(TabControlAssist),
+ new FrameworkPropertyMetadata(HorizontalAlignment.Left, FrameworkPropertyMetadataOptions.Inherits, null)
+ );
+
+ ///
+ /// Gets the alignment of the horizontal tab headers in the TabControl.
+ ///
+ ///
+ ///
+ public static HorizontalAlignment GetTabHeaderHorizontalAlignment(DependencyObject element)
+ {
+ return (HorizontalAlignment)element.GetValue(TabHeaderHorizontalAlignmentProperty);
+ }
+
+ ///
+ /// Sets the alignment of the horizontal tab headers in the TabControl.
+ ///
+ ///
+ ///
+ public static void SetTabHeaderHorizontalAlignment(DependencyObject element, HorizontalAlignment value)
+ {
+ element.SetValue(TabHeaderHorizontalAlignmentProperty, value);
+ }
+
+ ///
+ /// The alignment of the vertical tab headers in the TabControl.
+ ///
+ public static readonly DependencyProperty TabHeaderVerticalAlignmentProperty = DependencyProperty.RegisterAttached(
+ "TabHeaderVerticalAlignment",
+ typeof(VerticalAlignment),
+ typeof(TabControlAssist),
+ new FrameworkPropertyMetadata(VerticalAlignment.Top, FrameworkPropertyMetadataOptions.Inherits, null)
+ );
+
+ ///
+ /// Gets the alignment of the vertical tab headers in the TabControl.
+ ///
+ ///
+ ///
+ public static VerticalAlignment GetTabHeaderVerticalAlignment(DependencyObject element)
+ {
+ return (VerticalAlignment)element.GetValue(TabHeaderVerticalAlignmentProperty);
+ }
+
+ ///
+ /// Sets the alignment of the vertical tab headers in the TabControl.
+ ///
+ ///
+ ///
+ public static void SetTabHeaderVerticalAlignment(DependencyObject element, VerticalAlignment value)
+ {
+ element.SetValue(TabHeaderVerticalAlignmentProperty, value);
+ }
+
+ ///
+ /// The brush for not selected tab headers.
+ ///
+ public static readonly DependencyProperty TabHeaderInactiveBrushProperty = DependencyProperty.RegisterAttached(
+ "TabHeaderInactiveBrush",
+ typeof(Brush),
+ typeof(TabControlAssist),
+ new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, null)
+ );
+
+ ///
+ /// Gets the brush for not selected tab headers.
+ ///
+ ///
+ ///
+ public static Brush GetTabHeaderInactiveBrush(DependencyObject element)
+ {
+ return (Brush)element.GetValue(TabHeaderInactiveBrushProperty);
+ }
+
+ ///
+ /// Sets the brush for not selected tab headers.
+ ///
+ ///
+ ///
+ public static void SetTabHeaderInactiveBrush(DependencyObject element, Brush value)
+ {
+ element.SetValue(TabHeaderInactiveBrushProperty, value);
+ }
+
+ ///
+ /// The opacity for not selected tab headers.
+ ///
+ public static readonly DependencyProperty TabHeaderInactiveOpacityProperty = DependencyProperty.RegisterAttached(
+ "TabHeaderInactiveOpacity",
+ typeof(double),
+ typeof(TabControlAssist),
+ new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.Inherits, null)
+ );
+
+ ///
+ /// Gets the opacity for not selected tab headers.
+ ///
+ ///
+ ///
+ public static double GetTabHeaderInactiveOpacity(DependencyObject element)
+ {
+ return (double)element.GetValue(TabHeaderInactiveOpacityProperty);
+ }
+
+ ///
+ /// Sets the ppacity for not selected tab headers.
+ ///
+ ///
+ ///
+ public static void SetTabHeaderInactiveOpacity(DependencyObject element, double value)
+ {
+ element.SetValue(TabHeaderInactiveOpacityProperty, value);
+ }
+
+ ///
+ /// The highlight color of the selected tab item header.
+ ///
+ public static readonly DependencyProperty TabHeaderHighlightBrushProperty = DependencyProperty.RegisterAttached(
+ "TabHeaderHighlightBrush",
+ typeof(Brush),
+ typeof(TabControlAssist),
+ new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, null)
+ );
+
+ ///
+ /// Gets the highlight color of the selected tab item header.
+ ///
+ ///
+ ///
+ public static Brush GetTabHeaderHighlightBrush(DependencyObject element)
+ {
+ return (Brush)element.GetValue(TabHeaderHighlightBrushProperty);
+ }
+
+ ///
+ /// Sets the highlight color of the selected tab item header.
+ ///
+ ///
+ ///
+ public static void SetTabHeaderHighlightBrush(DependencyObject element, Brush value)
+ {
+ element.SetValue(TabHeaderHighlightBrushProperty, value);
+ }
+
+ ///
+ /// The current color of the tab item header. Intended to be read-only.
+ ///
+ public static readonly DependencyProperty TabHeaderForegroundProperty = DependencyProperty.RegisterAttached(
+ "TabHeaderForeground",
+ typeof(Brush),
+ typeof(TabControlAssist),
+ new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, null)
+ );
+
+ ///
+ /// Gets the current color of the tab item header.
+ ///
+ ///
+ ///
+ public static Brush GetTabHeaderForeground(DependencyObject element)
+ {
+ return (Brush)element.GetValue(TabHeaderForegroundProperty);
+ }
+
+ ///
+ /// Sets the current color of the tab item header.
+ ///
+ ///
+ ///
+ public static void SetTabHeaderForeground(DependencyObject element, Brush value)
+ {
+ element.SetValue(TabHeaderForegroundProperty, value);
+ }
+
+ ///
+ /// The current font size of the tab item header. Intended to be read-only.
+ ///
+ public static readonly DependencyProperty TabHeaderFontSizeProperty = DependencyProperty.RegisterAttached(
+ "TabHeaderFontSize",
+ typeof(double),
+ typeof(TabControlAssist),
+ new FrameworkPropertyMetadata(14.0, FrameworkPropertyMetadataOptions.Inherits, null)
+ );
+
+ ///
+ /// Gets the current font size of the tab item header.
+ ///
+ ///
+ ///
+ public static double GetTabHeaderFontSize(DependencyObject element)
+ {
+ return (double)element.GetValue(TabHeaderFontSizeProperty);
+ }
+
+ ///
+ /// Sets the current font size of the tab item header.
+ ///
+ ///
+ ///
+ public static void SetTabHeaderFontSize(DependencyObject element, double value)
+ {
+ element.SetValue(TabHeaderFontSizeProperty, value);
+ }
+
+ ///
+ /// The current font weight of the tab item header. Intended to be read-only.
+ ///
+ public static readonly DependencyProperty TabHeaderFontWeightProperty = DependencyProperty.RegisterAttached(
+ "TabHeaderFontWeight",
+ typeof(FontWeight),
+ typeof(TabControlAssist),
+ new FrameworkPropertyMetadata(FontWeights.Medium, FrameworkPropertyMetadataOptions.Inherits, null)
+ );
+
+ ///
+ /// Gets the current font weight of the tab item header.
+ ///
+ ///
+ ///
+ public static FontWeight GetTabHeaderFontWeight(DependencyObject element)
+ {
+ return (FontWeight)element.GetValue(TabHeaderFontWeightProperty);
+ }
+
+ ///
+ /// Sets the current font weight of the tab item header.
+ ///
+ ///
+ ///
+ public static void SetTabHeaderFontWeight(DependencyObject element, FontWeight value)
+ {
+ element.SetValue(TabHeaderFontWeightProperty, value);
+ }
+
+
+ ///
+ /// The current margin of the tab item header's content. Intended to be read-only.
+ ///
+ public static readonly DependencyProperty TabHeaderMarginProperty = DependencyProperty.RegisterAttached(
+ "TabHeaderMargin",
+ typeof(Thickness),
+ typeof(TabControlAssist),
+ new FrameworkPropertyMetadata(new Thickness(24,12,24,12), FrameworkPropertyMetadataOptions.Inherits, null)
+ );
+
+ ///
+ /// Gets the current margin of the tab item header's content.
+ ///
+ ///
+ ///
+ public static Thickness GetTabHeaderMargin(DependencyObject element)
+ {
+ return (Thickness)element.GetValue(TabHeaderMarginProperty);
+ }
+
+ ///
+ /// Sets the current margin of the tab item header's content.
+ ///
+ ///
+ ///
+ public static void SetTabHeaderMargin(DependencyObject element, Thickness value)
+ {
+ element.SetValue(TabHeaderMarginProperty, value);
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Controls/TabControlStepper.cs b/MaterialDesignExtensions/Controls/TabControlStepper.cs
index 98224414..79f7c852 100644
--- a/MaterialDesignExtensions/Controls/TabControlStepper.cs
+++ b/MaterialDesignExtensions/Controls/TabControlStepper.cs
@@ -13,6 +13,7 @@
using System.Windows.Markup;
using System.Windows.Media.Animation;
+using MaterialDesignExtensions.Commands.Internal;
using MaterialDesignExtensions.Controllers;
using MaterialDesignExtensions.Model;
@@ -23,26 +24,6 @@ namespace MaterialDesignExtensions.Controls
///
public class TabControlStepper : TabControl, IStepper
{
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand BackCommand = new RoutedCommand();
-
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand CancelCommand = new RoutedCommand();
-
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand ContinueCommand = new RoutedCommand();
-
- ///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
- ///
- public static readonly RoutedCommand StepSelectedCommand = new RoutedCommand();
-
///
/// An event raised by navigating to the previous in a linear order.
///
@@ -221,6 +202,28 @@ public ICommand ContinueNavigationCommand
}
}
+ ///
+ /// An alternative icon template done steps.
+ ///
+ public static readonly DependencyProperty DoneIconTemplateProperty = DependencyProperty.Register(
+ nameof(DoneIconTemplate), typeof(DataTemplate), typeof(TabControlStepper), new PropertyMetadata(null, null));
+
+ ///
+ /// An alternative icon template done steps.
+ ///
+ public DataTemplate DoneIconTemplate
+ {
+ get
+ {
+ return (DataTemplate)GetValue(DoneIconTemplateProperty);
+ }
+
+ set
+ {
+ SetValue(DoneIconTemplateProperty, value);
+ }
+ }
+
///
/// Enables the linear mode by disabling the buttons of the header.
/// The navigation must be accomplished by using the navigation commands.
@@ -290,22 +293,39 @@ public ICommand StepNavigationCommand
}
///
- /// Gets the controller for this .
- /// Must to be public for the bindings.
+ /// An alternative icon template to indicate validation errors.
+ ///
+ public static readonly DependencyProperty ValidationErrorIconTemplateProperty = DependencyProperty.Register(
+ nameof(ValidationErrorIconTemplate), typeof(DataTemplate), typeof(TabControlStepper), new PropertyMetadata(null, null));
+
+ ///
+ /// An alternative icon template to indicate validation errors.
///
- public StepperController Controller
+ public DataTemplate ValidationErrorIconTemplate
{
get
{
- return m_controller;
+ return (DataTemplate)GetValue(ValidationErrorIconTemplateProperty);
+ }
+
+ set
+ {
+ SetValue(ValidationErrorIconTemplateProperty, value);
}
}
- private StepperController m_controller;
+ ///
+ /// Gets the controller for this .
+ /// Must to be public for the bindings.
+ ///
+ public StepperController Controller { get; private set; }
static TabControlStepper()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TabControlStepper), new FrameworkPropertyMetadata(typeof(TabControlStepper)));
+
+ object selectedIndexDefaultValue = SelectedIndexProperty.GetMetadata(typeof(TabControl)).DefaultValue;
+ SelectedIndexProperty.OverrideMetadata(typeof(TabControlStepper), new FrameworkPropertyMetadata(selectedIndexDefaultValue, SelectedIndexChangedHandler));
}
///
@@ -314,20 +334,20 @@ static TabControlStepper()
public TabControlStepper()
: base()
{
- m_controller = new StepperController();
+ Controller = new StepperController();
Loaded += LoadedHandler;
Unloaded += UnloadedHandler;
- CommandBindings.Add(new CommandBinding(BackCommand, BackHandler));
- CommandBindings.Add(new CommandBinding(CancelCommand, CancelHandler));
- CommandBindings.Add(new CommandBinding(ContinueCommand, ContinueHandler));
- CommandBindings.Add(new CommandBinding(StepSelectedCommand, StepSelectedHandler, CanExecuteStepSelectedHandler));
+ CommandBindings.Add(new CommandBinding(StepperCommands.BackCommand, BackHandler));
+ CommandBindings.Add(new CommandBinding(StepperCommands.CancelCommand, CancelHandler));
+ CommandBindings.Add(new CommandBinding(StepperCommands.ContinueCommand, ContinueHandler));
+ CommandBindings.Add(new CommandBinding(StepperCommands.StepSelectedCommand, StepSelectedHandler, CanExecuteStepSelectedHandler));
}
private void LoadedHandler(object sender, RoutedEventArgs args)
{
- m_controller.PropertyChanged += PropertyChangedHandler;
+ Controller.PropertyChanged += PropertyChangedHandler;
// there is no event raised if the Content of a ContentControl changes
// therefore trigger the animation in code
@@ -336,7 +356,7 @@ private void LoadedHandler(object sender, RoutedEventArgs args)
private void UnloadedHandler(object sender, RoutedEventArgs args)
{
- m_controller.PropertyChanged -= PropertyChangedHandler;
+ Controller.PropertyChanged -= PropertyChangedHandler;
}
private void InitSteps()
@@ -348,7 +368,7 @@ private void InitSteps()
steps.Add(new Step() { Header = tabItem.Header, Content = tabItem.Content });
}
- m_controller.InitSteps(steps);
+ Controller.InitSteps(steps);
}
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs args)
@@ -358,9 +378,26 @@ protected override void OnItemsChanged(NotifyCollectionChangedEventArgs args)
InitSteps();
}
+ private static void SelectedIndexChangedHandler(DependencyObject obj, DependencyPropertyChangedEventArgs args)
+ {
+ int newValue = (int)args.NewValue;
+ int oldValue = (int)args.OldValue;
+
+ if (newValue != oldValue)
+ {
+ if (obj is TabControlStepper stepper)
+ {
+ if (stepper.Controller.Steps != null && newValue >= 0 && newValue < stepper.Controller.Steps.Length && newValue != stepper.Controller.GetActiveStepIndex())
+ {
+ stepper.StepSelectedHandler(stepper.Controller.InternalSteps[newValue]);
+ }
+ }
+ }
+ }
+
private void BackHandler(object sender, ExecutedRoutedEventArgs args)
{
- StepperNavigationEventArgs navigationArgs = new StepperNavigationEventArgs(BackNavigationEvent, this, m_controller.ActiveStep, m_controller.PreviousStep, false);
+ StepperNavigationEventArgs navigationArgs = new StepperNavigationEventArgs(BackNavigationEvent, this, Controller.ActiveStep, Controller.PreviousStep, false);
RaiseEvent(navigationArgs);
if (BackNavigationCommand != null && BackNavigationCommand.CanExecute(navigationArgs))
@@ -370,7 +407,7 @@ private void BackHandler(object sender, ExecutedRoutedEventArgs args)
if (!navigationArgs.Cancel)
{
- m_controller.Back();
+ Controller.Back();
}
}
@@ -381,7 +418,7 @@ private void CancelHandler(object sender, ExecutedRoutedEventArgs args)
return;
}
- StepperNavigationEventArgs navigationArgs = new StepperNavigationEventArgs(CancelNavigationEvent, this, m_controller.ActiveStep, null, false);
+ StepperNavigationEventArgs navigationArgs = new StepperNavigationEventArgs(CancelNavigationEvent, this, Controller.ActiveStep, null, false);
RaiseEvent(navigationArgs);
if (CancelNavigationCommand != null && CancelNavigationCommand.CanExecute(navigationArgs))
@@ -392,7 +429,7 @@ private void CancelHandler(object sender, ExecutedRoutedEventArgs args)
private void ContinueHandler(object sender, ExecutedRoutedEventArgs args)
{
- StepperNavigationEventArgs navigationArgs = new StepperNavigationEventArgs(ContinueNavigationEvent, this, m_controller.ActiveStep, m_controller.NextStep, false);
+ StepperNavigationEventArgs navigationArgs = new StepperNavigationEventArgs(ContinueNavigationEvent, this, Controller.ActiveStep, Controller.NextStep, false);
RaiseEvent(navigationArgs);
if (ContinueNavigationCommand != null && ContinueNavigationCommand.CanExecute(navigationArgs))
@@ -402,7 +439,7 @@ private void ContinueHandler(object sender, ExecutedRoutedEventArgs args)
if (!navigationArgs.Cancel)
{
- m_controller.Continue();
+ Controller.Continue();
}
}
@@ -412,10 +449,15 @@ private void CanExecuteStepSelectedHandler(object sender, CanExecuteRoutedEventA
}
private void StepSelectedHandler(object sender, ExecutedRoutedEventArgs args)
+ {
+ StepSelectedHandler((StepperStepViewModel)args.Parameter);
+ }
+
+ private void StepSelectedHandler(StepperStepViewModel stepperStepViewModel)
{
if (!IsLinear)
{
- StepperNavigationEventArgs navigationArgs = new StepperNavigationEventArgs(StepNavigationEvent, this, m_controller.ActiveStep, ((StepperStepViewModel)args.Parameter).Step, false);
+ StepperNavigationEventArgs navigationArgs = new StepperNavigationEventArgs(StepNavigationEvent, this, Controller.ActiveStep, stepperStepViewModel.Step, false);
RaiseEvent(navigationArgs);
if (StepNavigationCommand != null && StepNavigationCommand.CanExecute(navigationArgs))
@@ -425,20 +467,24 @@ private void StepSelectedHandler(object sender, ExecutedRoutedEventArgs args)
if (!navigationArgs.Cancel)
{
- m_controller.GotoStep((StepperStepViewModel)args.Parameter);
+ Controller.GotoStep(stepperStepViewModel);
}
}
}
private void PropertyChangedHandler(object sender, PropertyChangedEventArgs args)
{
- if (sender == m_controller && args.PropertyName == nameof(m_controller.ActiveStepContent)
- && m_controller.ActiveStepContent != null && Layout == StepperLayout.Horizontal)
+ if (sender == Controller && args.PropertyName == nameof(Controller.ActiveStepContent)
+ && Controller.ActiveStepContent != null && Layout == StepperLayout.Horizontal)
{
// there is no event raised if the Content of a ContentControl changes
// therefore trigger the animation in code
PlayHorizontalContentAnimation();
}
+ else if (sender == Controller && args.PropertyName == nameof(Controller.ActiveStep))
+ {
+ SelectedIndex = Controller.GetActiveStepIndex();
+ }
}
private void PlayHorizontalContentAnimation()
diff --git a/MaterialDesignExtensions/Controls/TextBoxFileSystemPath.cs b/MaterialDesignExtensions/Controls/TextBoxFileSystemPath.cs
new file mode 100644
index 00000000..601a5abc
--- /dev/null
+++ b/MaterialDesignExtensions/Controls/TextBoxFileSystemPath.cs
@@ -0,0 +1,126 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+
+using MaterialDesignThemes.Wpf;
+
+namespace MaterialDesignExtensions.Controls
+{
+ ///
+ /// Base class for a control with a text box and a button to open a file system dialog.
+ ///
+ public abstract class TextBoxFileSystemPath : Control
+ {
+ protected const string ShowDialogButtonName = "showButtonDialog";
+
+ ///
+ /// The dialog host ot show the dialog.
+ ///
+ public static readonly DependencyProperty DialogHostProperty = DependencyProperty.Register(
+ nameof(DialogHost), typeof(DialogHost), typeof(TextBoxFileSystemPath));
+
+ ///
+ /// The dialog host ot show the dialog.
+ ///
+ public DialogHost DialogHost
+ {
+ get
+ {
+ return (DialogHost)GetValue(DialogHostProperty);
+ }
+
+ set
+ {
+ SetValue(DialogHostProperty, value);
+ }
+ }
+
+ ///
+ /// The name of the dialog host to show the dialog.
+ ///
+ public static readonly DependencyProperty DialogHostNameProperty = DependencyProperty.Register(
+ nameof(DialogHostName), typeof(string), typeof(TextBoxFileSystemPath));
+
+ ///
+ /// The name of the dialog host to show the dialog.
+ ///
+ public string DialogHostName
+ {
+ get
+ {
+ return (string)GetValue(DialogHostNameProperty);
+ }
+
+ set
+ {
+ SetValue(DialogHostNameProperty, value);
+ }
+ }
+
+ ///
+ /// The for the inside the template.
+ ///
+ public static readonly DependencyProperty TextBoxStyleProperty = DependencyProperty.Register(
+ nameof(TextBoxStyle), typeof(Style), typeof(TextBoxFileSystemPath));
+
+ ///
+ /// The for the inside the template.
+ ///
+ public Style TextBoxStyle
+ {
+ get
+ {
+ return (Style)GetValue(TextBoxStyleProperty);
+ }
+
+ set
+ {
+ SetValue(TextBoxStyleProperty, value);
+ }
+ }
+
+ protected Button m_showButtonDialog;
+
+ static TextBoxFileSystemPath()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBoxFileSystemPath), new FrameworkPropertyMetadata(typeof(TextBoxFileSystemPath)));
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ public TextBoxFileSystemPath()
+ : base()
+ {
+ m_showButtonDialog = null;
+ }
+
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ if (m_showButtonDialog != null)
+ {
+ m_showButtonDialog.Click -= ShowDialogButtonClickHandler;
+ }
+
+ m_showButtonDialog = Template.FindName(ShowDialogButtonName, this) as Button;
+ m_showButtonDialog.Click += ShowDialogButtonClickHandler;
+ }
+
+ private async void ShowDialogButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ await ShowDialogAsync();
+ }
+
+ ///
+ /// Shows the according dialog for the control.
+ ///
+ ///
+ protected abstract Task ShowDialogAsync();
+ }
+}
diff --git a/MaterialDesignExtensions/Controls/TextBoxOpenDirectory.cs b/MaterialDesignExtensions/Controls/TextBoxOpenDirectory.cs
new file mode 100644
index 00000000..964be697
--- /dev/null
+++ b/MaterialDesignExtensions/Controls/TextBoxOpenDirectory.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace MaterialDesignExtensions.Controls
+{
+ ///
+ /// A control with a text box and a button to open a directory dialog.
+ ///
+ public class TextBoxOpenDirectory : TextBoxFileSystemPath
+ {
+ ///
+ /// The arguments for the dialog.
+ ///
+ public static readonly DependencyProperty DialogArgsProperty = DependencyProperty.Register(
+ nameof(DialogArgs), typeof(OpenDirectoryDialogArguments), typeof(TextBoxOpenDirectory));
+
+ ///
+ /// The arguments for the dialog.
+ ///
+ public OpenDirectoryDialogArguments DialogArgs
+ {
+ get
+ {
+ return (OpenDirectoryDialogArguments)GetValue(DialogArgsProperty);
+ }
+
+ set
+ {
+ SetValue(DialogArgsProperty, value);
+ }
+ }
+
+ ///
+ /// The selected directory.
+ ///
+ public static readonly DependencyProperty DirectoryProperty = DependencyProperty.Register(
+ nameof(Directory), typeof(string), typeof(TextBoxOpenDirectory));
+
+ ///
+ /// The selected directory.
+ ///
+ public string Directory
+ {
+ get
+ {
+ return (string)GetValue(DirectoryProperty);
+ }
+
+ set
+ {
+ SetValue(DirectoryProperty, value);
+ }
+ }
+
+ static TextBoxOpenDirectory()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBoxOpenDirectory), new FrameworkPropertyMetadata(typeof(TextBoxOpenDirectory)));
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ public TextBoxOpenDirectory() : base() { }
+
+ ///
+ /// Shows the according dialog for the control.
+ ///
+ ///
+ protected override async Task ShowDialogAsync()
+ {
+ OpenDirectoryDialogArguments args = null;
+
+ if (DialogArgs != null)
+ {
+ args = new OpenDirectoryDialogArguments(DialogArgs);
+ }
+ else
+ {
+ args = new OpenDirectoryDialogArguments();
+ }
+
+ if (!string.IsNullOrWhiteSpace(Directory) && System.IO.Directory.Exists(Directory))
+ {
+ args.CurrentDirectory = Directory;
+ }
+
+ OpenDirectoryDialogResult result = null;
+
+ if (DialogHost != null)
+ {
+ result = await OpenDirectoryDialog.ShowDialogAsync(DialogHost, args);
+ } else
+ {
+ result = await OpenDirectoryDialog.ShowDialogAsync(DialogHostName, args);
+ }
+
+ if (result != null && result.Confirmed)
+ {
+ Directory = result.DirectoryInfo.FullName;
+ }
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Controls/TextBoxOpenFile.cs b/MaterialDesignExtensions/Controls/TextBoxOpenFile.cs
new file mode 100644
index 00000000..63b1c5b0
--- /dev/null
+++ b/MaterialDesignExtensions/Controls/TextBoxOpenFile.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace MaterialDesignExtensions.Controls
+{
+ public class TextBoxOpenFile : TextBoxFileSystemPath
+ {
+ ///
+ /// The arguments for the dialog.
+ ///
+ public static readonly DependencyProperty DialogArgsProperty = DependencyProperty.Register(
+ nameof(DialogArgs), typeof(OpenFileDialogArguments), typeof(TextBoxOpenFile));
+
+ ///
+ /// The arguments for the dialog.
+ ///
+ public OpenFileDialogArguments DialogArgs
+ {
+ get
+ {
+ return (OpenFileDialogArguments)GetValue(DialogArgsProperty);
+ }
+
+ set
+ {
+ SetValue(DialogArgsProperty, value);
+ }
+ }
+
+ ///
+ /// The selected file.
+ ///
+ public static readonly DependencyProperty FileProperty = DependencyProperty.Register(
+ nameof(File), typeof(string), typeof(TextBoxOpenFile));
+
+ ///
+ /// The selected file.
+ ///
+ public string File
+ {
+ get
+ {
+ return (string)GetValue(FileProperty);
+ }
+
+ set
+ {
+ SetValue(FileProperty, value);
+ }
+ }
+
+ static TextBoxOpenFile()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBoxOpenFile), new FrameworkPropertyMetadata(typeof(TextBoxOpenFile)));
+ }
+
+ public TextBoxOpenFile() : base() { }
+
+ ///
+ /// Shows the according dialog for the control.
+ ///
+ ///
+ protected override async Task ShowDialogAsync()
+ {
+ OpenFileDialogArguments args = null;
+
+ if (DialogArgs != null)
+ {
+ args = new OpenFileDialogArguments(DialogArgs);
+ }
+ else
+ {
+ args = new OpenFileDialogArguments();
+ }
+
+ if (!string.IsNullOrWhiteSpace(File))
+ {
+ string directory = Path.GetDirectoryName(File);
+
+ if (!string.IsNullOrWhiteSpace(directory) && Directory.Exists(directory))
+ {
+ args.CurrentDirectory = directory;
+ }
+ }
+
+ OpenFileDialogResult result = null;
+
+ if (DialogHost != null)
+ {
+ result = await OpenFileDialog.ShowDialogAsync(DialogHost, args);
+ }
+ else
+ {
+ result = await OpenFileDialog.ShowDialogAsync(DialogHostName, args);
+ }
+
+ if (result != null && result.Confirmed)
+ {
+ File = result.FileInfo.FullName;
+ }
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Controls/TextBoxSaveFile.cs b/MaterialDesignExtensions/Controls/TextBoxSaveFile.cs
new file mode 100644
index 00000000..6e347957
--- /dev/null
+++ b/MaterialDesignExtensions/Controls/TextBoxSaveFile.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace MaterialDesignExtensions.Controls
+{
+ public class TextBoxSaveFile : TextBoxFileSystemPath
+ {
+ ///
+ /// The arguments for the dialog.
+ ///
+ public static readonly DependencyProperty DialogArgsProperty = DependencyProperty.Register(
+ nameof(DialogArgs), typeof(SaveFileDialogArguments), typeof(TextBoxSaveFile));
+
+ ///
+ /// The arguments for the dialog.
+ ///
+ public SaveFileDialogArguments DialogArgs
+ {
+ get
+ {
+ return (SaveFileDialogArguments)GetValue(DialogArgsProperty);
+ }
+
+ set
+ {
+ SetValue(DialogArgsProperty, value);
+ }
+ }
+
+ ///
+ /// The selected file.
+ ///
+ public static readonly DependencyProperty FileProperty = DependencyProperty.Register(
+ nameof(File), typeof(string), typeof(TextBoxSaveFile));
+
+ ///
+ /// The selected file.
+ ///
+ public string File
+ {
+ get
+ {
+ return (string)GetValue(FileProperty);
+ }
+
+ set
+ {
+ SetValue(FileProperty, value);
+ }
+ }
+
+ static TextBoxSaveFile()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBoxSaveFile), new FrameworkPropertyMetadata(typeof(TextBoxSaveFile)));
+ }
+
+ public TextBoxSaveFile() : base() { }
+
+ protected override async Task ShowDialogAsync()
+ {
+ SaveFileDialogArguments args = null;
+
+ if (DialogArgs != null)
+ {
+ args = new SaveFileDialogArguments(DialogArgs);
+ }
+ else
+ {
+ args = new SaveFileDialogArguments();
+ }
+
+ if (!string.IsNullOrWhiteSpace(File))
+ {
+ string directory = Path.GetDirectoryName(File);
+
+ if (!string.IsNullOrWhiteSpace(directory) && Directory.Exists(directory))
+ {
+ args.CurrentDirectory = directory;
+ }
+ }
+
+ SaveFileDialogResult result = null;
+
+ if (DialogHost != null)
+ {
+ result = await SaveFileDialog.ShowDialogAsync(DialogHost, args);
+ }
+ else
+ {
+ result = await SaveFileDialog.ShowDialogAsync(DialogHostName, args);
+ }
+
+ if (result != null && result.Confirmed)
+ {
+ File = result.FileInfo.FullName;
+ }
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Controls/TextBoxSuggestions.cs b/MaterialDesignExtensions/Controls/TextBoxSuggestions.cs
index aefdd493..3715e2fd 100644
--- a/MaterialDesignExtensions/Controls/TextBoxSuggestions.cs
+++ b/MaterialDesignExtensions/Controls/TextBoxSuggestions.cs
@@ -6,10 +6,10 @@
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
-using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Markup;
+using MaterialDesignExtensions.Commands.Internal;
using MaterialDesignExtensions.Controllers;
using MaterialDesignExtensions.Model;
@@ -25,9 +25,26 @@ public class TextBoxSuggestions : ControlWithAutocompletePopup
private static readonly string SuggestionItemsPopupName = "suggestionItemsPopup";
///
- /// Internal command used by the XAML template (public to be available in the XAML template). Not intended for external usage.
+ /// True to keep the focus on the text box after selecting a suggestion.
///
- public static readonly RoutedCommand SelectSuggestionItemCommand = new RoutedCommand();
+ public static readonly DependencyProperty KeepFocusOnSelectionProperty = DependencyProperty.Register(
+ nameof(KeepFocusOnSelection), typeof(bool), typeof(TextBoxSuggestions), new PropertyMetadata(false));
+
+ ///
+ /// True to keep the focus on the text box after selecting a suggestion.
+ ///
+ public bool KeepFocusOnSelection
+ {
+ get
+ {
+ return (bool)GetValue(KeepFocusOnSelectionProperty);
+ }
+
+ set
+ {
+ SetValue(KeepFocusOnSelectionProperty, value);
+ }
+ }
///
/// The TextBox to decorate.
@@ -92,7 +109,7 @@ public TextBoxSuggestions()
m_autocompleteController = new AutocompleteController() { AutocompleteSource = TextBoxSuggestionsSource };
- CommandBindings.Add(new CommandBinding(SelectSuggestionItemCommand, SelectSuggestionItemCommandHandler));
+ CommandBindings.Add(new CommandBinding(TextBoxSuggestionsCommands.SelectSuggestionItemCommand, SelectSuggestionItemCommandHandler));
Loaded += LoadedHandler;
Unloaded += UnloadedHandler;
@@ -148,7 +165,17 @@ private void SelectSuggestionItemCommandHandler(object sender, ExecutedRoutedEve
{
if (TextBox != null)
{
- TextBox.Text = args.Parameter as string;
+ TextBox.Text = args.Parameter as string ?? string.Empty;
+
+ if (KeepFocusOnSelection)
+ {
+ Keyboard.Focus(TextBox);
+ TextBox.CaretIndex = TextBox.Text.Length;
+ }
+ else
+ {
+ Keyboard.Focus(null);
+ }
}
}
@@ -174,7 +201,7 @@ private void TextBoxChangedHandler(TextBox oldTextBox, TextBox newTextBox)
private void TextBoxTextChangedHandler(object sender, TextChangedEventArgs args)
{
- if (sender == TextBox)
+ if (sender == TextBox && IsEnabled && IsLoaded && TextBox.IsLoaded && TextBox.IsFocused)
{
m_autocompleteController?.Search(TextBox.Text);
}
diff --git a/MaterialDesignExtensions/Controls/TransitionContentControl.cs b/MaterialDesignExtensions/Controls/TransitionContentControl.cs
new file mode 100644
index 00000000..70742231
--- /dev/null
+++ b/MaterialDesignExtensions/Controls/TransitionContentControl.cs
@@ -0,0 +1,203 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media.Animation;
+
+namespace MaterialDesignExtensions.Controls
+{
+ ///
+ /// A basic content control which uses an animation for switching its content.
+ ///
+ public class TransitionContentControl : Control
+ {
+ private const string ContentControl1Name = "ContentControl1";
+ private const string ContentControl2Name = "ContentControl2";
+
+ private object m_lockObject = new object();
+
+ private bool AnimationIsRunning
+ {
+ get
+ {
+ lock (m_lockObject)
+ {
+ return m_animationIsRunning;
+ }
+ }
+
+ set
+ {
+ lock (m_lockObject)
+ {
+ m_animationIsRunning = value;
+ }
+ }
+ }
+
+ ///
+ /// The content of the control.
+ ///
+ public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(
+ nameof(Content), typeof(object), typeof(TransitionContentControl), new PropertyMetadata(null, ContentPropertyChangedCallback));
+
+ ///
+ /// The content of the control.
+ ///
+ public object Content
+ {
+ get
+ {
+ return GetValue(ContentProperty);
+ }
+
+ set
+ {
+ SetValue(ContentProperty, value);
+ }
+ }
+
+ ///
+ /// The transition animation for switching the content.
+ ///
+ public static readonly DependencyProperty TransitionTypeProperty = DependencyProperty.Register(
+ nameof(TransitionType), typeof(TransitionContentControlTransitionType), typeof(TransitionContentControl), new PropertyMetadata(TransitionContentControlTransitionType.FadeInAndGrow, null));
+
+ ///
+ /// The transition animation for switching the content.
+ ///
+ public TransitionContentControlTransitionType TransitionType
+ {
+ get
+ {
+ return (TransitionContentControlTransitionType)GetValue(TransitionTypeProperty);
+ }
+
+ set
+ {
+ SetValue(TransitionTypeProperty, value);
+ }
+ }
+
+ private static void ContentPropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
+ {
+ if (sender is TransitionContentControl control)
+ {
+ control.SwitchContent(args.NewValue);
+ }
+ }
+
+ private ContentControl[] m_contentControls;
+ private IDictionary m_storyboards;
+
+ private int m_foregroundIndex;
+ private bool m_animationIsRunning;
+
+ static TransitionContentControl()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(TransitionContentControl), new FrameworkPropertyMetadata(typeof(TransitionContentControl)));
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ public TransitionContentControl()
+ : base()
+ {
+ m_contentControls = null;
+ m_storyboards = null;
+
+ m_foregroundIndex = 0;
+ }
+
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ m_contentControls = new ContentControl[]
+ {
+ GetTemplateChild(ContentControl1Name) as ContentControl,
+ GetTemplateChild(ContentControl2Name) as ContentControl
+ };
+
+ m_storyboards = new Dictionary();
+
+ foreach (TransitionContentControlTransitionType transitionType in Enum.GetValues(typeof(TransitionContentControlTransitionType)))
+ {
+ m_storyboards[transitionType] = Template.Resources[GetStoryboardNameForTransitionType(transitionType)] as Storyboard;
+ }
+ }
+
+ private async void SwitchContent(object content)
+ {
+ if (m_contentControls != null)
+ {
+ if (!AnimationIsRunning)
+ {
+ try
+ {
+ AnimationIsRunning = true;
+
+ // set new content and push it into foreground
+ int currentIndex = m_foregroundIndex;
+ m_foregroundIndex++;
+
+ if (m_foregroundIndex >= m_contentControls.Length)
+ {
+ m_foregroundIndex = 0;
+ }
+
+ m_contentControls[m_foregroundIndex].Content = content;
+
+ // delay the animation until the rendering of the new content is finished
+ // by running the code via the Dispatcher with a priority lower than the rendering
+ await Dispatcher.Invoke(async () =>
+ {
+ // move the new content into foreground
+ Panel.SetZIndex(m_contentControls[m_foregroundIndex], Panel.GetZIndex(m_contentControls[currentIndex]) + 1);
+ Panel.SetZIndex(m_contentControls[currentIndex], 0);
+
+ // start the animation
+ Storyboard storyboard = m_storyboards[TransitionType];
+ storyboard.Begin(m_contentControls[m_foregroundIndex]);
+
+ // wait until the animation completes and finally remove the hidden content to free memory
+ // add a short delay to the animation duration
+ int animationDuration = (int)storyboard.Children.Max(x => x.Duration.TimeSpan.TotalMilliseconds);
+
+ await Task.Delay(animationDuration + 50);
+
+ m_contentControls[currentIndex].Content = null;
+ }, System.Windows.Threading.DispatcherPriority.Loaded);
+ }
+ finally
+ {
+ AnimationIsRunning = false;
+ }
+ }
+ else
+ {
+ m_contentControls[m_foregroundIndex].Content = content;
+ }
+ }
+ }
+
+ private string GetStoryboardNameForTransitionType(TransitionContentControlTransitionType transitionType)
+ {
+ return $"{Enum.GetName(typeof(TransitionContentControlTransitionType), transitionType)}Storyboard";
+ }
+ }
+
+ ///
+ /// The available animations for .
+ ///
+ public enum TransitionContentControlTransitionType : byte
+ {
+ FadeIn,
+ Grow,
+ FadeInAndGrow
+ }
+}
diff --git a/MaterialDesignExtensions/Converters/AsyncImageTask.cs b/MaterialDesignExtensions/Converters/AsyncImageTask.cs
index e94a00c6..dd477dd9 100644
--- a/MaterialDesignExtensions/Converters/AsyncImageTask.cs
+++ b/MaterialDesignExtensions/Converters/AsyncImageTask.cs
@@ -18,41 +18,70 @@ namespace MaterialDesignExtensions.Converters
///
public class AsyncImageTask : INotifyPropertyChanged
{
+ private readonly object m_lockObject = new object();
+
///
/// The property changed event.
///
public event PropertyChangedEventHandler PropertyChanged;
-
+
+ private object m_image;
+
///
/// The loaded image.
///
- public object Image { get; private set; }
+ public object Image
+ {
+ get
+ {
+ lock (m_lockObject)
+ {
+ return m_image;
+ }
+ }
+
+ private set
+ {
+ lock (m_lockObject)
+ {
+ if (m_image != value)
+ {
+ m_image = value;
+
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Image)));
+ }
+ }
+ }
+ }
///
/// Creates a new AsyncImageTask to load the image with the specified width and height keeping its ratio.
///
- ///
- ///
- ///
+ /// The full filename of the image
+ /// The target width of the image
+ /// The target height of the image
+ /// True to enable caching
public AsyncImageTask(string imageFilename, int targetWidth = 40, int targetHeight = 40, bool useCache = false)
{
- Image = PackIconKind.FileImage;
+ m_image = PackIconKind.FileImage;
LoadImageAsync(imageFilename, targetWidth, targetHeight, useCache);
}
private async void LoadImageAsync(string imageFilename, int targetWidth, int targetHeight, bool useCache)
{
- object image = await Task.Run(() => BitmapImageHelper.LoadImage(imageFilename, targetWidth, targetHeight, useCache));
-
- if (image == null)
+ await Task.Run(async () =>
{
- image = PackIconKind.Image;
- }
-
- Image = image;
+#if DEBUG
+ Console.WriteLine($"get image {imageFilename}");
+#endif
+ BitmapImage image = await BitmapImageHelper.LoadImageAsync(imageFilename, targetWidth, targetHeight, useCache).ConfigureAwait(false);
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Image)));
+ if (image != null)
+ {
+ Image = image;
+ }
+ }).ConfigureAwait(false);
}
}
}
diff --git a/MaterialDesignExtensions/Converters/BoolToVisibilityConverter.cs b/MaterialDesignExtensions/Converters/BoolToVisibilityConverter.cs
index 74e4fbda..25f71e5e 100644
--- a/MaterialDesignExtensions/Converters/BoolToVisibilityConverter.cs
+++ b/MaterialDesignExtensions/Converters/BoolToVisibilityConverter.cs
@@ -9,12 +9,24 @@
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Converter to map a boolean to a .
+ ///
public class BoolToVisibilityConverter : IValueConverter
{
+ ///
+ /// The visibility value if the argument is false.
+ ///
public Visibility FalseValue { get; set; }
+ ///
+ /// The visibility value if the argument is true.
+ ///
public Visibility TrueValue { get; set; }
+ ///
+ /// Creates a new .
+ ///
public BoolToVisibilityConverter()
{
FalseValue = Visibility.Collapsed;
diff --git a/MaterialDesignExtensions/Converters/BooleanAndConverter.cs b/MaterialDesignExtensions/Converters/BooleanAndConverter.cs
index a1039e41..227aff09 100644
--- a/MaterialDesignExtensions/Converters/BooleanAndConverter.cs
+++ b/MaterialDesignExtensions/Converters/BooleanAndConverter.cs
@@ -8,8 +8,14 @@
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Converter to apply boolean "and" operation.
+ ///
public class BooleanAndConverter : IMultiValueConverter
{
+ ///
+ /// Creates a new .
+ ///
public BooleanAndConverter() { }
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
diff --git a/MaterialDesignExtensions/Converters/BooleanAndToVisibilityConverter.cs b/MaterialDesignExtensions/Converters/BooleanAndToVisibilityConverter.cs
index 19f67cb9..3c8536e9 100644
--- a/MaterialDesignExtensions/Converters/BooleanAndToVisibilityConverter.cs
+++ b/MaterialDesignExtensions/Converters/BooleanAndToVisibilityConverter.cs
@@ -9,11 +9,17 @@
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Converter to apply boolean "and" operation and map to a .
+ ///
public class BooleanAndToVisibilityConverter : IMultiValueConverter
{
private BooleanAndConverter m_booleanAndConverter;
private BoolToVisibilityConverter m_boolToVisibilityConverter;
+ ///
+ /// The visibility value if the argument is false.
+ ///
public Visibility FalseValue
{
get
@@ -27,6 +33,9 @@ public Visibility FalseValue
}
}
+ ///
+ /// The visibility value if the argument is true.
+ ///
public Visibility TrueValue
{
get
@@ -40,6 +49,9 @@ public Visibility TrueValue
}
}
+ ///
+ /// Creates a new .
+ ///
public BooleanAndToVisibilityConverter()
{
m_booleanAndConverter = new BooleanAndConverter();
diff --git a/MaterialDesignExtensions/Converters/BooleanOrConverter.cs b/MaterialDesignExtensions/Converters/BooleanOrConverter.cs
index aa25ba93..56145559 100644
--- a/MaterialDesignExtensions/Converters/BooleanOrConverter.cs
+++ b/MaterialDesignExtensions/Converters/BooleanOrConverter.cs
@@ -8,8 +8,14 @@
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Converter to apply boolean "or" operation.
+ ///
public class BooleanOrConverter : IMultiValueConverter
{
+ ///
+ /// Creates a new .
+ ///
public BooleanOrConverter() { }
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
diff --git a/MaterialDesignExtensions/Converters/BooleanOrToVisibilityConverter.cs b/MaterialDesignExtensions/Converters/BooleanOrToVisibilityConverter.cs
index 4414ea1a..2b395946 100644
--- a/MaterialDesignExtensions/Converters/BooleanOrToVisibilityConverter.cs
+++ b/MaterialDesignExtensions/Converters/BooleanOrToVisibilityConverter.cs
@@ -9,11 +9,17 @@
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Converter to apply boolean "and" operation and map to a .
+ ///
public class BooleanOrToVisibilityConverter : IMultiValueConverter
{
private BooleanOrConverter m_booleanOrConverter;
private BoolToVisibilityConverter m_boolToVisibilityConverter;
+ ///
+ /// The visibility value if the argument is false.
+ ///
public Visibility FalseValue
{
get
@@ -27,6 +33,9 @@ public Visibility FalseValue
}
}
+ ///
+ /// The visibility value if the argument is true.
+ ///
public Visibility TrueValue
{
get
@@ -40,6 +49,9 @@ public Visibility TrueValue
}
}
+ ///
+ /// Creates a new .
+ ///
public BooleanOrToVisibilityConverter()
{
m_booleanOrConverter = new BooleanOrConverter();
diff --git a/MaterialDesignExtensions/Converters/DateTimeAgoConverter.cs b/MaterialDesignExtensions/Converters/DateTimeAgoConverter.cs
index de2d5a1a..9db62273 100644
--- a/MaterialDesignExtensions/Converters/DateTimeAgoConverter.cs
+++ b/MaterialDesignExtensions/Converters/DateTimeAgoConverter.cs
@@ -8,8 +8,14 @@
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Converter for displaying a past .
+ ///
public class DateTimeAgoConverter : IValueConverter
{
+ ///
+ /// Creates a new .
+ ///
public DateTimeAgoConverter() { }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
@@ -19,7 +25,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn
DateTime now = DateTime.Now;
TimeSpan timeSpan = now - dateTime;
- if (timeSpan.TotalHours < 24)
+ if (now.Date == dateTime.Date && timeSpan.TotalHours < 24)
{
return dateTime.ToShortTimeString();
}
diff --git a/MaterialDesignExtensions/Converters/EmptyEnumerableToBoolConverter.cs b/MaterialDesignExtensions/Converters/EmptyEnumerableToBoolConverter.cs
index bfabf9c4..7849dbb5 100644
--- a/MaterialDesignExtensions/Converters/EmptyEnumerableToBoolConverter.cs
+++ b/MaterialDesignExtensions/Converters/EmptyEnumerableToBoolConverter.cs
@@ -9,10 +9,19 @@
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Maps a null or empty to a boolean value.
+ ///
public class EmptyEnumerableToBoolConverter : IValueConverter
{
+ ///
+ /// The boolean value, if the is empty or null.
+ ///
public bool EmptyValue { get; set; }
+ ///
+ /// Creates a new .
+ ///
public EmptyEnumerableToBoolConverter() { }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
diff --git a/MaterialDesignExtensions/Converters/EmptyEnumerableVisibilityConverter.cs b/MaterialDesignExtensions/Converters/EmptyEnumerableVisibilityConverter.cs
index 74fb806c..955a7109 100644
--- a/MaterialDesignExtensions/Converters/EmptyEnumerableVisibilityConverter.cs
+++ b/MaterialDesignExtensions/Converters/EmptyEnumerableVisibilityConverter.cs
@@ -10,12 +10,24 @@
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Maps a null or empty to a .
+ ///
public class EmptyEnumerableVisibilityConverter : IValueConverter
{
+ ///
+ /// The visibility value of an empty or null .
+ ///
public Visibility EmptyVisibility { get; set; }
+ ///
+ /// The visibility value of a non empty .
+ ///
public Visibility NotEmptyVisibility { get; set; }
+ ///
+ /// Creates a new .
+ ///
public EmptyEnumerableVisibilityConverter()
{
EmptyVisibility = Visibility.Collapsed;
diff --git a/MaterialDesignExtensions/Converters/FileFiltersTypeConverter.cs b/MaterialDesignExtensions/Converters/FileFiltersTypeConverter.cs
index 4f42b544..96230c07 100644
--- a/MaterialDesignExtensions/Converters/FileFiltersTypeConverter.cs
+++ b/MaterialDesignExtensions/Converters/FileFiltersTypeConverter.cs
@@ -11,8 +11,14 @@
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Converter for mappings between and .
+ ///
public class FileFiltersTypeConverter : TypeConverter
{
+ ///
+ /// Creates a new .
+ ///
public FileFiltersTypeConverter() { }
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
diff --git a/MaterialDesignExtensions/Converters/FileSizeConverter.cs b/MaterialDesignExtensions/Converters/FileSizeConverter.cs
index 7f67380c..6869021b 100644
--- a/MaterialDesignExtensions/Converters/FileSizeConverter.cs
+++ b/MaterialDesignExtensions/Converters/FileSizeConverter.cs
@@ -8,8 +8,14 @@
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Converts a file size of bytes into a user friendly string.
+ ///
public class FileSizeConverter : IValueConverter
{
+ ///
+ /// Creates a new .
+ ///
public FileSizeConverter() { }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
diff --git a/MaterialDesignExtensions/Converters/FileSystemInfoIconConverter.cs b/MaterialDesignExtensions/Converters/FileSystemInfoIconConverter.cs
index 5368df95..a85eb163 100644
--- a/MaterialDesignExtensions/Converters/FileSystemInfoIconConverter.cs
+++ b/MaterialDesignExtensions/Converters/FileSystemInfoIconConverter.cs
@@ -11,21 +11,45 @@
using MaterialDesignExtensions.Controllers;
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using DirectoryInfo = Pri.LongPath.DirectoryInfo;
+using FileInfo = Pri.LongPath.FileInfo;
+#endif
+
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Converts a file extension to a content related icon.
+ ///
public class FileSystemInfoIconConverter : IValueConverter
{
private ISet m_imageFileExtensions;
private IDictionary m_contentForFileExtension;
+ ///
+ /// The content mode to control the type of icons or thumbnails for image file types.
+ ///
public FileSystemInfoIconConverterImageMode ImageMode { get; set; }
+ ///
+ /// The width of a loaded thumbnail image.
+ ///
public int ImageTargetWidth { get; set; }
+ ///
+ /// The height of a loaded thumbnail image.
+ ///
public int ImageTargetHeight { get; set; }
+ ///
+ /// True to use a cache for loaded images.
+ ///
public bool UseCache { get; set; }
+ ///
+ /// Creates a new .
+ ///
public FileSystemInfoIconConverter()
{
ImageMode = FileSystemInfoIconConverterImageMode.Icon;
@@ -48,15 +72,15 @@ public FileSystemInfoIconConverter()
// code
["cs"] = PackIconKind.LanguageCsharp,
["xaml"] = PackIconKind.Xml,
- ["ts"] = PackIconKind.CodeBraces,
+ ["ts"] = PackIconKind.LanguageTypescript,
["js"] = PackIconKind.LanguageJavascript,
- ["java"] = PackIconKind.CodeBraces,
+ ["java"] = PackIconKind.LanguageJava,
["c"] = PackIconKind.LanguageC,
["cpp"] = PackIconKind.LanguageCpp,
["h"] = PackIconKind.CodeBraces,
["py"] = PackIconKind.LanguagePython,
["php"] = PackIconKind.LanguagePhp,
- ["r"] = PackIconKind.CodeBraces,
+ ["r"] = PackIconKind.LanguageR,
// compiled code and executables
["exe"] = PackIconKind.Settings,
@@ -74,7 +98,7 @@ public FileSystemInfoIconConverter()
["htm"] = PackIconKind.Xml,
["css"] = PackIconKind.CodeTags,
["xml"] = PackIconKind.Xml,
- ["json"] = PackIconKind.Json,
+ ["json"] = PackIconKind.CodeJson,
["xsl"] = PackIconKind.Xml,
["xslt"] = PackIconKind.Xml,
["sql"] = PackIconKind.Database,
@@ -198,10 +222,24 @@ private object GetContentForFile(string filename)
}
}
+ ///
+ /// The content mode to control the type of icons or thumbnails for image file types.
+ ///
public enum FileSystemInfoIconConverterImageMode : byte
{
+ ///
+ /// Only use icons
+ ///
Icon,
+
+ ///
+ /// Use thumbnails for images
+ ///
Image,
+
+ ///
+ /// Use async task to load thumbnail images
+ ///
AsyncImageTask
}
}
diff --git a/MaterialDesignExtensions/Converters/FileSystemInfoPackIconColorConverter.cs b/MaterialDesignExtensions/Converters/FileSystemInfoPackIconColorConverter.cs
index ecfc24f1..def2f44b 100644
--- a/MaterialDesignExtensions/Converters/FileSystemInfoPackIconColorConverter.cs
+++ b/MaterialDesignExtensions/Converters/FileSystemInfoPackIconColorConverter.cs
@@ -11,10 +11,16 @@
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Converts a to a special color for displaying it.
+ ///
public class FileSystemInfoPackIconColorConverter : IValueConverter
{
private IDictionary m_brushesForPackIcon;
+ ///
+ /// Creates a new .
+ ///
public FileSystemInfoPackIconColorConverter()
{
m_brushesForPackIcon = new Dictionary()
diff --git a/MaterialDesignExtensions/Converters/NotNullBooleanConverter.cs b/MaterialDesignExtensions/Converters/NotNullBooleanConverter.cs
index eeeaa18e..31bc9c4c 100644
--- a/MaterialDesignExtensions/Converters/NotNullBooleanConverter.cs
+++ b/MaterialDesignExtensions/Converters/NotNullBooleanConverter.cs
@@ -8,8 +8,15 @@
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Converts a not null value to true, otherwise false.
+ /// A special logic for strings will be applied to handle empty or whitespace only strings like null values.
+ ///
public class NotNullBooleanConverter : IValueConverter
{
+ ///
+ /// Creates a new .
+ ///
public NotNullBooleanConverter() { }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
diff --git a/MaterialDesignExtensions/Converters/NotNullToVisibilityConverter.cs b/MaterialDesignExtensions/Converters/NotNullToVisibilityConverter.cs
index c14c8d42..afdb6f96 100644
--- a/MaterialDesignExtensions/Converters/NotNullToVisibilityConverter.cs
+++ b/MaterialDesignExtensions/Converters/NotNullToVisibilityConverter.cs
@@ -9,10 +9,19 @@
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Converts null or not null to a .
+ ///
public class NotNullToVisibilityConverter : IValueConverter
{
+ ///
+ /// The visibility value if the argument is null.
+ ///
public Visibility NullValue { get; set; }
+ ///
+ /// Creates a new .
+ ///
public NotNullToVisibilityConverter()
{
NullValue = Visibility.Collapsed;
diff --git a/MaterialDesignExtensions/Converters/NullToVisibilityConverter.cs b/MaterialDesignExtensions/Converters/NullToVisibilityConverter.cs
index 7db51c48..46afb2e4 100644
--- a/MaterialDesignExtensions/Converters/NullToVisibilityConverter.cs
+++ b/MaterialDesignExtensions/Converters/NullToVisibilityConverter.cs
@@ -9,12 +9,24 @@
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Converts a null value to a .
+ ///
public class NullToVisibilityConverter : IValueConverter
{
+ ///
+ /// The visibility value for a null value.
+ ///
public Visibility NullValue { get; set; }
+ ///
+ /// The visibility value for a not null value.
+ ///
public Visibility NotNullValue { get; set; }
+ ///
+ /// Creates a new .
+ ///
public NullToVisibilityConverter()
{
NullValue = Visibility.Collapsed;
diff --git a/MaterialDesignExtensions/Converters/ObjectCollectionToVisibilityConverter.cs b/MaterialDesignExtensions/Converters/ObjectCollectionToVisibilityConverter.cs
index 9daa0c5c..1de9ace9 100644
--- a/MaterialDesignExtensions/Converters/ObjectCollectionToVisibilityConverter.cs
+++ b/MaterialDesignExtensions/Converters/ObjectCollectionToVisibilityConverter.cs
@@ -11,10 +11,19 @@
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Converts an empty collection to a .
+ ///
public class ObjectCollectionToVisibilityConverter : IValueConverter
{
+ ///
+ /// The visibility value of an empty collection.
+ ///
public Visibility EmptyValue { get; set; }
+ ///
+ /// Creates a new .
+ ///
public ObjectCollectionToVisibilityConverter()
{
EmptyValue = Visibility.Collapsed;
diff --git a/MaterialDesignExtensions/Converters/ObjectHasTypeConverter.cs b/MaterialDesignExtensions/Converters/ObjectHasTypeConverter.cs
index 64c06c0d..58c4ba15 100644
--- a/MaterialDesignExtensions/Converters/ObjectHasTypeConverter.cs
+++ b/MaterialDesignExtensions/Converters/ObjectHasTypeConverter.cs
@@ -8,24 +8,21 @@
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Checks the type of the argument if it is of a specified type.
+ ///
public class ObjectHasTypeConverter : IMultiValueConverter
{
+ ///
+ /// The fully qualified name of the type.
+ ///
public string FullTypeName { get; set; }
+ ///
+ /// Creates a new .
+ ///
public ObjectHasTypeConverter() { }
- /*public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
- {
- string valueType = value != null ? value.GetType().FullName : "null";
-
- return valueType == FullTypeName;
- }
-
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
- {
- return Binding.DoNothing;
- }*/
-
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values != null && values.Length == 2)
diff --git a/MaterialDesignExtensions/Converters/ObjectToTypeStringConverter.cs b/MaterialDesignExtensions/Converters/ObjectToTypeStringConverter.cs
index 6e498928..bd70467f 100644
--- a/MaterialDesignExtensions/Converters/ObjectToTypeStringConverter.cs
+++ b/MaterialDesignExtensions/Converters/ObjectToTypeStringConverter.cs
@@ -8,8 +8,14 @@
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Converts an object to its fully qualified type name.
+ ///
public class ObjectToTypeStringConverter : IValueConverter
{
+ ///
+ /// Creates a new .
+ ///
public ObjectToTypeStringConverter() { }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
diff --git a/MaterialDesignExtensions/Converters/StepIconTemplateConverter.cs b/MaterialDesignExtensions/Converters/StepIconTemplateConverter.cs
new file mode 100644
index 00000000..91645e6a
--- /dev/null
+++ b/MaterialDesignExtensions/Converters/StepIconTemplateConverter.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Data;
+
+using MaterialDesignExtensions.Controls;
+using MaterialDesignExtensions.Model;
+using MaterialDesignExtensions.TemplateSelectors;
+
+namespace MaterialDesignExtensions.Converters
+{
+ ///
+ /// A converter triggering a for selecting an item for a step.
+ /// This converter is necessary to react on changing data of the stepper and steps to call the selector logic again.
+ ///
+ public class StepIconTemplateConverter : IMultiValueConverter
+ {
+ private StepIconTemplateSelector _iconTemplateSelector;
+
+ ///
+ /// Creates a new .
+ ///
+ public StepIconTemplateConverter()
+ {
+ _iconTemplateSelector = new StepIconTemplateSelector();
+ }
+
+ public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (values == null)
+ {
+ throw new ArgumentNullException(nameof(values));
+ }
+
+ IStepper stepper = values[0] as IStepper;
+ FrameworkElement element = values[1] as FrameworkElement;
+ StepperStepViewModel stepViewModel = values[2] as StepperStepViewModel;
+
+ return _iconTemplateSelector.SelectTemplate(stepper, element, stepViewModel);
+ }
+
+ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Converters/UpperCaseConverter.cs b/MaterialDesignExtensions/Converters/UpperCaseConverter.cs
index bb421d80..0546c4f1 100644
--- a/MaterialDesignExtensions/Converters/UpperCaseConverter.cs
+++ b/MaterialDesignExtensions/Converters/UpperCaseConverter.cs
@@ -8,8 +8,14 @@
namespace MaterialDesignExtensions.Converters
{
+ ///
+ /// Converts a string to upper case.
+ ///
public class UpperCaseConverter : IValueConverter
{
+ ///
+ /// Creates a new .
+ ///
public UpperCaseConverter() { }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
diff --git a/MaterialDesignExtensions/Converters/WindowCaptionButtonBaseConverter.cs b/MaterialDesignExtensions/Converters/WindowCaptionButtonBaseConverter.cs
new file mode 100644
index 00000000..6b448302
--- /dev/null
+++ b/MaterialDesignExtensions/Converters/WindowCaptionButtonBaseConverter.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+
+namespace MaterialDesignExtensions.Converters
+{
+ ///
+ /// Base class for the converters controlling the visibility and enabled state of window caption buttons.
+ ///
+ public abstract class WindowCaptionButtonBaseConverter : IMultiValueConverter
+ {
+ ///
+ /// Identifier for the minimize caption button.
+ ///
+ public string MinimizeButtonName => "minimizeButton";
+
+ ///
+ /// Identifier for the maximize/restore caption button.
+ ///
+ public string MaximizeRestoreButtonName => "maximizeRestoreButton";
+
+ ///
+ /// Identifier for the close caption button.
+ ///
+ public string CloseButtonName => "closeButton";
+
+ ///
+ /// Creates a new .
+ ///
+ public WindowCaptionButtonBaseConverter() { }
+
+ public abstract object Convert(object[] values, Type targetType, object parameter, CultureInfo culture);
+
+ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Converters/WindowCaptionButtonEnabledConverter.cs b/MaterialDesignExtensions/Converters/WindowCaptionButtonEnabledConverter.cs
new file mode 100644
index 00000000..a5916364
--- /dev/null
+++ b/MaterialDesignExtensions/Converters/WindowCaptionButtonEnabledConverter.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace MaterialDesignExtensions.Converters
+{
+ ///
+ /// Converts a of a window into an enabled state of an according caption button.
+ ///
+ public class WindowCaptionButtonEnabledConverter : WindowCaptionButtonBaseConverter
+ {
+ ///
+ /// Creates a new .
+ ///
+ public WindowCaptionButtonEnabledConverter() : base() { }
+
+ public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+ {
+ try
+ {
+ if (values != null && values.Length == 2)
+ {
+ string buttonName = (string)values[0];
+ ResizeMode resizeMode = (ResizeMode)values[1];
+
+ if (buttonName == CloseButtonName)
+ {
+ return true;
+ }
+ else if (buttonName == MinimizeButtonName)
+ {
+ return resizeMode != ResizeMode.NoResize;
+ }
+ else if (buttonName == MaximizeRestoreButtonName)
+ {
+ return resizeMode != ResizeMode.NoResize && resizeMode != ResizeMode.CanMinimize;
+ }
+ }
+ }
+ catch (Exception)
+ {
+ // use the default return value below
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Converters/WindowCaptionButtonVisibilityConverter.cs b/MaterialDesignExtensions/Converters/WindowCaptionButtonVisibilityConverter.cs
new file mode 100644
index 00000000..f5978f42
--- /dev/null
+++ b/MaterialDesignExtensions/Converters/WindowCaptionButtonVisibilityConverter.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace MaterialDesignExtensions.Converters
+{
+ ///
+ /// Converts a and a of a window into a of an according caption button.
+ ///
+ public class WindowCaptionButtonVisibilityConverter : WindowCaptionButtonBaseConverter
+ {
+ ///
+ /// Creates a new .
+ ///
+ public WindowCaptionButtonVisibilityConverter() : base() { }
+
+ public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+ {
+ try
+ {
+ if (values != null && values.Length == 3)
+ {
+ string buttonName = (string)values[0];
+ WindowStyle windowStyle = (WindowStyle)values[1];
+ ResizeMode resizeMode = (ResizeMode)values[2];
+
+ if (buttonName == CloseButtonName)
+ {
+ if (windowStyle != WindowStyle.None)
+ {
+ return Visibility.Visible;
+ }
+ else
+ {
+ return Visibility.Collapsed;
+ }
+ }
+ else
+ {
+ if (resizeMode != ResizeMode.NoResize
+ && (windowStyle == WindowStyle.SingleBorderWindow || windowStyle == WindowStyle.ThreeDBorderWindow))
+ {
+ return Visibility.Visible;
+ }
+ else
+ {
+ return Visibility.Collapsed;
+ }
+ }
+ }
+ }
+ catch (Exception)
+ {
+ // use the default return value below
+ }
+
+ return Visibility.Visible;
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Converters/WindowTitleBarIconVisibilityConverter.cs b/MaterialDesignExtensions/Converters/WindowTitleBarIconVisibilityConverter.cs
new file mode 100644
index 00000000..93492cb6
--- /dev/null
+++ b/MaterialDesignExtensions/Converters/WindowTitleBarIconVisibilityConverter.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Data;
+
+namespace MaterialDesignExtensions.Converters
+{
+ ///
+ /// Converts a and icon of a window into a for the icon.
+ ///
+ public class WindowTitleBarIconVisibilityConverter : IMultiValueConverter
+ {
+ ///
+ /// Creates a new .
+ ///
+ public WindowTitleBarIconVisibilityConverter() { }
+
+ public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+ {
+ try
+ {
+ if (values != null && values.Length == 2)
+ {
+ object icon = values[0];
+ WindowStyle windowStyle = (WindowStyle)values[1];
+
+ if (icon != null && (windowStyle == WindowStyle.SingleBorderWindow || windowStyle == WindowStyle.ThreeDBorderWindow))
+ {
+ return Visibility.Visible;
+ }
+ else
+ {
+ return Visibility.Collapsed;
+ }
+ }
+ }
+ catch (Exception)
+ {
+ // use the default return value below
+ }
+
+ return Visibility.Visible;
+ }
+
+ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Converters/WindowTitleVisibilityConverter.cs b/MaterialDesignExtensions/Converters/WindowTitleVisibilityConverter.cs
new file mode 100644
index 00000000..799e6373
--- /dev/null
+++ b/MaterialDesignExtensions/Converters/WindowTitleVisibilityConverter.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Data;
+
+namespace MaterialDesignExtensions.Converters
+{
+ ///
+ /// Converts a of a window into a of the whole title bar.
+ ///
+ public class WindowTitleVisibilityConverter : IMultiValueConverter
+ {
+ ///
+ /// Creates a new .
+ ///
+ public WindowTitleVisibilityConverter() { }
+
+ public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+ {
+ try
+ {
+ if (values != null && values.Length >= 1)
+ {
+ WindowStyle windowStyle = (WindowStyle)values[0];
+
+ if (windowStyle != WindowStyle.None)
+ {
+ return Visibility.Visible;
+ }
+ else
+ {
+ return Visibility.Collapsed;
+ }
+ }
+ }
+ catch (Exception)
+ {
+ // use the default return value below
+ }
+
+ return Visibility.Visible;
+ }
+
+ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Localization/Strings.Designer.cs b/MaterialDesignExtensions/Localization/Strings.Designer.cs
index 232eb964..baf4ad4a 100644
--- a/MaterialDesignExtensions/Localization/Strings.Designer.cs
+++ b/MaterialDesignExtensions/Localization/Strings.Designer.cs
@@ -19,7 +19,7 @@ namespace MaterialDesignExtensions.Localization {
// -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
// Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
// mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Strings {
@@ -87,6 +87,15 @@ public static string Close {
}
}
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Create ähnelt.
+ ///
+ public static string Create {
+ get {
+ return ResourceManager.GetString("Create", resourceCulture);
+ }
+ }
+
///
/// Sucht eine lokalisierte Zeichenfolge, die Created ähnelt.
///
@@ -105,6 +114,15 @@ public static string Desktop {
}
}
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Details ähnelt.
+ ///
+ public static string Details {
+ get {
+ return ResourceManager.GetString("Details", resourceCulture);
+ }
+ }
+
///
/// Sucht eine lokalisierte Zeichenfolge, die Folder '{0}' not found ähnelt.
///
@@ -204,6 +222,24 @@ public static string LongPathsAreNotSupported {
}
}
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Maximize ähnelt.
+ ///
+ public static string Maximize {
+ get {
+ return ResourceManager.GetString("Maximize", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Minimize ähnelt.
+ ///
+ public static string Minimize {
+ get {
+ return ResourceManager.GetString("Minimize", resourceCulture);
+ }
+ }
+
///
/// Sucht eine lokalisierte Zeichenfolge, die Music ähnelt.
///
@@ -213,6 +249,42 @@ public static string Music {
}
}
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die New directory name ähnelt.
+ ///
+ public static string NewDirectoryName {
+ get {
+ return ResourceManager.GetString("NewDirectoryName", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die No selected directories ähnelt.
+ ///
+ public static string NoSelectedDirectories {
+ get {
+ return ResourceManager.GetString("NoSelectedDirectories", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die No selected files ähnelt.
+ ///
+ public static string NoSelectedFiles {
+ get {
+ return ResourceManager.GetString("NoSelectedFiles", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die OK ähnelt.
+ ///
+ public static string Ok {
+ get {
+ return ResourceManager.GetString("Ok", resourceCulture);
+ }
+ }
+
///
/// Sucht eine lokalisierte Zeichenfolge, die Open ähnelt.
///
@@ -240,6 +312,24 @@ public static string Pictures {
}
}
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Remove ähnelt.
+ ///
+ public static string Remove {
+ get {
+ return ResourceManager.GetString("Remove", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Restore ähnelt.
+ ///
+ public static string Restore {
+ get {
+ return ResourceManager.GetString("Restore", resourceCulture);
+ }
+ }
+
///
/// Sucht eine lokalisierte Zeichenfolge, die Save ähnelt.
///
@@ -285,6 +375,42 @@ public static string SelectDirectory {
}
}
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Selection ähnelt.
+ ///
+ public static string Selection {
+ get {
+ return ResourceManager.GetString("Selection", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die The directory name is invalid ähnelt.
+ ///
+ public static string TheDirectoryNameIsInvalid {
+ get {
+ return ResourceManager.GetString("TheDirectoryNameIsInvalid", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die The directory name must not be empty ähnelt.
+ ///
+ public static string TheDirectoryNameMustNotBeEmpty {
+ get {
+ return ResourceManager.GetString("TheDirectoryNameMustNotBeEmpty", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die The directory '{0}' already exists ähnelt.
+ ///
+ public static string TheDirectoryXAlreadyExists {
+ get {
+ return ResourceManager.GetString("TheDirectoryXAlreadyExists", resourceCulture);
+ }
+ }
+
///
/// Sucht eine lokalisierte Zeichenfolge, die User ähnelt.
///
diff --git a/MaterialDesignExtensions/Localization/Strings.ar-DZ.Designer.cs b/MaterialDesignExtensions/Localization/Strings.ar-DZ.Designer.cs
new file mode 100644
index 00000000..5f282702
--- /dev/null
+++ b/MaterialDesignExtensions/Localization/Strings.ar-DZ.Designer.cs
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Localization/Strings.ar-DZ.resx b/MaterialDesignExtensions/Localization/Strings.ar-DZ.resx
new file mode 100644
index 00000000..99ced4c8
--- /dev/null
+++ b/MaterialDesignExtensions/Localization/Strings.ar-DZ.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ تم رفض الوصول إلى المجلد "{0}"
+
+
+ إلغاء
+
+
+ إغلاق
+
+
+ منشأ
+
+
+ سطح المكتب
+
+
+ لم يتم العثور على المجلد "{0}"
+
+
+ المستندات
+
+
+ الأقراص
+
+
+ مجلد فارغ
+
+
+ الملفات
+
+
+ حجم الملف
+
+
+ المجلدات
+
+
+ آخر ولوج
+
+
+ آخر تعديل
+
+
+ قرص محلي
+
+
+ الموسيقى
+
+
+ فتح
+
+
+ فتح ملف
+
+
+ الصور
+
+
+ حفظ
+
+
+ حفظ الملف
+
+
+ تحديد
+
+
+ إختيار مجلد
+
+
+ المستخدم
+
+
+ الفيديوهات
+
+
+ البحث
+
+
+ المسارات الطويلة غير مدعومة
+
+
+ اسم الدليل غير صالح
+
+
+ يجب ألا يكون اسم الدليل فارغًا
+
+
+ الدليل '{0}' موجود بالفعل
+
+
+ إنشاء
+
+
+ إسم دليل جديد
+
+
+ تكبير
+
+
+ تصغير
+
+
+ إستعادة
+
+
+ التفاصيل
+
+
+ حذف
+
+
+ إختيار
+
+
+ لم يتم تحديد مجلدات
+
+
+ لم يتم تحديد ملفات
+
+
+ موافق
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Localization/Strings.cs-cz.Designer.cs b/MaterialDesignExtensions/Localization/Strings.cs-cz.Designer.cs
new file mode 100644
index 00000000..5f282702
--- /dev/null
+++ b/MaterialDesignExtensions/Localization/Strings.cs-cz.Designer.cs
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Localization/Strings.cs-cz.resx b/MaterialDesignExtensions/Localization/Strings.cs-cz.resx
new file mode 100644
index 00000000..98da819f
--- /dev/null
+++ b/MaterialDesignExtensions/Localization/Strings.cs-cz.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Přístup ke složce '{0}' odepřen
+
+
+ Zrušit
+
+
+ Zavřít
+
+
+ Vytvořeno
+
+
+ Plocha
+
+
+ Složka '{0}' nebyla nalezena
+
+
+ Dokumenty
+
+
+ Disky
+
+
+ Prázdná složka
+
+
+ Soubory
+
+
+ Velikost souboru
+
+
+ Složky
+
+
+ Naposledy otevřeno
+
+
+ Naposledy upraveno
+
+
+ Místní disk
+
+
+ Hudba
+
+
+ Otevřít
+
+
+ Otevřít soubor
+
+
+ Obrázky
+
+
+ Uložit
+
+
+ Uložit soubor
+
+
+ Vybrat
+
+
+ Vybrat složku
+
+
+ Uživatel
+
+
+ Videa
+
+
+ Hledat
+
+
+ Dlouhé cesty nejsou podporovány
+
+
+ Název složky je neplatný
+
+
+ Název složky nesmí být prázdný
+
+
+ Složka '{0}' již existuje
+
+
+ Vytvořit
+
+
+ Nový název složky
+
+
+ Maximalizovat
+
+
+ Minimalizovat
+
+
+ Obnovit
+
+
+ Podrobnosti
+
+
+ Odstranit
+
+
+ Výběr
+
+
+ Žádné vybrané složky
+
+
+ Žádné vybrané soubory
+
+
+ OK
+
+
diff --git a/MaterialDesignExtensions/Localization/Strings.de.resx b/MaterialDesignExtensions/Localization/Strings.de.resx
index bf3bc26f..3839712b 100644
--- a/MaterialDesignExtensions/Localization/Strings.de.resx
+++ b/MaterialDesignExtensions/Localization/Strings.de.resx
@@ -198,4 +198,43 @@
Lange Pfade werden nicht unterstützt
+
+ Der Ordnername ist ungültig
+
+
+ Der Ordername darf nicht leer sein
+
+
+ Der Ordner "{0}" existiert bereits
+
+
+ Erstellen
+
+
+ Neuer Ordnername
+
+
+ Maximieren
+
+
+ Minimieren
+
+
+ Verkleinern
+
+
+ Details
+
+
+ Entfernen
+
+
+ Auswahl
+
+
+ Keine ausgewählten Ordner
+
+
+ Keine ausgewählten Dateien
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Localization/Strings.fr-FR.Designer.cs b/MaterialDesignExtensions/Localization/Strings.fr-FR.Designer.cs
new file mode 100644
index 00000000..5f282702
--- /dev/null
+++ b/MaterialDesignExtensions/Localization/Strings.fr-FR.Designer.cs
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Localization/Strings.fr-FR.resx b/MaterialDesignExtensions/Localization/Strings.fr-FR.resx
new file mode 100644
index 00000000..e338dcc5
--- /dev/null
+++ b/MaterialDesignExtensions/Localization/Strings.fr-FR.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Accès au dossier '{0}' refusé
+
+
+ Annuler
+
+
+ Fermer
+
+
+ Créé
+
+
+ Bureau
+
+
+ Dossier '{0}' introuvable
+
+
+ Documents
+
+
+ Disques
+
+
+ Dossier vide
+
+
+ Dossiers
+
+
+ Taille du fichier
+
+
+ Dossiers
+
+
+ Dernier accès
+
+
+ Dernière modification
+
+
+ Disque local
+
+
+ Musique
+
+
+ Ouvrir
+
+
+ Ouvrir fichier
+
+
+ Photos
+
+
+ Enregistrer
+
+
+ Enregistrer le fichier
+
+
+ Sélectionner
+
+
+ Sélectionner le dossier
+
+
+ Utilisateur
+
+
+ Vidéos
+
+
+ Chercher
+
+
+ Longs chemins ne sont pas pris en charge
+
+
+ Nom du répertoire n'est pas valide
+
+
+ Nom du répertoire ne doit pas être vide
+
+
+ Répertoire '{0}' existe déjà
+
+
+ Créer
+
+
+ Nouveau nom de répertoire
+
+
+ Maximiser
+
+
+ Minimiser
+
+
+ Restaurer
+
+
+ Détails
+
+
+ Supprimer
+
+
+ Sélection
+
+
+ Aucun répertoire sélectionné
+
+
+ Aucun fichier sélectionné
+
+
+ OK
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Localization/Strings.ja-JP.Designer.cs b/MaterialDesignExtensions/Localization/Strings.ja-JP.Designer.cs
new file mode 100644
index 00000000..5f282702
--- /dev/null
+++ b/MaterialDesignExtensions/Localization/Strings.ja-JP.Designer.cs
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Localization/Strings.ja-JP.resx b/MaterialDesignExtensions/Localization/Strings.ja-JP.resx
new file mode 100644
index 00000000..3da11e1c
--- /dev/null
+++ b/MaterialDesignExtensions/Localization/Strings.ja-JP.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ フォルダー '{0}' へのアクセスが拒否されました。
+
+
+ キャンセル
+
+
+ 閉じる
+
+
+ 作成日時
+
+
+ デスクトップ
+
+
+ フォルダー '{0}' が見つかりませんでした。
+
+
+ ドキュメント
+
+
+ ドライブ
+
+
+ 空のフォルダー
+
+
+ ファイル
+
+
+ ファイルサイズ
+
+
+ フォルダー
+
+
+ アクセス日時
+
+
+ 更新日時
+
+
+ ローカル ディスク
+
+
+ ミュージック
+
+
+ 開く
+
+
+ ファイルを開く
+
+
+ ピクチャ
+
+
+ 保存
+
+
+ ファイルの保存
+
+
+ 選択
+
+
+ フォルダーの選択
+
+
+ ユーザー
+
+
+ ビデオ
+
+
+ 検索
+
+
+ ロングパスネームはサポートされていません。
+
+
+ ディレクトリ名が無効です。
+
+
+ ディレクトリ名は空にできません。
+
+
+ ディレクトリ '{0}' は既に存在します。
+
+
+ 作成
+
+
+ 新しいフォルダー
+
+
+ 最大化
+
+
+ 最小化
+
+
+ 元に戻す
+
+
+ 詳細
+
+
+ 削除
+
+
+ 選択
+
+
+ フォルダーが選択されていません。
+
+
+ ファイルが選択されていません。
+
+
+ OK
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Localization/Strings.pt-BR.Designer.cs b/MaterialDesignExtensions/Localization/Strings.pt-BR.Designer.cs
new file mode 100644
index 00000000..5f282702
--- /dev/null
+++ b/MaterialDesignExtensions/Localization/Strings.pt-BR.Designer.cs
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Localization/Strings.pt-BR.resx b/MaterialDesignExtensions/Localization/Strings.pt-BR.resx
new file mode 100644
index 00000000..636c9e74
--- /dev/null
+++ b/MaterialDesignExtensions/Localization/Strings.pt-BR.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Acesso negado à pasta '{0}'
+
+
+ Cancelar
+
+
+ Fechar
+
+
+ Criar
+
+
+ Criado
+
+
+ Área de Trabalho
+
+
+ Detalhe
+
+
+ Pasta '{0}' não encontrada
+
+
+ Documentos
+
+
+ Unidades
+
+
+ Pasta Vazia
+
+
+ Arquivos
+
+
+ Tamanho do Arquivo
+
+
+ Pastas
+
+
+ Último acesso
+
+
+ Última modificação
+
+
+ Unidade Local
+
+
+ Caminhos longos não são suportados
+
+
+ Maximizar
+
+
+ Minimizar
+
+
+ Música
+
+
+ Novo nome de diretório
+
+
+ Nenhum diretório selecionado
+
+
+ Nenhum arquivo selecionado
+
+
+ OK
+
+
+ Abrir
+
+
+ Abrir Arquivo
+
+
+ Imagens
+
+
+ Remover
+
+
+ Restaurar
+
+
+ Salvar
+
+
+ Salvar Arquivo
+
+
+ Pesquisar
+
+
+ Selecionar
+
+
+ Selecionar Pasta
+
+
+ Seleção
+
+
+ O nome do diretório não é válido
+
+
+ O nome do diretório não pode ficar vazio
+
+
+ O diretório '{0}' já existe
+
+
+ Usuário
+
+
+ Vídeos
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Localization/Strings.resx b/MaterialDesignExtensions/Localization/Strings.resx
index 81c903a2..af205b88 100644
--- a/MaterialDesignExtensions/Localization/Strings.resx
+++ b/MaterialDesignExtensions/Localization/Strings.resx
@@ -198,4 +198,46 @@
Long paths are not supported
+
+ The directory name is invalid
+
+
+ The directory name must not be empty
+
+
+ The directory '{0}' already exists
+
+
+ Create
+
+
+ New directory name
+
+
+ Maximize
+
+
+ Minimize
+
+
+ Restore
+
+
+ Details
+
+
+ Remove
+
+
+ Selection
+
+
+ No selected directories
+
+
+ No selected files
+
+
+ OK
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Localization/Strings.ru-ru.Designer.cs b/MaterialDesignExtensions/Localization/Strings.ru-ru.Designer.cs
new file mode 100644
index 00000000..e69de29b
diff --git a/MaterialDesignExtensions/Localization/Strings.ru-ru.resx b/MaterialDesignExtensions/Localization/Strings.ru-ru.resx
new file mode 100644
index 00000000..26c8f2cf
--- /dev/null
+++ b/MaterialDesignExtensions/Localization/Strings.ru-ru.resx
@@ -0,0 +1,240 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Доступ к папке '{0}' запрещен
+
+
+ Отмена
+
+
+ Закрыть
+
+
+ Создать
+
+
+ Создан
+
+
+ Рабочий стол
+
+
+ Информация
+
+
+ Папка '{0}' не найдена
+
+
+ Документы
+
+
+ Устройства и диски
+
+
+ Пустая папка
+
+
+ Файлы
+
+
+ Размер файла
+
+
+ Папки
+
+
+ Открыт
+
+
+ Изменен
+
+
+ Локальный диск
+
+
+ Длинные пути не поддерживаются
+
+
+ Развернуть
+
+
+ Свернуть
+
+
+ Музыка
+
+
+ Название новой директории
+
+
+ Не выбраны директории
+
+
+ Не выбраны файлы
+
+
+ Открыть
+
+
+ Открыть файл
+
+
+ Изображения
+
+
+ Удалить
+
+
+ Восстановить
+
+
+ Сохранить
+
+
+ Сохранить файл
+
+
+ Поиск
+
+
+ Выбрать
+
+
+ Выбрать папку
+
+
+ Выбрано
+
+
+ Некорректное наименование директории
+
+
+ Наименование директории не должно быть пустым
+
+
+ Директория '{0}' уже существует
+
+
+ Этот компьютер
+
+
+ Видео
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Localization/Strings.uz-Latn-UZ.Designer.cs b/MaterialDesignExtensions/Localization/Strings.uz-Latn-UZ.Designer.cs
new file mode 100644
index 00000000..e69de29b
diff --git a/MaterialDesignExtensions/Localization/Strings.uz-Latn-UZ.resx b/MaterialDesignExtensions/Localization/Strings.uz-Latn-UZ.resx
new file mode 100644
index 00000000..7d433e7d
--- /dev/null
+++ b/MaterialDesignExtensions/Localization/Strings.uz-Latn-UZ.resx
@@ -0,0 +1,201 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ '{0}' papkaga kirish rad etildi
+
+
+ Bekor qilish
+
+
+ Yopish
+
+
+ Yaratildi
+
+
+ Ish stoli
+
+
+ '{0}' papka topilmadi
+
+
+ Hujjatlar
+
+
+ Drayvlar
+
+
+ Bo'sh papka
+
+
+ Fayllar
+
+
+ Fayl hajmi
+
+
+ Papkalar
+
+
+ So'nggi kirish
+
+
+ Oxirgi o'zgartirishlar kiritilgan
+
+
+ Mahalliy draiver
+
+
+ Musiqa
+
+
+ Ochish
+
+
+ Faylni ochish
+
+
+ Rasmlar
+
+
+ Saqlash
+
+
+ Faylni saqlash
+
+
+ Tanlash
+
+
+ Papkani tanlash
+
+
+ Foydalanuvchi
+
+
+ Videolar
+
+
+ Qidirish
+
+
+ Fayl joylashgan joyga yo'l juda uzun bo'lsa, qo'llab-quvvatlanmaydi
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Localization/Strings.zh-CN.Designer.cs b/MaterialDesignExtensions/Localization/Strings.zh-CN.Designer.cs
new file mode 100644
index 00000000..e69de29b
diff --git a/MaterialDesignExtensions/Localization/Strings.zh-CN.resx b/MaterialDesignExtensions/Localization/Strings.zh-CN.resx
new file mode 100644
index 00000000..3e3b5635
--- /dev/null
+++ b/MaterialDesignExtensions/Localization/Strings.zh-CN.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 访问文件夹 '{0}' 被拒绝
+
+
+ 取消
+
+
+ 关闭
+
+
+ 创建
+
+
+ 桌面
+
+
+ 文件夹 '{0}' 未找到
+
+
+ 文档
+
+
+ 磁盘
+
+
+ 空文件夹
+
+
+ 文件
+
+
+ 文件大小
+
+
+ 文件夹
+
+
+ 最近访问
+
+
+ 最近修改
+
+
+ 本地磁盘
+
+
+ 音乐
+
+
+ 打开
+
+
+ 打开文件
+
+
+ 图片
+
+
+ 保存
+
+
+ 保存文件
+
+
+ 选择
+
+
+ 选择文件夹
+
+
+ 用户
+
+
+ 视频
+
+
+ 搜索
+
+
+ 不支持长路径
+
+
+ 文件夹名称不合法
+
+
+ 文件夹名称不能为空
+
+
+ 文件夹 '{0}' 已存在
+
+
+ 创建
+
+
+ 新文件夹名称
+
+
+ 最大化
+
+
+ 最小化
+
+
+ 恢复
+
+
+ 详细
+
+
+ 删除
+
+
+ 选择
+
+
+ 没有选中文件夹
+
+
+ 没有选中文件
+
+
+ 确定
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/MaterialDesignExtensions.LongPath.nuspec b/MaterialDesignExtensions/MaterialDesignExtensions.LongPath.nuspec
new file mode 100644
index 00000000..8c5c0194
--- /dev/null
+++ b/MaterialDesignExtensions/MaterialDesignExtensions.LongPath.nuspec
@@ -0,0 +1,44 @@
+
+
+
+ MaterialDesignExtensions.LongPath
+ 3.0.0-a02
+ MaterialDesignExtensions.LongPath
+ Philipp Spiegel
+ Philipp Spiegel
+ https://spiegelp.github.io/MaterialDesignExtensions/#license
+
+
+ https://spiegelp.github.io/MaterialDesignExtensions/
+ https://raw.githubusercontent.com/spiegelp/MaterialDesignExtensions/master/icon/icon.png
+
+ false
+ Special build of MaterialDesignExtensions supporting long file system paths via an additional library rather than System.IO.
+ Special build of MaterialDesignExtensions supporting long file system paths via an additional library rather than System.IO to support older Windows and .NET versions.
+
+If you do not need the long path support for older Windows and .NET version, please install the original Material Design Extensions package (https://www.nuget.org/packages/MaterialDesignExtensions/).
+ https://spiegelp.github.io/MaterialDesignExtensions/#releasenotes
+
+Important notice: The configuration of Material Design Extensions changed in order to enable changing the theme at runtime. Please change your configuration according to App.xaml of the demo.
+
+ Copyright (c) 2017-2019 Spiegel Philipp
+ Material Design UI WPF XAML MaterialDesign MD Stepper SideNavigation AppBar Autocomplete FileDialog DirectoryDialog Spinner MaterialWindow Window LongPath
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/MaterialDesignExtensions.csproj b/MaterialDesignExtensions/MaterialDesignExtensions.csproj
index 888a8b6a..ab064fae 100644
--- a/MaterialDesignExtensions/MaterialDesignExtensions.csproj
+++ b/MaterialDesignExtensions/MaterialDesignExtensions.csproj
@@ -1,236 +1,136 @@
-
-
+
+
- Debug
- AnyCPU
- {809632DA-5EB8-4EE8-AD71-57239701550C}
- library
- MaterialDesignExtensions
- MaterialDesignExtensions
- v4.5
- 512
- {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- 4
-
+ net462;net7.0-windows
+ true
+ Material Design Extensions
+ Material Design Extensions is based on Material Design in XAML Toolkit to provide additional controls and features for WPF apps. The controls might not be specified in the Material Design specification or would crash the scope of Material Design in XAML Toolkit.
+ Material Design Extensions is based on Material Design in XAML Toolkit to provide additional controls and features for WPF apps. The controls might not be specified in the Material Design specification or would crash the scope of Material Design in XAML Toolkit.
+
+Important notice: The configuration for version 2.6.0 changed. See the release notes of this version for details.
+ Philipp Spiegel
+ Philipp Spiegel
+ Material Design Extensions
+ Copyright © 2017-2021
+ 4.0.0.0
+ 4.0.0.0
+ 4.0.0
+ https://spiegelp.github.io/MaterialDesignExtensions/
+ https://github.com/spiegelp/MaterialDesignExtensions
+ git
+ Material Design UI WPF XAML MaterialDesign MD Stepper SideNavigation AppBar Autocomplete FileDialog DirectoryDialog Spinner MaterialWindow Window NavigationRail BusyOverlay
+ true
+ key.snk
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
+
+
+ bin\$(Configuration)\$(TargetFramework)\MaterialDesignExtensions.xml
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
- bin\Release\MaterialDesignExtensions.xml
+
+
+ bin\$(Configuration)\$(TargetFramework)\MaterialDesignExtensions.xml
+
-
- ..\packages\MaterialDesignColors.1.1.3\lib\net45\MaterialDesignColors.dll
-
-
- ..\packages\MaterialDesignThemes.2.4.0.1044\lib\net45\MaterialDesignThemes.Wpf.dll
-
-
-
-
-
-
-
-
-
-
- 4.0
-
-
-
-
+
+
+
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- MSBuild:Compile
- Designer
-
-
- Designer
- MSBuild:Compile
-
-
- MSBuild:Compile
- Designer
-
-
- MSBuild:Compile
- Designer
-
-
- Designer
- MSBuild:Compile
-
-
- MSBuild:Compile
- Designer
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- MSBuild:Compile
- Designer
-
-
- Designer
- MSBuild:Compile
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ True
True
+ Strings.resx
+
+
True
+ True
Strings.de.resx
-
+
+ True
True
+ Strings.ru-RU.resx
+
+
True
- Strings.resx
+ True
+ Strings.uz-Latn-UZ.resx
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Code
+
+ True
+ True
+ Strings.cs-cz.resx
+
+
+ True
+ True
+ Strings.pt-BR.resx
+
+
+ True
+ True
+ Strings.fr-FR.resx
-
+
+ True
True
+ Strings.ar-DZ.resx
+
+
True
- Resources.resx
+ True
+ Strings.ja-JP.resx
-
+
+ True
True
- Settings.settings
- True
+ Strings.zh-CN.resx
-
-
-
-
-
-
-
+
+
+
+
PublicResXFileCodeGenerator
+ Strings.Designer.cs
+
+
+ ResXFileCodeGenerator
Strings.de.Designer.cs
-
- PublicResXFileCodeGenerator
- Strings.Designer.cs
+
+ ResXFileCodeGenerator
+ Strings.ru-RU.Designer.cs
+
+
+ ResXFileCodeGenerator
+ Strings.uz-Latn-UZ.Designer.cs
+
+
+ ResXFileCodeGenerator
+ Strings.cs-cz.Designer.cs
+
+
+ ResXFileCodeGenerator
+ Strings.pt-BR.Designer.cs
+
+
+ ResXFileCodeGenerator
+ Strings.fr-FR.Designer.cs
+
+
+ ResXFileCodeGenerator
+ Strings.ar-DZ.Designer.cs
+
+
+ ResXFileCodeGenerator
+ Strings.ja-JP.Designer.cs
-
+
ResXFileCodeGenerator
- Resources.Designer.cs
+ Strings.zh-CN.Designer.cs
-
-
- SettingsSingleFileGenerator
- Settings.Designer.cs
-
-
-
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/MaterialDesignExtensions.nuspec b/MaterialDesignExtensions/MaterialDesignExtensions.nuspec
index 7fb442f2..11327230 100644
--- a/MaterialDesignExtensions/MaterialDesignExtensions.nuspec
+++ b/MaterialDesignExtensions/MaterialDesignExtensions.nuspec
@@ -2,26 +2,64 @@
MaterialDesignExtensions
- 2.4.0
+ 4.0.0-a02
Material Design Extensions
Philipp Spiegel
Philipp Spiegel
https://spiegelp.github.io/MaterialDesignExtensions/#license
+
+
https://spiegelp.github.io/MaterialDesignExtensions/
https://raw.githubusercontent.com/spiegelp/MaterialDesignExtensions/master/icon/icon.png
+
false
+ Material Design Extensions is based on Material Design in XAML Toolkit to provide additional controls and features for WPF apps. The controls might not be specified in the Material Design specification or would crash the scope of Material Design in XAML Toolkit.
Material Design Extensions is based on Material Design in XAML Toolkit to provide additional controls and features for WPF apps. The controls might not be specified in the Material Design specification or would crash the scope of Material Design in XAML Toolkit.
https://spiegelp.github.io/MaterialDesignExtensions/#releasenotes
- Copyright (c) 2017-2018 Spiegel Philipp
- Material Design UI WPF XAML MaterialDesign MD Stepper SideNavigation AppBar Autocomplete FileDialog
+
+ Copyright (c) 2017-2021 Spiegel Philipp
+ Material Design UI WPF XAML MaterialDesign MD Stepper SideNavigation AppBar Autocomplete FileDialog DirectoryDialog Spinner MaterialWindow MaterialNavigationWindow Window NavigationRail BusyOverlay
-
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Model/BaseNavigationItem.cs b/MaterialDesignExtensions/Model/BaseNavigationItem.cs
index 0528cf4a..436407cf 100644
--- a/MaterialDesignExtensions/Model/BaseNavigationItem.cs
+++ b/MaterialDesignExtensions/Model/BaseNavigationItem.cs
@@ -7,6 +7,9 @@
namespace MaterialDesignExtensions.Model
{
+ ///
+ /// Base class for an item in a .
+ ///
public abstract class BaseNavigationItem : INavigationItem
{
public event PropertyChangedEventHandler PropertyChanged;
@@ -15,6 +18,9 @@ public abstract class BaseNavigationItem : INavigationItem
protected bool m_isSelected;
protected NavigationItemSelectedCallback m_callback;
+ ///
+ /// True, if the user can select this navigation item.
+ ///
public virtual bool IsSelectable
{
get
@@ -28,6 +34,9 @@ public virtual bool IsSelectable
}
}
+ ///
+ /// True, if the navigation item is selected.
+ ///
public virtual bool IsSelected
{
get
@@ -43,6 +52,10 @@ public virtual bool IsSelected
}
}
+ ///
+ /// An optional callback method raised, when this navigation item will be selected.
+ /// This API is necessary because events are not async.
+ ///
public virtual NavigationItemSelectedCallback NavigationItemSelectedCallback
{
get
@@ -58,6 +71,9 @@ public virtual NavigationItemSelectedCallback NavigationItemSelectedCallback
}
}
+ ///
+ /// Creates a new .
+ ///
public BaseNavigationItem()
{
m_isSelectable = true;
diff --git a/MaterialDesignExtensions/Model/DirectoryInfoItem.cs b/MaterialDesignExtensions/Model/DirectoryInfoItem.cs
index 155519f4..cff64a6a 100644
--- a/MaterialDesignExtensions/Model/DirectoryInfoItem.cs
+++ b/MaterialDesignExtensions/Model/DirectoryInfoItem.cs
@@ -5,10 +5,21 @@
using System.Text;
using System.Threading.Tasks;
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using DirectoryInfo = Pri.LongPath.DirectoryInfo;
+#endif
+
namespace MaterialDesignExtensions.Model
{
+ ///
+ /// A directory item in the current directory list of file system controls.
+ ///
public class DirectoryInfoItem : FileSystemEntryItem
{
+ ///
+ /// Creates a new .
+ ///
public DirectoryInfoItem() : base() { }
}
}
diff --git a/MaterialDesignExtensions/Model/DividerNavigationItem.cs b/MaterialDesignExtensions/Model/DividerNavigationItem.cs
index 9edab558..9ff287b6 100644
--- a/MaterialDesignExtensions/Model/DividerNavigationItem.cs
+++ b/MaterialDesignExtensions/Model/DividerNavigationItem.cs
@@ -6,8 +6,14 @@
namespace MaterialDesignExtensions.Model
{
+ ///
+ /// A divider line in a .
+ ///
public class DividerNavigationItem : NotSelectableNavigationItem
{
+ ///
+ /// Creates a new .
+ ///
public DividerNavigationItem() : base() { }
}
}
diff --git a/MaterialDesignExtensions/Model/FileFilter.cs b/MaterialDesignExtensions/Model/FileFilter.cs
index bd06ae6e..1ac9766c 100644
--- a/MaterialDesignExtensions/Model/FileFilter.cs
+++ b/MaterialDesignExtensions/Model/FileFilter.cs
@@ -9,6 +9,11 @@
using MaterialDesignExtensions.Controllers;
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using FileInfo = Pri.LongPath.FileInfo;
+#endif
+
namespace MaterialDesignExtensions.Model
{
///
diff --git a/MaterialDesignExtensions/Model/FileInfoItem.cs b/MaterialDesignExtensions/Model/FileInfoItem.cs
index 940a4b27..3a7bd8b7 100644
--- a/MaterialDesignExtensions/Model/FileInfoItem.cs
+++ b/MaterialDesignExtensions/Model/FileInfoItem.cs
@@ -5,10 +5,21 @@
using System.Text;
using System.Threading.Tasks;
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using FileInfo = Pri.LongPath.FileInfo;
+#endif
+
namespace MaterialDesignExtensions.Model
{
+ ///
+ /// A file item in the current directory list of file system controls.
+ ///
public class FileInfoItem : FileSystemEntryItem
{
+ ///
+ /// Creates a new .
+ ///
public FileInfoItem() : base() { }
}
}
diff --git a/MaterialDesignExtensions/Model/FileSystemEntriesGroupHeader.cs b/MaterialDesignExtensions/Model/FileSystemEntriesGroupHeader.cs
index 13d6e985..69188157 100644
--- a/MaterialDesignExtensions/Model/FileSystemEntriesGroupHeader.cs
+++ b/MaterialDesignExtensions/Model/FileSystemEntriesGroupHeader.cs
@@ -7,6 +7,9 @@
namespace MaterialDesignExtensions.Model
{
+ ///
+ /// A group header in the items lists of file system controls to group directories and files.
+ ///
public class FileSystemEntriesGroupHeader : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
@@ -14,6 +17,9 @@ public class FileSystemEntriesGroupHeader : INotifyPropertyChanged
private string m_header;
private bool m_showSeparator;
+ ///
+ /// The header label.
+ ///
public string Header
{
get
@@ -32,6 +38,9 @@ public string Header
}
}
+ ///
+ /// True, to display a separator above the label.
+ ///
public bool ShowSeparator
{
get
@@ -50,6 +59,9 @@ public bool ShowSeparator
}
}
+ ///
+ /// Creates a new .
+ ///
public FileSystemEntriesGroupHeader()
{
m_header = null;
diff --git a/MaterialDesignExtensions/Model/FileSystemEntryItem.cs b/MaterialDesignExtensions/Model/FileSystemEntryItem.cs
index 3c3736bf..526b77d7 100644
--- a/MaterialDesignExtensions/Model/FileSystemEntryItem.cs
+++ b/MaterialDesignExtensions/Model/FileSystemEntryItem.cs
@@ -6,8 +6,16 @@
using System.Text;
using System.Threading.Tasks;
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using FileSystemInfo = Pri.LongPath.FileSystemInfo;
+#endif
+
namespace MaterialDesignExtensions.Model
{
+ ///
+ /// An item in the current directory list of file system controls.
+ ///
public abstract class FileSystemEntryItem : INotifyPropertyChanged where T : FileSystemInfo
{
public event PropertyChangedEventHandler PropertyChanged;
@@ -15,6 +23,9 @@ public abstract class FileSystemEntryItem : INotifyPropertyChanged where T :
private bool m_isSelected;
private T m_value;
+ ///
+ /// True, if the list item is selected.
+ ///
public bool IsSelected
{
get
@@ -33,6 +44,9 @@ public bool IsSelected
}
}
+ ///
+ /// The value (directory or file) of the lsit item.
+ ///
public T Value
{
get
@@ -51,6 +65,9 @@ public T Value
}
}
+ ///
+ /// Creates a new .
+ ///
public FileSystemEntryItem()
{
m_isSelected = false;
diff --git a/MaterialDesignExtensions/Model/FirstLevelNavigationItem.cs b/MaterialDesignExtensions/Model/FirstLevelNavigationItem.cs
index 761b92a7..1e13ba42 100644
--- a/MaterialDesignExtensions/Model/FirstLevelNavigationItem.cs
+++ b/MaterialDesignExtensions/Model/FirstLevelNavigationItem.cs
@@ -6,8 +6,14 @@
namespace MaterialDesignExtensions.Model
{
+ ///
+ /// A first level navigation item of a .
+ ///
public class FirstLevelNavigationItem : NavigationItem
{
+ ///
+ /// Creates a new .
+ ///
public FirstLevelNavigationItem() : base() { }
}
}
diff --git a/MaterialDesignExtensions/Model/IAutocompleteSource.cs b/MaterialDesignExtensions/Model/IAutocompleteSource.cs
index 7330469d..fbb227d8 100644
--- a/MaterialDesignExtensions/Model/IAutocompleteSource.cs
+++ b/MaterialDesignExtensions/Model/IAutocompleteSource.cs
@@ -7,22 +7,56 @@
namespace MaterialDesignExtensions.Model
{
+ ///
+ /// Interface for a autocomplete source as needed by controls for data binding.
+ ///
public interface IAutocompleteSource
{
+ ///
+ /// Does the search for the autocomplete.
+ ///
+ /// The term to search for
+ /// The items found for the search term
IEnumerable Search(string searchTerm);
}
+ ///
+ /// Generic version of the interface to work with type safety.
+ ///
+ ///
public interface IAutocompleteSource : IAutocompleteSource
{
+ ///
+ /// Does the search for the autocomplete.
+ ///
+ /// The term to search for
+ /// The items found for the search term
new IEnumerable Search(string searchTerm);
}
+ ///
+ /// Base class for autocomplete sources providing default implementations of the necessary interfaces for the controls.
+ ///
+ ///
public abstract class AutocompleteSource : IAutocompleteSource
{
+ ///
+ /// Creates a new .
+ ///
public AutocompleteSource() { }
+ ///
+ /// Does the search for the autocomplete.
+ ///
+ /// The term to search for
+ /// The items found for the search term
public abstract IEnumerable Search(string searchTerm);
+ ///
+ /// Does the search for the autocomplete.
+ ///
+ /// The term to search for
+ /// The items found for the search term
IEnumerable IAutocompleteSource.Search(string searchTerm)
{
return Search(searchTerm);
diff --git a/MaterialDesignExtensions/Model/IAutocompleteSourceChangingItems.cs b/MaterialDesignExtensions/Model/IAutocompleteSourceChangingItems.cs
index e2fa4446..410025f1 100644
--- a/MaterialDesignExtensions/Model/IAutocompleteSourceChangingItems.cs
+++ b/MaterialDesignExtensions/Model/IAutocompleteSourceChangingItems.cs
@@ -7,17 +7,37 @@
namespace MaterialDesignExtensions.Model
{
+ ///
+ /// An interface to notify the autocomplete control, that the underlying data source changed.
+ ///
public interface IAutocompleteSourceChangingItems : IAutocompleteSource
{
+ ///
+ /// An event to notify the autocomplete control, that the underlying data source changed.
+ ///
event AutocompleteSourceItemsChangedEventHandler AutocompleteSourceItemsChanged;
}
+ ///
+ /// Generic version of interface to work with type safety.
+ ///
+ ///
public interface IAutocompleteSourceChangingItems : IAutocompleteSourceChangingItems, IAutocompleteSource { }
+ ///
+ /// Base class to notify the autocomplete control, that the underlying data source changed.
+ ///
+ ///
public abstract class AutocompleteSourceChangingItems : AutocompleteSource, IAutocompleteSourceChangingItems
{
+ ///
+ /// An event to notify the autocomplete control, that the underlying data source changed.
+ ///
public event AutocompleteSourceItemsChangedEventHandler AutocompleteSourceItemsChanged;
+ ///
+ /// Creates a new .
+ ///
public AutocompleteSourceChangingItems() : base() { }
protected void OnAutocompleteSourceItemsChanged()
@@ -26,10 +46,21 @@ protected void OnAutocompleteSourceItemsChanged()
}
}
+ ///
+ /// The delegate for handling the event.
+ ///
+ ///
+ ///
public delegate void AutocompleteSourceItemsChangedEventHandler(object sender, AutocompleteSourceItemsChangedEventArgs args);
+ ///
+ /// The argument for the event.
+ ///
public class AutocompleteSourceItemsChangedEventArgs : EventArgs
{
+ ///
+ /// Creates a new .
+ ///
public AutocompleteSourceItemsChangedEventArgs() : base() { }
}
}
diff --git a/MaterialDesignExtensions/Model/INavigationItem.cs b/MaterialDesignExtensions/Model/INavigationItem.cs
index 927d50e4..d51f2b69 100644
--- a/MaterialDesignExtensions/Model/INavigationItem.cs
+++ b/MaterialDesignExtensions/Model/INavigationItem.cs
@@ -7,14 +7,32 @@
namespace MaterialDesignExtensions.Model
{
+ ///
+ /// The basic interface for an item of a .
+ ///
public interface INavigationItem : INotifyPropertyChanged
{
+ ///
+ /// True, if the user can select this navigation item.
+ ///
bool IsSelectable { get; set; }
+ ///
+ /// True, if the navigation item is selected.
+ ///
bool IsSelected { get; set; }
+ ///
+ /// An optional callback method raised, when this navigation item will be selected.
+ /// This API is necessary because events are not async.
+ ///
NavigationItemSelectedCallback NavigationItemSelectedCallback { get; set; }
}
+ ///
+ /// The delegate for a method.
+ ///
+ ///
+ ///
public delegate object NavigationItemSelectedCallback(INavigationItem navigationItem);
}
diff --git a/MaterialDesignExtensions/Model/ITextBoxSuggestionsSource.cs b/MaterialDesignExtensions/Model/ITextBoxSuggestionsSource.cs
index fc4fd384..ee528fa1 100644
--- a/MaterialDesignExtensions/Model/ITextBoxSuggestionsSource.cs
+++ b/MaterialDesignExtensions/Model/ITextBoxSuggestionsSource.cs
@@ -7,16 +7,35 @@
namespace MaterialDesignExtensions.Model
{
+ ///
+ /// Special version of for the controls.
+ ///
public interface ITextBoxSuggestionsSource : IAutocompleteSource
{
}
+ ///
+ /// Base class for text box suggestion sources providing default implementations of the necessary interface.
+ ///
public abstract class TextBoxSuggestionsSource : ITextBoxSuggestionsSource
{
+ ///
+ /// Creates a new .
+ ///
public TextBoxSuggestionsSource() { }
+ ///
+ /// Does the search controls.
+ ///
+ /// The term to search for
+ /// The items found for the search term
public abstract IEnumerable Search(string searchTerm);
+ ///
+ /// Does the search for the controls.
+ ///
+ /// The term to search for
+ /// The items found for the search term
IEnumerable IAutocompleteSource.Search(string searchTerm)
{
return Search(searchTerm);
diff --git a/MaterialDesignExtensions/Model/NavigationItem.cs b/MaterialDesignExtensions/Model/NavigationItem.cs
index d1190b9b..bbedc475 100644
--- a/MaterialDesignExtensions/Model/NavigationItem.cs
+++ b/MaterialDesignExtensions/Model/NavigationItem.cs
@@ -3,14 +3,22 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using System.Windows;
namespace MaterialDesignExtensions.Model
{
+ ///
+ /// An navigation item of a .
+ ///
public class NavigationItem : BaseNavigationItem
{
private object m_icon;
+ private DataTemplate m_iconTemplate;
private string m_label;
+ ///
+ /// The icon of this navigation item.
+ ///
public object Icon
{
get
@@ -26,6 +34,27 @@ public object Icon
}
}
+ ///
+ /// An optional template for the icon.
+ ///
+ public DataTemplate IconTemplate
+ {
+ get
+ {
+ return m_iconTemplate;
+ }
+
+ set
+ {
+ m_iconTemplate = value;
+
+ OnPropertyChanged(nameof(IconTemplate));
+ }
+ }
+
+ ///
+ /// The label of this navigation item.
+ ///
public string Label
{
get
@@ -41,6 +70,9 @@ public string Label
}
}
+ ///
+ /// Creates a new .
+ ///
public NavigationItem()
{
m_icon = null;
diff --git a/MaterialDesignExtensions/Model/NotSelectableNavigationItem.cs b/MaterialDesignExtensions/Model/NotSelectableNavigationItem.cs
index 9da4498d..43853ad4 100644
--- a/MaterialDesignExtensions/Model/NotSelectableNavigationItem.cs
+++ b/MaterialDesignExtensions/Model/NotSelectableNavigationItem.cs
@@ -6,8 +6,14 @@
namespace MaterialDesignExtensions.Model
{
+ ///
+ /// The base class for not selectable items (headers, dividers) in a .
+ ///
public abstract class NotSelectableNavigationItem : BaseNavigationItem
{
+ ///
+ /// True, if the user can select this navigation item.
+ ///
public override bool IsSelectable
{
get
@@ -18,6 +24,9 @@ public override bool IsSelectable
set { }
}
+ ///
+ /// True, if the navigation item is selected.
+ ///
public override bool IsSelected
{
get
@@ -28,6 +37,10 @@ public override bool IsSelected
set { }
}
+ ///
+ /// The delegate for a method.
+ ///
+ ///
public override NavigationItemSelectedCallback NavigationItemSelectedCallback
{
get
@@ -38,6 +51,9 @@ public override NavigationItemSelectedCallback NavigationItemSelectedCallback
set { }
}
+ ///
+ /// Creates a new .
+ ///
public NotSelectableNavigationItem() : base() { }
}
}
diff --git a/MaterialDesignExtensions/Model/SearchSuggestionItem.cs b/MaterialDesignExtensions/Model/SearchSuggestionItem.cs
index fa93a2e5..c930af38 100644
--- a/MaterialDesignExtensions/Model/SearchSuggestionItem.cs
+++ b/MaterialDesignExtensions/Model/SearchSuggestionItem.cs
@@ -7,6 +7,9 @@
namespace MaterialDesignExtensions.Model
{
+ ///
+ /// An item out of the suggestions of a search control.
+ ///
public class SearchSuggestionItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
@@ -14,6 +17,9 @@ public class SearchSuggestionItem : INotifyPropertyChanged
private bool m_isFromHistory;
private string m_suggestion;
+ ///
+ /// True, if this item is from an older search query.
+ ///
public bool IsFromHistory
{
get
@@ -29,6 +35,9 @@ public bool IsFromHistory
}
}
+ ///
+ /// The label of this suggestion.
+ ///
public string Suggestion
{
get
@@ -44,6 +53,9 @@ public string Suggestion
}
}
+ ///
+ /// Creates a new .
+ ///
public SearchSuggestionItem()
{
m_isFromHistory = false;
diff --git a/MaterialDesignExtensions/Model/SearchSuggestionSource.cs b/MaterialDesignExtensions/Model/SearchSuggestionSource.cs
deleted file mode 100644
index 8243c803..00000000
--- a/MaterialDesignExtensions/Model/SearchSuggestionSource.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace MaterialDesignExtensions.Model
-{
- public interface ISearchSuggestionsSource
- {
- ///
- /// Returns historical search suggestions for an empty and focused search.
- ///
- ///
- IList GetSearchSuggestions();
-
- ///
- /// Returns suggestions based on auto-completion.
- ///
- ///
- ///
- IList GetAutoCompletion(string searchTerm);
- }
-
- public class SearchSuggestionsSource : ISearchSuggestionsSource
- {
- public SearchSuggestionsSource() { }
-
- public IList GetAutoCompletion(string searchTerm)
- {
- return null;
- }
-
- public IList GetSearchSuggestions()
- {
- return null;
- }
- }
-}
diff --git a/MaterialDesignExtensions/Model/SearchSuggestionsSource.cs b/MaterialDesignExtensions/Model/SearchSuggestionsSource.cs
index 764a6de6..f06c8c6c 100644
--- a/MaterialDesignExtensions/Model/SearchSuggestionsSource.cs
+++ b/MaterialDesignExtensions/Model/SearchSuggestionsSource.cs
@@ -47,7 +47,6 @@ public IList GetAutoCompletion(string searchTerm)
///
/// Returns suggestions based on auto-completion.
///
- ///
///
public IList GetSearchSuggestions()
{
diff --git a/MaterialDesignExtensions/Model/SecondLevelNavigationItem.cs b/MaterialDesignExtensions/Model/SecondLevelNavigationItem.cs
index c445c9bf..8044afc6 100644
--- a/MaterialDesignExtensions/Model/SecondLevelNavigationItem.cs
+++ b/MaterialDesignExtensions/Model/SecondLevelNavigationItem.cs
@@ -6,8 +6,14 @@
namespace MaterialDesignExtensions.Model
{
+ ///
+ /// A second level navigation item of a .
+ ///
public class SecondLevelNavigationItem : NavigationItem
{
+ ///
+ /// Creates a new .
+ ///
public SecondLevelNavigationItem() : base() { }
}
}
diff --git a/MaterialDesignExtensions/Model/SpecialDirectory.cs b/MaterialDesignExtensions/Model/SpecialDirectory.cs
index c6b29b8e..602eaf28 100644
--- a/MaterialDesignExtensions/Model/SpecialDirectory.cs
+++ b/MaterialDesignExtensions/Model/SpecialDirectory.cs
@@ -7,16 +7,33 @@
using MaterialDesignThemes.Wpf;
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using DirectoryInfo = Pri.LongPath.DirectoryInfo;
+#endif
+
namespace MaterialDesignExtensions.Model
{
+ ///
+ /// A helper class to provide special locations (user folders etc.) inside the file system controls.
+ ///
public class SpecialDirectory
{
private string m_label;
+ ///
+ /// The icon on the user inferface for this special location.
+ ///
public PackIconKind Icon { get; set; }
+ ///
+ /// The object with the information for this special location.
+ ///
public DirectoryInfo Info { get; set; }
+ ///
+ /// The label the user inferface for this special location.
+ ///
public string Label
{
get
@@ -37,6 +54,9 @@ public string Label
}
}
+ ///
+ /// Creates a new .
+ ///
public SpecialDirectory() { }
}
}
diff --git a/MaterialDesignExtensions/Model/SpecialDrive.cs b/MaterialDesignExtensions/Model/SpecialDrive.cs
index a3c77942..0f96371c 100644
--- a/MaterialDesignExtensions/Model/SpecialDrive.cs
+++ b/MaterialDesignExtensions/Model/SpecialDrive.cs
@@ -9,14 +9,31 @@
namespace MaterialDesignExtensions.Model
{
+ ///
+ /// A helper class to provide drives inside the file system controls.
+ ///
public class SpecialDrive
{
+ ///
+ /// The icon on the user inferface for this special location.
+ ///
public PackIconKind Icon { get; set; }
+ ///
+ /// ///
+ /// The label the user inferface for this special location.
+ ///
+ ///
public string Label { get; set; }
+ ///
+ /// The object with the information for this special location.
+ ///
public DriveInfo Info { get; set; }
+ ///
+ /// Creates a new .
+ ///
public SpecialDrive() { }
}
}
diff --git a/MaterialDesignExtensions/Model/Step.cs b/MaterialDesignExtensions/Model/Step.cs
index 03a0cfb4..8f629638 100644
--- a/MaterialDesignExtensions/Model/Step.cs
+++ b/MaterialDesignExtensions/Model/Step.cs
@@ -4,11 +4,12 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using System.Windows;
namespace MaterialDesignExtensions.Model
{
///
- /// Represents a step inside a .
+ /// Represents a step inside a .
///
public interface IStep : INotifyPropertyChanged
{
@@ -27,6 +28,11 @@ public interface IStep : INotifyPropertyChanged
///
object Header { get; set; }
+ ///
+ /// An optional template for icon of the step header.
+ ///
+ DataTemplate IconTemplate { get; set; }
+
///
/// Validates this step.
/// Inherited classes may implement this method.
@@ -43,6 +49,7 @@ public class Step : IStep
public event PropertyChangedEventHandler PropertyChanged;
protected object _header;
+ protected DataTemplate _iconTemplate;
protected object _content;
protected bool _hasValidationErrors;
@@ -100,9 +107,28 @@ public virtual object Header
}
}
+ ///
+ /// An optional template for icon of the step header.
+ ///
+ public virtual DataTemplate IconTemplate
+ {
+ get
+ {
+ return _iconTemplate;
+ }
+
+ set
+ {
+ _iconTemplate = value;
+
+ OnPropertyChanged(nameof(IconTemplate));
+ }
+ }
+
public Step()
{
_header = null;
+ _iconTemplate = null;
_content = null;
_hasValidationErrors = false;
}
diff --git a/MaterialDesignExtensions/Model/StepTitleHeader.cs b/MaterialDesignExtensions/Model/StepTitleHeader.cs
index c3bef27e..d74d84d0 100644
--- a/MaterialDesignExtensions/Model/StepTitleHeader.cs
+++ b/MaterialDesignExtensions/Model/StepTitleHeader.cs
@@ -57,6 +57,9 @@ public string SecondLevelTitle
}
}
+ ///
+ /// Creates a new .
+ ///
public StepTitleHeader()
{
m_firstLevelTitle = null;
diff --git a/MaterialDesignExtensions/Model/SubheaderNavigationItem.cs b/MaterialDesignExtensions/Model/SubheaderNavigationItem.cs
index c5540aa8..260d22fd 100644
--- a/MaterialDesignExtensions/Model/SubheaderNavigationItem.cs
+++ b/MaterialDesignExtensions/Model/SubheaderNavigationItem.cs
@@ -6,10 +6,16 @@
namespace MaterialDesignExtensions.Model
{
+ ///
+ /// A header item of a .
+ ///
public class SubheaderNavigationItem : NotSelectableNavigationItem
{
private string m_subheader;
+ ///
+ /// The label of this header.
+ ///
public string Subheader
{
get
@@ -25,6 +31,9 @@ public string Subheader
}
}
+ ///
+ /// Creates a new .
+ ///
public SubheaderNavigationItem()
: base()
{
diff --git a/MaterialDesignExtensions/Properties/AssemblyInfo.cs b/MaterialDesignExtensions/Properties/AssemblyInfo.cs
index 00641604..92e9834d 100644
--- a/MaterialDesignExtensions/Properties/AssemblyInfo.cs
+++ b/MaterialDesignExtensions/Properties/AssemblyInfo.cs
@@ -3,18 +3,19 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
+using System.Windows.Markup;
// Allgemeine Informationen über eine Assembly werden über die folgenden
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
// die einer Assembly zugeordnet sind.
-[assembly: AssemblyTitle("Material Design Extensions")]
+/*[assembly: AssemblyTitle("Material Design Extensions")]
[assembly: AssemblyDescription("Material Design Extensions is based on Material Design in XAML Toolkit to provide additional controls and features for WPF apps")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Philipp Spiegel")]
[assembly: AssemblyProduct("Material Design Extensions")]
-[assembly: AssemblyCopyright("Copyright © 2017-2018")]
+[assembly: AssemblyCopyright("Copyright © 2017-2019")]
[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
+[assembly: AssemblyCulture("")]*/
// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
@@ -51,5 +52,10 @@
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
// übernehmen, indem Sie "*" eingeben:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("2.4.0.0")]
-[assembly: AssemblyFileVersion("2.4.0.0")]
+/*[assembly: AssemblyVersion("3.0.0.0")]
+[assembly: AssemblyFileVersion("3.0.0.0")]*/
+
+[assembly: XmlnsPrefix("https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml", "mde")]
+[assembly: XmlnsDefinition("https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml", "MaterialDesignExtensions.Controls")]
+[assembly: XmlnsDefinition("https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml", "MaterialDesignExtensions.Converters")]
+[assembly: XmlnsDefinition("https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml", "MaterialDesignExtensions.Model")]
diff --git a/MaterialDesignExtensions/TemplateSelectors/FileSystemEntryInfoTemplateSelector.cs b/MaterialDesignExtensions/TemplateSelectors/FileSystemEntryInfoTemplateSelector.cs
index 66b474b9..ce784540 100644
--- a/MaterialDesignExtensions/TemplateSelectors/FileSystemEntryInfoTemplateSelector.cs
+++ b/MaterialDesignExtensions/TemplateSelectors/FileSystemEntryInfoTemplateSelector.cs
@@ -7,6 +7,12 @@
using System.Windows;
using System.Windows.Controls;
+// use Pri.LongPath classes instead of System.IO for the MaterialDesignExtensions.LongPath build to support long file system paths on older Windows and .NET versions
+#if LONG_PATH
+using DirectoryInfo = Pri.LongPath.DirectoryInfo;
+using FileInfo = Pri.LongPath.FileInfo;
+#endif
+
namespace MaterialDesignExtensions.TemplateSelectors
{
internal class FileSystemEntryInfoTemplateSelector : DataTemplateSelector
diff --git a/MaterialDesignExtensions/TemplateSelectors/FileSystemEntryItemTemplateSelector.cs b/MaterialDesignExtensions/TemplateSelectors/FileSystemEntryItemTemplateSelector.cs
index 128389d1..fcadb892 100644
--- a/MaterialDesignExtensions/TemplateSelectors/FileSystemEntryItemTemplateSelector.cs
+++ b/MaterialDesignExtensions/TemplateSelectors/FileSystemEntryItemTemplateSelector.cs
@@ -12,7 +12,13 @@ namespace MaterialDesignExtensions.TemplateSelectors
{
internal class FileSystemEntryItemTemplateSelector : DataTemplateSelector
{
- public FileSystemEntryItemTemplateSelector() : base() { }
+ public bool ForMultipleSelection { get; set; }
+
+ public FileSystemEntryItemTemplateSelector()
+ : base()
+ {
+ ForMultipleSelection = false;
+ }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
@@ -24,7 +30,14 @@ public override DataTemplate SelectTemplate(object item, DependencyObject contai
}
else if (item is FileInfoItem)
{
- return element.FindResource("fileInfoItemTemplate") as DataTemplate;
+ if (ForMultipleSelection)
+ {
+ return element.FindResource("fileInfoItemMultipleTemplate") as DataTemplate;
+ }
+ else
+ {
+ return element.FindResource("fileInfoItemTemplate") as DataTemplate;
+ }
}
else if (item is FileSystemEntriesGroupHeader)
{
diff --git a/MaterialDesignExtensions/TemplateSelectors/StepIconTemplateSelector.cs b/MaterialDesignExtensions/TemplateSelectors/StepIconTemplateSelector.cs
new file mode 100644
index 00000000..e39e19ee
--- /dev/null
+++ b/MaterialDesignExtensions/TemplateSelectors/StepIconTemplateSelector.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+
+using MaterialDesignExtensions.Controls;
+using MaterialDesignExtensions.Model;
+
+namespace MaterialDesignExtensions.TemplateSelectors
+{
+ ///
+ /// A template selector for selecting an item for a step.
+ ///
+ public class StepIconTemplateSelector : DataTemplateSelector
+ {
+ ///
+ /// The stepper with the steps to apply this icon template selector on.
+ ///
+ public IStepper Stepper { get; set; }
+
+ ///
+ /// Creates a new .
+ ///
+ public StepIconTemplateSelector() : this(null) { }
+
+ ///
+ /// Creates a new .
+ ///
+ ///
+ public StepIconTemplateSelector(IStepper stepper)
+ {
+ Stepper = stepper;
+ }
+
+ ///
+ /// Selects a template for the icon of the specified step.
+ ///
+ ///
+ ///
+ ///
+ public override DataTemplate SelectTemplate(object item, DependencyObject container)
+ {
+ if (Stepper != null && item is StepperStepViewModel stepViewModel && container is FrameworkElement element)
+ {
+ return SelectTemplate(Stepper, element, stepViewModel);
+ }
+ else
+ {
+ return base.SelectTemplate(item, container);
+ }
+ }
+
+ ///
+ /// Selects a template for the icon of the specified step.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public DataTemplate SelectTemplate(IStepper stepper, FrameworkElement element, StepperStepViewModel stepViewModel)
+ {
+ if (stepper != null && stepViewModel != null && element != null)
+ {
+ if (stepViewModel.Step.IconTemplate != null)
+ {
+ return stepViewModel.Step.IconTemplate;
+ }
+ else if (stepViewModel.Step.HasValidationErrors && stepper.ValidationErrorIconTemplate != null)
+ {
+ return stepper.ValidationErrorIconTemplate;
+ }
+ else if (stepper.Controller.ActiveStepViewModel != null && stepper.Controller.ActiveStepViewModel.Number > stepViewModel.Number
+ && stepper.DoneIconTemplate != null)
+ {
+ return stepper.DoneIconTemplate;
+ } else {
+ return element.FindResource("MaterialDesignStepNumberIconTemplate") as DataTemplate;
+ }
+ }
+ else
+ {
+ return base.SelectTemplate(stepViewModel, element);
+ }
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Themes/AppBarTemplates.xaml b/MaterialDesignExtensions/Themes/AppBarTemplates.xaml
index 5b1f85be..4e82ba21 100644
--- a/MaterialDesignExtensions/Themes/AppBarTemplates.xaml
+++ b/MaterialDesignExtensions/Themes/AppBarTemplates.xaml
@@ -1,11 +1,14 @@
+
+
+
+
@@ -31,7 +34,7 @@
-
+
@@ -77,8 +80,7 @@
-
-
+
@@ -103,9 +105,10 @@
-
+
@@ -130,21 +133,14 @@
-
-
-
-
-
-
-
-
+
+
-
@@ -172,7 +168,7 @@
-
+
diff --git a/MaterialDesignExtensions/Themes/AutocompleteTemplates.xaml b/MaterialDesignExtensions/Themes/AutocompleteTemplates.xaml
index 964394c7..bc57bc7a 100644
--- a/MaterialDesignExtensions/Themes/AutocompleteTemplates.xaml
+++ b/MaterialDesignExtensions/Themes/AutocompleteTemplates.xaml
@@ -1,14 +1,16 @@
+ xmlns:converters="clr-namespace:MaterialDesignExtensions.Converters"
+ xmlns:internalCommands="clr-namespace:MaterialDesignExtensions.Commands.Internal">
+
+
-
+
@@ -23,7 +25,7 @@
-
+
@@ -70,7 +72,7 @@
-
-
-
+
+
@@ -96,7 +98,7 @@
-
-
-
+
@@ -187,15 +189,15 @@
+ Command="{x:Static internalCommands:AutocompleteCommands.SelectAutocompleteItemCommand}" CommandParameter="{Binding}">
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Themes/ExtendedTheme.cs b/MaterialDesignExtensions/Themes/ExtendedTheme.cs
new file mode 100644
index 00000000..76babffa
--- /dev/null
+++ b/MaterialDesignExtensions/Themes/ExtendedTheme.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Media;
+
+using MaterialDesignThemes.Wpf;
+
+namespace MaterialDesignExtensions.Themes
+{
+ public class ExtendedTheme : Theme, IExtendedTheme
+ {
+ public static IExtendedBaseTheme ExtendedLightTheme { get; } = new MaterialDesignExtendedLightTheme();
+
+ public static IExtendedBaseTheme ExtendedDarkTheme { get; } = new MaterialDesignExtendedDarkTheme();
+
+ public Color NavigationItemIcon { get; set; }
+
+ public Color NavigationItemText { get; set; }
+
+ public Color NavigationItemSubheader { get; set; }
+
+ public Color StepperInactiveStep { get; set; }
+
+ public Color StepperActiveStep { get; set; }
+
+ public Color StepperSeparator { get; set; }
+
+ public static ExtendedTheme Create(IExtendedBaseTheme baseTheme, Color primary, Color accent)
+ {
+ if (baseTheme == null)
+ {
+ throw new ArgumentNullException(nameof(baseTheme));
+ }
+
+ ExtendedTheme theme = new ExtendedTheme();
+
+ theme.SetBaseTheme(baseTheme);
+ theme.SetPrimaryColor(primary);
+ theme.SetSecondaryColor(accent);
+
+ return theme;
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Themes/ExtendedThemeExtensions.cs b/MaterialDesignExtensions/Themes/ExtendedThemeExtensions.cs
new file mode 100644
index 00000000..e9347802
--- /dev/null
+++ b/MaterialDesignExtensions/Themes/ExtendedThemeExtensions.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using MaterialDesignThemes.Wpf;
+
+namespace MaterialDesignExtensions.Themes
+{
+ public static class ExtendedThemeExtensions
+ {
+ public static IExtendedBaseTheme GetExtendedBaseTheme(this BaseTheme baseTheme)
+ {
+ switch (baseTheme)
+ {
+ case BaseTheme.Dark:
+ return ExtendedTheme.ExtendedDarkTheme;
+
+ case BaseTheme.Light:
+ return ExtendedTheme.ExtendedLightTheme;
+
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+
+ public static void SetBaseTheme(this IExtendedTheme theme, IExtendedBaseTheme baseTheme)
+ {
+ // call implementation of MaterialDesignThemes
+ theme.SetBaseTheme((IBaseTheme)baseTheme);
+
+ // set extended properties of the theme
+ theme.NavigationItemIcon = baseTheme.MaterialDesignNavigationItemIcon;
+ theme.NavigationItemText = baseTheme.MaterialDesignNavigationItemText;
+ theme.NavigationItemSubheader = baseTheme.MaterialDesignNavigationItemSubheader;
+ theme.StepperInactiveStep = baseTheme.MaterialDesignStepperInactiveStep;
+ theme.StepperActiveStep = baseTheme.MaterialDesignStepperActiveStep;
+ theme.StepperSeparator = baseTheme.MaterialDesignStepperSeparator;
+ }
+ }
+}
diff --git a/MaterialDesignExtensions/Themes/FileSystemControlTemplates.xaml b/MaterialDesignExtensions/Themes/FileSystemControlTemplates.xaml
index 35ddd3f6..8a19efb7 100644
--- a/MaterialDesignExtensions/Themes/FileSystemControlTemplates.xaml
+++ b/MaterialDesignExtensions/Themes/FileSystemControlTemplates.xaml
@@ -1,17 +1,20 @@
+
+
+
-
+
@@ -25,9 +28,12 @@
+
+
-
+
+
@@ -58,7 +64,7 @@
-
+
@@ -83,10 +89,10 @@
-
+
@@ -97,7 +103,7 @@
+ IsChecked="{Binding Path=IsTopDrawerOpen, RelativeSource={RelativeSource AncestorType={x:Type md:DrawerHost}}}" />
@@ -130,9 +136,9 @@
+ Command="{x:Static internalCommands:FileSystemControlCommands.SelectDirectoryItemCommand}" CommandParameter="{Binding}">
-
+
@@ -152,7 +158,7 @@
+ IsChecked="{Binding Path=IsLeftDrawerOpen, RelativeSource={RelativeSource AncestorType={x:Type md:DrawerHost}}}" />
+ IsChecked="{Binding Path=IsLeftDrawerOpen, RelativeSource={RelativeSource AncestorType={x:Type md:DrawerHost}}}" />
-
+
@@ -302,6 +308,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
@@ -396,23 +444,24 @@
+ Command="{x:Static internalCommands:FileSystemControlCommands.SelectFileSystemEntryCommand}" CommandParameter="{Binding Path=Value}">
-
+
-
+
-
+ ContentTemplateSelector="{StaticResource fileSystemEntryItemIconTemplateSelector}"
+ Focusable="False" />
+
-
+
@@ -469,23 +518,30 @@
+ Command="{x:Static internalCommands:FileSystemControlCommands.SelectFileSystemEntryCommand}" CommandParameter="{Binding Path=Value}">
+
+
+
+
-
+
-
+
-
+ ContentTemplateSelector="{StaticResource fileSystemEntryItemIconTemplateSelector}"
+ Focusable="False" />
+
+ Text="{Binding Path=Value.Name, Mode=OneTime}" ToolTip="{Binding Path=Value.Name, Mode=OneTime}" TextTrimming="CharacterEllipsis" />
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -551,72 +922,150 @@
Content="{Binding Path=Image}" ContentTemplateSelector="{StaticResource fileSystemEntryItemIconTemplateSelector}" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -625,70 +1074,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -697,74 +1176,381 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MaterialDesignExtensions/Themes/FileSystemDialogTemplates.xaml b/MaterialDesignExtensions/Themes/FileSystemDialogTemplates.xaml
index a71706e2..e6e717ef 100644
--- a/MaterialDesignExtensions/Themes/FileSystemDialogTemplates.xaml
+++ b/MaterialDesignExtensions/Themes/FileSystemDialogTemplates.xaml
@@ -1,20 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Themes/MessageDialogTemplates.xaml b/MaterialDesignExtensions/Themes/MessageDialogTemplates.xaml
new file mode 100644
index 00000000..47b857d2
--- /dev/null
+++ b/MaterialDesignExtensions/Themes/MessageDialogTemplates.xaml
@@ -0,0 +1,223 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Themes/OversizedNumberSpinnerTemplate.xaml b/MaterialDesignExtensions/Themes/OversizedNumberSpinnerTemplate.xaml
index c6b7c73a..21e2595b 100644
--- a/MaterialDesignExtensions/Themes/OversizedNumberSpinnerTemplate.xaml
+++ b/MaterialDesignExtensions/Themes/OversizedNumberSpinnerTemplate.xaml
@@ -1,9 +1,11 @@
+ xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls"
+ xmlns:internalCommands="clr-namespace:MaterialDesignExtensions.Commands.Internal">
+
@@ -123,15 +125,7 @@
-
+ Command="{x:Static internalCommands:OversizedNumberSpinnerCommands.PlusCommand}">
@@ -141,18 +135,7 @@
-
+ Command="{x:Static internalCommands:OversizedNumberSpinnerCommands.MinusCommand}">
@@ -160,7 +143,7 @@
-
+
-
-
+
@@ -214,147 +225,17 @@
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Themes/SideNavigationTemplates.xaml b/MaterialDesignExtensions/Themes/SideNavigationTemplates.xaml
index 3f647a05..55dd9a4d 100644
--- a/MaterialDesignExtensions/Themes/SideNavigationTemplates.xaml
+++ b/MaterialDesignExtensions/Themes/SideNavigationTemplates.xaml
@@ -1,16 +1,21 @@
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Themes/StepperTemplates.xaml b/MaterialDesignExtensions/Themes/StepperTemplates.xaml
index 7f27df73..afd586fd 100644
--- a/MaterialDesignExtensions/Themes/StepperTemplates.xaml
+++ b/MaterialDesignExtensions/Themes/StepperTemplates.xaml
@@ -1,14 +1,19 @@
+
+
+
+
-
+
+
@@ -26,7 +31,7 @@
-
+
@@ -38,14 +43,14 @@
+ Effect="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(md:ShadowAssist.ShadowDepth), Converter={x:Static md:ShadowConverter.Instance}}">
-
+
@@ -84,6 +89,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
@@ -580,7 +618,7 @@
-
+
@@ -591,17 +629,15 @@
-
+
-
-
-
-
+
+
@@ -612,7 +648,7 @@
-
+
@@ -621,10 +657,8 @@
-
-
-
-
+
+
@@ -635,7 +669,7 @@
-
+
@@ -643,10 +677,8 @@
-
-
-
-
+
+
@@ -703,7 +735,7 @@
-
+
@@ -732,10 +764,8 @@
-
-
-
-
+
+
diff --git a/MaterialDesignExtensions/Themes/TabControlTemplates.xaml b/MaterialDesignExtensions/Themes/TabControlTemplates.xaml
new file mode 100644
index 00000000..334196d7
--- /dev/null
+++ b/MaterialDesignExtensions/Themes/TabControlTemplates.xaml
@@ -0,0 +1,242 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Themes/TextBoxFileSystemPathTemplates.xaml b/MaterialDesignExtensions/Themes/TextBoxFileSystemPathTemplates.xaml
new file mode 100644
index 00000000..71921b3c
--- /dev/null
+++ b/MaterialDesignExtensions/Themes/TextBoxFileSystemPathTemplates.xaml
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/Themes/TextBoxSuggestionsTemplates.xaml b/MaterialDesignExtensions/Themes/TextBoxSuggestionsTemplates.xaml
index d5293e79..e16241a1 100644
--- a/MaterialDesignExtensions/Themes/TextBoxSuggestionsTemplates.xaml
+++ b/MaterialDesignExtensions/Themes/TextBoxSuggestionsTemplates.xaml
@@ -1,14 +1,16 @@
+ xmlns:converters="clr-namespace:MaterialDesignExtensions.Converters"
+ xmlns:internalCommands="clr-namespace:MaterialDesignExtensions.Commands.Internal">
+
+
-
+
@@ -47,7 +49,7 @@
-
+
@@ -102,15 +104,15 @@
+ Command="{x:Static internalCommands:TextBoxSuggestionsCommands.SelectSuggestionItemCommand}" CommandParameter="{Binding}">
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensions/key.snk b/MaterialDesignExtensions/key.snk
new file mode 100644
index 00000000..6f42b837
Binary files /dev/null and b/MaterialDesignExtensions/key.snk differ
diff --git a/MaterialDesignExtensions/packages.config b/MaterialDesignExtensions/packages.config
deleted file mode 100644
index 6fec607a..00000000
--- a/MaterialDesignExtensions/packages.config
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/MaterialDesignExtensionsBuildUtility/App.config b/MaterialDesignExtensionsBuildUtility/App.config
new file mode 100644
index 00000000..8e156463
--- /dev/null
+++ b/MaterialDesignExtensionsBuildUtility/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensionsBuildUtility/BuildConfiguration.cs b/MaterialDesignExtensionsBuildUtility/BuildConfiguration.cs
new file mode 100644
index 00000000..8e7b37c9
--- /dev/null
+++ b/MaterialDesignExtensionsBuildUtility/BuildConfiguration.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MaterialDesignExtensionsBuildUtility
+{
+ public class BuildConfiguration
+ {
+ public string Name { get; }
+
+ public string BuildDirectory { get; }
+
+ public string NuspecFilename { get; }
+
+ public BuildConfiguration(string name, string buildDirectory, string nuspecFilename)
+ {
+ Name = name;
+ BuildDirectory = buildDirectory;
+ NuspecFilename = nuspecFilename;
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsBuildUtility/BuildException.cs b/MaterialDesignExtensionsBuildUtility/BuildException.cs
new file mode 100644
index 00000000..b1eb1611
--- /dev/null
+++ b/MaterialDesignExtensionsBuildUtility/BuildException.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MaterialDesignExtensionsBuildUtility
+{
+ public class BuildException : Exception
+ {
+ public BuildException(string message) : base(message) { }
+ }
+}
diff --git a/MaterialDesignExtensionsBuildUtility/Configuration.cs b/MaterialDesignExtensionsBuildUtility/Configuration.cs
new file mode 100644
index 00000000..ecbef599
--- /dev/null
+++ b/MaterialDesignExtensionsBuildUtility/Configuration.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MaterialDesignExtensionsBuildUtility
+{
+ public class Configuration
+ {
+ public string MsBuildExePath { get; set; }
+
+ public string NuGetExePath { get; set; }
+
+ public string RepositoryBaseDirectory { get; set; }
+
+ public string ProjectDirectory { get; set; }
+
+ public string ProjectFile { get; set; }
+
+ public BuildConfiguration[] BuildConfigurations { get; set; }
+
+ public string PackageDirectory { get; set; }
+
+ public Configuration() { }
+ }
+}
diff --git a/MaterialDesignExtensionsBuildUtility/ConfigurationBuilder.cs b/MaterialDesignExtensionsBuildUtility/ConfigurationBuilder.cs
new file mode 100644
index 00000000..6ec06d45
--- /dev/null
+++ b/MaterialDesignExtensionsBuildUtility/ConfigurationBuilder.cs
@@ -0,0 +1,174 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MaterialDesignExtensionsBuildUtility
+{
+ public class ConfigurationBuilder
+ {
+ private const string ProjectDirectoryArgumentName = "projectDirectory";
+ private const string BuildConfigurationArgumentName = "buildConfiguration";
+ private const char BuildConfigurationsSeparator = ';';
+
+ private const string ProjectDirectoryName = "MaterialDesignExtensions";
+ private const string ProjectFileName = "MaterialDesignExtensions.csproj";
+
+ private static readonly string[] MsBuildExePaths = new string[]
+ {
+ @"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe",
+ @"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\MSBuild.exe",
+ @"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe",
+ @"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Current\Bin\MSBuild.exe"
+ };
+
+ private static readonly ISet AllBuildConfigurations = new HashSet()
+ {
+ new BuildConfiguration("Release", @"bin\Release", "MaterialDesignExtensions.nuspec"),
+ new BuildConfiguration("Debug", @"bin\Debug", null)
+ // MaterialDesignExtensions.LongPath since v3.0.0 not supported anymore
+ /*new BuildConfiguration("ReleaseLongPath", @"bin\ReleaseLongPath", "MaterialDesignExtensions.LongPath.nuspec"),
+ new BuildConfiguration("DebugLongPath", @"bin\Debug", null)*/
+ };
+
+ public static Configuration CreateConfiguration(string[] args)
+ {
+ Configuration configuration = new Configuration();
+
+ ParseArguments(configuration, args);
+
+ InitRepositoryProjectConfiguration(configuration);
+
+ if (string.IsNullOrWhiteSpace(configuration.ProjectFile) || !File.Exists(configuration.ProjectFile))
+ {
+ throw new ArgumentException("Did not find project file");
+ }
+
+ InitCommandsConfiguration(configuration);
+
+ if (string.IsNullOrWhiteSpace(configuration.MsBuildExePath) || !File.Exists(configuration.MsBuildExePath))
+ {
+ throw new ArgumentException("Did not find MSBuild.exe");
+ }
+
+ if (string.IsNullOrWhiteSpace(configuration.NuGetExePath) || !File.Exists(configuration.NuGetExePath))
+ {
+ throw new ArgumentException("Did not find nuget.exe");
+ }
+
+ if (configuration.BuildConfigurations == null || configuration.BuildConfigurations.Length == 0)
+ {
+ configuration.BuildConfigurations = AllBuildConfigurations.ToArray();
+ }
+
+ configuration.BuildConfigurations = configuration.BuildConfigurations.OrderBy(buildConfiguration => buildConfiguration.Name).ToArray();
+
+ return configuration;
+ }
+
+ private static void ParseArguments(Configuration configuration, string[] args)
+ {
+ if (args != null && args.Length > 0)
+ {
+ for (int i = 0; i < args.Length; i++)
+ {
+ if (args[i].StartsWith($"-{ProjectDirectoryArgumentName}"))
+ {
+ i++;
+
+ if (i < args.Length)
+ {
+ configuration.ProjectDirectory = StripQuotes(args[i]).Trim();
+ }
+ }
+ else if (args[i].StartsWith($"-{BuildConfigurationArgumentName}"))
+ {
+ i++;
+
+ if (i < args.Length)
+ {
+ string buildConfigurationsStr = StripQuotes(args[i]);
+ ISet buildConfigurationNames = new HashSet();
+
+ if (buildConfigurationsStr.Contains(BuildConfigurationsSeparator))
+ {
+ buildConfigurationNames.UnionWith(buildConfigurationsStr.Split(BuildConfigurationsSeparator).Select(str => str.Trim()));
+ }
+ else
+ {
+ buildConfigurationNames.Add(buildConfigurationsStr.Trim());
+ }
+
+ configuration.BuildConfigurations = AllBuildConfigurations.Where(buildConfiguration => buildConfigurationNames.Contains(buildConfiguration.Name)).ToArray();
+ }
+ }
+ }
+ }
+ }
+
+ private static string StripQuotes(string str)
+ {
+ if (!string.IsNullOrWhiteSpace(str))
+ {
+ if (str.StartsWith("\"") && str.Length > 1)
+ {
+ str = str.Substring(1);
+ }
+
+ if (str.EndsWith("\""))
+ {
+ str = str.Substring(0, str.Length - 1);
+ }
+ }
+
+ return str;
+ }
+
+ private static void InitRepositoryProjectConfiguration(Configuration configuration)
+ {
+ bool repositoryDirectoryFound = false;
+ DirectoryInfo currentDirectory = null;
+
+ if (string.IsNullOrWhiteSpace(configuration.ProjectDirectory))
+ {
+ currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory());
+
+ while (!(repositoryDirectoryFound = IsRepositoryDirectory(currentDirectory)) && currentDirectory.Parent != null)
+ {
+ currentDirectory = currentDirectory.Parent;
+ }
+ }
+ else
+ {
+ currentDirectory = new DirectoryInfo(configuration.ProjectDirectory).Parent;
+ repositoryDirectoryFound = true;
+ }
+
+ if (repositoryDirectoryFound)
+ {
+ configuration.RepositoryBaseDirectory = currentDirectory.FullName;
+ configuration.ProjectDirectory = $@"{configuration.RepositoryBaseDirectory}\{ProjectDirectoryName}";
+ configuration.ProjectFile = $@"{configuration.ProjectDirectory}\{ProjectFileName}";
+ configuration.PackageDirectory = $@"{configuration.RepositoryBaseDirectory}\packageBuilds";
+ }
+ }
+
+ private static bool IsRepositoryDirectory(DirectoryInfo directory)
+ {
+ return directory.GetDirectories()
+ .Any(directoryItem => directoryItem.Name.Equals(ProjectDirectoryName, StringComparison.InvariantCultureIgnoreCase));
+ }
+
+ private static void InitCommandsConfiguration(Configuration configuration)
+ {
+ configuration.MsBuildExePath = MsBuildExePaths.FirstOrDefault(msBuildExePath => File.Exists(msBuildExePath));
+
+ configuration.NuGetExePath = Environment.GetEnvironmentVariable("PATH").Split(';')
+ .Select(path => Path.Combine(path, "nuget.exe"))
+ .Where(file => File.Exists(file))
+ .FirstOrDefault();
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsBuildUtility/MaterialDesignExtensionsBuildUtility.csproj b/MaterialDesignExtensionsBuildUtility/MaterialDesignExtensionsBuildUtility.csproj
new file mode 100644
index 00000000..48f6d8d3
--- /dev/null
+++ b/MaterialDesignExtensionsBuildUtility/MaterialDesignExtensionsBuildUtility.csproj
@@ -0,0 +1,10 @@
+
+
+
+
+ Exe
+ net7.0
+ false
+
+
+
\ No newline at end of file
diff --git a/MaterialDesignExtensionsBuildUtility/Program.cs b/MaterialDesignExtensionsBuildUtility/Program.cs
new file mode 100644
index 00000000..d791da1a
--- /dev/null
+++ b/MaterialDesignExtensionsBuildUtility/Program.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MaterialDesignExtensionsBuildUtility
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ try
+ {
+ Configuration configuration = Init(args);
+
+ if (configuration.BuildConfigurations != null && configuration.BuildConfigurations.Length > 0)
+ {
+ foreach (BuildConfiguration buildConfiguration in configuration.BuildConfigurations)
+ {
+ Build(configuration, buildConfiguration);
+ }
+
+ foreach (BuildConfiguration buildConfiguration in configuration.BuildConfigurations)
+ {
+ if (!string.IsNullOrWhiteSpace(buildConfiguration.NuspecFilename))
+ {
+ Package(configuration, buildConfiguration);
+ }
+ }
+ }
+ }
+ catch (ArgumentException exc)
+ {
+ Console.WriteLine(exc.Message);
+ }
+ catch (BuildException exc)
+ {
+ Console.WriteLine(exc.Message);
+ }
+ catch (Exception exc)
+ {
+ Console.WriteLine(exc);
+ }
+
+ Console.WriteLine("Press any key to exit...");
+ Console.ReadKey();
+ }
+
+ private static Configuration Init(string[] args)
+ {
+ Console.WriteLine("Initialization...");
+
+ return ConfigurationBuilder.CreateConfiguration(args);
+ }
+
+ private static void Build(Configuration configuration, BuildConfiguration buildConfiguration)
+ {
+ Console.WriteLine($"Building {buildConfiguration.Name}...");
+
+ if (!RunProcess($"\"{configuration.MsBuildExePath}\"", $"\"{configuration.ProjectFile}\" -property:Configuration={buildConfiguration.Name} -consoleloggerparameters:PerformanceSummary;Summary;ErrorsOnly"))
+ {
+ throw new BuildException($"Build of {buildConfiguration.Name} failed");
+ }
+
+ Console.WriteLine($"Build of {buildConfiguration.Name} succeeded");
+ }
+
+ private static void Package(Configuration configuration, BuildConfiguration buildConfiguration)
+ {
+ Console.WriteLine($"Packing {buildConfiguration.Name}...");
+
+ if (!Directory.Exists(configuration.PackageDirectory))
+ {
+ Directory.CreateDirectory(configuration.PackageDirectory);
+ }
+
+ if (!RunProcess($"\"{configuration.NuGetExePath}\"", $"pack \"{configuration.ProjectDirectory}\\{buildConfiguration.NuspecFilename}\" -OutputDirectory \"{configuration.PackageDirectory}\""))
+ {
+ throw new BuildException($"Packing of {buildConfiguration.Name} failed");
+ }
+
+ Console.WriteLine($"Packing of {buildConfiguration.Name} succeeded");
+ }
+
+ private static bool RunProcess(string filename, string arguments)
+ {
+ ProcessStartInfo processStartInfo = new ProcessStartInfo(filename, arguments)
+ {
+ UseShellExecute = false,
+ RedirectStandardOutput = true
+ };
+
+ Process process = Process.Start(processStartInfo);
+
+ Console.WriteLine(process.StandardOutput.ReadToEnd());
+
+ process.WaitForExit();
+
+ return process.ExitCode == 0;
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsBuildUtility/Properties/AssemblyInfo.cs b/MaterialDesignExtensionsBuildUtility/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..809e741c
--- /dev/null
+++ b/MaterialDesignExtensionsBuildUtility/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// Allgemeine Informationen über eine Assembly werden über die folgenden
+// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
+// die einer Assembly zugeordnet sind.
+[assembly: AssemblyTitle("MaterialDesignExtensionsBuildUtility")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("MaterialDesignExtensionsBuildUtility")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
+// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
+// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
+[assembly: ComVisible(false)]
+
+// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
+[assembly: Guid("2e40d411-ce99-489e-a1e4-9f28a1399ca1")]
+
+// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
+//
+// Hauptversion
+// Nebenversion
+// Buildnummer
+// Revision
+//
+// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
+// übernehmen, indem Sie "*" eingeben:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/MaterialDesignExtensionsBuildUtility/Readme.md b/MaterialDesignExtensionsBuildUtility/Readme.md
new file mode 100644
index 00000000..63cde1f5
--- /dev/null
+++ b/MaterialDesignExtensionsBuildUtility/Readme.md
@@ -0,0 +1 @@
+A small utility app to automate builds and package creation for new releases of Material Design Extensions.
\ No newline at end of file
diff --git a/MaterialDesignExtensionsDemo/App.xaml b/MaterialDesignExtensionsDemo/App.xaml
index 059ee6de..d7e2515c 100644
--- a/MaterialDesignExtensionsDemo/App.xaml
+++ b/MaterialDesignExtensionsDemo/App.xaml
@@ -1,13 +1,16 @@
+
+
@@ -16,12 +19,12 @@
-
-
-
-
-
-
+
+
+
+
+
+
@@ -29,8 +32,18 @@
-
-
+
+
+
+
+
+
+
+
diff --git a/MaterialDesignExtensionsDemo/App.xaml.cs b/MaterialDesignExtensionsDemo/App.xaml.cs
index 0fae41f3..abc8d175 100644
--- a/MaterialDesignExtensionsDemo/App.xaml.cs
+++ b/MaterialDesignExtensionsDemo/App.xaml.cs
@@ -1,17 +1,16 @@
-using System;
-using System.Collections.Generic;
-using System.Configuration;
-using System.Data;
-using System.Linq;
-using System.Threading.Tasks;
+using System.Globalization;
+using System.Threading;
using System.Windows;
namespace MaterialDesignExtensionsDemo
{
- ///
- /// Interaktionslogik für "App.xaml"
- ///
public partial class App : Application
{
+ protected override void OnStartup(StartupEventArgs args)
+ {
+ // change the culture to test localized resource files for display strings
+ /*Thread.CurrentThread.CurrentCulture = new CultureInfo("en-us");
+ Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-us");*/
+ }
}
}
diff --git a/MaterialDesignExtensionsDemo/Controls/AppBarControl.xaml b/MaterialDesignExtensionsDemo/Controls/AppBarControl.xaml
index 01be89f3..852b9ae9 100644
--- a/MaterialDesignExtensionsDemo/Controls/AppBarControl.xaml
+++ b/MaterialDesignExtensionsDemo/Controls/AppBarControl.xaml
@@ -4,9 +4,10 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MaterialDesignExtensionsDemo.Controls"
- xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
+ xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
+ xmlns:mde="https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml"
mc:Ignorable="d"
- d:DesignHeight="300" d:DesignWidth="500" Background="Transparent">
+ d:DesignHeight="300" d:DesignWidth="500" Background="{DynamicResource MaterialDesignBackground}">
@@ -18,9 +19,9 @@
-
-
-
+
+
+
@@ -33,32 +34,65 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MaterialDesignExtensionsDemo/Controls/AutocompleteControl.xaml b/MaterialDesignExtensionsDemo/Controls/AutocompleteControl.xaml
index 8b8a9cd1..66403b72 100644
--- a/MaterialDesignExtensionsDemo/Controls/AutocompleteControl.xaml
+++ b/MaterialDesignExtensionsDemo/Controls/AutocompleteControl.xaml
@@ -4,24 +4,23 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MaterialDesignExtensionsDemo.Controls"
- xmlns:wpfLib="http://materialdesigninxaml.net/winfx/xaml/themes"
- xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
- xmlns:converters="clr-namespace:MaterialDesignExtensions.Converters;assembly=MaterialDesignExtensions"
+ xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
+ xmlns:mde="https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml"
mc:Ignorable="d"
- d:DesignHeight="450" d:DesignWidth="700">
+ d:DesignHeight="450" d:DesignWidth="700" Background="{DynamicResource MaterialDesignBackground}">
-
+
-
+
-
+
@@ -30,22 +29,24 @@
-
-
+
-
+
-
-
+
+
+
-
diff --git a/MaterialDesignExtensionsDemo/Controls/AutocompleteControl.xaml.cs b/MaterialDesignExtensionsDemo/Controls/AutocompleteControl.xaml.cs
index 71e85bf8..4cd2ba31 100644
--- a/MaterialDesignExtensionsDemo/Controls/AutocompleteControl.xaml.cs
+++ b/MaterialDesignExtensionsDemo/Controls/AutocompleteControl.xaml.cs
@@ -21,5 +21,10 @@ public AutocompleteControl()
{
InitializeComponent();
}
+
+ private void ClearSelectionButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ autocomplete.ClearSelection();
+ }
}
}
diff --git a/MaterialDesignExtensionsDemo/Controls/AutocompleteInTabControlControl.xaml b/MaterialDesignExtensionsDemo/Controls/AutocompleteInTabControlControl.xaml
index a294f4e6..d0e7c248 100644
--- a/MaterialDesignExtensionsDemo/Controls/AutocompleteInTabControlControl.xaml
+++ b/MaterialDesignExtensionsDemo/Controls/AutocompleteInTabControlControl.xaml
@@ -4,15 +4,14 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MaterialDesignExtensionsDemo.Controls"
- xmlns:wpfLib="http://materialdesigninxaml.net/winfx/xaml/themes"
- xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
- xmlns:converters="clr-namespace:MaterialDesignExtensions.Converters;assembly=MaterialDesignExtensions"
+ xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
+ xmlns:mde="https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml"
mc:Ignorable="d"
- d:DesignHeight="450" d:DesignWidth="700">
+ d:DesignHeight="450" d:DesignWidth="700" Background="{DynamicResource MaterialDesignBackground}">
-
+
@@ -22,30 +21,30 @@
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
-
-
+
-
+
-
-
+
+
-
-
+
-
+
-
-
+
+
diff --git a/MaterialDesignExtensionsDemo/Controls/BusyOverlayControl.xaml b/MaterialDesignExtensionsDemo/Controls/BusyOverlayControl.xaml
new file mode 100644
index 00000000..e907ccb2
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/BusyOverlayControl.xaml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MaterialDesignExtensionsDemo/Controls/BusyOverlayControl.xaml.cs b/MaterialDesignExtensionsDemo/Controls/BusyOverlayControl.xaml.cs
new file mode 100644
index 00000000..35b2ee8a
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/BusyOverlayControl.xaml.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Text;
+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 MaterialDesignExtensionsDemo.ViewModel;
+
+namespace MaterialDesignExtensionsDemo.Controls
+{
+ public partial class BusyOverlayControl : UserControl
+ {
+ public BusyOverlayControl()
+ {
+ InitializeComponent();
+ }
+
+ private async void BeBusyButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ await ((BusyOverlayViewModel)DataContext).BeBusyAsync();
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/Controls/FileSystemDialogControl.xaml b/MaterialDesignExtensionsDemo/Controls/FileSystemDialogControl.xaml
index 3d65a46f..2cfb16e4 100644
--- a/MaterialDesignExtensionsDemo/Controls/FileSystemDialogControl.xaml
+++ b/MaterialDesignExtensionsDemo/Controls/FileSystemDialogControl.xaml
@@ -5,9 +5,10 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MaterialDesignExtensionsDemo.Controls"
mc:Ignorable="d"
- d:DesignHeight="500" d:DesignWidth="700">
+ d:DesignHeight="500" d:DesignWidth="700" Background="{DynamicResource MaterialDesignBackground}">
+
@@ -16,6 +17,10 @@
-
+
+
+
+
+
diff --git a/MaterialDesignExtensionsDemo/Controls/FileSystemDialogControl.xaml.cs b/MaterialDesignExtensionsDemo/Controls/FileSystemDialogControl.xaml.cs
index cbd1ddec..735ddd8d 100644
--- a/MaterialDesignExtensionsDemo/Controls/FileSystemDialogControl.xaml.cs
+++ b/MaterialDesignExtensionsDemo/Controls/FileSystemDialogControl.xaml.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -32,7 +31,8 @@ private async void OpenDirectoryDialogButtonClickHandler(object sender, RoutedEv
OpenDirectoryDialogArguments dialogArgs = new OpenDirectoryDialogArguments()
{
Width = 600,
- Height = 400
+ Height = 400,
+ CreateNewDirectoryEnabled = true
};
OpenDirectoryDialogResult result = await OpenDirectoryDialog.ShowDialogAsync(MainWindow.DialogHostName, dialogArgs);
@@ -80,7 +80,8 @@ private async void SaveFileDialogButtonClickHandler(object sender, RoutedEventAr
{
Width = 600,
Height = 400,
- Filters = "All files|*.*|C# files|*.cs|XAML files|*.xaml"
+ Filters = "All files|*.*|C# files|*.cs|XAML files|*.xaml",
+ CreateNewDirectoryEnabled = true
};
SaveFileDialogResult result = await SaveFileDialog.ShowDialogAsync(MainWindow.DialogHostName, dialogArgs);
@@ -97,5 +98,59 @@ private async void SaveFileDialogButtonClickHandler(object sender, RoutedEventAr
}
}
}
+
+ private async void OpenMultipleDirectoriesDialogButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ OpenMultipleDirectoriesDialogArguments dialogArgs = new OpenMultipleDirectoriesDialogArguments()
+ {
+ Width = 600,
+ Height = 400,
+ CreateNewDirectoryEnabled = true
+ };
+
+ OpenMultipleDirectoriesDialogResult result = await OpenMultipleDirectoriesDialog.ShowDialogAsync(MainWindow.DialogHostName, dialogArgs);
+
+ if (DataContext is FileSystemDialogViewModel viewModel)
+ {
+ if (!result.Canceled)
+ {
+ StringBuilder sb = new StringBuilder("Selected directories: ");
+ result.Directories.ForEach(directory => sb.Append($"{directory}; "));
+
+ viewModel.SelectedAction = sb.ToString();
+ }
+ else
+ {
+ viewModel.SelectedAction = "Cancel open multiple directories";
+ }
+ }
+ }
+
+ private async void OpenMultipleFilesDialogButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ OpenMultipleFilesDialogArguments dialogArgs = new OpenMultipleFilesDialogArguments()
+ {
+ Width = 600,
+ Height = 400,
+ Filters = "All files|*.*|C# files|*.cs|XAML files|*.xaml"
+ };
+
+ OpenMultipleFilesDialogResult result = await OpenMultipleFilesDialog.ShowDialogAsync(MainWindow.DialogHostName, dialogArgs);
+
+ if (DataContext is FileSystemDialogViewModel viewModel)
+ {
+ if (!result.Canceled)
+ {
+ StringBuilder sb = new StringBuilder("Selected files: ");
+ result.Files.ForEach(file => sb.Append($"{file}; "));
+
+ viewModel.SelectedAction = sb.ToString();
+ }
+ else
+ {
+ viewModel.SelectedAction = "Cancel open multiple files";
+ }
+ }
+ }
}
}
diff --git a/MaterialDesignExtensionsDemo/Controls/GridListControl.xaml b/MaterialDesignExtensionsDemo/Controls/GridListControl.xaml
index 54664344..f3b186c0 100644
--- a/MaterialDesignExtensionsDemo/Controls/GridListControl.xaml
+++ b/MaterialDesignExtensionsDemo/Controls/GridListControl.xaml
@@ -6,7 +6,7 @@
xmlns:local="clr-namespace:MaterialDesignExtensionsDemo.Controls"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
- d:DesignHeight="400" d:DesignWidth="600">
+ d:DesignHeight="400" d:DesignWidth="600" Background="{DynamicResource MaterialDesignBackground}">
diff --git a/MaterialDesignExtensionsDemo/Controls/LanguageControl.xaml b/MaterialDesignExtensionsDemo/Controls/LanguageControl.xaml
new file mode 100644
index 00000000..19cea345
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/LanguageControl.xaml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MaterialDesignExtensionsDemo/Controls/LanguageControl.xaml.cs b/MaterialDesignExtensionsDemo/Controls/LanguageControl.xaml.cs
new file mode 100644
index 00000000..dfe09181
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/LanguageControl.xaml.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+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;
+
+namespace MaterialDesignExtensionsDemo.Controls
+{
+ public partial class LanguageControl : UserControl
+ {
+ public LanguageControl()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/Controls/MessageDialogControl.xaml b/MaterialDesignExtensionsDemo/Controls/MessageDialogControl.xaml
new file mode 100644
index 00000000..2cbb5fb5
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/MessageDialogControl.xaml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MaterialDesignExtensionsDemo/Controls/MessageDialogControl.xaml.cs b/MaterialDesignExtensionsDemo/Controls/MessageDialogControl.xaml.cs
new file mode 100644
index 00000000..32b57ed9
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/MessageDialogControl.xaml.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+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.Threading.Tasks;
+
+using MaterialDesignThemes;
+
+using MaterialDesignExtensions.Controls;
+using MaterialDesignThemes.Wpf;
+using MaterialDesignExtensionsDemo.ViewModel;
+using System.Linq;
+
+namespace MaterialDesignExtensionsDemo.Controls
+{
+ public partial class MessageDialogControl : UserControl
+ {
+ public MessageDialogControl()
+ {
+ InitializeComponent();
+ }
+
+ private async void ShowAlertDialogButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ AlertDialogArguments dialogArgs = new AlertDialogArguments
+ {
+ Title = "Greetings",
+ Message = "Hello, I'm MaterialDesignExtensions.",
+ OkButtonLabel = "GOT IT"
+ };
+
+ await AlertDialog.ShowDialogAsync(MainWindow.DialogHostName, dialogArgs);
+ }
+
+ private async void ShowConfirmationDialogButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ await ShowConfirmationDialogAsync(false);
+ }
+
+ private async void ShowConfirmationDialogStackedButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ await ShowConfirmationDialogAsync(true);
+ }
+
+ private async Task ShowConfirmationDialogAsync(bool stackedButtons)
+ {
+ ConfirmationDialogArguments dialogArgs = new ConfirmationDialogArguments
+ {
+ Title = "Delete files",
+ Message = "Do you really want to permanently delete all files?",
+ OkButtonLabel = "DELETE",
+ CancelButtonLabel = "CANCEL",
+ StackedButtons = stackedButtons
+ };
+
+ bool result = await ConfirmationDialog.ShowDialogAsync(MainWindow.DialogHostName, dialogArgs);
+
+ System.Diagnostics.Debug.WriteLine($"{typeof(ConfirmationDialog)} result: {result}");
+ }
+
+ private async void ShowAlertDialogWithContentButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ AlertDialogArguments dialogArgs = new AlertDialogArguments
+ {
+ Title = "Sports",
+ Message = "Some great sports:",
+ OkButtonLabel = "OK",
+ CustomContent = FindResource("SportsStackPanel")
+ };
+
+ await AlertDialog.ShowDialogAsync(MainWindow.DialogHostName, dialogArgs);
+ }
+
+ private async void ShowConfirmationDialogWithContentButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ ConfirmationDialogArguments dialogArgs = new ConfirmationDialogArguments
+ {
+ Title = "Sports",
+ Message = "Which sports do you enjoy?",
+ OkButtonLabel = "OK",
+ CancelButtonLabel = "CANCEL",
+ CustomContent = FindResource("SimpleTextBox")
+ };
+
+ await ConfirmationDialog.ShowDialogAsync(MainWindow.DialogHostName, dialogArgs);
+ }
+
+ private async void ShowInputDialogButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ m_sportsSelectionTextBlock.Text = null;
+
+ SportsSelectionViewModel viewModel = new SportsSelectionViewModel();
+
+ InputDialogArguments dialogArgs = new InputDialogArguments
+ {
+ Title = "Sports",
+ Message = "Which sports do you enjoy?",
+ OkButtonLabel = "THAT'S IT",
+ CancelButtonLabel = "CANCEL",
+ CustomContent = viewModel,
+ CustomContentTemplate = FindResource("SportsSelectionViewModelTemplate") as DataTemplate,
+ ValidationHandler = viewModel.ValidationHandler
+ };
+
+ bool result = await InputDialog.ShowDialogAsync(MainWindow.DialogHostName, dialogArgs);
+
+ if (result)
+ {
+ List sportsItems = viewModel.SportsItems
+ .Where(sportsItem => sportsItem.IsSelected)
+ .Select(sportsItem => sportsItem.Label)
+ .ToList();
+
+ m_sportsSelectionTextBlock.Text = $"Selected sports: {string.Join(", ", sportsItems)}";
+ }
+ else
+ {
+ m_sportsSelectionTextBlock.Text = "Sports selection cancelled";
+ }
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/Controls/NavigationControl.xaml b/MaterialDesignExtensionsDemo/Controls/NavigationControl.xaml
index ff5cac63..5e445323 100644
--- a/MaterialDesignExtensionsDemo/Controls/NavigationControl.xaml
+++ b/MaterialDesignExtensionsDemo/Controls/NavigationControl.xaml
@@ -4,9 +4,15 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MaterialDesignExtensionsDemo.Controls"
- xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
+ xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
+ xmlns:mde="https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml"
mc:Ignorable="d"
- d:DesignHeight="450" d:DesignWidth="800" Background="Transparent">
+ d:DesignHeight="450" d:DesignWidth="800" Background="{DynamicResource MaterialDesignBackground}">
+
+
+
+
+
@@ -26,12 +32,12 @@
-
-
-
diff --git a/MaterialDesignExtensionsDemo/Controls/NavigationControl.xaml.cs b/MaterialDesignExtensionsDemo/Controls/NavigationControl.xaml.cs
index 5f9485e7..92a66d00 100644
--- a/MaterialDesignExtensionsDemo/Controls/NavigationControl.xaml.cs
+++ b/MaterialDesignExtensionsDemo/Controls/NavigationControl.xaml.cs
@@ -15,6 +15,8 @@
using MaterialDesignExtensions.Model;
+using MaterialDesignExtensionsDemo.ViewModel;
+
namespace MaterialDesignExtensionsDemo.Controls
{
public partial class NavigationControl : UserControl
@@ -32,6 +34,16 @@ private void NavigationControl_Loaded(object sender, RoutedEventArgs args)
navigation1.WillSelectNavigationItemCallbackAsync = WillSelectNavigationItemCallbackAsync;
navigation2.WillSelectNavigationItemCallbackAsync = WillSelectNavigationItemCallbackAsync;
navigation3.WillSelectNavigationItemCallbackAsync = WillSelectNavigationItemCallbackAsync;
+
+ // just a demo for showing how to override the default template of a navigation item's icon
+ /*if (DataContext is NavigationViewModel viewModel)
+ {
+ viewModel.NavigationItems
+ .Where(navigationItem => navigationItem is FirstLevelNavigationItem && ((FirstLevelNavigationItem)navigationItem).Icon != null)
+ .Select(navigationItem => (FirstLevelNavigationItem)navigationItem)
+ .ToList()
+ .ForEach(navigationItem => navigationItem.IconTemplate = TryFindResource("itemIconTemplate") as DataTemplate);
+ }*/
}
private void NavigationControl_Unloaded(object sender, RoutedEventArgs args)
diff --git a/MaterialDesignExtensionsDemo/Controls/NavigationRailControl.xaml b/MaterialDesignExtensionsDemo/Controls/NavigationRailControl.xaml
new file mode 100644
index 00000000..d6c193d6
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/NavigationRailControl.xaml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MaterialDesignExtensionsDemo/Controls/NavigationRailControl.xaml.cs b/MaterialDesignExtensionsDemo/Controls/NavigationRailControl.xaml.cs
new file mode 100644
index 00000000..dbec7fde
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/NavigationRailControl.xaml.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+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 MaterialDesignExtensions.Model;
+
+namespace MaterialDesignExtensionsDemo.Controls
+{
+ public partial class NavigationRailControl : UserControl
+ {
+ public NavigationRailControl()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/Controls/OpenDirectoryControlControl.xaml b/MaterialDesignExtensionsDemo/Controls/OpenDirectoryControlControl.xaml
index 2ff0cca0..1c84bcec 100644
--- a/MaterialDesignExtensionsDemo/Controls/OpenDirectoryControlControl.xaml
+++ b/MaterialDesignExtensionsDemo/Controls/OpenDirectoryControlControl.xaml
@@ -4,9 +4,9 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MaterialDesignExtensionsDemo.Controls"
- xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
+ xmlns:mde="https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml"
mc:Ignorable="d"
- d:DesignHeight="500" d:DesignWidth="700">
+ d:DesignHeight="500" d:DesignWidth="700" Background="{DynamicResource MaterialDesignBackground}">
@@ -19,10 +19,16 @@
+
+
+
+
-
+
diff --git a/MaterialDesignExtensionsDemo/Controls/OpenFileControlControl.xaml b/MaterialDesignExtensionsDemo/Controls/OpenFileControlControl.xaml
index 4dfa1c5f..2114d8a1 100644
--- a/MaterialDesignExtensionsDemo/Controls/OpenFileControlControl.xaml
+++ b/MaterialDesignExtensionsDemo/Controls/OpenFileControlControl.xaml
@@ -4,9 +4,9 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MaterialDesignExtensionsDemo.Controls"
- xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
+ xmlns:mde="https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml"
mc:Ignorable="d"
- d:DesignHeight="500" d:DesignWidth="700">
+ d:DesignHeight="500" d:DesignWidth="700" Background="{DynamicResource MaterialDesignBackground}">
@@ -19,11 +19,14 @@
+
+
-
+
diff --git a/MaterialDesignExtensionsDemo/Controls/OpenMultipleDirectoriesControlControl.xaml b/MaterialDesignExtensionsDemo/Controls/OpenMultipleDirectoriesControlControl.xaml
new file mode 100644
index 00000000..e57c7d20
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/OpenMultipleDirectoriesControlControl.xaml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MaterialDesignExtensionsDemo/Controls/OpenMultipleDirectoriesControlControl.xaml.cs b/MaterialDesignExtensionsDemo/Controls/OpenMultipleDirectoriesControlControl.xaml.cs
new file mode 100644
index 00000000..ee0b2a43
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/OpenMultipleDirectoriesControlControl.xaml.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+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 MaterialDesignExtensions.Controls;
+
+using MaterialDesignExtensionsDemo.ViewModel;
+
+namespace MaterialDesignExtensionsDemo.Controls
+{
+ public partial class OpenMultipleDirectoriesControlControl : UserControl
+ {
+ public OpenMultipleDirectoriesControlControl()
+ {
+ InitializeComponent();
+ }
+
+ private void OpenMultipleDirectoriesControl_DirectoriesSelected(object sender, RoutedEventArgs args)
+ {
+ if (args is DirectoriesSelectedEventArgs eventArgs && DataContext is OpenMultipleDirectoriesControlViewModel viewModel)
+ {
+ StringBuilder sb = new StringBuilder("Selected directories: ");
+ eventArgs.Directories.ForEach(directory => sb.Append($"{directory}; "));
+
+ viewModel.SelectedAction = sb.ToString();
+ }
+ }
+
+ private void OpenMultipleDirectoriesControl_Cancel(object sender, RoutedEventArgs args)
+ {
+ if (DataContext is OpenMultipleDirectoriesControlViewModel viewModel)
+ {
+ viewModel.SelectedAction = "Cancel open directories";
+ }
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/Controls/OpenMultipleFilesControlControl.xaml b/MaterialDesignExtensionsDemo/Controls/OpenMultipleFilesControlControl.xaml
new file mode 100644
index 00000000..35b6294f
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/OpenMultipleFilesControlControl.xaml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MaterialDesignExtensionsDemo/Controls/OpenMultipleFilesControlControl.xaml.cs b/MaterialDesignExtensionsDemo/Controls/OpenMultipleFilesControlControl.xaml.cs
new file mode 100644
index 00000000..fdb9b605
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/OpenMultipleFilesControlControl.xaml.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+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 MaterialDesignExtensions.Controls;
+
+using MaterialDesignExtensionsDemo.ViewModel;
+
+namespace MaterialDesignExtensionsDemo.Controls
+{
+ public partial class OpenMultipleFilesControlControl : UserControl
+ {
+ public OpenMultipleFilesControlControl()
+ {
+ InitializeComponent();
+ }
+
+ private void OpenMultipleFilesControl_DirectoriesSelected(object sender, RoutedEventArgs args)
+ {
+ if (args is FilesSelectedEventArgs eventArgs && DataContext is OpenMultipleFilesControlViewModel viewModel)
+ {
+ StringBuilder sb = new StringBuilder("Selected files: ");
+ eventArgs.Files.ForEach(file => sb.Append($"{file}; "));
+
+ viewModel.SelectedAction = sb.ToString();
+ }
+ }
+
+ private void OpenMultipleFilesControl_Cancel(object sender, RoutedEventArgs args)
+ {
+ if (DataContext is OpenMultipleFilesControlViewModel viewModel)
+ {
+ viewModel.SelectedAction = "Cancel open files";
+ }
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/Controls/OversizedNumberSpinnerControl.xaml b/MaterialDesignExtensionsDemo/Controls/OversizedNumberSpinnerControl.xaml
index 11a6a359..54ace898 100644
--- a/MaterialDesignExtensionsDemo/Controls/OversizedNumberSpinnerControl.xaml
+++ b/MaterialDesignExtensionsDemo/Controls/OversizedNumberSpinnerControl.xaml
@@ -4,9 +4,9 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MaterialDesignExtensionsDemo.Controls"
- xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
+ xmlns:mde="https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml"
mc:Ignorable="d"
- d:DesignHeight="300" d:DesignWidth="500" Background="Transparent">
+ d:DesignHeight="300" d:DesignWidth="500" Background="{DynamicResource MaterialDesignBackground}">
@@ -15,8 +15,8 @@
-
-
+
+
diff --git a/MaterialDesignExtensionsDemo/Controls/SaveFileControlControl.xaml b/MaterialDesignExtensionsDemo/Controls/SaveFileControlControl.xaml
index beaba8b6..d25289cb 100644
--- a/MaterialDesignExtensionsDemo/Controls/SaveFileControlControl.xaml
+++ b/MaterialDesignExtensionsDemo/Controls/SaveFileControlControl.xaml
@@ -4,9 +4,9 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MaterialDesignExtensionsDemo.Controls"
- xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
+ xmlns:mde="https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml"
mc:Ignorable="d"
- d:DesignHeight="500" d:DesignWidth="700">
+ d:DesignHeight="500" d:DesignWidth="700" Background="{DynamicResource MaterialDesignBackground}">
@@ -16,14 +16,20 @@
-
+
-
+
+
+
+
+
-
+
diff --git a/MaterialDesignExtensionsDemo/Controls/SearchControl.xaml b/MaterialDesignExtensionsDemo/Controls/SearchControl.xaml
index f59da099..28b0509e 100644
--- a/MaterialDesignExtensionsDemo/Controls/SearchControl.xaml
+++ b/MaterialDesignExtensionsDemo/Controls/SearchControl.xaml
@@ -1,23 +1,38 @@
+ d:DesignHeight="450" d:DesignWidth="700" Background="{DynamicResource MaterialDesignBackground}">
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MaterialDesignExtensionsDemo/Controls/SearchControl.xaml.cs b/MaterialDesignExtensionsDemo/Controls/SearchControl.xaml.cs
index f8b21800..13b1bdf1 100644
--- a/MaterialDesignExtensionsDemo/Controls/SearchControl.xaml.cs
+++ b/MaterialDesignExtensionsDemo/Controls/SearchControl.xaml.cs
@@ -28,5 +28,15 @@ private void SearchHandler1(object sender, SearchEventArgs args)
{
searchResultTextBlock1.Text = "Your are looking for '" + args.SearchTerm + "'.";
}
+
+ private void SearchHandler2(object sender, SearchEventArgs args)
+ {
+ searchResultTextBlock2.Text = "Your are looking for '" + args.SearchTerm + "'.";
+ }
+
+ private void SearchHandler3(object sender, SearchEventArgs args)
+ {
+ searchResultTextBlock3.Text = "Your are looking for '" + args.SearchTerm + "'.";
+ }
}
}
diff --git a/MaterialDesignExtensionsDemo/Controls/StepperControl.xaml b/MaterialDesignExtensionsDemo/Controls/StepperControl.xaml
index c87908ac..9d980d1d 100644
--- a/MaterialDesignExtensionsDemo/Controls/StepperControl.xaml
+++ b/MaterialDesignExtensionsDemo/Controls/StepperControl.xaml
@@ -5,21 +5,19 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MaterialDesignExtensionsDemo.Controls"
xmlns:viewModel="clr-namespace:MaterialDesignExtensionsDemo.ViewModel"
- xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
- xmlns:converters="clr-namespace:MaterialDesignExtensions.Converters;assembly=MaterialDesignExtensions"
- xmlns:model="clr-namespace:MaterialDesignExtensions.Model;assembly=MaterialDesignExtensions"
+ xmlns:mde="https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml"
mc:Ignorable="d"
- d:DesignHeight="300" d:DesignWidth="500" Background="Transparent">
+ d:DesignHeight="300" d:DesignWidth="500" Background="{DynamicResource MaterialDesignBackground}">
-
+
-
+
@@ -28,7 +26,7 @@
-
+
@@ -57,11 +55,11 @@
-
+
-
+
@@ -73,9 +71,16 @@
Accept the licence terms
-
+
+
+
+
+
+
+
+
@@ -93,47 +98,58 @@
-
+
+
+
+
-
+
+
+ -->
diff --git a/MaterialDesignExtensionsDemo/Controls/StepperControl.xaml.cs b/MaterialDesignExtensionsDemo/Controls/StepperControl.xaml.cs
index 874d8c35..dabc1b1d 100644
--- a/MaterialDesignExtensionsDemo/Controls/StepperControl.xaml.cs
+++ b/MaterialDesignExtensionsDemo/Controls/StepperControl.xaml.cs
@@ -16,6 +16,7 @@
using MaterialDesignThemes.Wpf;
using MaterialDesignExtensions.Controls;
+using MaterialDesignExtensions.Model;
using MaterialDesignExtensionsDemo.ViewModel;
@@ -28,6 +29,17 @@ public StepperControl()
InitializeComponent();
stepper.NavigationCanceledByValidation += Stepper_NavigationCanceledByValidation;
+
+ // demo for custom icon template
+ //Loaded += StepperControl_Loaded;
+ }
+
+ private void StepperControl_Loaded(object sender, RoutedEventArgs args)
+ {
+ if (FindResource("CustomStepIconTemplate") is DataTemplate iconTemplate)
+ {
+ ((IStep)stepper.Steps[1]).IconTemplate = iconTemplate;
+ }
}
private void Stepper_NavigationCanceledByValidation(object sender, NavigationCanceledByValidationEventArgs args)
diff --git a/MaterialDesignExtensionsDemo/Controls/TabControlControl.xaml b/MaterialDesignExtensionsDemo/Controls/TabControlControl.xaml
new file mode 100644
index 00000000..3a0a6131
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/TabControlControl.xaml
@@ -0,0 +1,205 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Animals
+ Plants
+ Vehicles
+
+
+
+
+
+ Animals
+ Plants
+ Vehicles
+
+
+
+
+
+ Animals
+ Plants
+ Vehicles
+
+
+
+
+
+ Animals
+ Plants
+ Vehicles
+
+
+
+
+
+
+
+
+
diff --git a/MaterialDesignExtensionsDemo/Controls/TabControlControl.xaml.cs b/MaterialDesignExtensionsDemo/Controls/TabControlControl.xaml.cs
new file mode 100644
index 00000000..397c8fca
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/TabControlControl.xaml.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+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;
+
+namespace MaterialDesignExtensionsDemo.Controls
+{
+ public partial class TabControlControl : UserControl
+ {
+ public TabControlControl()
+ {
+ InitializeComponent();
+ }
+
+ private void RemoveTabsButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ foreach (object item in m_tabControl.Items)
+ {
+ ((TabItem)item).Template = null;
+ }
+
+ m_tabControl.Items.Clear();
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/Controls/TabControlStepperControl.xaml b/MaterialDesignExtensionsDemo/Controls/TabControlStepperControl.xaml
index 9e8efe31..94ddd22d 100644
--- a/MaterialDesignExtensionsDemo/Controls/TabControlStepperControl.xaml
+++ b/MaterialDesignExtensionsDemo/Controls/TabControlStepperControl.xaml
@@ -4,10 +4,9 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MaterialDesignExtensionsDemo.Controls"
- xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
- xmlns:model="clr-namespace:MaterialDesignExtensions.Model;assembly=MaterialDesignExtensions"
+ xmlns:mde="https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml"
mc:Ignorable="d"
- d:DesignHeight="300" d:DesignWidth="500" Background="Transparent">
+ d:DesignHeight="300" d:DesignWidth="500" Background="{DynamicResource MaterialDesignBackground}">
@@ -21,39 +20,41 @@
Animations enabled
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/MaterialDesignExtensionsDemo/Controls/TabControlStepperControl.xaml.cs b/MaterialDesignExtensionsDemo/Controls/TabControlStepperControl.xaml.cs
index 5f2b9167..cf0351fd 100644
--- a/MaterialDesignExtensionsDemo/Controls/TabControlStepperControl.xaml.cs
+++ b/MaterialDesignExtensionsDemo/Controls/TabControlStepperControl.xaml.cs
@@ -20,6 +20,14 @@ public partial class TabControlStepperControl : UserControl
public TabControlStepperControl()
{
InitializeComponent();
+
+ Loaded += LoadedHandler;
+ }
+
+ private void LoadedHandler(object sender, RoutedEventArgs args)
+ {
+ // demo for setting a step via SelectedIndex property
+ //m_stepper.SelectedIndex = 1;
}
}
}
diff --git a/MaterialDesignExtensionsDemo/Controls/TextBoxFileSystemPathsControl.xaml b/MaterialDesignExtensionsDemo/Controls/TextBoxFileSystemPathsControl.xaml
new file mode 100644
index 00000000..d1647f79
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/TextBoxFileSystemPathsControl.xaml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MaterialDesignExtensionsDemo/Controls/TextBoxFileSystemPathsControl.xaml.cs b/MaterialDesignExtensionsDemo/Controls/TextBoxFileSystemPathsControl.xaml.cs
new file mode 100644
index 00000000..f51f9c1f
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/TextBoxFileSystemPathsControl.xaml.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+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;
+
+namespace MaterialDesignExtensionsDemo.Controls
+{
+ public partial class TextBoxFileSystemPathsControl : UserControl
+ {
+ public string DialogHostName
+ {
+ get
+ {
+ return MainWindow.DialogHostName;
+ }
+ }
+
+ public TextBoxFileSystemPathsControl()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/Controls/TextBoxSuggestionsControl.xaml b/MaterialDesignExtensionsDemo/Controls/TextBoxSuggestionsControl.xaml
index 0c716b35..db45e2ca 100644
--- a/MaterialDesignExtensionsDemo/Controls/TextBoxSuggestionsControl.xaml
+++ b/MaterialDesignExtensionsDemo/Controls/TextBoxSuggestionsControl.xaml
@@ -4,24 +4,40 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MaterialDesignExtensionsDemo.Controls"
- xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
- xmlns:converters="clr-namespace:MaterialDesignExtensions.Converters;assembly=MaterialDesignExtensions"
+ xmlns:mde="https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml"
mc:Ignorable="d"
- d:DesignHeight="450" d:DesignWidth="700">
+ d:DesignHeight="450" d:DesignWidth="700" Background="{DynamicResource MaterialDesignBackground}">
-
+
-
+
+
-
+
+
diff --git a/MaterialDesignExtensionsDemo/Controls/ThemesControl.xaml b/MaterialDesignExtensionsDemo/Controls/ThemesControl.xaml
new file mode 100644
index 00000000..6021f64b
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/ThemesControl.xaml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MaterialDesignExtensionsDemo/Controls/ThemesControl.xaml.cs b/MaterialDesignExtensionsDemo/Controls/ThemesControl.xaml.cs
new file mode 100644
index 00000000..fa5a98b2
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/ThemesControl.xaml.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+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;
+
+namespace MaterialDesignExtensionsDemo.Controls
+{
+ public partial class ThemesControl : UserControl
+ {
+ public ThemesControl()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/Controls/WindowStyleControl.xaml b/MaterialDesignExtensionsDemo/Controls/WindowStyleControl.xaml
new file mode 100644
index 00000000..b33390d6
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/WindowStyleControl.xaml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MaterialDesignExtensionsDemo/Controls/WindowStyleControl.xaml.cs b/MaterialDesignExtensionsDemo/Controls/WindowStyleControl.xaml.cs
new file mode 100644
index 00000000..6ca36df3
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Controls/WindowStyleControl.xaml.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+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 MaterialDesignExtensionsDemo.ViewModel;
+
+namespace MaterialDesignExtensionsDemo.Controls
+{
+ public partial class WindowStyleControl : UserControl
+ {
+ public WindowStyleControl()
+ {
+ InitializeComponent();
+ }
+
+ private void ShowWindowButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ DemoWindow window = new DemoWindow { WindowStyle = ((WindowStyleViewModel)DataContext).SelectedWindowStyle };
+ window.ShowDialog();
+ }
+
+ private void ShowNavigationWindowButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ DemoNavigationWindow window = new DemoNavigationWindow { WindowStyle = ((WindowStyleViewModel)DataContext).SelectedWindowStyle };
+ window.ShowDialog();
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/DelegateCommand.cs b/MaterialDesignExtensionsDemo/DelegateCommand.cs
new file mode 100644
index 00000000..bc1fec73
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/DelegateCommand.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace MaterialDesignExtensionsDemo
+{
+ public class DelegateCommand : ICommand
+ {
+ public event EventHandler CanExecuteChanged;
+
+ private readonly Predicate _canExecuteHandler;
+ private readonly Action _executeHandler;
+
+ public DelegateCommand(Action executeHandler, Predicate canExecuteHandler)
+ {
+ _executeHandler = executeHandler;
+ _canExecuteHandler = canExecuteHandler;
+ }
+
+ public bool CanExecute(object parameter)
+ {
+ if (_canExecuteHandler != null)
+ {
+ return _canExecuteHandler(parameter);
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ public void Execute(object parameter)
+ {
+ if (CanExecute(parameter))
+ {
+ _executeHandler(parameter);
+ }
+ }
+
+ public void RaiseCanExecuteChanged()
+ {
+ CanExecuteChanged?.Invoke(this, EventArgs.Empty);
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/DemoNavigationWindow.xaml b/MaterialDesignExtensionsDemo/DemoNavigationWindow.xaml
new file mode 100644
index 00000000..96c12342
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/DemoNavigationWindow.xaml
@@ -0,0 +1,17 @@
+
+
diff --git a/MaterialDesignExtensionsDemo/DemoNavigationWindow.xaml.cs b/MaterialDesignExtensionsDemo/DemoNavigationWindow.xaml.cs
new file mode 100644
index 00000000..c5919ae7
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/DemoNavigationWindow.xaml.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+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.Shapes;
+
+using MaterialDesignExtensions.Controls;
+
+namespace MaterialDesignExtensionsDemo
+{
+ public partial class DemoNavigationWindow : MaterialNavigationWindow
+ {
+ public DemoNavigationWindow()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/DemoWindow.xaml b/MaterialDesignExtensionsDemo/DemoWindow.xaml
new file mode 100644
index 00000000..c36e0f51
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/DemoWindow.xaml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MaterialDesignExtensionsDemo/DemoWindow.xaml.cs b/MaterialDesignExtensionsDemo/DemoWindow.xaml.cs
new file mode 100644
index 00000000..63f5b0f8
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/DemoWindow.xaml.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+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.Shapes;
+
+using MaterialDesignExtensions.Controls;
+
+namespace MaterialDesignExtensionsDemo
+{
+ public partial class DemoWindow : MaterialWindow
+ {
+ public ResizeMode[] ResizeModes
+ {
+ get
+ {
+ return new ResizeMode[] { ResizeMode.NoResize, ResizeMode.CanMinimize, ResizeMode.CanResize, ResizeMode.CanResizeWithGrip };
+ }
+ }
+
+ public DemoWindow()
+ {
+ InitializeComponent();
+ }
+
+ private void CloseButtonClickHandler(object sender, RoutedEventArgs args)
+ {
+ Close();
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/MainWindow.xaml b/MaterialDesignExtensionsDemo/MainWindow.xaml
index 79295688..c4752872 100644
--- a/MaterialDesignExtensionsDemo/MainWindow.xaml
+++ b/MaterialDesignExtensionsDemo/MainWindow.xaml
@@ -1,24 +1,26 @@
-
+
+ Command="md:DialogHost.CloseDialogCommand">
False
@@ -34,6 +36,9 @@
+
+
+
@@ -49,32 +54,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
@@ -84,21 +137,30 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
+
-
-
+
+
-
+
diff --git a/MaterialDesignExtensionsDemo/MainWindow.xaml.cs b/MaterialDesignExtensionsDemo/MainWindow.xaml.cs
index 0349b979..904e5690 100644
--- a/MaterialDesignExtensionsDemo/MainWindow.xaml.cs
+++ b/MaterialDesignExtensionsDemo/MainWindow.xaml.cs
@@ -23,12 +23,20 @@
namespace MaterialDesignExtensionsDemo
{
- public partial class MainWindow : Window
+ public partial class MainWindow : MaterialWindow
{
public const string DialogHostName = "dialogHost";
private List m_navigationItems;
+ public DialogHost DialogHost
+ {
+ get
+ {
+ return m_dialogHost;
+ }
+ }
+
public List NavigationItems
{
get
@@ -45,31 +53,50 @@ public MainWindow()
new FirstLevelNavigationItem() { Label = "App bar", NavigationItemSelectedCallback = item => new AppBarViewModel() },
new FirstLevelNavigationItem() { Label = "Oversized number spinner", NavigationItemSelectedCallback = item => new OversizedNumberSpinnerViewModel() },
new FirstLevelNavigationItem() { Label = "Grid list", NavigationItemSelectedCallback = item => new GridListViewModel() },
+ new FirstLevelNavigationItem() { Label = "TabControl", NavigationItemSelectedCallback = item => new TabControlViewModel() },
new FirstLevelNavigationItem() { Label = "Stepper", NavigationItemSelectedCallback = item => new StepperViewModel() },
new FirstLevelNavigationItem() { Label = "TabControl as stepper", NavigationItemSelectedCallback = item => new TabControlStepperViewModel() },
new FirstLevelNavigationItem() { Label = "Autocomplete", NavigationItemSelectedCallback = item => new AutocompleteViewModel() },
//new FirstLevelNavigationItem() { Label = "Autocomplete", NavigationItemSelectedCallback = item => new AutocompleteInTabControlViewModel() },
new FirstLevelNavigationItem() { Label = "TextBoxSuggestions", NavigationItemSelectedCallback = item => new TextBoxSuggestionsViewModel() },
+ new FirstLevelNavigationItem() { Label = "Message dialogs", NavigationItemSelectedCallback = item => new MessageDialogViewModel() },
+ new FirstLevelNavigationItem() { Label = "Busy overlay", NavigationItemSelectedCallback = item => new BusyOverlayViewModel() },
new DividerNavigationItem(),
new SubheaderNavigationItem() { Subheader = "Directories and files" },
new FirstLevelNavigationItem() { Label = "Open directory", Icon = PackIconKind.Folder, NavigationItemSelectedCallback = item => new OpenDirectoryControlViewModel() },
+ new FirstLevelNavigationItem() { Label = "Open multiple directories", Icon = PackIconKind.Folder, NavigationItemSelectedCallback = item => new OpenMultipleDirectoriesControlViewModel() },
new FirstLevelNavigationItem() { Label = "Open file", Icon = PackIconKind.File, NavigationItemSelectedCallback = item => new OpenFileControlViewModel() },
+ new FirstLevelNavigationItem() { Label = "Open multiple files", Icon = PackIconKind.File, NavigationItemSelectedCallback = item => new OpenMultipleFilesControlViewModel() },
new FirstLevelNavigationItem() { Label = "Save file", Icon = PackIconKind.File, NavigationItemSelectedCallback = item => new SaveFileControlViewModel() },
new FirstLevelNavigationItem() { Label = "Directory and file dialogs", NavigationItemSelectedCallback = item => new FileSystemDialogViewModel() },
+ new FirstLevelNavigationItem() { Label = "Text boxes with path", NavigationItemSelectedCallback = item => new TextBoxFileSystemPathsViewModel() },
new DividerNavigationItem(),
new SubheaderNavigationItem() { Subheader = "Navigation and searching" },
new FirstLevelNavigationItem() { Label = "Navigation", Icon = PackIconKind.Menu, NavigationItemSelectedCallback = item => new NavigationViewModel() },
- new FirstLevelNavigationItem() { Label = "Search", Icon = PackIconKind.Magnify, NavigationItemSelectedCallback = item => new SearchViewModel() }
+ new FirstLevelNavigationItem() { Label = "Navigation rail", Icon = PackIconKind.DotsVertical, NavigationItemSelectedCallback = item => new NavigationRailViewModel() },
+ new FirstLevelNavigationItem() { Label = "Search", Icon = PackIconKind.Magnify, NavigationItemSelectedCallback = item => new SearchViewModel() },
+ new DividerNavigationItem(),
+ new SubheaderNavigationItem() { Subheader = "Themes" },
+ new FirstLevelNavigationItem() { Label = "Themes", Icon = PackIconKind.Palette, NavigationItemSelectedCallback = item => new ThemesViewModel() },
+ new FirstLevelNavigationItem() { Label = "Material window", Icon = PackIconKind.WindowMaximize, NavigationItemSelectedCallback = item => new WindowStyleViewModel() },
+ new DividerNavigationItem(),
+ new SubheaderNavigationItem() { Subheader = "i18n" },
+ new FirstLevelNavigationItem() { Label = "Language", Icon = PackIconKind.Translate, NavigationItemSelectedCallback = item => new LanguageViewModel() }
};
InitializeComponent();
+ sideNav.DataContext = this;
+ navigationDrawerNav.DataContext = this;
+
+ Loaded += LoadedHandler;
+ }
+
+ private void LoadedHandler(object sender, RoutedEventArgs args)
+ {
navigationDrawerNav.SelectedItem = m_navigationItems[1];
sideNav.SelectedItem = m_navigationItems[1];
m_navigationItems[1].IsSelected = true;
-
- sideNav.DataContext = this;
- navigationDrawerNav.DataContext = this;
}
private void NavigationItemSelectedHandler(object sender, NavigationItemSelectedEventArgs args)
@@ -81,7 +108,12 @@ private void SelectNavigationItem(INavigationItem navigationItem)
{
if (navigationItem != null)
{
- contentControl.Content = navigationItem.NavigationItemSelectedCallback(navigationItem);
+ object newContent = navigationItem.NavigationItemSelectedCallback(navigationItem);
+
+ if (contentControl.Content == null || contentControl.Content.GetType() != newContent.GetType())
+ {
+ contentControl.Content = newContent;
+ }
}
else
{
@@ -96,7 +128,7 @@ private void SelectNavigationItem(INavigationItem navigationItem)
private void GoToGitHubButtonClickHandler(object sender, RoutedEventArgs args)
{
- Process.Start("https://github.com/spiegelp/MaterialDesignExtensions");
+ OpenLink("https://github.com/spiegelp/MaterialDesignExtensions");
}
private void GoToDocumentation(object sender, RoutedEventArgs args)
@@ -104,8 +136,19 @@ private void GoToDocumentation(object sender, RoutedEventArgs args)
if (contentControl.Content is ViewModel.ViewModel viewModel && !string.IsNullOrWhiteSpace(viewModel.DocumentationUrl))
{
- Process.Start(viewModel.DocumentationUrl);
+ OpenLink(viewModel.DocumentationUrl);
}
}
+
+ private void OpenLink(string url)
+ {
+ ProcessStartInfo psi = new ProcessStartInfo
+ {
+ FileName = url,
+ UseShellExecute = true
+ };
+
+ Process.Start(psi);
+ }
}
}
diff --git a/MaterialDesignExtensionsDemo/MaterialDesignExtensionsDemo.csproj b/MaterialDesignExtensionsDemo/MaterialDesignExtensionsDemo.csproj
index 9d20eb39..737d8e31 100644
--- a/MaterialDesignExtensionsDemo/MaterialDesignExtensionsDemo.csproj
+++ b/MaterialDesignExtensionsDemo/MaterialDesignExtensionsDemo.csproj
@@ -1,227 +1,34 @@
-
-
+
+
- Debug
- AnyCPU
- {279D7E62-1206-4928-890E-00F51CD0181C}
WinExe
- MaterialDesignExtensionsDemo
- MaterialDesignExtensionsDemo
- v4.6.1
- 512
- {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- 4
- true
+
+ net7.0-windows
+ true
+ false
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- AnyCPU
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
- ..\packages\MaterialDesignColors.1.1.3\lib\net45\MaterialDesignColors.dll
-
-
- ..\packages\MaterialDesignThemes.2.4.0.1044\lib\net45\MaterialDesignThemes.Wpf.dll
-
-
-
-
-
-
-
-
-
-
- 4.0
-
-
-
-
-
+
-
- MSBuild:Compile
- Designer
-
-
- AppBarControl.xaml
-
-
- AutocompleteControl.xaml
-
-
- AutocompleteInTabControlControl.xaml
-
-
- FileSystemDialogControl.xaml
-
-
- GridListControl.xaml
-
-
- NavigationControl.xaml
-
-
- OpenDirectoryControlControl.xaml
-
-
- OpenFileControlControl.xaml
-
-
- OversizedNumberSpinnerControl.xaml
-
-
- SearchControl.xaml
-
-
- StepperControl.xaml
-
-
- SaveFileControlControl.xaml
-
-
- TabControlStepperControl.xaml
-
-
- TextBoxSuggestionsControl.xaml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- MSBuild:Compile
- Designer
-
-
- App.xaml
- Code
-
-
- MainWindow.xaml
- Code
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
+
+
-
-
- Code
-
-
- True
- True
- Resources.resx
-
-
- True
- Settings.settings
- True
-
-
- ResXFileCodeGenerator
- Resources.Designer.cs
-
-
-
- SettingsSingleFileGenerator
- Settings.Designer.cs
-
-
-
-
+
+
+
+
+ icon_on_background.ico
+
+
-
- {809632da-5eb8-4ee8-ad71-57239701550c}
- MaterialDesignExtensions
-
+
+ PreserveNewest
+
+
+ PreserveNewest
+
-
+
\ No newline at end of file
diff --git a/MaterialDesignExtensionsDemo/Pages/Page1.xaml b/MaterialDesignExtensionsDemo/Pages/Page1.xaml
new file mode 100644
index 00000000..627866c7
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Pages/Page1.xaml
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Go to page 2
+
+
+
+
diff --git a/MaterialDesignExtensionsDemo/Pages/Page1.xaml.cs b/MaterialDesignExtensionsDemo/Pages/Page1.xaml.cs
new file mode 100644
index 00000000..6fd76926
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Pages/Page1.xaml.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+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;
+
+namespace MaterialDesignExtensionsDemo.Pages
+{
+ public partial class Page1 : Page
+ {
+ public Page1()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/Pages/Page2.xaml b/MaterialDesignExtensionsDemo/Pages/Page2.xaml
new file mode 100644
index 00000000..2c58a4c2
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Pages/Page2.xaml
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Go to page 1
+
+
+
+
diff --git a/MaterialDesignExtensionsDemo/Pages/Page2.xaml.cs b/MaterialDesignExtensionsDemo/Pages/Page2.xaml.cs
new file mode 100644
index 00000000..09c22006
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/Pages/Page2.xaml.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+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;
+
+namespace MaterialDesignExtensionsDemo.Pages
+{
+ public partial class Page2 : Page
+ {
+ public Page2()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/Properties/AssemblyInfo.cs b/MaterialDesignExtensionsDemo/Properties/AssemblyInfo.cs
index 636d59b8..61f64597 100644
--- a/MaterialDesignExtensionsDemo/Properties/AssemblyInfo.cs
+++ b/MaterialDesignExtensionsDemo/Properties/AssemblyInfo.cs
@@ -12,7 +12,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MaterialDesignExtensionsDemo")]
-[assembly: AssemblyCopyright("Copyright © 2017")]
+[assembly: AssemblyCopyright("Copyright © 2017-2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
diff --git a/MaterialDesignExtensionsDemo/ViewModel/AutocompleteViewModel.cs b/MaterialDesignExtensionsDemo/ViewModel/AutocompleteViewModel.cs
index 01e8789d..a60a5ce8 100644
--- a/MaterialDesignExtensionsDemo/ViewModel/AutocompleteViewModel.cs
+++ b/MaterialDesignExtensionsDemo/ViewModel/AutocompleteViewModel.cs
@@ -81,17 +81,17 @@ public OperatingSystemAutocompleteSource()
new OperatingSystemItem() { Icon = PackIconKind.Android, Name = "Android Nougat" },
new OperatingSystemItem() { Icon = PackIconKind.Linux, Name = "Debian" },
new OperatingSystemItem() { Icon = PackIconKind.DesktopMac, Name = "Mac OSX" },
- new OperatingSystemItem() { Icon = PackIconKind.Raspberrypi, Name = "Raspbian" },
+ new OperatingSystemItem() { Icon = PackIconKind.DeveloperBoard, Name = "Raspbian" },
new OperatingSystemItem() { Icon = PackIconKind.Ubuntu, Name = "Ubuntu Wily Werewolf" },
new OperatingSystemItem() { Icon = PackIconKind.Ubuntu, Name = "Ubuntu Xenial Xerus" },
new OperatingSystemItem() { Icon = PackIconKind.Ubuntu, Name = "Ubuntu Yakkety Yak" },
new OperatingSystemItem() { Icon = PackIconKind.Ubuntu, Name = "Ubuntu Zesty Zapus" },
- new OperatingSystemItem() { Icon = PackIconKind.Windows, Name = "Windows 7" },
- new OperatingSystemItem() { Icon = PackIconKind.Windows, Name = "Windows 8" },
- new OperatingSystemItem() { Icon = PackIconKind.Windows, Name = "Windows 8.1" },
- new OperatingSystemItem() { Icon = PackIconKind.Windows, Name = "Windows 10" },
- new OperatingSystemItem() { Icon = PackIconKind.Windows, Name = "Windows Vista" },
- new OperatingSystemItem() { Icon = PackIconKind.Windows, Name = "Windows XP" }
+ new OperatingSystemItem() { Icon = PackIconKind.MicrosoftWindows, Name = "Windows 7" },
+ new OperatingSystemItem() { Icon = PackIconKind.MicrosoftWindows, Name = "Windows 8" },
+ new OperatingSystemItem() { Icon = PackIconKind.MicrosoftWindows, Name = "Windows 8.1" },
+ new OperatingSystemItem() { Icon = PackIconKind.MicrosoftWindows, Name = "Windows 10" },
+ new OperatingSystemItem() { Icon = PackIconKind.MicrosoftWindows, Name = "Windows Vista" },
+ new OperatingSystemItem() { Icon = PackIconKind.MicrosoftWindows, Name = "Windows XP" }
};
}
@@ -145,4 +145,54 @@ public IEnumerable Search(string searchTerm)
// return m_operatingSystemItems.Where(item => item.Name.ToLower().Contains(searchTerm));
// }
//}
+
+ // a very unrealistic example, but it shows how the update of the items works
+ /*public class OperatingSystemAutocompleteSource : AutocompleteSourceChangingItems
+ {
+ private List m_operatingSystemItems;
+
+ public OperatingSystemAutocompleteSource()
+ {
+ m_operatingSystemItems = new List()
+ {
+ new OperatingSystemItem() { Icon = PackIconKind.Android, Name = "Android Gingerbread" },
+ new OperatingSystemItem() { Icon = PackIconKind.Android, Name = "Android Icecream Sandwich" },
+ new OperatingSystemItem() { Icon = PackIconKind.Android, Name = "Android Jellybean" },
+ new OperatingSystemItem() { Icon = PackIconKind.Android, Name = "Android Lollipop" },
+ new OperatingSystemItem() { Icon = PackIconKind.Android, Name = "Android Nougat" },
+ new OperatingSystemItem() { Icon = PackIconKind.Linux, Name = "Debian" },
+ new OperatingSystemItem() { Icon = PackIconKind.DesktopMac, Name = "Mac OSX" },
+ new OperatingSystemItem() { Icon = PackIconKind.Raspberrypi, Name = "Raspbian" },
+ new OperatingSystemItem() { Icon = PackIconKind.Ubuntu, Name = "Ubuntu Wily Werewolf" },
+ new OperatingSystemItem() { Icon = PackIconKind.Ubuntu, Name = "Ubuntu Xenial Xerus" },
+ new OperatingSystemItem() { Icon = PackIconKind.Ubuntu, Name = "Ubuntu Yakkety Yak" },
+ new OperatingSystemItem() { Icon = PackIconKind.Ubuntu, Name = "Ubuntu Zesty Zapus" },
+ new OperatingSystemItem() { Icon = PackIconKind.Windows, Name = "Windows 7" },
+ new OperatingSystemItem() { Icon = PackIconKind.Windows, Name = "Windows 8" },
+ new OperatingSystemItem() { Icon = PackIconKind.Windows, Name = "Windows 8.1" },
+ new OperatingSystemItem() { Icon = PackIconKind.Windows, Name = "Windows 10" },
+ new OperatingSystemItem() { Icon = PackIconKind.Windows, Name = "Windows Vista" },
+ new OperatingSystemItem() { Icon = PackIconKind.Windows, Name = "Windows XP" }
+ };
+ }
+
+ public override IEnumerable Search(string searchTerm)
+ {
+ searchTerm = searchTerm ?? string.Empty;
+ searchTerm = searchTerm.ToLower();
+
+ // trigger an update for testing purposes
+ if (m_operatingSystemItems.Count <= 18)
+ {
+ Task.Delay(4000).ContinueWith(previousTask =>
+ {
+ m_operatingSystemItems.AddRange(m_operatingSystemItems);
+
+ OnAutocompleteSourceItemsChanged();
+ });
+ }
+
+ return m_operatingSystemItems.Where(item => item.Name.ToLower().Contains(searchTerm));
+ }
+ }*/
}
diff --git a/MaterialDesignExtensionsDemo/ViewModel/BusyOverlayViewModel.cs b/MaterialDesignExtensionsDemo/ViewModel/BusyOverlayViewModel.cs
new file mode 100644
index 00000000..09f3333b
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/ViewModel/BusyOverlayViewModel.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace MaterialDesignExtensionsDemo.ViewModel
+{
+ public class BusyOverlayViewModel : ViewModel
+ {
+ private bool m_isBusy;
+ private int m_progress;
+
+ public bool IsBusy
+ {
+ get
+ {
+ return m_isBusy;
+ }
+
+ set
+ {
+ m_isBusy = value;
+
+ OnPropertyChanged(nameof(IsBusy));
+ }
+ }
+
+ public int Progress
+ {
+ get
+ {
+ return m_progress;
+ }
+
+ set
+ {
+ m_progress = value;
+
+ OnPropertyChanged(nameof(Progress));
+ }
+ }
+
+ public BusyOverlayViewModel()
+ : base()
+ {
+ m_isBusy = false;
+ m_progress = 0;
+ }
+
+ public async Task BeBusyAsync()
+ {
+ try
+ {
+ Progress = 0;
+ IsBusy = true;
+
+ await Task.Run(async () =>
+ {
+ int progress = 0;
+
+ while (progress < 100)
+ {
+ await Task.Delay(250);
+
+ progress += 10;
+ Progress = progress;
+ }
+ });
+ }
+ finally
+ {
+ IsBusy = false;
+ }
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/ViewModel/FileSystemControlViewModel.cs b/MaterialDesignExtensionsDemo/ViewModel/FileSystemControlViewModel.cs
index 0ee6524a..b85d2d7e 100644
--- a/MaterialDesignExtensionsDemo/ViewModel/FileSystemControlViewModel.cs
+++ b/MaterialDesignExtensionsDemo/ViewModel/FileSystemControlViewModel.cs
@@ -11,6 +11,8 @@ public abstract class FileSystemControlViewModel : ViewModel
private string m_selectedAction;
private bool m_showHiddenFilesAndDirectories;
private bool m_showSystemFilesAndDirectories;
+ private bool m_createNewDirectoryEnabled;
+ private bool m_switchPathPartsAsButtonsEnabled;
public override string DocumentationUrl
{
@@ -20,6 +22,21 @@ public override string DocumentationUrl
}
}
+ public bool CreateNewDirectoryEnabled
+ {
+ get
+ {
+ return m_createNewDirectoryEnabled;
+ }
+
+ set
+ {
+ m_createNewDirectoryEnabled = value;
+
+ OnPropertyChanged(nameof(CreateNewDirectoryEnabled));
+ }
+ }
+
public string SelectedAction
{
get
@@ -65,12 +82,29 @@ public bool ShowSystemFilesAndDirectories
}
}
+ public bool SwitchPathPartsAsButtonsEnabled
+ {
+ get
+ {
+ return m_switchPathPartsAsButtonsEnabled;
+ }
+
+ set
+ {
+ m_switchPathPartsAsButtonsEnabled = value;
+
+ OnPropertyChanged(nameof(SwitchPathPartsAsButtonsEnabled));
+ }
+ }
+
public FileSystemControlViewModel()
: base()
{
m_selectedAction = null;
m_showHiddenFilesAndDirectories = false;
m_showSystemFilesAndDirectories = false;
+ m_createNewDirectoryEnabled = false;
+ m_switchPathPartsAsButtonsEnabled = false;
}
}
}
diff --git a/MaterialDesignExtensionsDemo/ViewModel/GridListViewModel.cs b/MaterialDesignExtensionsDemo/ViewModel/GridListViewModel.cs
index 6175657c..a667fc91 100644
--- a/MaterialDesignExtensionsDemo/ViewModel/GridListViewModel.cs
+++ b/MaterialDesignExtensionsDemo/ViewModel/GridListViewModel.cs
@@ -34,16 +34,16 @@ public GridListViewModel()
m_items = new List()
{
new GridListItem() { Kind = PackIconKind.Android, Label = "Android" },
- new GridListItem() { Kind = PackIconKind.Windows, Label = "Windows" },
+ new GridListItem() { Kind = PackIconKind.MicrosoftWindows, Label = "Windows" },
new GridListItem() { Kind = PackIconKind.AppleIos, Label = "iOS" },
new GridListItem() { Kind = PackIconKind.Android, Label = "Android" },
- new GridListItem() { Kind = PackIconKind.Windows, Label = "Windows" },
+ new GridListItem() { Kind = PackIconKind.MicrosoftWindows, Label = "Windows" },
new GridListItem() { Kind = PackIconKind.AppleIos, Label = "iOS" },
new GridListItem() { Kind = PackIconKind.Android, Label = "Android" },
- new GridListItem() { Kind = PackIconKind.Windows, Label = "Windows" },
+ new GridListItem() { Kind = PackIconKind.MicrosoftWindows, Label = "Windows" },
new GridListItem() { Kind = PackIconKind.AppleIos, Label = "iOS" },
new GridListItem() { Kind = PackIconKind.Android, Label = "Android" },
- new GridListItem() { Kind = PackIconKind.Windows, Label = "Windows" },
+ new GridListItem() { Kind = PackIconKind.MicrosoftWindows, Label = "Windows" },
new GridListItem() { Kind = PackIconKind.AppleIos, Label = "iOS" }
};
}
diff --git a/MaterialDesignExtensionsDemo/ViewModel/LanguageViewModel.cs b/MaterialDesignExtensionsDemo/ViewModel/LanguageViewModel.cs
new file mode 100644
index 00000000..c9b994f7
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/ViewModel/LanguageViewModel.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace MaterialDesignExtensionsDemo.ViewModel
+{
+ public class LanguageViewModel : ViewModel
+ {
+ public ICommand SelectLanguageCommand { get; private set; }
+
+ public LanguageViewModel()
+ : base()
+ {
+ SelectLanguageCommand = new DelegateCommand(ExecuteSelectLanguage, null);
+ }
+
+ private void ExecuteSelectLanguage(object parameter)
+ {
+ if (parameter is string languageName)
+ {
+ CultureInfo cultureInfo = CultureInfo.CreateSpecificCulture(languageName);
+
+ Thread.CurrentThread.CurrentCulture = cultureInfo;
+ Thread.CurrentThread.CurrentUICulture = cultureInfo;
+ }
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/ViewModel/MessageDialogViewModel.cs b/MaterialDesignExtensionsDemo/ViewModel/MessageDialogViewModel.cs
new file mode 100644
index 00000000..96aea54e
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/ViewModel/MessageDialogViewModel.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using MaterialDesignExtensions.Controls;
+using MaterialDesignThemes.Wpf;
+
+namespace MaterialDesignExtensionsDemo.ViewModel
+{
+ public class MessageDialogViewModel : ViewModel
+ {
+ public MessageDialogViewModel() : base() { }
+ }
+
+ public class SportsSelectionViewModel : ViewModel
+ {
+ private bool m_isValid;
+
+ public bool IsValid
+ {
+ get
+ {
+ return m_isValid;
+ }
+
+ set
+ {
+ m_isValid = value;
+
+ OnPropertyChanged(nameof(IsValid));
+ }
+ }
+
+ public List SportsItems { get; private set; }
+
+ public SportsSelectionViewModel()
+ : base()
+ {
+ m_isValid = true;
+
+ SportsItems = new List
+ {
+ new SportsItem("Football", PackIconKind.Soccer),
+ new SportsItem("Handball", PackIconKind.Handball),
+ new SportsItem("Hockey", PackIconKind.HockeySticks),
+ new SportsItem("Racing", PackIconKind.RacingHelmet),
+ new SportsItem("Tennis", PackIconKind.TennisRacket),
+ new SportsItem("Volleyball", PackIconKind.Volleyball)
+ };
+ }
+
+ public void ValidationHandler(object sender, InputDialogValidationEventArgs args)
+ {
+ IsValid = SportsItems.Any(sportsItem => sportsItem.IsSelected);
+
+ args.CancelConfirmation = !IsValid;
+ }
+ }
+
+ public class SportsItem : ViewModel
+ {
+ private string m_label;
+ private PackIconKind m_icon;
+ private bool m_isSelected;
+
+ public PackIconKind Icon
+ {
+ get
+ {
+ return m_icon;
+ }
+
+ set
+ {
+ m_icon = value;
+
+ OnPropertyChanged(nameof(Icon));
+ }
+ }
+
+ public bool IsSelected
+ {
+ get
+ {
+ return m_isSelected;
+ }
+
+ set
+ {
+ m_isSelected = value;
+
+ OnPropertyChanged(nameof(IsSelected));
+ }
+ }
+
+ public string Label
+ {
+ get
+ {
+ return m_label;
+ }
+
+ set
+ {
+ m_label = value;
+
+ OnPropertyChanged(nameof(Label));
+ }
+ }
+
+ public SportsItem(string label, PackIconKind icon)
+ {
+ m_label = label;
+ m_icon = icon;
+ m_isSelected = false;
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/ViewModel/NavigationRailViewModel.cs b/MaterialDesignExtensionsDemo/ViewModel/NavigationRailViewModel.cs
new file mode 100644
index 00000000..57f9722f
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/ViewModel/NavigationRailViewModel.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using MaterialDesignThemes.Wpf;
+
+using MaterialDesignExtensions.Model;
+
+namespace MaterialDesignExtensionsDemo.ViewModel
+{
+
+ public class NavigationRailViewModel : ViewModel
+ {
+ public override string DocumentationUrl
+ {
+ get
+ {
+ return "https://spiegelp.github.io/MaterialDesignExtensions/#documentation/navigation";
+ }
+ }
+
+ public List NavigationItems
+ {
+ get
+ {
+ return new List()
+ {
+ new FirstLevelNavigationItem() { Label = "Files", Icon = PackIconKind.FileDocument, IsSelected = true },
+ new FirstLevelNavigationItem() { Label = "Images", Icon = PackIconKind.Image },
+ new FirstLevelNavigationItem() { Label = "Music", Icon = PackIconKind.Music },
+ new FirstLevelNavigationItem() { Label = "Videos", Icon = PackIconKind.Video }
+ };
+ }
+ }
+
+ public NavigationRailViewModel() { }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/ViewModel/OpenMultipleDirectoriesControlViewModel.cs b/MaterialDesignExtensionsDemo/ViewModel/OpenMultipleDirectoriesControlViewModel.cs
new file mode 100644
index 00000000..8453631e
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/ViewModel/OpenMultipleDirectoriesControlViewModel.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MaterialDesignExtensionsDemo.ViewModel
+{
+ public class OpenMultipleDirectoriesControlViewModel : FileSystemControlViewModel
+ {
+ public OpenMultipleDirectoriesControlViewModel() : base() { }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/ViewModel/OpenMultipleFilesControlViewModel.cs b/MaterialDesignExtensionsDemo/ViewModel/OpenMultipleFilesControlViewModel.cs
new file mode 100644
index 00000000..13b913ea
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/ViewModel/OpenMultipleFilesControlViewModel.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MaterialDesignExtensionsDemo.ViewModel
+{
+ public class OpenMultipleFilesControlViewModel : FileSystemControlViewModel
+ {
+ public OpenMultipleFilesControlViewModel() : base() { }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/ViewModel/TabControlViewModel.cs b/MaterialDesignExtensionsDemo/ViewModel/TabControlViewModel.cs
new file mode 100644
index 00000000..fa2cec6f
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/ViewModel/TabControlViewModel.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MaterialDesignExtensionsDemo.ViewModel
+{
+ public class TabControlViewModel : ViewModel
+ {
+ public TabControlViewModel() : base() { }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/ViewModel/TextBoxFileSystemPathsViewModel.cs b/MaterialDesignExtensionsDemo/ViewModel/TextBoxFileSystemPathsViewModel.cs
new file mode 100644
index 00000000..575b90b0
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/ViewModel/TextBoxFileSystemPathsViewModel.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MaterialDesignExtensionsDemo.ViewModel
+{
+ public class TextBoxFileSystemPathsViewModel : ViewModel
+ {
+ public TextBoxFileSystemPathsViewModel() : base() { }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/ViewModel/TextBoxSuggestionsViewModel.cs b/MaterialDesignExtensionsDemo/ViewModel/TextBoxSuggestionsViewModel.cs
index abfe094b..68c82d29 100644
--- a/MaterialDesignExtensionsDemo/ViewModel/TextBoxSuggestionsViewModel.cs
+++ b/MaterialDesignExtensionsDemo/ViewModel/TextBoxSuggestionsViewModel.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -46,12 +47,20 @@ public ITextBoxSuggestionsSource TextBoxSuggestionsSource
}
}
+ public List Devices { get; private set; } = new List();
+
public TextBoxSuggestionsViewModel()
: base()
{
m_textBoxSuggestionsSource = new OperatingSystemTextBoxSuggestionsSource();
m_text = null;
+ m_text = "Windows 10";
+
+ /*for (int i = 0; i < 200; i++)
+ {
+ Devices.Add(new Device { OperatingSystem = "Windows 10" });
+ }*/
}
}
@@ -92,4 +101,36 @@ public override IEnumerable Search(string searchTerm)
return m_operatingSystemItems.Where(item => item.ToLower().Contains(searchTerm));
}
}
+
+ public class Device : INotifyPropertyChanged
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ private string m_operatingSystem;
+
+ public string OperatingSystem
+ {
+ get
+ {
+ return m_operatingSystem;
+ }
+
+ set
+ {
+ m_operatingSystem = value;
+
+ OnPropertyChanged(nameof(OperatingSystem));
+ }
+ }
+
+ public Device() { }
+
+ private void OnPropertyChanged(string propertyName)
+ {
+ if (PropertyChanged != null && !string.IsNullOrWhiteSpace(propertyName))
+ {
+ PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
+ }
+ }
+ }
}
diff --git a/MaterialDesignExtensionsDemo/ViewModel/ThemesViewModel.cs b/MaterialDesignExtensionsDemo/ViewModel/ThemesViewModel.cs
new file mode 100644
index 00000000..80df2ed6
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/ViewModel/ThemesViewModel.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+using MaterialDesignExtensions.Themes;
+
+namespace MaterialDesignExtensionsDemo.ViewModel
+{
+ public class ThemesViewModel : ViewModel
+ {
+ private PaletteHelper m_paletteHelper;
+
+ private bool m_isDarkTheme;
+
+ public bool IsDarkTheme
+ {
+ get
+ {
+ return m_isDarkTheme;
+ }
+
+ set
+ {
+ if (m_isDarkTheme != value)
+ {
+ m_isDarkTheme = value;
+
+ OnPropertyChanged(nameof(IsDarkTheme));
+
+ SetTheme(m_isDarkTheme);
+ }
+ }
+ }
+
+ public ThemesViewModel()
+ : base()
+ {
+ m_paletteHelper = new PaletteHelper();
+
+ m_isDarkTheme = m_paletteHelper.IsDarkTheme();
+ }
+
+ private void SetTheme(bool isDarkTheme)
+ {
+ m_paletteHelper.SetLightDark(m_isDarkTheme);
+
+ ((MainWindow)Application.Current.MainWindow).DialogHost.DialogTheme = isDarkTheme ? MaterialDesignThemes.Wpf.BaseTheme.Dark : MaterialDesignThemes.Wpf.BaseTheme.Light;
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/ViewModel/WindowStyleViewModel.cs b/MaterialDesignExtensionsDemo/ViewModel/WindowStyleViewModel.cs
new file mode 100644
index 00000000..fa645f4c
--- /dev/null
+++ b/MaterialDesignExtensionsDemo/ViewModel/WindowStyleViewModel.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows;
+
+namespace MaterialDesignExtensionsDemo.ViewModel
+{
+ public class WindowStyleViewModel : ViewModel
+ {
+ private WindowStyle m_selectedWindowStyle;
+
+ public List WindowStyles
+ {
+ get
+ {
+ return new List
+ {
+ WindowStyle.SingleBorderWindow, WindowStyle.ThreeDBorderWindow, WindowStyle.ToolWindow, WindowStyle.None
+ };
+ }
+ }
+
+ public WindowStyle SelectedWindowStyle
+ {
+ get
+ {
+ return m_selectedWindowStyle;
+ }
+
+ set
+ {
+ m_selectedWindowStyle = value;
+
+ OnPropertyChanged(nameof(SelectedWindowStyle));
+ }
+ }
+
+ public WindowStyleViewModel()
+ : base()
+ {
+ m_selectedWindowStyle = WindowStyle.SingleBorderWindow;
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsDemo/icon_on_background.ico b/MaterialDesignExtensionsDemo/icon_on_background.ico
new file mode 100644
index 00000000..7ea28495
Binary files /dev/null and b/MaterialDesignExtensionsDemo/icon_on_background.ico differ
diff --git a/MaterialDesignExtensionsDemo/icon_white.ico b/MaterialDesignExtensionsDemo/icon_white.ico
new file mode 100644
index 00000000..8a90eb30
Binary files /dev/null and b/MaterialDesignExtensionsDemo/icon_white.ico differ
diff --git a/MaterialDesignExtensionsDemo/packages.config b/MaterialDesignExtensionsDemo/packages.config
deleted file mode 100644
index 1b97d843..00000000
--- a/MaterialDesignExtensionsDemo/packages.config
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/MaterialDesignExtensionsTests/Controllers/FileFilterTest.cs b/MaterialDesignExtensionsTests/Controllers/FileFilterTest.cs
new file mode 100644
index 00000000..780dafa8
--- /dev/null
+++ b/MaterialDesignExtensionsTests/Controllers/FileFilterTest.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using Xunit;
+
+using MaterialDesignExtensions.Controllers;
+using MaterialDesignExtensions.Model;
+
+namespace MaterialDesignExtensionsTests.Controllers
+{
+ public class FileFilterTest
+ {
+ [Fact]
+ public void TestConvertFileFilterToString()
+ {
+ IFileFilter fileFilter = FileFilter.Create("Test", "*.cs");
+ string filterStr1 = FileFilterHelper.ConvertFileFilterToString(fileFilter);
+ string filterStr2 = filterStr1.ToString();
+
+ Assert.Equal("Test|*.cs", filterStr1);
+ Assert.Equal("Test|*.cs", filterStr2);
+ }
+
+ [Fact]
+ public void TestConvertFileFiltersToString()
+ {
+ IList fileFilters = new List()
+ {
+ FileFilter.Create("Test", "*.cs"),
+ FileFilter.Create("Web", "*.html;*.js")
+ };
+
+ string filtersStr = FileFilterHelper.ConvertFileFiltersToString(fileFilters);
+
+ Assert.Equal("Test|*.cs|Web|*.html;*.js", filtersStr);
+ }
+
+ [Fact]
+ public void TestParseFileFilter()
+ {
+ IFileFilter fileFilter = FileFilterHelper.ParseFileFilter("Test", "*.cs");
+
+ Assert.Equal("Test", fileFilter.Label);
+ Assert.Equal("*.cs", fileFilter.Filters);
+ }
+
+ [Fact]
+ public void TestParseFileFilters()
+ {
+ IList fileFilters = FileFilterHelper.ParseFileFilters("Test|*.cs|Web|*.html;*.js");
+
+ Assert.Equal("Test", fileFilters[0].Label);
+ Assert.Equal("*.cs", fileFilters[0].Filters);
+
+ Assert.Equal("Web", fileFilters[1].Label);
+ Assert.Equal("*.html;*.js", fileFilters[1].Filters);
+ }
+
+ [Fact]
+ public void TestRegularExpression()
+ {
+ IFileFilter fileFilter = FileFilterHelper.ParseFileFilter("Test", "*.cs;*.xaml;file.*;cs*.*");
+ string filename1 = "Test.cs";
+ string filename2 = "Test.xaml";
+ string filename3 = "Test.html";
+ string filename4 = "Test.css";
+ string filename5 = "file.html";
+ string filename6 = "csfile1_2.js";
+ string filename7 = "cs.js";
+
+ Assert.True(fileFilter.IsMatch(filename1));
+ Assert.True(fileFilter.IsMatch(filename2));
+ Assert.False(fileFilter.IsMatch(filename3));
+ Assert.False(fileFilter.IsMatch(filename4));
+ Assert.True(fileFilter.IsMatch(filename5));
+ Assert.True(fileFilter.IsMatch(filename6));
+ Assert.True(fileFilter.IsMatch(filename7));
+ }
+
+ [Fact]
+ public void TestRegularExpressionAny()
+ {
+ IFileFilter fileFilter = FileFilterHelper.ParseFileFilter("Test", "*.*");
+ string filename = "Test.cs";
+
+ Assert.True(fileFilter.IsMatch(filename));
+ }
+
+ [Fact]
+ public void TestGetFileExtensionsFromFilter()
+ {
+ IFileFilter fileFilter = FileFilterHelper.ParseFileFilter("Test", "*.cs;file.*;cs*.*;*.xaml;test;*.txt.bak");
+ IEnumerable fileExtensions = FileFilterHelper.GetFileExtensionsFromFilter(fileFilter);
+
+ Assert.NotNull(fileExtensions);
+ Assert.Equal(3, fileExtensions.Count());
+ Assert.Contains(fileExtensions, fileExtension => fileExtension == "cs");
+ Assert.Contains(fileExtensions, fileExtension => fileExtension == "xaml");
+ Assert.Contains(fileExtensions, fileExtension => fileExtension == "bak");
+
+ fileExtensions = FileFilterHelper.GetFileExtensionsFromFilter(null);
+
+ Assert.True(fileExtensions == null || !fileExtensions.Any());
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsTests/Controllers/FileNameTest.cs b/MaterialDesignExtensionsTests/Controllers/FileNameTest.cs
new file mode 100644
index 00000000..bc46519a
--- /dev/null
+++ b/MaterialDesignExtensionsTests/Controllers/FileNameTest.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+
+using Xunit;
+
+using MaterialDesignExtensions.Controllers;
+
+namespace MaterialDesignExtensionsTests.Controllers
+{
+ public class FileNameTest
+ {
+ [Fact]
+ public void TestCheckFileName()
+ {
+ Assert.True(FileNameHelper.CheckFileName("myDirectory"));
+ Assert.True(FileNameHelper.CheckFileName("myTextFile.txt"));
+ Assert.False(FileNameHelper.CheckFileName(""));
+ Assert.False(FileNameHelper.CheckFileName(null));
+ Assert.False(FileNameHelper.CheckFileName("t_<_.txt"));
+ Assert.False(FileNameHelper.CheckFileName("t_>_.txt"));
+ Assert.False(FileNameHelper.CheckFileName("t_:_.txt"));
+ Assert.False(FileNameHelper.CheckFileName("t_\"_.txt"));
+ Assert.False(FileNameHelper.CheckFileName("t_/_.txt"));
+ Assert.False(FileNameHelper.CheckFileName("t_\\_.txt"));
+ Assert.False(FileNameHelper.CheckFileName("t_|_.txt"));
+ Assert.False(FileNameHelper.CheckFileName("t_?_.txt"));
+ Assert.False(FileNameHelper.CheckFileName("t_*_.txt"));
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsTests/Controllers/FileSystemControllerTest.cs b/MaterialDesignExtensionsTests/Controllers/FileSystemControllerTest.cs
new file mode 100644
index 00000000..63277f5d
--- /dev/null
+++ b/MaterialDesignExtensionsTests/Controllers/FileSystemControllerTest.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Linq;
+
+using Xunit;
+
+using MaterialDesignExtensions.Controllers;
+
+namespace MaterialDesignExtensionsTests.Controllers
+{
+ [Trait("Category", "SkipCI")]
+ public class FileSystemControllerTest
+ {
+ private readonly string m_directory = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
+
+ [Fact]
+ public void TestBuildFullFileNameForInCurrentDirectory()
+ {
+ FileSystemController fileSystemController = new FileSystemController()
+ {
+ ForceFileExtensionOfFileFilter = true,
+ FileFilterToApply = FileFilterHelper.ParseFileFilter("Test", "*.cs;*.xaml")
+ };
+
+ fileSystemController.SelectDirectory(m_directory);
+
+ string filename = fileSystemController.BuildFullFileNameForInCurrentDirectory("test.xaml");
+
+ Assert.Equal($@"{m_directory}\test.xaml", filename);
+ }
+
+ [Fact]
+ public void TestBuildFullFileNameForInCurrentDirectoryWithForcedFileExtension()
+ {
+ FileSystemController fileSystemController = new FileSystemController()
+ {
+ ForceFileExtensionOfFileFilter = true,
+ FileFilterToApply = FileFilterHelper.ParseFileFilter("Test", "*.cs;*.xaml")
+ };
+
+ fileSystemController.SelectDirectory(m_directory);
+
+ string filename = fileSystemController.BuildFullFileNameForInCurrentDirectory("test.txt");
+
+ Assert.Equal($@"{m_directory}\test.txt.cs", filename);
+ }
+
+ [Fact]
+ public void TestBuildFullFileNameForInCurrentDirectoryWithoutForcedFileExtension()
+ {
+ FileSystemController fileSystemController = new FileSystemController()
+ {
+ ForceFileExtensionOfFileFilter = false,
+ FileFilterToApply = FileFilterHelper.ParseFileFilter("Test", "*.cs;*.xaml")
+ };
+
+ fileSystemController.SelectDirectory(m_directory);
+
+ string filename = fileSystemController.BuildFullFileNameForInCurrentDirectory("test.txt");
+
+ Assert.Equal($@"{m_directory}\test.txt", filename);
+ }
+
+ [Fact]
+ public void TestSelectOrRemoveDirectoryForMultipleSelection()
+ {
+ string myDocuments = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
+ string myPictures = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
+ string myMusic = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic);
+
+ FileSystemController fileSystemController = new FileSystemController();
+
+ Assert.False(fileSystemController.SelectedDirectories.Any());
+
+ fileSystemController.SelectOrRemoveDirectoryForMultipleSelection(myDocuments);
+ fileSystemController.SelectOrRemoveDirectoryForMultipleSelection(myPictures);
+ fileSystemController.SelectOrRemoveDirectoryForMultipleSelection(myMusic);
+
+ Assert.Contains(fileSystemController.SelectedDirectories, directory => directory.FullName == myDocuments);
+ Assert.Contains(fileSystemController.SelectedDirectories, directory => directory.FullName == myPictures);
+ Assert.Contains(fileSystemController.SelectedDirectories, directory => directory.FullName == myMusic);
+
+ fileSystemController.SelectOrRemoveDirectoryForMultipleSelection(myMusic);
+
+ Assert.Contains(fileSystemController.SelectedDirectories, directory => directory.FullName == myDocuments);
+ Assert.Contains(fileSystemController.SelectedDirectories, directory => directory.FullName == myPictures);
+ Assert.DoesNotContain(fileSystemController.SelectedDirectories, directory => directory.FullName == myMusic);
+ }
+
+ [Fact]
+ public void TestSelectOrRemoveFileForMultipleSelection()
+ {
+ string gitconfigFile = $@"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}\.gitconfig";
+
+ FileSystemController fileSystemController = new FileSystemController();
+
+ Assert.False(fileSystemController.SelectedFiles.Any());
+
+ fileSystemController.SelectOrRemoveFileForMultipleSelection(gitconfigFile);
+
+ Assert.Contains(fileSystemController.SelectedFiles, file => file.FullName == gitconfigFile);
+
+ fileSystemController.SelectOrRemoveFileForMultipleSelection(gitconfigFile);
+
+ Assert.DoesNotContain(fileSystemController.SelectedFiles, file => file.FullName == gitconfigFile);
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsTests/Converters/DateTimeAgoConverterTest.cs b/MaterialDesignExtensionsTests/Converters/DateTimeAgoConverterTest.cs
new file mode 100644
index 00000000..6fa8225e
--- /dev/null
+++ b/MaterialDesignExtensionsTests/Converters/DateTimeAgoConverterTest.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Globalization;
+using System.Threading;
+
+using Xunit;
+
+using MaterialDesignExtensions.Converters;
+
+namespace MaterialDesignExtensionsTests.Converters
+{
+ public class DateTimeAgoConverterTest
+ {
+ private void SetThreadCulture(string cultureString = "de-at")
+ {
+ Thread.CurrentThread.CurrentCulture = new CultureInfo(cultureString);
+ Thread.CurrentThread.CurrentUICulture = new CultureInfo(cultureString);
+ }
+
+ [Fact]
+ public void TestArgumentOfSameDay()
+ {
+ SetThreadCulture();
+
+ DateTime dateTime = DateTime.Now;
+
+ string result = new DateTimeAgoConverter().Convert(dateTime, typeof(string), null, Thread.CurrentThread.CurrentCulture) as string;
+
+ Assert.Equal(result, dateTime.ToShortTimeString());
+ }
+
+ [Fact]
+ public void TestArgumentOfYesterday()
+ {
+ SetThreadCulture();
+
+ DateTime dateTime = DateTime.Now.AddDays(-1);
+
+ string result = new DateTimeAgoConverter().Convert(dateTime, typeof(string), null, Thread.CurrentThread.CurrentCulture) as string;
+
+ Assert.Equal(result, dateTime.ToShortDateString());
+ }
+
+ [Fact]
+ public void TestArgumentNotOfTypeDateTime()
+ {
+ SetThreadCulture();
+
+ string result = new DateTimeAgoConverter().Convert(4, typeof(string), null, Thread.CurrentThread.CurrentCulture) as string;
+
+ Assert.Equal(result, string.Empty);
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsTests/Converters/FileFiltersTypeConverterTest.cs b/MaterialDesignExtensionsTests/Converters/FileFiltersTypeConverterTest.cs
new file mode 100644
index 00000000..80264041
--- /dev/null
+++ b/MaterialDesignExtensionsTests/Converters/FileFiltersTypeConverterTest.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+
+using Xunit;
+
+using MaterialDesignExtensions.Converters;
+using MaterialDesignExtensions.Model;
+
+namespace MaterialDesignExtensionsTests.Converters
+{
+ public class FileFiltersTypeConverterTest
+ {
+ [Fact]
+ public void TestConvertFromString()
+ {
+ FileFiltersTypeConverter converter = new FileFiltersTypeConverter();
+
+ Assert.True(converter.CanConvertFrom(typeof(string)));
+ Assert.True(converter.CanConvertFrom(typeof(IList)));
+
+ IList filters = converter.ConvertFrom("Test|*.cs") as IList;
+
+ Assert.NotNull(filters);
+ Assert.Equal(1, filters.Count);
+ Assert.Equal("Test", filters[0].Label);
+ Assert.Equal("*.cs", filters[0].Filters);
+
+ filters = converter.ConvertFrom(filters) as IList;
+
+ Assert.NotNull(filters);
+ Assert.Equal(1, filters.Count);
+ Assert.Equal("Test", filters[0].Label);
+ Assert.Equal("*.cs", filters[0].Filters);
+
+ filters = converter.ConvertFrom(null) as IList;
+
+ Assert.Null(filters);
+ }
+
+ [Fact]
+ public void TestConvertTo()
+ {
+ FileFiltersTypeConverter converter = new FileFiltersTypeConverter();
+
+ Assert.True(converter.CanConvertTo(typeof(string)));
+ Assert.True(converter.CanConvertTo(typeof(IList)));
+
+ IList filters = new List()
+ {
+ FileFilter.Create("Test", "*.cs")
+ };
+
+ string filterStr = converter.ConvertTo(filters, typeof(string)) as string;
+
+ Assert.NotNull(filterStr);
+ Assert.Equal("Test|*.cs", filterStr);
+
+ filterStr = converter.ConvertTo(filterStr, typeof(string)) as string;
+
+ Assert.NotNull(filterStr);
+ Assert.Equal("Test|*.cs", filterStr);
+
+ filterStr = converter.ConvertFrom(null) as string;
+
+ Assert.Null(filterStr);
+ }
+ }
+}
diff --git a/MaterialDesignExtensionsTests/FileFilterTest.cs b/MaterialDesignExtensionsTests/FileFilterTest.cs
deleted file mode 100644
index 63d52b3f..00000000
--- a/MaterialDesignExtensionsTests/FileFilterTest.cs
+++ /dev/null
@@ -1,89 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-using MaterialDesignExtensions.Controllers;
-using MaterialDesignExtensions.Model;
-
-namespace MaterialDesignExtensionsTests
-{
- [TestClass]
- public class FileFilterTest
- {
- [TestMethod]
- public void TestConvertFileFilterToString()
- {
- IFileFilter fileFilter = FileFilter.Create("Test", "*.cs");
- string filterStr1 = FileFilterHelper.ConvertFileFilterToString(fileFilter);
- string filterStr2 = filterStr1.ToString();
-
- Assert.AreEqual("Test|*.cs", filterStr1);
- Assert.AreEqual("Test|*.cs", filterStr2);
- }
-
- [TestMethod]
- public void TestConvertFileFiltersToString()
- {
- IList fileFilters = new List()
- {
- FileFilter.Create("Test", "*.cs"),
- FileFilter.Create("Web", "*.html;*.js")
- };
-
- string filtersStr = FileFilterHelper.ConvertFileFiltersToString(fileFilters);
-
- Assert.AreEqual("Test|*.cs|Web|*.html;*.js", filtersStr);
- }
-
- [TestMethod]
- public void TestParseFileFilter()
- {
- IFileFilter fileFilter = FileFilterHelper.ParseFileFilter("Test", "*.cs");
-
- Assert.AreEqual("Test", fileFilter.Label);
- Assert.AreEqual("*.cs", fileFilter.Filters);
- }
-
- [TestMethod]
- public void TestParseFileFilters()
- {
- IList fileFilters = FileFilterHelper.ParseFileFilters("Test|*.cs|Web|*.html;*.js");
-
- Assert.AreEqual("Test", fileFilters[0].Label);
- Assert.AreEqual("*.cs", fileFilters[0].Filters);
-
- Assert.AreEqual("Web", fileFilters[1].Label);
- Assert.AreEqual("*.html;*.js", fileFilters[1].Filters);
- }
-
- [TestMethod]
- public void TestRegularExpression()
- {
- IFileFilter fileFilter = FileFilterHelper.ParseFileFilter("Test", "*.cs;*.xaml;file.*;cs*.*");
- string filename1 = "Test.cs";
- string filename2 = "Test.xaml";
- string filename3 = "Test.html";
- string filename4 = "Test.css";
- string filename5 = "file.html";
- string filename6 = "csfile1_2.js";
- string filename7 = "cs.js";
-
- Assert.AreEqual(true, fileFilter.IsMatch(filename1));
- Assert.AreEqual(true, fileFilter.IsMatch(filename2));
- Assert.AreEqual(false, fileFilter.IsMatch(filename3));
- Assert.AreEqual(false, fileFilter.IsMatch(filename4));
- Assert.AreEqual(true, fileFilter.IsMatch(filename5));
- Assert.AreEqual(true, fileFilter.IsMatch(filename6));
- Assert.AreEqual(true, fileFilter.IsMatch(filename7));
- }
-
- [TestMethod]
- public void TestRegularExpressionAny()
- {
- IFileFilter fileFilter = FileFilterHelper.ParseFileFilter("Test", "*.*");
- string filename = "Test.cs";
-
- Assert.AreEqual(true, fileFilter.IsMatch(filename));
- }
- }
-}
diff --git a/MaterialDesignExtensionsTests/FileFiltersTypeConverterTest.cs b/MaterialDesignExtensionsTests/FileFiltersTypeConverterTest.cs
deleted file mode 100644
index 815457ee..00000000
--- a/MaterialDesignExtensionsTests/FileFiltersTypeConverterTest.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-using MaterialDesignExtensions.Controllers;
-using MaterialDesignExtensions.Converters;
-using MaterialDesignExtensions.Model;
-
-namespace MaterialDesignExtensionsTests
-{
- [TestClass]
- public class FileFiltersTypeConverterTest
- {
- [TestMethod]
- public void TestConvertFromString()
- {
- FileFiltersTypeConverter converter = new FileFiltersTypeConverter();
-
- Assert.AreEqual(true, converter.CanConvertFrom(typeof(string)));
- Assert.AreEqual(true, converter.CanConvertFrom(typeof(IList)));
-
- IList filters = converter.ConvertFrom("Test|*.cs") as IList;
-
- Assert.IsNotNull(filters);
- Assert.AreEqual(1, filters.Count);
- Assert.AreEqual("Test", filters[0].Label);
- Assert.AreEqual("*.cs", filters[0].Filters);
-
- filters = converter.ConvertFrom(filters) as IList;
-
- Assert.IsNotNull(filters);
- Assert.AreEqual(1, filters.Count);
- Assert.AreEqual("Test", filters[0].Label);
- Assert.AreEqual("*.cs", filters[0].Filters);
-
- filters = converter.ConvertFrom(null) as IList;
-
- Assert.IsNull(filters);
- }
-
- [TestMethod]
- public void TestConvertTo()
- {
- FileFiltersTypeConverter converter = new FileFiltersTypeConverter();
-
- Assert.AreEqual(true, converter.CanConvertTo(typeof(string)));
- Assert.AreEqual(true, converter.CanConvertTo(typeof(IList)));
-
- IList filters = new List()
- {
- FileFilter.Create("Test", "*.cs")
- };
-
- string filterStr = converter.ConvertTo(filters, typeof(string)) as string;
-
- Assert.IsNotNull(filterStr);
- Assert.AreEqual("Test|*.cs", filterStr);
-
- filterStr = converter.ConvertTo(filterStr, typeof(string)) as string;
-
- Assert.IsNotNull(filterStr);
- Assert.AreEqual("Test|*.cs", filterStr);
-
- filterStr = converter.ConvertFrom(null) as string;
-
- Assert.IsNull(filterStr);
- }
- }
-}
diff --git a/MaterialDesignExtensionsTests/MaterialDesignExtensionsTests.csproj b/MaterialDesignExtensionsTests/MaterialDesignExtensionsTests.csproj
index 4e78c039..4ad0ca4b 100644
--- a/MaterialDesignExtensionsTests/MaterialDesignExtensionsTests.csproj
+++ b/MaterialDesignExtensionsTests/MaterialDesignExtensionsTests.csproj
@@ -1,74 +1,23 @@
-
-
+
+
- Debug
- AnyCPU
- {DCF16057-4955-48F1-BD0E-28D671DF59B0}
- Library
- Properties
- MaterialDesignExtensionsTests
- MaterialDesignExtensionsTests
- v4.5
- 512
- {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- 15.0
- $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
- $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
- False
- UnitTest
-
-
+ net7.0-windows
+ false
+ false
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
- ..\packages\MSTest.TestFramework.1.2.0\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll
-
-
- ..\packages\MSTest.TestFramework.1.2.0\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll
-
-
-
-
-
-
-
-
-
+
-
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
-
- {809632da-5eb8-4ee8-ad71-57239701550c}
- MaterialDesignExtensions
-
+
-
-
-
-
- Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Verwenden Sie die Wiederherstellung von NuGet-Paketen, um die fehlenden Dateien herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}".
-
-
-
-
-
+
\ No newline at end of file
diff --git a/MaterialDesignExtensionsTests/packages.config b/MaterialDesignExtensionsTests/packages.config
deleted file mode 100644
index 03805ce5..00000000
--- a/MaterialDesignExtensionsTests/packages.config
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index 6a4f00fe..38bdb5d1 100644
--- a/README.md
+++ b/README.md
@@ -1,24 +1,33 @@
-
-
# Material Design Extensions
-Material Design Extensions is based on [Material Design in XAML Toolkit](https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit) to provide additional controls and features for WPF apps. The controls might not be specified in the [Material Design specification](https://material.io/guidelines/material-design/introduction.html) or would crash the scope of [Material Design in XAML Toolkit](https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit).
+
+
+
+
+Material Design Extensions is based on Material Design in XAML Toolkit to provide additional controls and features for WPF apps. The controls might not be specified in the Material Design specification or would crash the scope of Material Design in XAML Toolkit .
+
+
+[](https://dev.azure.com/spiegelp/MaterialDesignExtensions/_build/latest?definitionId=2)
-# NuGet
+## NuGet
-[](https://www.nuget.org/packages/MaterialDesignExtensions/)
+[](https://www.nuget.org/packages/MaterialDesignExtensions/)
Install NuGet package. `PM> Install-Package MaterialDesignExtensions`
-Assemblies are compiled for .NET Framework 4.5
+Assemblies are compiled for .NET Core 3.1 and .NET Framework 4.5.2
-# Getting started
+## Getting started
1. Create a WPF desktop application
2. Install Material Design Extensions via [NuGet](https://www.nuget.org/packages/MaterialDesignExtensions/)
3. Add the styles to your App.xaml (see [App.xaml](https://github.com/spiegelp/MaterialDesignExtensions/blob/master/MaterialDesignExtensionsDemo/App.xaml) in the demo)
4. Add the namespace `xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"` to your XAML
5. You are ready to use the controls
-# Controls
+## Important notice
+The configuration of Material Design Extensions v2.6.0 changed in order to enable changing the theme at runtime.
+Please change your configuration according to [App.xaml](https://github.com/spiegelp/MaterialDesignExtensions/blob/master/MaterialDesignExtensionsDemo/App.xaml) of the demo.
+
+## Controls
Material Design Extensions features the following controls:
| Control | Details | Status |
@@ -29,13 +38,21 @@ Material Design Extensions features the following controls:
| [Open directory](https://spiegelp.github.io/MaterialDesignExtensions/#documentation/filesystemcontrols) | Custom `OpenDirectoryControl` and `OpenDirectoryDialog` control | Done |
| [Open file](https://spiegelp.github.io/MaterialDesignExtensions/#documentation/filesystemcontrols) | Custom `OpenFileControl` and `OpenFileDialog` control | Done |
| [Save file](https://spiegelp.github.io/MaterialDesignExtensions/#documentation/filesystemcontrols) | Custom `SaveFileControl` and `SaveFileDialog` control | Done |
+| [Open multiple directories](https://spiegelp.github.io/MaterialDesignExtensions/#documentation/filesystemcontrols) | Custom `OpenMultipleDirectoriesControl` and `OpenMultipleDirectoriesDialog` control | Done |
+| [Open multiple files](https://spiegelp.github.io/MaterialDesignExtensions/#documentation/filesystemcontrols) | Custom `OpenMultipleFilesControl` and `OpenMultipleFilesDialog` control | Done |
+| [Text box with file path](https://spiegelp.github.io/MaterialDesignExtensions/#documentation/filesystemcontrols) | Custom `TextBoxOpenDirectory`, `TextBoxOpenFile` and `TextBoxSaveFile` control | Done |
| [App bar](https://spiegelp.github.io/MaterialDesignExtensions/#documentation/appbar) | Custom `AppBar` control ([specification](https://material.io/design/components/app-bars-top.html#usage)) | Done |
| [Persistent search](https://spiegelp.github.io/MaterialDesignExtensions/#documentation/search) | Custom `PersistentSearch` control ([specification](https://material.io/design/navigation/search.html)) | Done |
| [Side navigation](https://spiegelp.github.io/MaterialDesignExtensions/#documentation/navigation) | Custom `SideNavigation` control ([specification](https://material.io/design/components/navigation-drawer.html#usage)) | Done |
+| [Navigation rail](https://spiegelp.github.io/MaterialDesignExtensions/#documentation/navigation) | Custom `NavigationRail` control ([specification](https://material.io/components/navigation-rail/)) | Done |
| [Autocomplete](https://spiegelp.github.io/MaterialDesignExtensions/#documentation/autocomplete) | Custom `Autocomplete` control | Done |
| [Text box suggestions](https://spiegelp.github.io/MaterialDesignExtensions/#documentation/textboxsuggestions) | Custom `TextBoxSuggestions` control | Done |
+| [Tabs](https://spiegelp.github.io/MaterialDesignExtensions/#documentation/tabs) | Templates for `TabControl` ([specification](https://material.io/design/components/tabs.html)) | Done |
+| [Busy overlay](https://spiegelp.github.io/MaterialDesignExtensions/#documentation/busyoverlay) | Custom `BusyOverlay` control | Done |
+| [Material window](https://spiegelp.github.io/MaterialDesignExtensions/#documentation/materialwindow) | Custom `MaterialWindow` control | Done |
+| [Material navigation window](https://spiegelp.github.io/MaterialDesignExtensions/#documentation/materialwindow) | Custom `MaterialNavigationWindow` control | In development |
-# Screenshots
+## Screenshots
### Horizontal stepper

@@ -45,8 +62,23 @@ Material Design Extensions features the following controls:
### Side navigation

-### App bar
-
+### Navigation rail
+
+
+### Tabs
+
+
+### Material window and app bar
+
+
+### Open directory
+
+
+### Open file
+
+
+### Save file
+
### Grid list

@@ -60,8 +92,8 @@ Material Design Extensions features the following controls:
### Oversized number spinner

-# Documentation
+## Documentation
You will find the API documentation on the [website](https://spiegelp.github.io/MaterialDesignExtensions/#documentation).
-# License
+## License
Material Design Extensions is licensed under the [MIT](https://github.com/spiegelp/MaterialDesignExtensions/blob/master/LICENSE) license.
diff --git a/ReleaseNotes.md b/ReleaseNotes.md
index 13b59c50..d1295806 100644
--- a/ReleaseNotes.md
+++ b/ReleaseNotes.md
@@ -87,6 +87,130 @@
* New interface `IAutocompleteSourceChangingItems` to propagate source changes to `Autocomplete`
#### Fixes
* Handle `PathTooLongException`
-### vX.X.X (upcoming release)
+### v2.5.0
#### Features
* New control `StepTitleHeaderControl` to use bindings in a XAML defined step
+* `TabControl` styles to render it in [Material Design](https://material.io/design/components/tabs.html)
+* New icons for file system controls
+#### Fixes
+* Handle broken image files in `BitmapImageHelper`
+* Updated dependency to MaterialDesignThemes version 2.5.1 to bypass a bug in version 2.5.0.1205
+* Use `Dispatcher` in `Autocomplete.AutocompleteSourceItemsChangedHandler()`
+### v2.6.0
+#### Features
+* Localization for Uzbekistan
+* Create new directories inside `OpenDirectoryControl` and `SaveFileControl`
+* Helper `PaletteHelper` for changing the theme at runtime
+#### Fixes
+* List used resources explicitly in the XAML files containing the templates
+* Prevent `NullReferenceException` in `SideNavigation` before the template will be applied
+#### Important notice
+The configuration of Material Design Extensions changed in order to enable changing the theme at runtime.
+Please change your configuration according to [App.xaml](https://github.com/spiegelp/MaterialDesignExtensions/blob/master/MaterialDesignExtensionsDemo/App.xaml) of the demo.
+### v2.7.0
+#### Features
+* New package `MaterialDesignExtensions.LongPath` for supporting long file system paths on older Windows and .NET versions
+* Improvements for file system controls
+ * Improved loading of preview images
+ * Smoother scrolling in directories and files list
+* New `SaveFileControl.ForceFileExtensionOfFileFilter` property to enforce a file extension of the selected filter
+* Better support of dark theme in file system dialogs
+* Localization for Russian
+* Updated dependency to MaterialDesignThemes version 2.6.0
+#### Fixes
+* Fixed `DateTime` conversion inside `DateTimeAgoConverter`
+### v2.8.0
+#### Features
+* New window class `MaterialWindow` for a Material Design like styled window
+* Support of `TabStripPlacement` in `TabControl` styles
+* `OpenMultipleDirectoriesControl` and `OpenMultipleDirectoriesDialog` to select multiple directories
+* `OpenMultipleFilesControl` and `OpenMultipleFilesDialog` to select multiple files
+#### Fixes
+* Fixed content layout of horizontal steppers
+#### Obsolete
+* Attached property `TabControlAssist.TabHeaderAlignment` will be replaced by `TabControlAssist.TabHeaderHorizontalAlignment`
+### v3.0.0
+#### Features
+* Support for .NET Core 3
+* Select file with double click in `OpenFileDialog` and `SaveFileDialog`
+* Improved keyboard navigation for file system controls
+* Dense style for `PersistentSearch`
+* Optional icon templates for steps inside a stepper
+* Improved stepper navigation
+* Added `MaterialWindow.TitleBarIcon` property
+#### Breaking API
+* Removed obsolete members
+ * `TabControlAssist.TabHeaderAlignment` attached property
+ * `OpenDirectoryDialog.ShowDialogAsync` methods
+ * `OpenFileDialog.ShowDialogAsync` methods
+ * `SaveFileDialog.ShowDialogAsync` methods
+* Extendend `IStepper` interface to implement new features for steppers
+* Extendend `IStep` interface to implement new features for steppers
+### v3.1.0
+#### Features
+* Update to .NET Core 3.1
+* Controls for simple alert and confirmation dialogs
+* New `TextBoxSuggestions.KeepFocusOnSelection` property to control the focus after selecting a suggestion
+* New controls combining a `TextBox` and a `FileSystemDialog`
+ * `TextBoxOpenDirectory`
+ * `TextBoxOpenFile`
+ * `TextBoxSaveFile`
+* Improvements for `MaterialWindow`
+ * New `MaterialWindow.TitleTemplate` property to customize the window title bar
+ * Different looks according to `Window.WindowStyle` property
+* New control `NavigationRail`
+#### Fixes
+* Catch exception if network drive is not accessible
+### v3.2.0
+#### Features
+* New control `BusyOverlay`
+* New `TextBoxFileSystemPath.TextBoxStyle` property to enable custom styles for the embedded `TextBox`
+* New localizations
+ * Arabic
+ * Czech
+ * French
+ * Portuguese
+* Save file in `SaveFileControl` and `SaveFileDialog` by hitting enter
+* New `ClearSelection` method for `Autocomplete`
+* `TabControl` style supports `FlowDirection = RightToLeft`
+#### Fixes
+* Fixed exception in `Stepper` events
+### v3.3.0
+#### Features
+* Added `XmlnsDefinition` `https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml`
+* Consider `ResizeMode` for the window caption buttons
+* `ResizeGrip` in `MaterialWindow`
+* New control `TransitionContentControl`
+* New dialog features
+ * Optional custom content for dialogs
+ * Control for simple input dialogs
+* Strong named assembly
+* Current directory path optionally as text box in file system controls
+* `IconTemplate` property for `NavigationItem`
+* Handle setting of `TabControlStepper.SelectedIndex`
+* New properties to control tab control item headers
+ * `TabHeaderFontSize`
+ * `TabHeaderFontWeight`
+ * `TabHeaderMargin`
+* Layout improvements for `MaterialWindow`
+* New `SearchBase.CancelIcon` and `SearchBase.ClearIcon` properties
+#### Fixes
+* Fixed reflection code in `ResourceDictionaryExtensions`
+* Fixed usage of `SecondaryHueMidBrush` and `SecondaryHueMidForegroundBrush` resources
+* Fixed `NullReferenceException` in `FileSystemControl`
+### v4.0.0 (upcoming release)
+#### Features
+* New `SideNavigation.LabelFontSize` property
+* Layout improvements for `NavigationRail`
+* More customizable content area for `AppBar`
+* Localization for Japanese
+* Added `SideNavigation.SelectionBackgroundOpacity` property
+* New window class `MaterialNavigationWindow` for a Material Design like styled navigation window
+* Updated dependency to MaterialDesignThemes version 4.1.0
+#### Fixes
+* Avoid unnecessary searches in `TextBoxSuggestions`
+#### Breaking API
+* `AppBar.Children` replaced by `AppBar.ContentAreaContent`
+ * `ContentAreaContent` is `object` instead of `IList`
+ * Additional `ContentAreaContentTemplate`
+* Minimum version for .NET Framework raised to 4.5.2
diff --git a/additionalPackageFiles/License.txt b/additionalPackageFiles/License.txt
new file mode 100644
index 00000000..b84e73eb
--- /dev/null
+++ b/additionalPackageFiles/License.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017-2020 Philipp Spiegel
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/additionalPackageFiles/Notice.txt b/additionalPackageFiles/Notice.txt
new file mode 100644
index 00000000..a990451c
--- /dev/null
+++ b/additionalPackageFiles/Notice.txt
@@ -0,0 +1,201 @@
+#############################################
+#### Attribution of third party software ####
+#############################################
+
+#### Material Design In XAML Toolkit ####
+
+Control styles and templates imported from [Material Design In XAML Toolkit](https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit).
+
+The MIT License (MIT)
+
+Copyright (c) James Willock, Mulholland Software and Contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+
+#### Pri.LongPath ####
+
+Long path support of the package `MaterialDesignExtensions.LongPath` enabled via [Pri.LongPath](https://github.com/peteraritchie/LongPath).
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/additionalPackageFiles/PackageReadme.md b/additionalPackageFiles/PackageReadme.md
new file mode 100644
index 00000000..c115f94f
--- /dev/null
+++ b/additionalPackageFiles/PackageReadme.md
@@ -0,0 +1,13 @@
+# Getting started
+1. Create a WPF desktop application
+2. Install Material Design Extensions via [NuGet](https://www.nuget.org/packages/MaterialDesignExtensions/)
+3. Add the styles to your App.xaml (see [App.xaml](https://github.com/spiegelp/MaterialDesignExtensions/blob/master/MaterialDesignExtensionsDemo/App.xaml) in the demo)
+4. Add the namespace `xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"` to your XAML
+5. You are ready to use the controls
+
+# Important notice
+The configuration of Material Design Extensions v2.6.0 changed in order to enable changing the theme at runtime.
+Please change your configuration according to [App.xaml](https://github.com/spiegelp/MaterialDesignExtensions/blob/master/MaterialDesignExtensionsDemo/App.xaml) of the demo.
+
+# Release notes
+You will find the release notes on the [project website](https://spiegelp.github.io/MaterialDesignExtensions/#releasenotes).
\ No newline at end of file
diff --git a/buildNugetReleasePackage.bat b/buildNugetReleasePackage.bat
new file mode 100644
index 00000000..4d4da795
--- /dev/null
+++ b/buildNugetReleasePackage.bat
@@ -0,0 +1 @@
+"MaterialDesignExtensionsBuildUtility\bin\Debug\netcoreapp3.1\MaterialDesignExtensionsBuildUtility.exe" -buildConfiguration Release
\ No newline at end of file
diff --git a/docs/css/style.css b/docs/css/style.css
index 7cfe0191..6f173b3e 100644
--- a/docs/css/style.css
+++ b/docs/css/style.css
@@ -50,6 +50,11 @@ code[class*="language-"], pre[class*="language-"] {
min-width: 200px;
}
+.screenshot-image--small {
+ max-width: 1024px;
+ min-width: 16px;
+}
+
.mdc-card__documentation_overview {
display: inline-block;
margin: 8px;
diff --git a/docs/js/AppViewModel.js b/docs/js/AppViewModel.js
index 8824dbb3..069792dc 100644
--- a/docs/js/AppViewModel.js
+++ b/docs/js/AppViewModel.js
@@ -14,15 +14,18 @@ function AppViewModel(contentDivId, drawer) {
];
self.documentationItems = [
- new DocumentationItem('appbar', 'App bar', 'https://raw.githubusercontent.com/spiegelp/MaterialDesignExtensions/master/screenshots/AppBar1.png', 'snippets/documentation/appbar.html'),
- new DocumentationItem('autocomplete', 'Autocomplate', 'https://raw.githubusercontent.com/spiegelp/MaterialDesignExtensions/master/screenshots/Autocomplete.png', 'snippets/documentation/autocomplete.html'),
- new DocumentationItem('filesystemcontrols', 'File system controls', null, 'snippets/documentation/filesystemcontrols.html'),
+ new DocumentationItem('appbar', 'App bar', 'https://raw.githubusercontent.com/spiegelp/MaterialDesignExtensions/master/screenshots/MaterialWindow.png', 'snippets/documentation/appbar.html'),
+ new DocumentationItem('autocomplete', 'Autocomplete', 'https://raw.githubusercontent.com/spiegelp/MaterialDesignExtensions/master/screenshots/Autocomplete.png', 'snippets/documentation/autocomplete.html'),
+ new DocumentationItem('busyoverlay', 'Busy overlay', 'https://raw.githubusercontent.com/spiegelp/MaterialDesignExtensions/master/screenshots/BusyOverlay.png', 'snippets/documentation/busyoverlay.html'),
+ new DocumentationItem('filesystemcontrols', 'File system controls', 'https://raw.githubusercontent.com/spiegelp/MaterialDesignExtensions/master/screenshots/OpenFileControl1.png', 'snippets/documentation/filesystemcontrols.html'),
new DocumentationItem('gridlist', 'Grid list', 'https://raw.githubusercontent.com/spiegelp/MaterialDesignExtensions/master/screenshots/GridList.png', 'snippets/documentation/gridlist.html'),
+ new DocumentationItem('materialwindow', 'Material window', 'https://raw.githubusercontent.com/spiegelp/MaterialDesignExtensions/master/screenshots/MaterialWindow.png', 'snippets/documentation/materialwindow.html'),
new DocumentationItem('navigation', 'Navigation', 'https://raw.githubusercontent.com/spiegelp/MaterialDesignExtensions/master/screenshots/SideNavigation.png', 'snippets/documentation/navigation.html'),
new DocumentationItem('oversizednumberspinner', 'Oversized number spinner', 'https://raw.githubusercontent.com/spiegelp/MaterialDesignExtensions/master/screenshots/OversizedNumberSpinner.png', 'snippets/documentation/oversizednumberspinner.html'),
new DocumentationItem('search', 'Search', 'https://raw.githubusercontent.com/spiegelp/MaterialDesignExtensions/master/screenshots/PersistentSearch.png', 'snippets/documentation/search.html'),
new DocumentationItem('stepper', 'Stepper', 'https://raw.githubusercontent.com/spiegelp/MaterialDesignExtensions/master/screenshots/HorizontalStepper.png', 'snippets/documentation/stepper.html'),
- new DocumentationItem('textboxsuggestions', 'Text box suggestions', null, 'snippets/documentation/textboxsuggestions.html')
+ new DocumentationItem('tabs', 'Tabs', 'https://raw.githubusercontent.com/spiegelp/MaterialDesignExtensions/master/screenshots/TabControl1.png', 'snippets/documentation/tabs.html'),
+ new DocumentationItem('textboxsuggestions', 'Text box suggestions', 'https://raw.githubusercontent.com/spiegelp/MaterialDesignExtensions/master/screenshots/TextBoxSuggestions.png', 'snippets/documentation/textboxsuggestions.html')
];
self.goToNavigationItem = function (navigationItem) {
diff --git a/docs/snippets/documentation/autocomplete.html b/docs/snippets/documentation/autocomplete.html
index 0ac72755..13796caa 100644
--- a/docs/snippets/documentation/autocomplete.html
+++ b/docs/snippets/documentation/autocomplete.html
@@ -1,4 +1,85 @@
Autocomplete
- Documentation under construction
-
\ No newline at end of file
+
+ The following predefined styles are available:
+
+ MaterialDesignAutocomplete
+ MaterialDesignAutocompleteDense
+
+
+
+ Screenshots
+
+ Code example
+
+ Item template
+
+<DataTemplate x:Key="itemTemplate">
+ <DockPanel>
+ <md:PackIcon DockPanel.Dock="Left" Kind="{Binding Path=Icon}" Width="24" Height="24" VerticalAlignment="Center" SnapsToDevicePixels="True" />
+ <TextBlock FontSize="14" Text="{Binding Path=Name}" VerticalAlignment="Center" Margin="24,0,0,0" />
+ </DockPanel>
+</DataTemplate>
+
+
+ Autocomplete control
+
+<mde:Autocomplete Style="{StaticResource MaterialDesignAutocomplete}"
+ AutocompleteSource="{Binding Path=AutocompleteSource}"
+ Hint="Which OS?"
+ Margin="0,16,0,0"
+ ItemTemplate="{StaticResource itemTemplate}" />
+
+
+ Autocomplete data source
+
+public class AutocompleteViewModel : ViewModel
+{
+ private IAutocompleteSource _autocompleteSource;
+
+ public IAutocompleteSource AutocompleteSource
+ {
+ get => _autocompleteSource;
+ }
+
+ public AutocompleteViewModel() : base()
+ {
+ _autocompleteSource = new OperatingSystemAutocompleteSource();
+ }
+}
+
+public class OperatingSystemItem
+{
+ public PackIconKind Icon { get; set; }
+ public string Name { get; set; }
+ public OperatingSystemItem() { }
+}
+
+public class OperatingSystemAutocompleteSource : IAutocompleteSource
+{
+ private List _operatingSystemItems;
+
+ public OperatingSystemAutocompleteSource()
+ {
+ _operatingSystemItems = new List()
+ {
+ new OperatingSystemItem() { Icon = PackIconKind.MicrosoftWindows, Name = "Windows 7" },
+ new OperatingSystemItem() { Icon = PackIconKind.MicrosoftWindows, Name = "Windows 8" },
+ new OperatingSystemItem() { Icon = PackIconKind.MicrosoftWindows, Name = "Windows 8.1" },
+ new OperatingSystemItem() { Icon = PackIconKind.MicrosoftWindows, Name = "Windows 10" }
+ };
+ }
+
+ public IEnumerable Search(string searchTerm)
+ {
+ searchTerm = searchTerm ?? string.Empty;
+ searchTerm = searchTerm.ToLower();
+
+ return _operatingSystemItems.Where(item => item.Name.ToLower().Contains(searchTerm));
+ }
+}
+
+
+
diff --git a/docs/snippets/documentation/busyoverlay.html b/docs/snippets/documentation/busyoverlay.html
new file mode 100644
index 00000000..926f80cd
--- /dev/null
+++ b/docs/snippets/documentation/busyoverlay.html
@@ -0,0 +1,85 @@
+
+
Busy overlay
+
+ The following predefined styles are available:
+
+ MaterialBusyOverlayCircular
+ MaterialBusyOverlayCircularProgress
+ MaterialBusyOverlayLinear
+ MaterialBusyOverlayLinearProgress
+
+
+
+
Screenshots
+
+
+
Code example
+
+
Busy overlay control
+
+<mde:BusyOverlay IsBusy="{Binding Path=IsBusy}"
+ Progress="{Binding Path=Progress}"
+ Style="{StaticResource MaterialBusyOverlayCircular}" />
+
+
+
Busy overlay show and progress bindings
+
+public class BusyOverlayViewModel : ViewModel
+{
+ private bool _isBusy;
+ public bool IsBusy
+ {
+ get => _isBusy;
+ set
+ {
+ _isBusy = value;
+ OnPropertyChanged(nameof(IsBusy));
+ }
+ }
+
+ private int _progress;
+ public int Progress
+ {
+ get => _progress;
+ set
+ {
+ _progress = value;
+ OnPropertyChanged(nameof(Progress));
+ }
+ }
+
+ public BusyOverlayViewModel() : base()
+ {
+ _isBusy = false;
+ _progress = 0;
+ }
+
+ public async Task BeBusyAsync()
+ {
+ try
+ {
+ Progress = 0;
+ IsBusy = true;
+
+ //Simulate work and update progress
+ await Task.Run(async () =>
+ {
+ int progress = 0;
+
+ while (progress < 100)
+ {
+ await Task.Delay(250);
+
+ progress += 10;
+ Progress = progress;
+ }
+ });
+ }
+ finally
+ {
+ IsBusy = false;
+ }
+ }
+}
+
+
\ No newline at end of file
diff --git a/docs/snippets/documentation/filesystemcontrols.html b/docs/snippets/documentation/filesystemcontrols.html
index 1282c42a..91a06c30 100644
--- a/docs/snippets/documentation/filesystemcontrols.html
+++ b/docs/snippets/documentation/filesystemcontrols.html
@@ -1,4 +1,439 @@
File system controls
- Documentation under construction
+
+ The file system controls provide the selection features for opening a directory or file, and saving a file. They can be used instead
+ of the default Windows dialogs to get a consistent look and feel in Material Design.
+
+
+ Each control has a dialog counterpart for wrapping the control into a modal Material Design dialog:
+
+
+ Open a directory
+
+
+ OpenDirectoryControl
+
+
+ OpenDirectoryDialog
+
+
+
+
+ Open a file
+
+
+ OpenFileControl
+
+
+ OpenFileDialog
+
+
+
+
+ Save a file
+
+
+ SaveFileControl
+
+
+ SaveFileDialog
+
+
+
+
+
+
Screenshots
+
+
+
+
+
+
+
+
+
+
API
+
FileSystemControl
+
+
+
+
+ Property
+ Description
+
+
+
+
+
+ CreateNewDirectoryEnabled
+
+
+ Enables the feature to create new directories. Notice: It does not have any effects for OpenFileControl.
+
+
+
+
+ CurrentDirectory
+
+
+ The current directory of the control.
+
+
+
+
+ FileSystemInfoToShow
+
+
+ The currently selected directory or file to display additional information about it.
+
+
+
+
+ NewDirectoryName
+
+
+ The name for the new directory.
+
+
+
+
+ ShowHiddenFilesAndDirectories
+
+
+ Shows or hides hidden directories and files.
+
+
+
+
+ ShowSystemFilesAndDirectories
+
+
+ Shows or hides protected directories and files of the system.
+
+
+
+
+
+
+
+
+
+ Event
+ Description
+
+
+
+
+
+ Cancel
+
+
+ An event raised by canceling the operation.
+
+
+
+
+
+
OpenDirectoryControl (extends FileSystemControl)
+
+
+
+
+ Event
+ Description
+
+
+
+
+
+ DirectorySelected
+
+
+ An event raised by selecting a directory to open.
+
+
+
+
+
+
+
+
+
+ Command
+ Description
+
+
+
+
+
+ DirectorySelectedCommand
+
+
+ An command called by by selecting a directory to open.
+
+
+
+
+
+
BaseFileControl (extends FileSystemControl)
+
+
+
+
+ Property
+ Description
+
+
+
+
+
+ ClearCacheOnUnload
+
+
+ True, to clear the cache during unloading the control.
+
+
+
+
+ CurrentFile
+
+
+ The current file of the control.
+
+
+
+
+ Filters
+
+
+ The possible file filters to select from for applying to the files inside the current directory.
+
+ Strings according to the original .NET API will be converted automatically
+ (see original .NET API ).
+
+
+
+
+ FilterIndex
+
+
+ The index of the file filter to apply to the files inside the current directory.
+
+
+
+
+ GroupFoldersAndFiles
+
+
+ Shows folders and files as a group with a header.
+
+
+
+
+
+
+
+
+
+ Event
+ Description
+
+
+
+
+
+ FileSelected
+
+
+ An event raised by selecting a file.
+
+
+
+
+
+
+
+
+
+ Command
+ Description
+
+
+
+
+
+ FileSelectedCommand
+
+
+ An command called by by selecting a file.
+
+
+
+
+
+
OpenFileControl (extends BaseFileControl)
+
+ OpenFileControl does not have any further properties, events or commands.
+
+
SaveFileControl (extends BaseFileControl)
+
+
+
+
+ Property
+ Description
+
+
+
+
+
+ Filename
+
+
+ The name of the file itself without the full path.
+
+
+
+
+ ForceFileExtensionOfFileFilter
+
+
+ Forces the possible file extension of the selected file filter for new filenames.
+
+
+
+
+
+
DirectorySelectedEventArgs
+
+ The arguments for the OpenDirectoryControl.DirectorySelected event.
+
+
+
+
+
+ Property
+ Description
+
+
+
+
+
+ Directory
+
+
+ The selected directory as full filename string.
+
+
+
+
+ DirectoryInfo
+
+
+ The selected directory as DirectoryInfo.
+
+
+
+
+
+
FileSelectedEventArgs
+
+ The arguments for the BaseFileControl.FileSelected event.
+
+
+
+
+
+ Property
+ Description
+
+
+
+
+
+ File
+
+
+ The selected file as full filename string.
+
+
+
+
+ FileInfo
+
+
+ The selected file as FileInfo.
+
+
+
+
+
+
Code example
+
Controls
+
+ Add the control versions to any container control.
+
+
<!-- import namespaces -->
+xmlns:mde="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
+
+<!-- open directory -->
+<mde:OpenDirectoryControl ShowHiddenFilesAndDirectories="False"
+ ShowSystemFilesAndDirectories="False"
+ CreateNewDirectoryEnabled="True"
+ DirectorySelected="OpenDirectoryControl_DirectorySelected"
+ Cancel="OpenDirectoryControl_Cancel" />
+
+<!-- open file -->
+<mde:OpenFileControl ShowHiddenFilesAndDirectories="False"
+ ShowSystemFilesAndDirectories="False"
+ Filters="All files|*.*|C# files|*.cs|XAML files|*.xaml"
+ FileSelected="OpenFileControl_FileSelected"
+ Cancel="OpenFileControl_Cancel" />
+
+<!-- save file -->
+<mde:SaveFileControl ShowHiddenFilesAndDirectories="False"
+ ShowSystemFilesAndDirectories="False"
+ CreateNewDirectoryEnabled="True"
+ Filters="All files|*.*|C# files|*.cs|XAML files|*.xaml"
+ FileSelected="SaveFileControl_FileSelected"
+ Cancel="SaveFileControl_Cancel" />
+
Dialogs
+
+ To open a dialog, use the according helper method as shown below.
+
+
using MaterialDesignExtensions.Controls;
+
+// open directory
+OpenDirectoryDialogArguments dialogArgs = new OpenDirectoryDialogArguments()
+{
+ Width = 600,
+ Height = 400,
+ CreateNewDirectoryEnabled = true
+};
+
+OpenDirectoryDialogResult result = await OpenDirectoryDialog.ShowDialogAsync("DialogHostName", dialogArgs);
+
+// open file
+OpenFileDialogArguments dialogArgs = new OpenFileDialogArguments()
+{
+ Width = 600,
+ Height = 400,
+ Filters = "All files|*.*|C# files|*.cs|XAML files|*.xaml"
+};
+
+OpenFileDialogResult result = await OpenFileDialog.ShowDialogAsync(MainWindow.DialogHostName, dialogArgs);
+
+// save file
+SaveFileDialogArguments dialogArgs = new SaveFileDialogArguments()
+{
+ Width = 600,
+ Height = 400,
+ Filters = "All files|*.*|C# files|*.cs|XAML files|*.xaml",
+ CreateNewDirectoryEnabled = true
+};
+
+SaveFileDialogResult result = await SaveFileDialog.ShowDialogAsync(MainWindow.DialogHostName, dialogArgs);
+
\ No newline at end of file
diff --git a/docs/snippets/documentation/materialwindow.html b/docs/snippets/documentation/materialwindow.html
new file mode 100644
index 00000000..11a43548
--- /dev/null
+++ b/docs/snippets/documentation/materialwindow.html
@@ -0,0 +1,73 @@
+
+
Material window
+
+ MaterialWindow is a custom window class featuring a Material Design like style.
+
+
Screenshots
+
+
API
+
+
+
+
+ Property
+ Description
+
+
+
+
+
+ BorderBackgroundBrush
+
+
+ The color for the border and caption area background of the window.
+
+
+
+
+ BorderForegroundBrush
+
+
+ The forground color for the caption area of the window.
+
+
+
+
+ FadeContentIfInactive
+
+
+ Lets the content of the window fade out if the window is inactive. The default is true (enabled).
+
+
+
+
+
+
Code example
+
+ To use the material window style, derive your windows class from MaterialWindow.
+
+
using MaterialDesignExtensions.Controls;
+...
+namespace MaterialDesignExtensionsDemo
+{
+ public partial class MainWindow : MaterialWindow
+ {
+ ...
+ }
+}
+
<mde:MaterialWindow x:Class="MaterialDesignExtensionsDemo.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:system="clr-namespace:System;assembly=mscorlib"
+ xmlns:local="clr-namespace:MaterialDesignExtensionsDemo"
+ xmlns:mde="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
+ mc:Ignorable="d"
+ Title="Material Design Extensions - Demo" Height="800" Width="1300">
+ ...
+</mde:MaterialWindow>
+
+
\ No newline at end of file
diff --git a/docs/snippets/documentation/navigation.html b/docs/snippets/documentation/navigation.html
index 1c7af94e..c88ab338 100644
--- a/docs/snippets/documentation/navigation.html
+++ b/docs/snippets/documentation/navigation.html
@@ -1,4 +1,44 @@
-
Side navivation
+
Side navigation and navigation rail
Documentation under construction
+
+
Code example
+
+ We begin by defining the items for our navigation as a property of our view model or data context:
+
+
public List NavigationItems
+{
+ get
+ {
+ return new List
+ {
+ new SubheaderNavigationItem() { Subheader = "Documents" },
+ new FirstLevelNavigationItem() { Label = "Files", Icon = PackIconKind.FileDocument, IsSelected = true },
+ new DividerNavigationItem(),
+ new SubheaderNavigationItem() { Subheader = "Media" },
+ new FirstLevelNavigationItem() { Label = "Images", Icon = PackIconKind.Image },
+ new SecondLevelNavigationItem() { Label = "Camera", Icon = PackIconKind.Camera }
+ new FirstLevelNavigationItem() { Label = "Music", Icon = PackIconKind.Music },
+ new FirstLevelNavigationItem() { Label = "Videos", Icon = PackIconKind.Video }
+ };
+ }
+}
+
+ Then we can add a side navigation control to our user interface and set the items via binding:
+
+
<!-- import namespaces -->
+xmlns:mde="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
+
+<mde:SideNavigation Items="{Binding Path=NavigationItems, Mode=OneTime}"
+ NavigationItemSelected="NavigationItemSelectedHandler" />
+
+ Finally we can implement the navigation logic using an event handler:
+
+
private void NavigationItemSelectedHandler(object sender, NavigationItemSelectedEventArgs args)
+{
+ // do navigation according to the selected item in args.NavigationItem
+}
+
\ No newline at end of file
diff --git a/docs/snippets/documentation/oversizednumberspinner.html b/docs/snippets/documentation/oversizednumberspinner.html
index dc19c9b6..afc18204 100644
--- a/docs/snippets/documentation/oversizednumberspinner.html
+++ b/docs/snippets/documentation/oversizednumberspinner.html
@@ -45,7 +45,10 @@ API
Code example
- <controls:OversizedNumberSpinner Value="2" Min="0" Max="4" />
+ <!-- import namespaces -->
+xmlns:mde="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
+
+<mde:OversizedNumberSpinner Value="2" Min="0" Max="4" />
diff --git a/docs/snippets/documentation/search.html b/docs/snippets/documentation/search.html
index 6dada801..9f0b97b1 100644
--- a/docs/snippets/documentation/search.html
+++ b/docs/snippets/documentation/search.html
@@ -1,4 +1,82 @@
-
-
Search
- Documentation under construction
-
\ No newline at end of file
+
+
Persistent search
+
+ The following predefined styles are available:
+
+ MaterialDesignPersistentSearch
+ MaterialDesignPersistentSearchDense
+
+
+
+
Screenshots
+
+
+
Code example
+
+
Persistent search control
+
+<mde:PersistentSearch
+ Margin="8"
+ VerticalAlignment="Top"
+ SearchSuggestionsSource="{Binding SearchSuggestionsSource}" />
+
+
+
Persistent search data source
+
+public class SearchViewModel : ViewModel
+{
+ public ISearchSuggestionsSource SearchSuggestionsSource
+ {
+ get => new OperatingSystemsSearchSuggestionsSource();
+ }
+}
+
+public class OperatingSystemsSearchSuggestionsSource : ISearchSuggestionsSource
+{
+ private List _operatingSystems;
+
+ public OperatingSystemsSearchSuggestionsSource()
+ {
+ _operatingSystems = new List
+ {
+ "Windows 7",
+ "Windows 8",
+ "Windows 8.1",
+ "Windows 10"
+ };
+ }
+
+ public IList GetAutoCompletion(string searchTerm)
+ {
+ return _operatingSystems.Where(os => os.ToLower().Contains(searchTerm.ToLower())).ToList();
+ }
+
+ public IList GetSearchSuggestions()
+ {
+ return new List { "Windows 10", "Windows 8.1" };
+ }
+}
+
+
+
Custom icons
+
+
Make sure to include this namespace
+
+xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
+
+
+
Set your desired icons like this
+
+<mde:PersistentSearch
+ Margin="8"
+ VerticalAlignment="Top"
+ SearchSuggestionsSource="{Binding SearchSuggestionsSource}"
+ SearchIcon="{x:Static md:PackIconKind.PrinterSearch}"
+ CancelIcon="{x:Static md:PackIconKind.BellCancel}"
+ ClearIcon="{x:Static md:PackIconKind.CircleArrows}" />
+
+
+
+
diff --git a/docs/snippets/documentation/stepper.html b/docs/snippets/documentation/stepper.html
index 1ddf8114..bbbf3e5a 100644
--- a/docs/snippets/documentation/stepper.html
+++ b/docs/snippets/documentation/stepper.html
@@ -370,13 +370,13 @@ Code example
<!-- import namespaces -->
xmlns:viewModel="clr-namespace:MaterialDesignExtensionsDemo.ViewModel"
-xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
+xmlns:mde="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
<!-- define the data templates -->
<DataTemplate DataType="{x:Type viewModel:StepperTutorialOneViewModel}">
<StackPanel Orientation="Vertical">
<TextBlock Text="Steppers are handy to break a big task into smaller parts. These are so called steps. It displays the progress of the full task as a numbered sequence of steps." TextWrapping="WrapWithOverflow" />
- <controls:StepButtonBar Continue="CONTINUE" Cancel="CANCEL" />
+ <mde:StepButtonBar Continue="CONTINUE" Cancel="CANCEL" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type viewModel:StepperTutorialTwoViewModel}">
@@ -384,27 +384,27 @@ Code example
<TextBlock Text="There a two layouts for a Stepper, namely horizontal and vertical. It can be set by using the Layout property." TextWrapping="WrapWithOverflow" />
<TextBlock Margin="0,16,0,0" Text="Additionally the Stepper will be in linear mode by setting the IsLinear property to true. This means that the user can only edit the steps in their fixed order. A non-linear Stepper allows the user to edit the steps in any order." TextWrapping="WrapWithOverflow" />
<TextBlock Margin="0,16,0,0" Text="The basic navigation inside a stepper will be accomplished by using simple back and continue buttons. They allow the user to browse through the steps in their order. Just use the StepButtonBar like this tutorial to avoid the nasty reimplementation on your own. The user may also switch the steps of a non-linear Stepper by clicking on the headers. " TextWrapping="WrapWithOverflow" />
- <controls:StepButtonBar Back="BACK" Continue="CONTINUE" Cancel="CANCEL" />
+ <mde:StepButtonBar Back="BACK" Continue="CONTINUE" Cancel="CANCEL" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type viewModel:StepperTutorialThreeViewModel}">
<StackPanel Orientation="Vertical">
<TextBlock Text="The Stepper uses the steps out of its Steps property. This property expects a collection of IStep objects. The Step class already implements this basic interface for a step." TextWrapping="WrapWithOverflow" />
<TextBlock Margin="0,16,0,0" Text="A step consists out of a header and a content. Consider to define one view model class per step content and a DataTemplate for it (just the everyday MVVM magic). The header may contain arbitrary content. If you like the header of this tutorial, just use the StepTitleHeader class." TextWrapping="WrapWithOverflow" />
- <controls:StepButtonBar Back="BACK" Continue="CONTINUE" Cancel="CANCEL" />
+ <mde:StepButtonBar Back="BACK" Continue="CONTINUE" Cancel="CANCEL" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type viewModel:StepperTutorialFourViewModel}">
<StackPanel Orientation="Vertical">
<TextBlock Text="Each time the user switches to another step, an optional validation phase for the until now active step will be started by the Stepper. The Validate() method of the step will be called first. Afterwards the StepValidation event will be raised followed by the call of the StepValidationCommand command." TextWrapping="WrapWithOverflow" />
<TextBlock Margin="0,16,0,0" Text="The different validation handlers may set the HasValidationErrors property of the step to indicate input errors. If the BlockNavigationOnValidationErrors property of the Stepper is true, the Stepper blocks the navigation as long as the active step has invalid data." TextWrapping="WrapWithOverflow" />
- <controls:StepButtonBar Back="BACK" Continue="FINISH" Cancel="CANCEL" />
+ <mde:StepButtonBar Back="BACK" Continue="FINISH" Cancel="CANCEL" />
</StackPanel>
</DataTemplate>
Finally, we can create the Stepper:
- <controls:Stepper IsLinear="False" Layout="Horizontal" Steps="{Binding Path=Steps, Mode=OneTime}" />
+ <mde:Stepper IsLinear="False" Layout="Horizontal" Steps="{Binding Path=Steps, Mode=OneTime}" />
You can define the steps inside the XAML alternatively, if you do not like the code behind:
@@ -413,7 +413,7 @@ Code example
<!-- assuming the data templates are available -->
-<controls:Stepper IsLinear="False" Layout="Horizontal">
+<mde:Stepper IsLinear="False" Layout="Horizontal">
<model:Step>
<model:Step.Header>
<model:StepTitleHeader FirstLevelTitle="What is a Stepper?" />
@@ -446,7 +446,7 @@ Code example
<viewModel:StepperTutorialFourViewModel />
</model:Step.Content>
</model:Step>
-</controls:Stepper>
+</mde:Stepper>
Validation
The Stepper supports different ways to run custom validation logic for its steps. The validation procedure will be triggered right before
@@ -516,7 +516,7 @@
Register for the event or command
}
}
<!-- register the event handler via XAML -->
-<controls:Stepper IsLinear="False" Layout="Horizontal" Steps="{Binding Path=Steps, Mode=OneTime}"
+<mde:Stepper IsLinear="False" Layout="Horizontal" Steps="{Binding Path=Steps, Mode=OneTime}"
StepValidation="StepValidationHandler"
StepValidationCommand="{x:static local:MyControl.MyValidationCommand}" />
TabControlStepper
@@ -524,17 +524,17 @@ TabControlStepper
TabControlStepper is a simple version of a stepper. It extends TabControl to enable a stepper style for tab controls.
<!-- import namespaces -->
-xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
+xmlns:mde="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
xmlns:model="clr-namespace:MaterialDesignExtensions.Model;assembly=MaterialDesignExtensions"
-<controls:TabControlStepper IsLinear="False" Layout="Horizontal">
+<mde:TabControlStepper IsLinear="False" Layout="Horizontal">
<TabItem>
<TabItem.Header>
<model:StepTitleHeader FirstLevelTitle="What is a Stepper?" />
</TabItem.Header>
<StackPanel Orientation="Vertical">
<TextBlock Text="Steppers are handy to break a big task into smaller parts. These are so called steps. It displays the progress of the full task as a numbered sequence of steps." TextWrapping="WrapWithOverflow" />
- <controls:StepButtonBar Continue="CONTINUE" Cancel="CANCEL" />
+ <mde:StepButtonBar Continue="CONTINUE" Cancel="CANCEL" />
</StackPanel>
</TabItem>
<TabItem>
@@ -545,7 +545,7 @@ TabControlStepper
<TextBlock Text="There a two layouts for a Stepper, namely horizontal and vertical. It can be set by using the Layout property." TextWrapping="WrapWithOverflow" />
<TextBlock Margin="0,16,0,0" Text="Additionally the Stepper will be in linear mode by setting the IsLinear property to true. This means that the user can only edit the steps in their fixed order. A non-linear Stepper allows the user to edit the steps in any order." TextWrapping="WrapWithOverflow" />
<TextBlock Margin="0,16,0,0" Text="The basic navigation inside a stepper will be accomplished by using simple back and continue buttons. They allow the user to browse through the steps in their order. Just use the StepButtonBar like this tutorial to avoid the nasty reimplementation on your own. The user may also switch the steps of a non-linear Stepper by clicking on the headers. " TextWrapping="WrapWithOverflow" />
- <controls:StepButtonBar Back="BACK" Continue="CONTINUE" Cancel="CANCEL" />
+ <mde:StepButtonBar Back="BACK" Continue="CONTINUE" Cancel="CANCEL" />
</StackPanel>
</TabItem>
<TabItem>
@@ -554,10 +554,10 @@ TabControlStepper
</TabItem.Header>
<StackPanel>
<TextBlock Text="Well, that's all to say about this simple stepper version." />
- <controls:StepButtonBar Back="BACK" Continue="FINISH" Cancel="CANCEL" />
+ <mde:StepButtonBar Back="BACK" Continue="FINISH" Cancel="CANCEL" />
</StackPanel>
</TabItem>
-</controls:TabControlStepper>
+</mde:TabControlStepper>
diff --git a/docs/snippets/documentation/tabs.html b/docs/snippets/documentation/tabs.html
new file mode 100644
index 00000000..11dbbb9a
--- /dev/null
+++ b/docs/snippets/documentation/tabs.html
@@ -0,0 +1,27 @@
+
+
Tabs
+
+ Material Design Extensions features styles and attached properties for styling a WPF TabControl to match the tabs styles in the
+ Material Design specification . The following predefined
+ styles are available:
+
+ MaterialDesignTabControl
+ MaterialDesignAppBarTabControl
+ MaterialDesignAppBarAccentTabControl
+
+
+
Screenshots
+
+
Code example
+
+ Styling a TabControl in Material Design is as easy as applying a style to a control in XAML:
+
+
<TabControl Style="{StaticResource MaterialDesignTabControl}">
+ <TabItem Header="ANIMALS"></TabItem>
+ <TabItem Header="PLANTS"></TabItem>
+ <TabItem Header="VEHICLES"></TabItem>
+</TabControl>
+
+
\ No newline at end of file
diff --git a/docs/snippets/documentation/textboxsuggestions.html b/docs/snippets/documentation/textboxsuggestions.html
index dbd9acdf..551708fd 100644
--- a/docs/snippets/documentation/textboxsuggestions.html
+++ b/docs/snippets/documentation/textboxsuggestions.html
@@ -1,4 +1,68 @@
Text box suggestions
- Documentation under construction
+
+
Screenshots
+
+
+
Code example
+
+
Text box suggestions control
+
+<mde:TextBoxSuggestions TextBoxSuggestionsSource="{Binding Path=TextBoxSuggestionsSource}">
+ <TextBox Text="{Binding Path=Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
+</mde:TextBoxSuggestions>
+
+
+
Text box suggestions data source
+
+public class TextBoxSuggestionsViewModel : ViewModel
+{
+ private string _text;
+ public string Text
+ {
+ get => _text;
+ set
+ {
+ _text = value;
+ OnPropertyChanged(nameof(Text));
+ }
+ }
+
+ private ITextBoxSuggestionsSource _textBoxSuggestionsSource;
+ public ITextBoxSuggestionsSource TextBoxSuggestionsSource
+ {
+ get => _textBoxSuggestionsSource;
+ }
+
+ public TextBoxSuggestionsViewModel() : base()
+ {
+ _textBoxSuggestionsSource = new OperatingSystemTextBoxSuggestionsSource();
+ _text = null;
+ }
+}
+
+public class OperatingSystemTextBoxSuggestionsSource : TextBoxSuggestionsSource
+{
+ private List m_operatingSystemItems;
+
+ public OperatingSystemTextBoxSuggestionsSource()
+ {
+ m_operatingSystemItems = new List()
+ {
+ "Windows 7",
+ "Windows 8",
+ "Windows 8.1",
+ "Windows 10"
+ };
+ }
+
+ public override IEnumerable Search(string searchTerm)
+ {
+ searchTerm = searchTerm ?? string.Empty;
+ searchTerm = searchTerm.ToLower();
+
+ return m_operatingSystemItems.Where(item => item.ToLower().Contains(searchTerm));
+ }
+}
+
\ No newline at end of file
diff --git a/docs/snippets/home.html b/docs/snippets/home.html
index e020e098..6e75c87a 100644
--- a/docs/snippets/home.html
+++ b/docs/snippets/home.html
@@ -9,6 +9,10 @@ Material Design Extensions
Material Design specification or would crash the scope of
Material Design in XAML Toolkit .
+
+
+
+
Getting started
@@ -23,7 +27,7 @@ Getting started
in the demo)
- Add the namespace xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions" to your XAML
+ Add the namespace xmlns:mde="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions" to your XAML
You are ready to use the controls
@@ -31,6 +35,12 @@ Getting started
+ Important notice
+
+ The configuration of Material Design Extensions v2.6.0 changed in order to enable changing the theme at runtime.
+ Please change your configuration according to App.xaml of the demo.
+
+
Screenshots
Horizontal stepper
@@ -48,9 +58,36 @@
Screenshots
- App bar
+ Navigation rail
+
+
+
+
+
+
+ Tabs
+
+
+
+
+ Open directory
+
+
+
+
+ Open file
+
+
+
+
+ Save file
+
+
+
+
+ Material window and app bar
-
+
Grid list
diff --git a/docs/snippets/license.html b/docs/snippets/license.html
index fe355002..6310e925 100644
--- a/docs/snippets/license.html
+++ b/docs/snippets/license.html
@@ -3,7 +3,7 @@
MIT License
- Copyright (c) 2017-2018 Philipp Spiegel
+ Copyright (c) 2017-2020 Philipp Spiegel
Permission is hereby granted, free of charge, to any person obtaining a copy
diff --git a/docs/snippets/releasenotes.html b/docs/snippets/releasenotes.html
index 83826bdc..2ac9df6e 100644
--- a/docs/snippets/releasenotes.html
+++ b/docs/snippets/releasenotes.html
@@ -1,9 +1,205 @@
Release notes
-
vX.X.X (upcoming release)
+
v4.0.0 (upcoming release)
+
Features
+
+ New SideNavigation.LabelFontSize property
+ Layout improvements for NavigationRail
+ More customizable content area for AppBar
+ Localization for Japanese
+ Added SideNavigation.SelectionBackgroundOpacity property
+ New window class MaterialNavigationWindow for a Material Design like styled navigation window
+ Updated dependency to MaterialDesignThemes version 4.1.0
+
+
Fixes
+
+ Avoid unnecessary searches in TextBoxSuggestions
+
+
Breaking API
+
+
+ AppBar.Children replaced by AppBar.ContentAreaContent
+
+ ContentAreaContent is object instead of IList
+ Additional ContentAreaContentTemplate
+
+
+ Minimum version for .NET Framework raised to 4.5.2
+
+
v3.3.0
+
Features
+
+ Added XmlnsDefinition https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml
+ Consider ResizeMode for the window caption buttons
+ ResizeGrip in MaterialWindow
+ New control TransitionContentControl
+
+ New dialog features
+
+ Optional custom content for dialogs
+ Control for simple input dialogs
+
+
+ Strong named assembly
+ Current directory path optionally as text box in file system controls
+ IconTemplate property for NavigationItem
+ Handle setting of TabControlStepper.SelectedIndex
+
+ New properties to control tab control item headers
+
+ TabHeaderFontSize
+ TabHeaderFontWeight
+ TabHeaderMargin
+
+
+ Layout improvements for MaterialWindow
+ New SearchBase.CancelIcon and SearchBase.ClearIcon properties
+
+
Fixes
+
+ Fixed reflection code in ResourceDictionaryExtensions
+ Fixed usage of SecondaryHueMidBrush and SecondaryHueMidForegroundBrush resources
+ Fixed NullReferenceException in FileSystemControl
+
+
v3.2.0
+
Features
+
+ New control BusyOverlay
+ New TextBoxFileSystemPath.TextBoxStyle property to enable custom styles for the embedded TextBox
+
+ New localizations
+
+ Arabic
+ Czech
+ French
+ Portuguese
+
+
+ Save file in SaveFileControl and SaveFileDialog by hitting enter
+ New ClearSelection method for Autocomplete
+ TabControl style supports FlowDirection = RightToLeft
+
+
Fixes
+
+ Fixed exception in Stepper events
+
+
v3.1.0
+
Features
+
+ Update to .NET Core 3.1
+ Controls for simple alert and confirmation dialogs
+ New TextBoxSuggestions.KeepFocusOnSelection property to control the focus after selecting a suggestion
+
+ New controls combining a TextBox and a FileSystemDialog
+
+ TextBoxOpenDirectory
+ TextBoxOpenFile
+ TextBoxSaveFile
+
+
+
+ Improvements for MaterialWindow
+
+ New MaterialWindow.TitleTemplate property to customize the window title bar
+ Different looks according to Window.WindowStyle property
+
+
+ New control NavigationRail
+
+
Fixes
+
+ Catch exception if network drive is not accessible
+
+
v3.0.0
+
Features
+
+ Support for .NET Core 3
+ Select file with double click in OpenFileDialog and SaveFileDialog
+ Improved keyboard navigation for file system controls
+ Dense style for PersistentSearch
+ Optional icon templates for steps inside a stepper
+ Improved stepper navigation
+ Added MaterialWindow.TitleBarIcon property
+
+
Breaking API
+
+
+ Removed obsolete members
+
+ TabControlAssist.TabHeaderAlignment attached property
+ OpenDirectoryDialog.ShowDialogAsync methods
+ OpenFileDialog.ShowDialogAsync methods
+ SaveFileDialog.ShowDialogAsync methods
+
+
+ Extendend IStepper interface to implement new features for steppers
+ Extendend IStep interface to implement new features for steppers
+
+
v2.8.0
+
Features
+
+ New window class MaterialWindow for a Material Design like styled window
+ Support of TabStripPlacement in TabControl styles
+ OpenMultipleDirectoriesControl and OpenMultipleDirectoriesDialog to select multiple directories
+ OpenMultipleFilesControl and OpenMultipleFilesDialog to select multiple files
+
+
Fixes
+
+ Fixed content layout of horizontal steppers
+
+
Obsolete
+
+ Attached property TabControlAssist.TabHeaderAlignment will be replaced by TabControlAssist.TabHeaderHorizontalAlignment
+
+
v2.7.0
+
Features
+
+ New package MaterialDesignExtensions.LongPath for supporting long file system paths on older Windows and .NET versions
+
+ Improvements for file system controls
+
+ Improved loading of preview images
+ Smoother scrolling in directories and files list
+
+
+ New SaveFileControl.ForceFileExtensionOfFileFilter` property to enforce a file extension of the selected filter
+ Better support of dark theme in file system dialogs
+ Localization for Russian
+ Updated dependency to MaterialDesignThemes version 2.6.0
+
+
Fixes
+
+ Fixed DateTime conversion inside DateTimeAgoConverter
+
+
v2.6.0
+
Features
+
+ Localization for Uzbekistan
+ Create new directories inside OpenDirectoryControl and SaveFileControl
+ Helper PaletteHelper for changing the theme at runtime
+
+
Fixes
+
+ List used resources explicitly in the XAML files containing the templates
+ Prevent NullReferenceException in SideNavigation before the template will be applied
+
+
Important notice
+
+ The configuration of Material Design Extensions changed in order to enable changing the theme at runtime.
+ Please change your configuration according to App.xaml of the demo.
+
+
v2.5.0
Features
New control StepTitleHeaderControl to use bindings in a XAML defined step
+ TabControl styles to render it in Material Design
+ New icons for file system controls
+
+
Fixes
+
+ Handle broken image files in BitmapImageHelper
+ Updated dependency to MaterialDesignThemes version 2.5.1 to bypass a bug in version 2.5.0.1205
+ Use Dispatcher in Autocomplete.AutocompleteSourceItemsChangedHandler()
v2.4.0
Features
diff --git a/icon/icon_on_background.png b/icon/icon_on_background.png
new file mode 100644
index 00000000..503be66e
Binary files /dev/null and b/icon/icon_on_background.png differ
diff --git a/screenshots/AlertDialog1.png b/screenshots/AlertDialog1.png
new file mode 100644
index 00000000..a8f850fb
Binary files /dev/null and b/screenshots/AlertDialog1.png differ
diff --git a/screenshots/BusyOverlay.png b/screenshots/BusyOverlay.png
new file mode 100644
index 00000000..a368d656
Binary files /dev/null and b/screenshots/BusyOverlay.png differ
diff --git a/screenshots/ConfirmationDialog1.png b/screenshots/ConfirmationDialog1.png
new file mode 100644
index 00000000..c58acd5f
Binary files /dev/null and b/screenshots/ConfirmationDialog1.png differ
diff --git a/screenshots/FileDetail1.png b/screenshots/FileDetail1.png
new file mode 100644
index 00000000..e14a23ae
Binary files /dev/null and b/screenshots/FileDetail1.png differ
diff --git a/screenshots/MaterialWindow.png b/screenshots/MaterialWindow.png
new file mode 100644
index 00000000..502032f0
Binary files /dev/null and b/screenshots/MaterialWindow.png differ
diff --git a/screenshots/MaterialWindow1.png b/screenshots/MaterialWindow1.png
new file mode 100644
index 00000000..03719652
Binary files /dev/null and b/screenshots/MaterialWindow1.png differ
diff --git a/screenshots/NavigationRail1.png b/screenshots/NavigationRail1.png
new file mode 100644
index 00000000..7fefff42
Binary files /dev/null and b/screenshots/NavigationRail1.png differ
diff --git a/screenshots/NavigationRail2.png b/screenshots/NavigationRail2.png
new file mode 100644
index 00000000..1518e96a
Binary files /dev/null and b/screenshots/NavigationRail2.png differ
diff --git a/screenshots/OpenDirectoryControl1.png b/screenshots/OpenDirectoryControl1.png
new file mode 100644
index 00000000..e35549f1
Binary files /dev/null and b/screenshots/OpenDirectoryControl1.png differ
diff --git a/screenshots/OpenFileControl1.png b/screenshots/OpenFileControl1.png
new file mode 100644
index 00000000..5cd9b94d
Binary files /dev/null and b/screenshots/OpenFileControl1.png differ
diff --git a/screenshots/SaveFileControl1.png b/screenshots/SaveFileControl1.png
new file mode 100644
index 00000000..cf9093f6
Binary files /dev/null and b/screenshots/SaveFileControl1.png differ
diff --git a/screenshots/TabControl1.png b/screenshots/TabControl1.png
new file mode 100644
index 00000000..37a2bec7
Binary files /dev/null and b/screenshots/TabControl1.png differ
diff --git a/screenshots/TextBoxOpenDirectory1.png b/screenshots/TextBoxOpenDirectory1.png
new file mode 100644
index 00000000..6f0cb511
Binary files /dev/null and b/screenshots/TextBoxOpenDirectory1.png differ
diff --git a/screenshots/TextBoxSuggestions.png b/screenshots/TextBoxSuggestions.png
new file mode 100644
index 00000000..6f602aa6
Binary files /dev/null and b/screenshots/TextBoxSuggestions.png differ