首页 > 解决方案 > UWP:为什么 DataTemplate 中的行为有一个空的 AssociatedObject?

问题描述

我想将 NavigationView Header 上的 CommandBar 绑定到一个集合以动态显示 AppBarButtons,我使用了这个答案中给出的方法。但是,当我在 DataTemplate 中的 CommandBar 上设置行为并运行程序时,它会引发异常,显示 AssociatedObject 为空。这是代码:
xaml

<i:Interaction.Behaviors>
    <behaviors:NavigationViewHeaderBehavior
        DefaultHeader="{x:Bind ViewModel.Selected.Content, Mode=OneWay}">
        <behaviors:NavigationViewHeaderBehavior.DefaultHeaderTemplate>
            <DataTemplate>
                <Grid>
                    <CommandBar Name="headerCommandBar">
                        <i:Interaction.Behaviors>
                            <behaviors:BindableCommandBarBehavior
                                PrimaryCommands="{Binding Path=Content.ViewModel.AppBarButtonList,ElementName=shellFrame, Mode=OneWay}" />
                        </i:Interaction.Behaviors>
                    </CommandBar>
                </Grid>
            </DataTemplate>
        </behaviors:NavigationViewHeaderBehavior.DefaultHeaderTemplate>
    </behaviors:NavigationViewHeaderBehavior>
</i:Interaction.Behaviors>

ViewModel 中的 C# 代码:

public ObservableCollection<AppBarButton> AppBarButtonList { get; set; }
    = new ObservableCollection<AppBarButton>
    {
        new AppBarButton { Icon = new SymbolIcon(Symbol.Accept), Label="Accept" },
        new AppBarButton { Icon = new SymbolIcon(Symbol.Add), Label="Add" }
    };

行为准则:

public class BindableCommandBarBehavior : Behavior<CommandBar>
{
    public ObservableCollection<AppBarButton> PrimaryCommands
    {
        get { return (ObservableCollection<AppBarButton>)GetValue(PrimaryCommandsProperty); }
        set { SetValue(PrimaryCommandsProperty, value); }
    }

    public static readonly DependencyProperty PrimaryCommandsProperty
        = DependencyProperty.Register(
            "PrimaryCommands",
            typeof(ObservableCollection<AppBarButton>),
            typeof(BindableCommandBarBehavior),
            new PropertyMetadata(default(ObservableCollection<AppBarButton>), UpdateCommands));

    private static void UpdateCommands(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
    {
        if (!(dependencyObject is BindableCommandBarBehavior behavior)) return;

        var oldList = dependencyPropertyChangedEventArgs.OldValue as ObservableCollection<AppBarButton>;
        if (dependencyPropertyChangedEventArgs.OldValue != null)
        {
            oldList.CollectionChanged -= behavior.PrimaryCommandsCollectionChanged;
        }

        var newList = dependencyPropertyChangedEventArgs.NewValue as ObservableCollection<AppBarButton>;
        if (dependencyPropertyChangedEventArgs.NewValue != null)
        {
            newList.CollectionChanged += behavior.PrimaryCommandsCollectionChanged;
        }
        behavior.UpdatePrimaryCommands();
    }


    private void PrimaryCommandsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        UpdatePrimaryCommands();
    }

    /// <summary>
    /// Update the primary commands for CommandBar.
    /// </summary>
    private void UpdatePrimaryCommands()
    {
        if (PrimaryCommands != null)
        {
            AssociatedObject.PrimaryCommands.Clear();
            foreach (var command in PrimaryCommands)
            {
                AssociatedObject.PrimaryCommands.Add(command);
            }
        }
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        if (PrimaryCommands != null)
        {
            PrimaryCommands.CollectionChanged -= PrimaryCommandsCollectionChanged;
        }
    }
}

在 UpdatePrimaryCommands 方法中引发异常。我想知道为什么会这样。

标签: c#xamluwpbehavior

解决方案


您的命令在AssociatedObject实际附加之前已更新。添加测试AssociatedObject != nullinUpdateCommands并创建OnAttachedUpdateCommands再次调用的方法:

/// <summary>
/// Update the primary commands for CommandBar.
/// </summary>
private void UpdatePrimaryCommands()
{
    if (PrimaryCommands != null && AssociatedObject != null)
    {
        AssociatedObject.PrimaryCommands.Clear();
        foreach (var command in PrimaryCommands)
        {
            AssociatedObject.PrimaryCommands.Add(command);
        }
    }
}

protected override void OnAttached()
{
    UpdatePrimaryCommands();
}


推荐阅读