Warm tip: This article is reproduced from serverfault.com, please click

c#-UWP:为什么DataTemplate中的行为具有空的AssociatedObject?

(c# - UWP: Why behaviors in DataTemplate has a null AssociatedObject?)

发布于 2020-12-02 07:35:19

我想将NavigationView Header上的CommandBar绑定到一个集合以动态显示AppBarButtons,我使用了此答案中给出的方法但是,当我在DataTemplate中的CommandBar上设置行为并运行该程序时,它将引发异常,表明AssociatedObject为null。这是代码:
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方法中引发异常。我想知道为什么会这样。

Questioner
myfix16
Viewed
0
Quercus 2020-12-02 15:42:26

AssociatedObject实际附加命令之前,你的命令已更新添加AssociatedObject != nullin的测试UpdateCommands并创建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();
}