如果 ItemsControl 出现验证错误则禁用按钮

问题描述 投票:0回答:1
wpf xaml
1个回答
0
投票

基于我的答案的示例https://stackoverflow.com/a/74293719/13349759

using System;
using System.Reflection;
using System.Windows;
using System.Windows.Data;

namespace CommonCore
{
    public static class BindingExpressionHelper
    {
        private static readonly Func<BindingExpressionBase, DependencyObject, DependencyProperty, object> GetValueOfBindingExpression;

        static BindingExpressionHelper()
        {
            Type beType = typeof(BindingExpressionBase);
            var beMethod = beType
                .GetMethod("GetValue", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, new Type[] { typeof(DependencyObject), typeof(DependencyProperty) })
                ?? throw new Exception("GetValue method not found.");
            var beFunc = (Func<BindingExpressionBase, DependencyObject, DependencyProperty, object>)
                beMethod.CreateDelegate(typeof(Func<BindingExpressionBase, DependencyObject, DependencyProperty, object>));
            GetValueOfBindingExpression = beFunc;
        }

        /// <summary>Returns the source value of this binding expression.</summary>
        /// <param name="bindingExpression">The binding expression whose value to get.</param>
        /// <returns>The value of the binding expression received.</returns>
        public static object GetSourceValue(this BindingExpressionBase bindingExpression)
        {
            DependencyObject target = bindingExpression.Target;
            DependencyProperty targetProperty = bindingExpression.TargetProperty;
            var value = GetValueOfBindingExpression(bindingExpression, target, targetProperty);

            return value;
        }
    }

}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using static System.Windows.Media.VisualTreeHelper;


namespace CommonCore.Helpers
{
    public static partial class VisualTreeHelper
    {
        public static IEnumerable<DependencyObject> GetChildren(this DependencyObject parent)
        {
            ArgumentNullException.ThrowIfNull(parent);
            Queue<DependencyObject> queue = new Queue<DependencyObject>(16);
            queue.Enqueue(parent);
            while (queue.Count != 0)
            {
                DependencyObject current = queue.Dequeue();
                yield return current;

                int count = GetChildrenCount(current);
                for (int i = 0; i < count; i++)
                {
                    queue.Enqueue(GetChild(current, i));
                }
            }
        }
        public static IEnumerable<T> GetChildren<T>(this DependencyObject parent)
           where T : DependencyObject
            => parent.GetChildren().OfType<T>();

        public static T GetFirstChild<T>(this DependencyObject parent)
           where T : DependencyObject
            => (T)parent.GetChildren().FirstOrDefault(child => child is T);

    }
}
using System.Globalization;
using System.Windows.Controls;
using System.Windows.Data;
using CommonCore;

namespace Core2024.SO.AlexeyTitov.question79081208
{
    public class OrderIDValidationRule : ValidationRule
    {

        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {

            int id;
            switch (value)
            {
                case int _id: id = _id; break;
                case string text: id = int.Parse(text, cultureInfo); break;
                case BindingExpressionBase bindingExpression:
                    var eee = bindingExpression.GetSourceValue();
                    var t = eee.GetType();
                    id = (int)(bindingExpression.GetSourceValue() ?? 0);
                    break;
                default:
                    id = int.MinValue;
                    break;
            }

            if (id < 0 || id > 100)
                return new ValidationResult(false, "Значение вне диапазона [0..100]");
            return ValidationResult.ValidResult;
        }
    }

}
using System.Collections.ObjectModel;

namespace Core2024.SO.AlexeyTitov.question79081208
{
    public class Order : BaseInpc
    {
        private int? _id;
        public int? ID
        {
            get => _id;
            set => Set(ref _id, value);
        }
    }

    public class OrdersViewMode : BaseInpc
    {
        public ObservableCollection<Order> OrderCollection { get; }
            = new ObservableCollection<Order>
            (
                Enumerable.Range(0, 20).Select(_ => new Order() { ID = Random.Shared.Next(-20, 120) })
            );
    }

}
<Window x:Class="Core2024.SO.AlexeyTitov.question79081208.TestErrorHandlerWindow"
        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:local="clr-namespace:Core2024.SO.AlexeyTitov.question79081208"
        mc:Ignorable="d"
        Title="TestErrorHandlerWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:OrdersViewMode/>
    </Window.DataContext>
        <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <ItemsControl x:Name="MyItemsControl"
                      ItemsSource="{Binding Path=OrderCollection}"
                      Validation.Error="OnOrderError">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <TextBox x:Name="MyTextBox">
                            <TextBox.Text>
                                <Binding Path="ID" Mode="TwoWay" NotifyOnValidationError="True">
                                    <Binding.ValidationRules>
                                    <!--<local:OrderIDValidationRule ValidationStep="ConvertedProposedValue"/>-->
                                    <local:OrderIDValidationRule ValidationStep="ConvertedProposedValue"
                                                                 ValidatesOnTargetUpdated="True"/>
                                </Binding.ValidationRules>
                                </Binding>
                            </TextBox.Text>
                        </TextBox>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>

            <Button x:Name="MyButton" Grid.Row="1"
                    Margin="5" Padding="15 5"
                    Content="Click Me"
                    HorizontalAlignment="Center" VerticalAlignment="Center">
            </Button>
        <x:Code>
            <![CDATA[
        private void OnOrderError(object sender, ValidationErrorEventArgs e)
        {
            bool hasError = ((DependencyObject)sender).GetChildren().Any(Validation.GetHasError);
            MyButton.IsEnabled = !hasError;
        }
            ]]>
        </x:Code>
        </Grid>
</Window>
© www.soinside.com 2019 - 2024. All rights reserved.