代码之家  ›  专栏  ›  技术社区  ›  Dominic Jonas

将属性值路由/隧道到另一个具有行为的属性

  •  0
  • Dominic Jonas  · 技术社区  · 6 年前

    我有一个 DataGrid 想通过 AlternationIndex 到绑定元素(当前对象之外)。

    细胞模板

    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <Grid>
                <TextBlock HorizontalAlignment="Center" Text="{Binding Index}"/>
                <i:Interaction.Behaviors>
                    <behaviors:RoutePropertyValue 
                        Source="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow}, Path=(ItemsControl.AlternationIndex)}"
                        Target="{Binding Index, Mode=TwoWay}"/>
                </i:Interaction.Behaviors>
            </Grid>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    

    *RoutePropertyValueBehavior**

    public class RoutePropertyValue : Behavior<FrameworkElement>
    {
        /// <summary>
        /// The source property value
        /// </summary>
        public object Source
        {
            get => (object)GetValue(SourceProperty);
            set => SetValue(SourceProperty, value);
        }
    
        /// <summary>
        /// The <see cref="Source"/> DependencyProperty.
        /// </summary>
        public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(object), typeof(RoutePropertyValue), new PropertyMetadata(null, SourceChangedCallback));
    
        private static void SourceChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs args)
        {
            if (d is RoutePropertyValue instance)
            {
                instance.OnSourceChanged();
            }
        }
    
        protected virtual void OnSourceChanged()
        {
            Target = Source;
        }
    
    
        /// <summary>
        /// The target where the value should be writetn
        /// </summary>
        public object Target
        {
            get => (object)GetValue(TargetProperty);
            set => SetValue(TargetProperty, value);
        }
    
        /// <summary>
        /// The <see cref="Target"/> DependencyProperty.
        /// </summary>
        public static readonly DependencyProperty TargetProperty = DependencyProperty.Register("Target", typeof(object), typeof(RoutePropertyValue), new PropertyMetadata(null));
    
    }
    

    实际上 Target 总是 null 调试时。如果改变了里面的顺序 数据网格 ,和 SourceChangedCallback 不会再接到电话了。因此,无论如何,将属性值“隧道”到另一个属性似乎是错误的。

    1 回复  |  直到 6 年前
        1
  •  1
  •   mm8    6 年前

    可以绑定到目标对象,然后指定要设置的源属性。无论何时设置了任何目标属性,都应尝试设置源属性。试试这个:

    public class RoutePropertyValue : Behavior<FrameworkElement>
    {
        public object Source
        {
            get => GetValue(SourceProperty);
            set => SetValue(SourceProperty, value);
        }
    
        public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(nameof(Source), typeof(object), 
            typeof(RoutePropertyValue), new PropertyMetadata(null, Callback));
    
        private static void Callback(DependencyObject d, DependencyPropertyChangedEventArgs args)
        {
            if (d is RoutePropertyValue instance)
                instance.OnAnyValueChanged();
        }
    
        protected virtual void OnAnyValueChanged()
        {
            if (!string.IsNullOrEmpty(TargetMember))
                TargetObject?.GetType().GetProperty(TargetMember)?.SetValue(TargetObject, Source);
        }
    
        public object TargetObject
        {
            get => GetValue(TargetObjectProperty);
            set => SetValue(TargetObjectProperty, value);
        }
    
        public static readonly DependencyProperty TargetObjectProperty = DependencyProperty.Register(nameof(TargetObject), typeof(object), 
            typeof(RoutePropertyValue), new PropertyMetadata(null, Callback));
    
        public string TargetMember
        {
            get => (string)GetValue(TargetMemberProperty);
            set => SetValue(TargetMemberProperty, value);
        }
    
        public static readonly DependencyProperty TargetMemberProperty = DependencyProperty.Register(nameof(TargetMember), typeof(string),
            typeof(RoutePropertyValue), new PropertyMetadata(null, Callback));
    }
    

    xaml:

    <behaviors:RoutePropertyValue 
        TargetObject="{Binding}"
        TargetMember="Index"
        Source="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow}, Path=(ItemsControl.AlternationIndex)}"
        />