如何创建可重用的UserControl并将命令绑​​定到它?

时间:2017-09-04 05:56:29

标签: c# data-binding uwp user-controls uwp-xaml

我正在尝试在carusel中绑定一个可重复使用的按钮,我想要实现的是一个添加让我们说6个按钮每个按钮将有一个命令,根据按钮名称将导航到正确的页面。

我可以这样做:

<toolkitcontrols:Carousel x:Name="NavigationMenuCarouselPanel"
                                      HorizontalAlignment="Center"
                                      VerticalAlignment="Center"
                                      Orientation="Horizontal"
                                      ItemsSource="{x:Bind ViewModel.MenuList, Mode=OneWay}"
                                      ItemMargin="25"
                                      ItemDepth="160"
                                      ItemRotationX="180"
                                      ItemRotationY="25"
                                      ItemRotationZ="0"
                                      SelectedIndex="2"
                                      Grid.Row="1">
                <toolkitcontrols:Carousel.EasingFunction>
                    <CubicEase EasingMode="EaseOut"/>
                </toolkitcontrols:Carousel.EasingFunction>
                   <Button Command="{x:Bind ViewModel.NavigateToPage1, Mode=OneWay}"
                           Content="{x:Bind ViewModel.Name, Mode=OneWay}"/>
            </toolkitcontrols:Carousel>

如果我这样做,我将添加5个按钮,我将不得不为每个按钮编写属性。

所以我想使用UserControl并写下这样的东西:

<toolkitcontrols:Carousel x:Name="NavigationMenuCarouselPanel"
                                      HorizontalAlignment="Center"
                                      VerticalAlignment="Center"
                                      Orientation="Horizontal"
                                      ItemsSource="{x:Bind ViewModel.MenuList, Mode=OneWay}"
                                      ItemMargin="25"
                                      ItemDepth="160"
                                      ItemRotationX="180"
                                      ItemRotationY="25"
                                      ItemRotationZ="0"
                                      SelectedIndex="2"
                                      Grid.Row="1">
                <toolkitcontrols:Carousel.EasingFunction>
                    <CubicEase EasingMode="EaseOut"/>
                </toolkitcontrols:Carousel.EasingFunction>
                <toolkitcontrols:Carousel.ItemTemplate>
                    <DataTemplate x:DataType="data:ButtonInfo">
                        <usercontrolvm:NavigationMenuButtonTemplate NavigateToPageCommand="{Binding NavigateToPageCommand}"/>
                    </DataTemplate>
                </toolkitcontrols:Carousel.ItemTemplate>
            </toolkitcontrols:Carousel>

但是我没有做到这一点,我发现了一些教程,但据我所知,所有这些都会让我像代码那样写这个:

<usercontrolvm:NavigationMenuButtonTemplate NavigateToPageCommand="{Binding NavigateToPageCommand}"/>

类似6次,我不知道如何将x:DataTemplate的DataType用于我的属性列表。

这是我的UserControl.xaml.cs

public sealed partial class NavigationMenuButtonTemplate : UserControl
{
    public ButtonInfo ButtonInfo => (DataContext as ButtonInfo);

    public NavigationMenuButtonTemplate()
    {
        this.InitializeComponent();
        Loaded += NavigationMenuButtonTemplate_Loaded;
    }

    private void NavigationMenuButtonTemplate_Loaded(object sender, RoutedEventArgs e)
    {
        Bindings.Update();
    }

    public DelegateCommand NavigateToPageCommand
    {
        get { return (DelegateCommand)GetValue(NavigateToPageCommandProperty); }
        set { SetValue(NavigateToPageCommandProperty, value); }
    }

    // Using a DependencyProperty as the backing store for NavigateToPageCommand.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty NavigateToPageCommandProperty =
        DependencyProperty.Register("NavigateToPageCommand", 
            typeof(DelegateCommand), 
            typeof(NavigationMenuButtonTemplate), 
            new PropertyMetadata(0));
}

这是我的ButtonInfo.cs

public class ButtonInfo
{
    public string Symbol { get; set; }
    public string FontFamily { get; set; }
    public string MenuName { get; set; }
    public string BenefitKind { get; set; }
    public string Status { get; set; }        
}

这是我的UserControl.xaml

<Button x:Name="NavigationMenuTemplate"
            Width="300"
            Height="300"
            Command="{Binding NavigateToPageCommand, ElementName=root, Mode=OneWay}">
        <Grid x:Name="ButtonLayout">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <TextBlock x:Name="NavigationMenuIconTextBlock"
                       Grid.Row="0"
                       Grid.Column="0"
                       Grid.ColumnSpan="2"
                       FontFamily="{x:Bind ButtonInfo.FontFamily, Mode=OneWay, FallbackValue='Webdings'}"
                       Text="{x:Bind ButtonInfo.Symbol, Mode=OneWay, FallbackValue='&#x91;'}"
                       FontSize="150"
                       Foreground="Black"
                       VerticalAlignment="Center"
                       HorizontalAlignment="Center"/>
            <TextBlock x:Name="NavigationMenuButtonNameTextBlock"
                       Grid.Row="1"
                       Grid.Column="0"
                       Grid.ColumnSpan="2"
                       Text="{x:Bind ButtonInfo.MenuName, Mode=OneWay, FallbackValue='CALCULADORA JORNADAS EXTRAORDINARIAS'}"
                       FontSize="12"
                       Foreground="Black"
                       HorizontalAlignment="Center"/>
            <TextBlock x:Name="NavigationMenuButtonBenefitKindTextBlock"
                       Grid.Row="2"
                       Grid.Column="0"
                       Text="{x:Bind ButtonInfo.BenefitKind, Mode=OneWay, FallbackValue='Subscripción'}"
                       FontSize="10"
                       Foreground="Black"
                       HorizontalAlignment="Left"/>
            <TextBlock x:Name="NavigationMenuButtonStatusTextBlock"
                       Grid.Row="2"
                       Grid.Column="1"
                       Text="{x:Bind ButtonInfo.Status, Mode=OneWay, FallbackValue='Vigente'}"
                       FontSize="10"
                       Foreground="Black"
                       HorizontalAlignment="Right"/>
        </Grid>            
    </Button>

请有人帮助我,并指出我正确的方向。 我错过了什么?

2 个答案:

答案 0 :(得分:3)

您问题中的ItemTemplate方法实际上是在正确的轨道上。

最后,您的XAML看起来类似于以下内容(仅包含一些属性,但您明白了这一点) -

<toolkitcontrols:Carousel ItemsSource="{x:Bind ButtonInfoCollection}">
    <toolkitcontrols:Carousel.ItemTemplate>
        <DataTemplate x:DataType="local:ButtonInfo">
            <local:NavigationMenuButton NavigateToPageCommand="{Binding DataContext.NavigateToPageCommand, ElementName=MyPageName}" 
                                        NavigateToPageCommandParameter="{x:Bind PageType}" 
                                        MenuName="{x:Bind MenuName}" 
                                        SymbolPath="{x:Bind Symbol}" />
        </DataTemplate>
    </toolkitcontrols:Carousel.ItemTemplate>
</toolkitcontrols:Carousel>

考虑到上述结构,您只需要在NavigationMenuButton用户控件中将这些属性公开为依赖项属性。请参阅下面的一个简单示例 -

NavigationMenuButton XAML

<UserControl x:Class="DesignTest.NavigationMenuButton">

    <!--If any of the properties can be updated, change the binding Mode to OneWay-->
    <Button Command="{x:Bind NavigateToPageCommand, Mode=OneWay}" CommandParameter="{x:Bind NavigateToPageCommandParameter}">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="20" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>

            <Image x:Name="SymbolImage" Stretch="UniformToFill" />
            <TextBlock Text="{x:Bind MenuName, FallbackValue='JORNADAS EXTRAORDINARIAS', TargetNullValue='JORNADAS EXTRAORDINARIAS'}" Grid.Column="1" />
        </Grid>
    </Button>
</UserControl>

NavigationMenuButton代码隐藏

public sealed partial class NavigationMenuButton : UserControl
{
    public NavigationMenuButton()
    {
        InitializeComponent();
    }

    public ICommand NavigateToPageCommand
    {
        get => (ICommand)GetValue(NavigateToPageCommandProperty);
        set => SetValue(NavigateToPageCommandProperty, value);
    }
    public static readonly DependencyProperty NavigateToPageCommandProperty = DependencyProperty.Register(
        "NavigateToPageCommand", typeof(ICommand), typeof(NavigationMenuButton), new PropertyMetadata(null));

    public object NavigateToPageCommandParameter
    {
        get => GetValue(NavigateToPageCommandParameterProperty);
        set => SetValue(NavigateToPageCommandParameterProperty, value);
    }
    public static readonly DependencyProperty NavigateToPageCommandParameterProperty = DependencyProperty.Register(
        "NavigateToPageCommandParameter", typeof(object), typeof(NavigationMenuButton), new PropertyMetadata(null));

    public string MenuName
    {
        get => (string)GetValue(MenuNameProperty);
        set => SetValue(MenuNameProperty, value);
    }
    public static readonly DependencyProperty MenuNameProperty = DependencyProperty.Register(
        "MenuName", typeof(string), typeof(NavigationMenuButton), new PropertyMetadata(null));

    public string SymbolPath
    {
        get => (string)GetValue(SymbolPathProperty);
        set => SetValue(SymbolPathProperty, value);
    }
    public static readonly DependencyProperty SymbolPathProperty = DependencyProperty.Register(
        "SymbolPath", typeof(string), typeof(NavigationMenuButton), new PropertyMetadata(null, (s, e) =>
        {
            // We don't do the x:Bind for this property in XAML because the Image control's Source property
            // doesn't accept a string but a BitmapImage, so one workaround is to do the conversion here.

            var self = (NavigationMenuButton)s;
            var image = self.SymbolImage;
            var symbolPath = (string)e.NewValue;

           image.Source = new BitmapImage(new Uri(self.BaseUri, symbolPath ?? "/Assets/default_path"));
        }));
}

请注意,您需要在PageType课程中添加ButtonInfo属性以用于导航。

public Type PageType { get; set; }

我个人不喜欢在项目级别定义导航命令(即在ButtonInfo类中),而是在ElementName中使用Carousel绑定数据模板,用于搜索某个级别并绑定到页面NavigateToPageCommand中定义的DataContext,该页面为ViewModel

这意味着此ViewModel将同时定义ButtonInfoCollectionNavigateToPageCommand -

public ObservableCollection<ButtonInfo> ButtonInfoCollection { get; } = new ObservableCollection<ButtonInfo>
{
    new ButtonInfo { MenuName = "New Menu", PageType = typeof(BlankPage1), Symbol = "/Assets/StoreLogo.png" }
};

public DelegateCommand<Type> NavigateToPageCommand { get; } = new DelegateCommand<Type>(type => 
    App.Frame.Navigate(type));

我希望这一切都有道理。祝你好运!

答案 1 :(得分:0)

好的,对Dilmah来说,它始终可以在任何itemTemplate中构建可重用的用户控件。而且我会告诉你现在和现在的情况。

我已经提出了两个解决方案,在阅读了很多关于数据绑定{x:Bind}和{Binding}标记之后,我在寻找它的第一个解决方案,我能够学习如何创建一个可重用的UserControlTemplate < / p>

解决方案1 ​​

首先,我将向您展示如何使用carusel控件创建导航菜单,该控件可以在nuget包中找到.Microsoft.Toolkit.Uwp.UI.Control

所以现在这是我的MainMenuPage引用carusel控件的代码:

<toolkitcontrols:Carousel x:Name="NavigationMenuCarouselPanel"
                                      HorizontalAlignment="Center"
                                      VerticalAlignment="Center"
                                      Orientation="Horizontal"
                                      ItemsSource="{x:Bind ViewModel.NavMenuButtonVMs}"
                                      ItemMargin="25"
                                      ItemDepth="160"
                                      ItemRotationX="180"
                                      ItemRotationY="25"
                                      ItemRotationZ="0"
                                      SelectedIndex="0"
                                      Grid.Row="1">
                <toolkitcontrols:Carousel.EasingFunction>
                    <CubicEase EasingMode="EaseOut"/>
                </toolkitcontrols:Carousel.EasingFunction>
                <toolkitcontrols:Carousel.ItemTemplate>
                    <DataTemplate>
                        <usercontrolvm:NavigationMenuButtonTemplate/>
                    </DataTemplate>
                </toolkitcontrols:Carousel.ItemTemplate>                 
            </toolkitcontrols:Carousel>

这段代码的重要部分是ItemSource属性,它是x:绑定到我的NavMenuButtonVms ObservableCollection,以及我的Usercontrol,它包含了Carousel.ItemTemplate和DataTemplate标签,这将使我们能够重用我们的代码并创建一个我们列表中的N个控件。

接下来是我的MainMenuPage的ViewModel:

public class MainMenuPageViewModel : Mvvm.ViewModelBase
{
    ObservableCollection<NavigationMenuButtonTemplateViewModel> _NavMenuButtonVMs = default(ObservableCollection<NavigationMenuButtonTemplateViewModel>);

    public MainMenuPageViewModel()
    {
        Shell.HamburgerMenu.IsFullScreen = false;
        NavMenuButtonVMs = GetNavMenuButtonInfo();
    }

    public string Title => GetLocalizeString("MainMenuPageViewModelTitle");
    public ObservableCollection<NavigationMenuButtonTemplateViewModel> NavMenuButtonVMs
    {
        get { return _NavMenuButtonVMs; }
        private set { Set(ref _NavMenuButtonVMs, value); }
    }

    public override Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary<string, object> state)
    {
        NavigationService.ClearHistory();
        return base.OnNavigatedToAsync(parameter, mode, state);
    }    
}

正如您所看到的,我在构造函数中初始化了我的ObservableCollection。 方法GetNavMenuButton()是Helpers命名空间中的静态类,但是我将向您展示代码,以便您可以了解如何为列表设定种子,您也可以注意到我没有调用静态类因为我使用C#6.0语法,你可以在你的类中直接调用静态方法。

你可以为静态类添加一个using语句,如下所示:

using static Ceneam.Helpers.NavigationMenuButtonViewModelHelper;

此语句允许您使用如下静态方法:

GetNavMenuButtonInfo();

而不是:

NavigationMenuButtonViewModelHelper.GetNavMenuButtonInfo(); 

如果您不理解我的代码,我会解释这一点。

然后我将创建我的usercontrol,我将向您展示xaml,xaml.cs以及viewmodel。 注意usercontrol上的绑定标记,因为你必须使用x:在可重用的用户控件中绑定来退出。

这是我的NavigationMenuButtonTemplate.xaml

<UserControl
x:Class="Ceneam.UserControlViews.NavigationMenuButtonTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Ceneam.UserControlViews"
xmlns:vm="using:Ceneam.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="400"
d:DesignWidth="400">

<Grid VerticalAlignment="Center"
      HorizontalAlignment="Center">        
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>

    <Button x:Name="NavigationMenuTemplate"
            Command="{Binding NavigateToPageCommand, Mode=OneWay}">
        <Grid x:Name="ButtonLayout">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <Image x:Name="NavigationMenuIconImage"
                   Source="{Binding ButtonInfo.Symbol, Mode=OneWay, FallbackValue='ms-appx:///Assets/AssetsMainMenuPage/OverTimeMoneyWhite256x256.png'}"
                   PointerEntered="NavigationMenuIconImage_PointerEntered"/>
            <TextBlock x:Name="NavigationMenuButtonNameTextBlock"
                       Text="{Binding ButtonInfo.MenuName, Mode=OneWay, FallbackValue='JORNADAS EXTRAORDINARIAS'}"/>
            <TextBlock x:Name="NavigationMenuButtonBenefitKindTextBlock"
                       Text="{Binding ButtonInfo.BenefitKind, Mode=OneWay, FallbackValue='Subscripción'}"/>
            <TextBlock x:Name="NavigationMenuButtonStatusTextBlock"
                       Text="{Binding ButtonInfo.Status, Mode=OneWay, FallbackValue='Vigente'}"/>
        </Grid>            
    </Button>
</Grid>

你可以看到我只使用绑定标记,原因是我使用了一个带有参数的viewmodel,我必须创建一个依赖于我的usercontrol:

public class NavigationMenuButtonTemplateViewModel : Mvvm.ViewModelBase
{
    ButtonInfo _ButtonInfo = default(ButtonInfo);

    public NavigationMenuButtonTemplateViewModel() { }
    public NavigationMenuButtonTemplateViewModel(ButtonInfo buttonInfo)
    {
        ButtonInfo = new ButtonInfo
        {
            BenefitKind = buttonInfo.BenefitKind,
            Status = buttonInfo.Status,
            MenuName = buttonInfo.MenuName,
            Symbol = buttonInfo.Symbol
        };
    }

    public ButtonInfo ButtonInfo
    {
        get { return _ButtonInfo; }
        set { Set(ref _ButtonInfo, value); }
    }

    public DelegateCommand NavigateToPageCommand => new DelegateCommand(async () => { await ExecuteNavigateToPageCommand(); });

    private async Task ExecuteNavigateToPageCommand()
    {
        var message = new MessageDialog("Test");
        await message.ShowAsync();
    }
}

因为你在viewmodel中创建了一个带有参数的构造函数,所以我无法使用该构造函数创建一个强类型绑定,这是让我留下x:bind标记为我的usercontrol的主要原因,这意味着你不能使用x :绑定事件的方法。您必须在usercontrol的xaml.cs文件中使用样式方法。

如果你在xaml中声明如下:

<UserControl.DataContext>
    <vm:usercontrol x:Name=ViewModel/>
<UserControl.DataContext>

它总会触发你的无参数构造函数去除你的初始值甚至更糟糕的获得NullReferenceExceptions,你也可以使用DataContext for DesignTime Data,但它必须在你文件的开头声明,我不会在这里居中。

最后在我的静态类中,我创建了我的UC(usercontrol),其中包含一个参数,这是我的静态类:

public static class NavigationMenuButtonViewModelHelper
{
    public static ObservableCollection<NavigationMenuButtonTemplateViewModel> GetNavMenuButtonInfo()
    {
        var data = new ObservableCollection<NavigationMenuButtonTemplateViewModel>();
        AddNavMenuButtonItem(data,
            new NavigationMenuButtonTemplateViewModel(new ButtonInfo
            {
                Symbol = @"ms-appx:///Assets/AssetsMainMenuPage/SatSunBonusWhite256x256.png",
                MenuName = "PRIMAS SABATINAS Y DOMINICALES",
                BenefitKind = "Subscripción",
                Status = "Vigente"
            }));
        AddNavMenuButtonItem(data,
            new NavigationMenuButtonTemplateViewModel(new ButtonInfo
            {
                Symbol = @"ms-appx:///Assets/AssetsMainMenuPage/OverTimeMoneyWhite256x256.png",
                MenuName = "JORNADAS EXTRAORDINARIAS",
                BenefitKind = "Subscripción",
                Status = "Vigente"
            }));
        AddNavMenuButtonItem(data,
            new NavigationMenuButtonTemplateViewModel(new ButtonInfo
            {
                Symbol = @"ms-appx:///Assets/AssetsMainMenuPage/VacationBonusWhite256x256.png",
                MenuName = "PRIMA VACACIONAL",
                BenefitKind = "Gratuito",
                Status = "Vigente"
            }));
        AddNavMenuButtonItem(data,
            new NavigationMenuButtonTemplateViewModel(new ButtonInfo
            {
                Symbol = @"ms-appx:///Assets/AssetsMainMenuPage/PecoWhite256x256.png",
                MenuName = "PERMISOS ECONOMICOS",
                BenefitKind = "Gratuito",
                Status = "Vigente"
            }));
        AddNavMenuButtonItem(data,
            new NavigationMenuButtonTemplateViewModel(new ButtonInfo
            {
                Symbol = @"ms-appx:///Assets/AssetsMainMenuPage/PunctualityBonusWhite256x256.png",
                MenuName = "INCENTIVO PUNTUALIDAD Y ASISTENCIA",
                BenefitKind = "Gratuito",
                Status = "Vigente"
            }));
        AddNavMenuButtonItem(data,
            new NavigationMenuButtonTemplateViewModel(new ButtonInfo
            {
                Symbol = @"ms-appx:///Assets/AssetsMainMenuPage/BonForSeniorityWhite256x256.png",
                MenuName = "BONO DE ANTIGUEDAD",
                BenefitKind = "Gratuito",
                Status = "Vigente"
            }));
        AddNavMenuButtonItem(data,
            new NavigationMenuButtonTemplateViewModel(new ButtonInfo
            {
                Symbol = @"ms-appx:///Assets/AssetsMainMenuPage/WageIncreaseWhite256x256.png",
                MenuName = "RETROACTIVO SUELDO",
                BenefitKind = "Gratuito",
                Status = "Vigente"
            }));

        return data;
    }

    private static void AddNavMenuButtonItem(ObservableCollection<NavigationMenuButtonTemplateViewModel> data, NavigationMenuButtonTemplateViewModel item)
    {
        data.Add(item);
    }
}

如果您希望以编程方式设置属性,则应该在xaml.cs中执行此操作,例如像这样:

public sealed partial class NavigationMenuButtonTemplate : UserControl
{
    public NavigationMenuButtonTemplate()
    {
        this.InitializeComponent();
    }

    private void NavigationMenuIconImage_PointerEntered(object sender, PointerRoutedEventArgs e)
    {
        var image = (Image)sender;
        var bitmapImage = image.Source as BitmapImage;
        var uri = bitmapImage?.UriSource;
        var uriPath = uri?.AbsolutePath;
        var newUriPath = $@"ms-appx://{uriPath.Replace("White", "Black")}";
        image.Source = new BitmapImage(new Uri(newUriPath, UriKind.RelativeOrAbsolute));
    }
}

**解决方案2:** 另一种解决方案可能是使用具有依赖属性的usercontrols,如下所示:

<toolkitcontrols:Carousel x:Name="NavigationMenuCarouselPanel"
                                      HorizontalAlignment="Center"
                                      VerticalAlignment="Center"
                                      Orientation="Horizontal"
                                      ItemSource="{x:Bind ViewModel.MenuList}"
                                      ItemMargin="25"
                                      ItemDepth="160"
                                      ItemRotationX="180"
                                      ItemRotationY="25"
                                      ItemRotationZ="0"
                                      SelectedIndex="0"
                                      Grid.Row="1">
                <toolkitcontrols:Carousel.EasingFunction>
                    <CubicEase EasingMode="EaseOut"/>
                </toolkitcontrols:Carousel.EasingFunction>                   
                <usercontrolvm:NavigationMenuButtonTemplate ButtonInfo="{x:Bind ViewModel.MenuList[0],Mode=OneWay}"

NavigateToPageCommand =&#34; {x:绑定ViewModel.NavigateToPageCommand}&#34; /&gt;                                                                                

您必须使用以下属性创建一个NavigationMenuButtonTemplate.xaml.cs:

public sealed partial class NavigationMenuButtonTemplate : UserControl
{
    public NavigationMenuButtonTemplate()
    {
        this.InitializeComponent();
    }

    public DelegateCommand NavigateToPageCommand
    {
        get { return (DelegateCommand)GetValue(NavigateToPageCommandProperty); }
        set { SetValue(NavigateToPageCommandProperty, value); }
    }

    // Using a DependencyProperty as the backing store for NavigateToPageCommand.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty NavigateToPageCommandProperty =
        DependencyProperty.Register("NavigateToPageCommand", 
            typeof(DelegateCommand), 
            typeof(NavigationMenuButtonTemplate), 
            new PropertyMetadata(0));

    public ButtonInfo ButtonInfo
    {
        get { return (ButtonInfo)GetValue(ButtonInfoProperty); }
        set { SetValue(ButtonInfoProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ButtonInfo.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ButtonInfoProperty =
        DependencyProperty.Register("ButtonInfo", 
            typeof(ButtonInfo), 
            typeof(NavigationMenuButtonTemplate), 
            new PropertyMetadata(0));        
}

我不喜欢这个解决方案,因为我必须在xaml文件中重复代码,但它也是一个不错的选择。

希望你喜欢我的回答我认为它可以被我们许多人使用,并且可以用你的想象力来应用于许多其他控件。