mirror of
https://github.com/ckaczor/ChrisKaczor.Wpf.Validation.git
synced 2026-01-13 17:22:33 -05:00
Handle tab controls when focusing on error
This commit is contained in:
@@ -1,25 +0,0 @@
|
||||
using System.Globalization;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace ChrisKaczor.Wpf.Validation
|
||||
{
|
||||
public class RequiredValidationRule : ValidationRule
|
||||
{
|
||||
public static string GetErrorMessage(object? fieldValue)
|
||||
{
|
||||
var errorMessage = string.Empty;
|
||||
|
||||
if (fieldValue == null || string.IsNullOrWhiteSpace(fieldValue.ToString()))
|
||||
errorMessage = "Required";
|
||||
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
|
||||
{
|
||||
var error = GetErrorMessage(value);
|
||||
|
||||
return !string.IsNullOrEmpty(error) ? new ValidationResult(false, error) : ValidationResult.ValidResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,17 @@
|
||||
using System.Collections.Generic;
|
||||
using DebounceThrottle;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace ChrisKaczor.Wpf.Validation
|
||||
namespace ChrisKaczor.Wpf.Validation;
|
||||
|
||||
public class BindingExpressionInfo
|
||||
{
|
||||
public class BindingExpressionInfo
|
||||
{
|
||||
public FrameworkElement FrameworkElement { get; }
|
||||
public BindingExpression BindingExpression { get; }
|
||||
|
||||
@@ -18,10 +20,10 @@ namespace ChrisKaczor.Wpf.Validation
|
||||
FrameworkElement = frameworkElement;
|
||||
BindingExpression = bindingExpression;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class WindowExtensions
|
||||
{
|
||||
public static class WindowExtensions
|
||||
{
|
||||
public static List<BindingExpressionInfo> GetBindingExpressions(this DependencyObject parent)
|
||||
{
|
||||
return GetBindingExpressions(parent, null);
|
||||
@@ -62,11 +64,12 @@ namespace ChrisKaczor.Wpf.Validation
|
||||
if (dependencyObject is FrameworkElement frameworkElement)
|
||||
{
|
||||
// Get the list of properties
|
||||
IEnumerable<DependencyProperty> dependencyProperties = (from PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(frameworkElement)
|
||||
select DependencyPropertyDescriptor.FromProperty(propertyDescriptor)
|
||||
into dependencyPropertyDescriptor
|
||||
where dependencyPropertyDescriptor != null
|
||||
select dependencyPropertyDescriptor.DependencyProperty).ToList();
|
||||
IEnumerable<DependencyProperty> dependencyProperties = TypeDescriptor.GetProperties(frameworkElement)
|
||||
.Cast<PropertyDescriptor>()
|
||||
.Select(DependencyPropertyDescriptor.FromProperty)
|
||||
.Where(dependencyPropertyDescriptor => dependencyPropertyDescriptor != null)
|
||||
.Select(dependencyPropertyDescriptor => dependencyPropertyDescriptor.DependencyProperty)
|
||||
.ToList();
|
||||
|
||||
// Loop over each dependency property in the list
|
||||
foreach (var dependencyProperty in dependencyProperties)
|
||||
@@ -87,19 +90,26 @@ namespace ChrisKaczor.Wpf.Validation
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateAllSources(this DependencyObject window, IEnumerable<BindingExpressionInfo> bindingExpressions)
|
||||
public static void UpdateAllSources(this DependencyObject _, IEnumerable<BindingExpressionInfo> bindingExpressions)
|
||||
{
|
||||
foreach (var expression in bindingExpressions)
|
||||
expression.BindingExpression.UpdateSource();
|
||||
}
|
||||
|
||||
public static void ClearAllValidationErrors(this DependencyObject window, IEnumerable<BindingExpressionInfo> bindingExpressions)
|
||||
public static void ClearAllValidationErrors(this DependencyObject _, IEnumerable<BindingExpressionInfo> bindingExpressions)
|
||||
{
|
||||
foreach (var expression in bindingExpressions)
|
||||
System.Windows.Controls.Validation.ClearInvalid(expression.BindingExpression);
|
||||
}
|
||||
|
||||
public static bool IsValid(this DependencyObject window)
|
||||
{
|
||||
return IsValid(window, null);
|
||||
}
|
||||
|
||||
private static readonly DebounceDispatcher FocusDispatcher = new(50);
|
||||
|
||||
public static bool IsValid(this DependencyObject window, TabControl? tabControl)
|
||||
{
|
||||
// Get a list of all framework elements and binding expressions
|
||||
var bindingExpressions = window.GetBindingExpressions();
|
||||
@@ -117,10 +127,31 @@ namespace ChrisKaczor.Wpf.Validation
|
||||
// Get the first framework element with an error
|
||||
var firstErrorElement = bindingExpressions.First(b => b.BindingExpression.HasError).FrameworkElement;
|
||||
|
||||
if (tabControl == null)
|
||||
{
|
||||
// Set focus
|
||||
firstErrorElement.Focus();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Loop over each tab item
|
||||
foreach (TabItem tabItem in tabControl.Items)
|
||||
{
|
||||
// Cast the content as visual
|
||||
var content = (Visual) tabItem.Content;
|
||||
|
||||
// See if the control with the error is a descendant
|
||||
if (!firstErrorElement.IsDescendantOf(content))
|
||||
continue;
|
||||
|
||||
// Select the tab
|
||||
tabItem.IsSelected = true;
|
||||
}
|
||||
|
||||
var dispatcher = Dispatcher.CurrentDispatcher;
|
||||
FocusDispatcher.Debounce(() => dispatcher.Invoke(() => firstErrorElement.Focus()));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,9 @@
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<AssemblyName>ChrisKaczor.Wpf.Validation</AssemblyName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DebounceThrottle" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="README.md">
|
||||
<Pack>True</Pack>
|
||||
|
||||
Reference in New Issue
Block a user