BindingOperations.GetBinding给出另一个绑定

时间:2019-01-18 15:41:23

标签: .net wpf xaml

我正在FooBox(升级的文本框)中动态使用ValidationRule。 直接在Window中使用时效果很好。

我还有另一个自定义控件(LatLonEditor),可以使用FooBox管理纬度和经度。 在这种特殊情况下,当我获得FooBox值的绑定时,我总是会获得第一个LatLonEditor的第一个FooBox的绑定。

我已经花了整整一天时间尝试解决此问题,而我的解决方案也用光了。 我已经阅读了BindingOperations.GetBinding源代码(没有给我一个提示)。 我创建了一个隔离的项目来重现该问题,剥离了代码的所有无用部分。

FooBox模板

<ControlTemplate x:Key="FooBoxTemplate" TargetType="{x:Type local:FooBox}">
    <TextBox x:Name="Editor" Text="{Binding Path=Value, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="0,0,1,0" />

    <ControlTemplate.Triggers>            
        <Trigger Property="Validation.HasError" Value="true">
            <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self},
                                Path=(Validation.Errors).CurrentItem.ErrorContent}"/>                
            <Setter Property="BorderBrush" TargetName="Editor" Value="Red" />                
        </Trigger>            
    </ControlTemplate.Triggers>
</ControlTemplate>

<Style x:Key="DefaultFooBoxStyle" TargetType="{x:Type local:FooBox}">
    <Setter Property="Template" Value="{StaticResource FooBoxTemplate}"/>
    <Setter Property="Height" Value="24" />             
    <Setter Property="Validation.ErrorTemplate" Value="{x:Null}" />
    <Setter Property="Focusable" Value="False" />
</Style>

<Style TargetType="{x:Type local:FooBox}" BasedOn="{StaticResource DefaultFooBoxStyle}" />

FooBox控件

 public class FooBox : Control
{
    static FooBox()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(FooBox), new FrameworkPropertyMetadata(typeof(FooBox)));
    }

    public enum Type
    {          
        Int,          
        Float,           
        Double,            
        String
    }

    private bool _templateApplied = false;
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        _templateApplied = true;
        LoadValidationRules();
    }

    public static readonly DependencyProperty ValueProperty =
   DependencyProperty.Register("Value", typeof(string), typeof(FooBox), new FrameworkPropertyMetadata()
   {
       BindsTwoWayByDefault = true,
       DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,

   });

    public string Value
    {
        get { return (string)GetValue(ValueProperty); }
        set
        {
            SetValue(ValueProperty, value);
        }
    }

    public static readonly DependencyProperty ValueTypeProperty =
     DependencyProperty.Register("ValueType", typeof(Type), typeof(FooBox), new FrameworkPropertyMetadata()
     {
         DefaultValue = Type.String
     });

    public Type ValueType
    {
        get { return (Type)GetValue(ValueTypeProperty); }
        set
        {
            SetValue(ValueTypeProperty, value);
        }
    }        

    /// <summary>
    /// For integral types, this is the max acceptable value
    /// </summary>
    public static readonly DependencyProperty DomainMaxProperty =
       DependencyProperty.Register("DomainMax", typeof(decimal?), typeof(FooBox), new FrameworkPropertyMetadata());
    public decimal? DomainMax
    {
        get { return (decimal?)GetValue(DomainMaxProperty); }
        set
        {
            SetValue(DomainMaxProperty, value);
        }
    }

    private void LoadValidationRules()
    {
        if (_templateApplied)
        {
            //For the second LatLonEditor, i've got the binding of the previous one
            Binding b = BindingOperations.GetBinding(this, ValueProperty);

            if (b != null)
            {
                b.ValidationRules.Clear();

                if (ValueType == Type.Double)
                {
                    b.ValidationRules.Add(new DoubleValidationRule()
                    {                          
                        DomainMax = DomainMax
                    });
                }
            }
        }
    }
}

LatLonEditor模板

 <ControlTemplate x:Key="LatLonDecimalDegreesEditorTemplate" TargetType="{x:Type local:LatLonEditor}">                                  
    <local:FooBox x:Name="PART_DD" ValueType="Double" Margin="2,0"
                    Value="{Binding Value, Delay=500, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,                                       
                            RelativeSource={RelativeSource TemplatedParent}}"/>          

    <ControlTemplate.Triggers>
        <Trigger Property="Type" Value="Latitude">
            <Setter TargetName="PART_DD" Property="DomainMax" Value="90" />
        </Trigger>
        <Trigger Property="Type" Value="Longitude">
            <Setter TargetName="PART_DD" Property="DomainMax" Value="180" />
        </Trigger>          
    </ControlTemplate.Triggers>
</ControlTemplate>    

<Style x:Key="DefaultLatLonEditorStyle" TargetType="{x:Type local:LatLonEditor}">
    <Setter Property="Template" Value="{StaticResource LatLonDecimalDegreesEditorTemplate}"/>        
</Style>

<Style BasedOn="{StaticResource DefaultLatLonEditorStyle}" TargetType="{x:Type local:LatLonEditor}" />

LatLonEditor控件

public class LatLonEditor : Control
{
    #region Statements            


    #endregion

    #region Constructor/Destructor

    static LatLonEditor()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(LatLonEditor), new FrameworkPropertyMetadata(typeof(LatLonEditor)));
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
    }     

    #endregion

    /// <summary>
    /// The types of value that can be input
    /// </summary>
    public enum CoordinateValueType : byte
    {
        Latitude,
        Longitude
    }

    #region Properties

    /// <summary>
    /// Get/Set the input mode for this instance
    /// </summary>
    public static readonly DependencyProperty TypeProperty =
        DependencyProperty.Register("Type", typeof(CoordinateValueType), typeof(LatLonEditor), new FrameworkPropertyMetadata()
        {
            DefaultValue = CoordinateValueType.Latitude
        });
    public CoordinateValueType Type
    {
        get { return (CoordinateValueType)GetValue(TypeProperty); }
        set { SetValue(TypeProperty, value); }
    }

    /// <summary>
    /// Formatted value to use externally
    /// </summary>
    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(double?), typeof(LatLonEditor), new FrameworkPropertyMetadata());
    public double? Value
    {
        get
        {
            return (double?)GetValue(ValueProperty);
        }
        set
        {
            SetValue(ValueProperty, value);
        }
    }
    #endregion
}

用法

 <controls:LatLonEditor x:Name="H3LP" Width="120"  Type="Longitude" Value="3" />
    <controls:LatLonEditor x:Name="IfYouPlease" Width="120" Type="Latitude" Value="5" />

第一个LatLonEditor的最大值应为180 第二个LatLonEditor的最大值应为90

DomainMax已由触发器正确设置。

实际结果是两个控件的最大值均为90 (第一次绑定将应用第二个控件的规则)

我当然想念什么,但是我看不到什么? :-(

1 个答案:

答案 0 :(得分:1)

您应该首先获得对您对其应用绑定的元素的引用,然后使用$today = date("D"); switch($today){ case "Mon": case "Tue": case "Wed": $days = (mktime(16, 0, 0) <= time())? 2 : 1; break; case "Thu": $days = (mktime(16, 0, 0) <= time())? 4 : 1; break; case "Fri": $days = (mktime(16, 0, 0) <= time())? 5 : 4; break; case "Sat": $days = 4; break; case "Sun": $days = 3;; break; default: break; } if ( isset($days) ) { echo "<p>For Delivery on <strong> " . date('D jS', strtotime($Date. " + {$days} days")). "</strong><p>"; } else { echo "No information available for that day."; }

BindingOperations.GetBinding

由于不应该修改private void LoadValidationRules() { if (_templateApplied) { TextBox Editor = Template.FindName("Editor", this) as TextBox; Binding b = BindingOperations.GetBinding(Editor, TextBox.TextProperty); if (b != null) { ... } } } ,因此您还可以通过编程方式创建初始绑定:

Binding

然后,您当然将为每个实例获得唯一的绑定。