C# BindingExpression在Textbox上始终返回null

C# BindingExpression在Textbox上始终返回null,c#,wpf,xaml,dependency-properties,behavior,C#,Wpf,Xaml,Dependency Properties,Behavior,我创建了一个行为,以便可以更改文本框上的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 Sys

我创建了一个行为,以便可以更改文本框上的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"/>
有人能帮忙吗


谢谢。

如果我理解正确,我相信这是您想要的,当ChangeBindingBehavior上的ValidateDataErrors属性为True时,它会修改文本绑定,使UpdateSourceTrigger的值为UpdateSourceTrigger.PropertyChanged

注意:要使用此程序集,您需要参考System.Windows.Interactivity,这可以通过提供此程序集(dll)的任何软件包从nuGet获得,有一个官方的MS one,但我似乎找不到名称

XAML:


行为中隐藏的代码:

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);
    }
}
公共密封类ChangeBindingBehavior:行为
{
公共静态只读DependencyProperty ValidatedataErrorProperty=DependencyProperty.Register(“ValidateDataErrors”,
类型(bool),
类型(ChangeBindingBehavior),
新的PropertyMetadata(默认值(bool),OnValidateDataErrorsChanged);
公共布尔值验证错误
{
获取{return(bool)GetValue(validatedataerrorproperty);}
set{SetValue(validatedataerrorproperty,value);}
}
受保护的覆盖无效附加()
{
base.onatached();
AssociatedObject.Loaded+=已加载;
}
ValidatedataErrorsChanged上的私有静态无效(DependencyObject d、DependencyPropertyChangedEventArgs args)
{
if(args.OldValue==args.NewValue)
{
回来
}
((ChangeBindingBehavior)d).OnValidateDataErrorsChanged((bool)args.NewValue);
}
私有void OnValidateDataErrorsChanged(bool newValue)
{
if(AssociatedObject==null)
{
回来
}
var expression=AssociatedObject.GetBindingExpression(TextBox.TextProperty);
if(表达式!=null)
{
如果(新值)
{
var newBinding=新绑定(“文本”)
{
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();
}
}
}
已加载专用void(对象发送方,RoutedEventArgs RoutedEventArgs)
{
OnValidatedataErrors已更改(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);
        }
    }
}

首先,为什么您没有创建一个合适的WPF行为来实现这一点?这里可以找到一个例子——因为我不使用Expression Blend。所以,行为不仅仅是关于Expression Blend的,它们是做你想做的事情的正确方式。你在尝试做什么,这个问题还不清楚?
            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);
        }
    }
}