UWP:为什么 DataTemplate 中的行为有一个空的 AssociatedObject?
UWP: Why behaviors in DataTemplate has a null AssociatedObject?
我想将 NavigationView Header 上的 CommandBar 绑定到一个集合以动态显示 AppBarButtons,我使用了 this answer 中给出的方法。但是,当我在 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 方法中抛出异常。我想知道为什么会这样。
您的命令在 AssociatedObject
实际附加之前已更新。在 UpdateCommands
中添加 AssociatedObject != null
的测试并创建将再次调用 UpdateCommands
的方法 OnAttached
:
/// <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();
}
我想将 NavigationView Header 上的 CommandBar 绑定到一个集合以动态显示 AppBarButtons,我使用了 this answer 中给出的方法。但是,当我在 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 方法中抛出异常。我想知道为什么会这样。
您的命令在 AssociatedObject
实际附加之前已更新。在 UpdateCommands
中添加 AssociatedObject != null
的测试并创建将再次调用 UpdateCommands
的方法 OnAttached
:
/// <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();
}