BindingExpression在Textbox上总是返回null

本文关键字:返回 null Textbox BindingExpression | 更新日期: 2023-09-27 18:23:59

我创建了一个行为,这样我就可以更改文本框上的UpdateSourceTrigger。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Controls;
using GalaSoft.MvvmLight.Command;
using System.Windows.Data;
namespace xxxxxx.xxx.Behaviors
{
public static class InputBindingValidation
{
    public static DependencyProperty ValidateDataErrorsProperty = DependencyProperty.RegisterAttached(
                   "ValidateDataErrors",
                   typeof(bool),
                   typeof(InputBindingValidation),
                   new UIPropertyMetadata(false, OnValidateDataErrors));
    private static void OnValidateDataErrors(DependencyObject target, DependencyPropertyChangedEventArgs e)
    {
        var element = target as TextBox;
        if (element == null)
        {
            throw new InvalidOperationException("This behavior can be attached to a TextBox item only.");
        }
        // TEST 1
        BindingExpression be = element.GetBindingExpression(TextBox.TextProperty);
        if (be != null)
        {
            be.ParentBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            be.ParentBinding.ValidatesOnDataErrors = true;
            element.SetBinding(TextBox.TextProperty, be.ParentBinding);
            be.UpdateSource();
        }
    }
    public static void SetValidateDataErrors(DependencyObject d, bool value)
    {
        d.SetValue(ValidateDataErrorsProperty, value);
    }
    public static bool GetValidateDataErrors(DependencyObject d)
    {
        return (bool)d.GetValue(ValidateDataErrorsProperty);
    }
}

}

我在我的xaml:中使用它

<efw:EditViewBase x:Class="DocumentManager.View.DocumentEditView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:efw="clr-namespace:FPLQ.EFW.Base;assembly=FPLQ.EFW"
         xmlns:efwcontrol="clr-namespace:FPLQ.EFW.Controls;assembly=FPLQ.EFW.Controls"
         xmlns:b="clr-namespace:xxxx.xxx.Behaviors;assembly=FPLQ.EFW"
         mc:Ignorable="d" 
         d:DesignHeight="518" d:DesignWidth="979"
         d:DataContext="{Binding Source={StaticResource VMLocator}, Path=DocumentEDVM}">
<GroupBox Style="{StaticResource ResourceKey=MainGrid}" >
                    <TextBox Grid.Column="1" Grid.Row="0"
                             Style="{StaticResource TextBoxNotes}" 
                             Text="{Binding Path=EntityViewModel.Title, ValidatesOnDataErrors=True, Mode=TwoWay}" 
                             IsReadOnly="{Binding Path=EntityViewModel.IsReadOnlyNever}"
                             b:InputBindingValidation.ValidateDataErrors="True"/>

"element.GetBindingExpression"行总是返回null,如何实现?

也尝试过,但没有好的结果:

         Binding newBinding = new Binding();
         newBinding.ValidatesOnDataErrors = true;
         newBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
         element.SetBinding(TextBox.TextProperty, newBinding);

有人能帮忙吗?

谢谢。

BindingExpression在Textbox上总是返回null

如果我理解正确,我相信这符合您的要求,当ChangeBindingBehavior的ValidateDataErrors属性为True时,它会修改Text绑定,使UpdateSourceTrigger的值为UpdateSourceTriger.PropertyChanged。

注意:要使用它,你需要引用System.Windows.Interactivity,这可以通过提供该程序集(dll)的任何程序包从nuGet获得,有一个正式的MS程序包,但我似乎找不到名称。

XAML:

            <TextBox Text="{Binding Path=SomeTextValue}">
                <i:Interaction.Behaviors>
                    <app:ChangeBindingBehavior ValidateDataErrors="True" />
                </i:Interaction.Behaviors>
            </TextBox>

行为背后的代码:

public sealed class ChangeBindingBehavior : Behavior<TextBox>
{
    public static readonly DependencyProperty ValidateDataErrorsProperty = DependencyProperty.Register("ValidateDataErrors",
        typeof (bool),
        typeof (ChangeBindingBehavior),
        new PropertyMetadata(default(bool), OnValidateDataErrorsChanged));
    public bool ValidateDataErrors
    {
        get { return (bool)GetValue(ValidateDataErrorsProperty); }
        set { SetValue(ValidateDataErrorsProperty, value); }
    }
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Loaded += OnLoaded;
    }
    private static void OnValidateDataErrorsChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
    {
        if (args.OldValue == args.NewValue)
        {
            return;
        }
        ((ChangeBindingBehavior)d).OnValidateDataErrorsChanged((bool)args.NewValue);
    }
    private void OnValidateDataErrorsChanged(bool newValue)
    {
        if (AssociatedObject == null)
        {
            return;
        }
        var expression = AssociatedObject.GetBindingExpression(TextBox.TextProperty);
        if (expression != null)
        {
            if (newValue)
            {
                var newBinding = new Binding("Text")
                {
                    Path = expression.ParentBinding.Path,
                    Source = AssociatedObject.DataContext,
                    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
                    Mode = expression.ParentBinding.Mode,
                    Converter = expression.ParentBinding.Converter
                };
                AssociatedObject.SetBinding(TextBox.TextProperty, newBinding);
                AssociatedObject.GetBindingExpression(TextBox.TextProperty).UpdateSource();
            }
        }
    }
    private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
    {
        OnValidateDataErrorsChanged(ValidateDataErrors);
    }
}

问题是在应用绑定之前调用了OnValidateDataErrors,因此GetBindingExpression始终返回null。这是我的最终解决方案,效果很好。

使用

            if (GetValidateDataErrors(target))
                element.Initialized += InitializeDataError;
            else
                element.Initialized -= InitializeDataError;

成功了。

完整代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Controls;
using GalaSoft.MvvmLight.Command;
using System.Windows.Data;
using xxxx.EFW.Helper;
namespace xxxx.EFW.Behaviors
{
    public sealed class InputBindingValidation
    {
        public static DependencyProperty ValidateDataErrorsProperty = DependencyProperty.RegisterAttached(
                   "ValidateDataErrors",
                   typeof(bool),
                   typeof(InputBindingValidation),
                   new UIPropertyMetadata(false, OnValidateDataErrors));
        private static void OnValidateDataErrors(DependencyObject target, DependencyPropertyChangedEventArgs e)
        {
            var element = target as TextBox;
            if (GetValidateDataErrors(target))
                element.Initialized += InitializeDataError;
            else
                element.Initialized -= InitializeDataError;
        }
        private static void InitializeDataError(object sender, EventArgs e)
        {
            var element = sender as TextBox;
            if (element == null)
                throw new InvalidOperationException("This behavior can be attached to a TextBox item only.");
            BindingExpression be = element.GetBindingExpression(TextBox.TextProperty);
            if (be != null)
            {
                Binding bind = new Binding()
                                {
                                    Path = be.ParentBinding.Path,
                                    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
                                    Mode = be.ParentBinding.Mode,
                                    Converter = be.ParentBinding.Converter,
                                    ValidatesOnDataErrors = true
                                };
                if (be.ParentBinding.Source != null)
                    bind.Source = be.ParentBinding.Source;
                element.SetBinding(TextBox.TextProperty, bind);
            }
        }
        public static void SetValidateDataErrors(DependencyObject d, bool value)
        {
            d.SetValue(ValidateDataErrorsProperty, value);
        }
        public static bool GetValidateDataErrors(DependencyObject d)
        {
            return (bool)d.GetValue(ValidateDataErrorsProperty);
        }
    }
}