BindingExpression始终在Textbox上返回null

时间:2014-09-23 12:28:45

标签: 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 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"/>

&#34; element.GetBindingExpression&#34; line总是返回null,我该怎么把它拉下来?

也试过这个,没有好结果:

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

有人可以帮忙吗?

感谢。

2 个答案:

答案 0 :(得分:0)

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

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

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);
    }
}

答案 1 :(得分:0)

问题是在应用绑定之前调用了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);
        }
    }
}