WPF依赖属性未被设置

11

我正在尝试通过XAML将一个依赖属性绑定到我的自定义WPF控件上。

这是我注册依赖属性的方式:

public static readonly DependencyProperty AltNamesProperty = 
    DependencyProperty.Register ("AltNames", typeof(string), typeof(DefectImages));

public string AltNames
{
    get { return (string) GetValue(AltNamesProperty); }
    set { SetValue(AltNamesProperty, value); }
}

以下是我在 XAML 中如何调用它:

<DataGrid.Columns>                
    <DataGridTemplateColumn IsReadOnly="True">
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <StackPanel Name="StackPanel1" Grid.Column="0" Width="950">
                    <TextBlock FontSize="16" TextDecorations="None" Text="{BindingPath=StandardName}" Foreground="Black"  FontWeight="Bold" Padding="5,10,0,0"></TextBlock>
                    <TextBlock Text="{Binding Path=AltNames}"TextWrapping="WrapWithOverflow" Padding="5,0,0,10"></TextBlock>
                    <!-- this part should be magic!! -->
                    <controls:DefectImages AltNames="{Binding Path=AltNames}"></controls:DefectImages>
                </StackPanel>
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
</DataGrid.Columns>

我知道我尝试绑定的 AltNames 属性是有效的,因为我可以在文本块中正常显示它。我是否注册依赖属性不正确?

我需要做什么才能在我的代码后台中正确地分配值给 AltNames


你尝试过使用 AltNames="{Binding Path=AltNames, Mode=TwoWay}" 吗?在运行时的输出窗口中有没有绑定错误? - nemesv
@nemesv 刚刚尝试了双向绑定,但没有成功。输出窗口中没有绑定错误。 - jacobsimeon
很可能是由于两个属性共享相同的名称而导致混淆。你尝试将其中一个重命名了吗?你标记为答案的解决方法似乎有些奇怪! - Gusdor
在我的情况下,属性并没有在我的“UserControl”的构造函数中设置,而是在“Loaded”事件中设置的。 - Walter Stabosz
2个回答

21

感谢 @Danko 给我提供的启示。我注册了一个回调函数来在属性更改时设置值。
这是我最终使用的代码:

private static void OnDefectIdChanged(DependencyObject defectImageControl, DependencyPropertyChangedEventArgs eventArgs)
{
  var control = (DefectImages) defectImageControl;
  control.DefectID = (Guid)eventArgs.NewValue;
}

/// <summary>
/// Registers a dependency property, enables us to bind to it via XAML
/// </summary>
public static readonly DependencyProperty DefectIdProperty = DependencyProperty.Register(
    "DefectID",
    typeof (Guid),
    typeof (DefectImages),
    new FrameworkPropertyMetadata(
      // use an empty Guid as default value
      Guid.Empty,
      // tell the binding system that this property affects how the control gets rendered
      FrameworkPropertyMetadataOptions.AffectsRender, 
      // run this callback when the property changes
      OnDefectIdChanged 
      )
    );

/// <summary>
/// DefectId accessor for for each instance of this control
/// Gets and sets the underlying dependency property value
/// </summary>
public Guid DefectID
{
  get { return (Guid) GetValue(DefectIdProperty); }
  set { SetValue(DefectIdProperty, value); }
}

2

如果属性影响控件的呈现方式,可能需要指定PropertyMetadata参数来注册DependencyProperty。例如:

DependencyProperty.Register("AltNames", typeof(string), typeof(DefectImages), 
                              new FrameworkPropertyMetadata( null,
                              FrameworkPropertyMetadataOptions.AffectsRender ) );

我尝试了这个,但还是不行。我在AltNames属性的setter上放了一个断点,但它从未被执行。 - jacobsimeon
2
好的,实际上 setter 永远不会被执行,因为绑定是在“幕后”执行的。您可以尝试使用 此 PropertyMetadata 构造函数 来指定在属性更改时执行的回调方法。另外,请查看 如何调试 WPF 绑定? - Danko Durbić
使用回调函数设置值对我很有效。感谢您让我找到正确的方向。 - jacobsimeon
1
是的,但这意味着每次想要绑定到 DP 时都必须使用回调函数?这很糟糕,如果你有像 10 个 DP,你将不得不有 10 个回调函数。DP 是按照你在 XAML 中设置它们的顺序设置的,所以我们不能依赖于一个 DP 被设置了其他 DP 也会被设置的事实,因为这并不是这样的情况。Loaded 事件也不行,因为绑定已经在那时触发了。 - IronHide

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接