【问题标题】:DependencyProperty binding not happening on initial load初始加载时未发生 DependencyProperty 绑定
【发布时间】:2012-06-11 00:07:54
【问题描述】:

我正在尝试做一些简单的事情——创建一个 DependencyProperty,然后绑定到它。但是,当我启动应用程序时,getter 似乎没有触发。 (我猜这个解决方案会让我拍脑袋然后说“Doh!”,但还是这样。:))

有什么想法吗?

代码隐藏代码:

public static readonly DependencyProperty PriorityProperty = 
        DependencyProperty.Register("Priority", 
        typeof (Priority), typeof (PriorityControl), null);

public Priority Priority
{
    get { return (Priority)GetValue(PriorityProperty); }
    set { SetValue(PriorityProperty, value); }
}

控制 XAML:

<ListBox Background="Transparent" 
         BorderThickness="0" 
         ItemsSource="{Binding Path=Priorities}" 
         Name="PriorityList" 
         SelectedItem="{Binding Path=Priority, Mode=TwoWay}">
  <ListBox.ItemTemplate>
    <DataTemplate>
        <Grid Height="16" Width="16">
          <Border BorderBrush="Black"
                  BorderThickness="2"
                  CornerRadius="3"
                  Visibility="{Binding RelativeSource=
                       {RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}, Path=IsSelected, Converter={StaticResource boolToVisibilityConverter}}" />
          <Border CornerRadius="3" Height="12" Width="12">
            <Border.Background>
              <SolidColorBrush Color="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}, Path=Content, Converter={StaticResource priorityToColorConverter}}" />
            </Border.Background>
          </Border>
        </Grid>
    </DataTemplate>
   </ListBox.ItemTemplate>
   <ListBox.ItemsPanel>
     <ItemsPanelTemplate>
       <StackPanel Orientation="Horizontal"/>
     </ItemsPanelTemplate>
   </ListBox.ItemsPanel>
 </ListBox>

绑定声明:

<UI:PriorityControl Grid.Column="8" 
                    Priority="{Binding Path=Priority}" 
                    VerticalAlignment="Center"/>

其他一些注意事项:

  • 绑定在用户控件中
  • UserControl 包含 PriorityControl
  • PriorityControl 包含 DependencyProperty
  • 我检查了 UserControl 的数据是否获得了适当的数据 -- 其他所有绑定都有效。
  • 如果我通过鼠标更改 PriorityControl 上的选择,一切都会适当地触发。只是值的初始设置不起作用。
  • 优先级是一个枚举。

编辑:我尝试了另外两件事。首先,我对值进行了双向绑定,但这不起作用。然后,我向依赖属性添加了一个属性更改回调,并使其调用 OnPropertyChanged,如下所示:

public static readonly DependencyProperty PriorityProperty =
        DependencyProperty.Register("Priority", typeof (Priority), typeof (PriorityControl), new PropertyMetadata(HandleValueChanged));

private static void HandleValueChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
   var npc = dependencyObject as PriorityControl;
   npc.OnPropertyChanged("Priority");
}

那也没用。我什至尝试在控件上覆盖 ApplyTemplate 以强制属性更改通知,但该值永远不会在初始加载时设置。我可以更改值并看到一切正常,但这是第一次什么都没有发生。

【问题讨论】:

  • +1 用于提供清晰的描述、代码 XAML :)

标签: silverlight dependency-properties


【解决方案1】:

DependencyProperty 的 getter 和 setter 不会被任何人调用除了你

它们只是为您的利益而生成的助手(为您节省大量的转换和对 GetValue/SetValue 的调用)。

DP 中的所有工作(动画、绑定等)直接通过调用 SetValue 和 GetValue 进行。

如果您需要捕捉值的变化,请在 Register 调用中提供更改回调。

注意:附加属性(即使用RegisterAttached而不是Register)实际上确实使用了setter,在解析XAML时 ,但那是another story,因为普通的 DP 不会。

更新:

您尚未在寄存器中设置默认值,因此它默认为 0(这是您的枚举值“Normal”)。如果将其设置为绑定中的第一个值,则不会更改,因此不会触发。

一个解决方案:添加一个“none”枚举作为您的第一个 0 值,这样“Normal”(值 1)将导致更改。或者在寄存器中设置一个非“正常”的默认值。

【讨论】:

  • 谢谢。 :) 我只是尝试进行显式的属性更改调用,但这并没有做任何事情。我什至尝试覆盖 ApplyTemplate 以强制更改通知,但也没有运气。 (我已经更新了问题以准确包含我所做的事情。)
  • @Ari Roth:感谢您提供更多代码。基本上,您的默认注册值 (0) 与您在 XAML 中设置的“正常”值相同,因此(正确地)没有要报告的值更改。请参阅更新的答案以了解一些替代方案。
【解决方案2】:

我注意到,如果在属性定义期间已经设置了值,则在执行依赖属性时,它将无法正确运行。您说在应用程序中设置值时没有问题,所以我假设没有管道问题。

考虑下面的例子:

XAML

<UI:PriorityControl Priority="{Binding Path=Priority, Mode=TwoWay}"/>

代码

public enum Priority
{
    Normal,
    Low,
    High
}

public class PriorityControl : UserControl
{    
    public static readonly DependencyProperty PriorityProperty =
      DependencyProperty.Register("Priority", typeof(Priority), typeof(PriorityControl), new PropertyMetadata(DependencyProperty.UnsetValue, OnPriorityPropertyChanged);

    public Priority Priority
    {
        get { return (Priority)this.GetValue(PriorityProperty); }
        set { this.SetValue(PriorityProperty, value); }
    }

    private static void OnPriorityPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        PriorityControl control = sender as PriorityControl;
        if (control != null)
        {
            // Do what you wanted to here.
        }
    }
}

如果您使用的是枚举,并且没有指定默认值(您似乎没有在创建时不向依赖属性提供 PropertyMetadata 对象),则默认值将是枚举的默认值。在我上面的示例中,这将是“正常”。现在,如果您在创建控件时尝试将值设置为 Normal,则不会调用回调,因为该值已经等于该值。

为了使其正常工作,您必须将 DependencyProperty.UnsetValue 传递给 PropertyMetadata 对象,就像我在定义属性时所做的那样。这将允许在最初设置值时调用 OnPriorityPropertyChanged 方法。

希望能帮助解决它!

【讨论】:

    【解决方案3】:

    不是 100% 确定,但它可能就像将 Priority 绑定更改为 TwoWay 一样简单。

    <UI:PriorityControl Grid.Column="8" 
                        Priority="{Binding Path=Priority, Mode=TwoWay}" 
                        VerticalAlignment="Center"/>
    

    【讨论】:

      猜你喜欢
      • 2013-04-10
      • 1970-01-01
      • 2011-07-16
      • 1970-01-01
      • 2019-10-14
      • 1970-01-01
      • 2022-06-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多