问题
I have made a UWP custom templated control that contains a collection of ICommandBarElement, much like the standard CommandBar control. The problem is that as soon as I click on any of the AppBarButton contained in my CommandBar implementation, an unhandled exception occurs: "No such interface supported".
There is something I must doing wrong but I just can't see it. Here is the code for the custom control:
public sealed class MyCommandBarControl : ContentControl
{
public MyCommandBarControl()
{
this.DefaultStyleKey = typeof(MyCommandBarControl);
this.PrimaryCommands = new ObservableCollection<ICommandBarElement>();
}
public ObservableCollection<ICommandBarElement> PrimaryCommands
{
get { return (ObservableCollection<ICommandBarElement>)GetValue(PrimaryCommandsProperty); }
set { SetValue(PrimaryCommandsProperty, value); }
}
/// <summary>
/// PrimaryCommands Dependency Property
/// </summary>
public static readonly DependencyProperty PrimaryCommandsProperty =
DependencyProperty.Register(
"PrimaryCommands",
typeof(ObservableCollection<ICommandBarElement>),
typeof(MainPage),
new PropertyMetadata(null, null));
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
var primaryItemsControl = GetTemplateChild("PrimaryItemsControl") as ItemsControl;
primaryItemsControl.ItemsSource = this.PrimaryCommands;
}
}
And the associated Style:
<Style TargetType="local:MyCommandBarControl" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyCommandBarControl">
<Grid x:Name="LayoutRoot" Background="{TemplateBinding Background}">
<Grid x:Name="ContentRoot"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Margin="{TemplateBinding Padding}"
Height="{TemplateBinding Height}"
Background="{TemplateBinding Background}"
Opacity="{TemplateBinding Opacity}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ContentControl
x:Name="ContentControl"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}"
Foreground="{TemplateBinding Foreground}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
IsTabStop="False"
Margin="10, 0, 0, 0"/>
<ItemsControl
x:Name="PrimaryItemsControl"
IsTabStop="False"
Grid.Column="1"
Margin="10, 0, 0, 0"
HorizontalAlignment="Right"
HorizontalContentAlignment="Right">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I have made a small project you can download that reproduces the problem. Any help resolving this exception would be appreciated.
回答1:
Why not inherit from CommandBar control, and don't need to manage the PrimaryCommands by ourselves.
So simply change your code to the following can solve the issue:
public sealed class MyCommandBarControl : CommandBar
{
public MyCommandBarControl()
{
this.DefaultStyleKey = typeof(MyCommandBarControl);
//this.PrimaryCommands = new ObservableCollection<ICommandBarElement>();
}
//public ObservableCollection<ICommandBarElement> PrimaryCommands
//{
// get { return (ObservableCollection<ICommandBarElement>)GetValue(PrimaryCommandsProperty); }
// set { SetValue(PrimaryCommandsProperty, value); }
//}
///// <summary>
///// PrimaryCommands Dependency Property
///// </summary>
//public static readonly DependencyProperty PrimaryCommandsProperty =
// DependencyProperty.Register(
// "PrimaryCommands",
// typeof(ObservableCollection<ICommandBarElement>),
// typeof(MainPage),
// new PropertyMetadata(null, null));
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
var primaryItemsControl = GetTemplateChild("PrimaryItemsControl") as ItemsControl;
primaryItemsControl.ItemsSource = this.PrimaryCommands;
}
}
[Update1]
I think there is underlying type conversion we cannot see or we have to use some interfaces like ICommandBar but we cannot use due to its protection level.
If you do hope to implement CommandBar by yourself, I think it's better to create your own Command button instead of using AppBarButton. But you need to make sure you have a solid reason to do it by yourself.
For example, the following will work if I use a default Button.
public sealed class MyCommandBarControl : ContentControl
{
public MyCommandBarControl()
{
this.DefaultStyleKey = typeof(MyCommandBarControl);
this.PrimaryCommands = new ObservableCollection<Button>();
}
public ObservableCollection<Button> PrimaryCommands
{
get { return (ObservableCollection<Button>)GetValue(PrimaryCommandsProperty); }
set { SetValue(PrimaryCommandsProperty, value); }
}
/// <summary>
/// PrimaryCommands Dependency Property
/// </summary>
public static readonly DependencyProperty PrimaryCommandsProperty =
DependencyProperty.Register(
"PrimaryCommands",
typeof(ObservableCollection<Button>),
typeof(MainPage),
new PropertyMetadata(null, null));
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
var primaryItemsControl = GetTemplateChild("PrimaryItemsControl") as ItemsControl;
primaryItemsControl.ItemsSource = this.PrimaryCommands;
}
}
In MainPage.xaml
<local:MyCommandBarControl>
<local:MyCommandBarControl.Content>
<TextBlock Text="My CommandBar" />
</local:MyCommandBarControl.Content>
<local:MyCommandBarControl.PrimaryCommands>
<Button Content="Pin" Click="PinBarButton_Click" />
<Button Content="UnPin" />
<Button Content="Sync" />
<Button Content="Remove" />
</local:MyCommandBarControl.PrimaryCommands>
</local:MyCommandBarControl>
来源:https://stackoverflow.com/questions/33508244/exception-occurs-when-button-clicked-inside-my-custom-control