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

Enr*_*elo 2 c# data-binding user-controls uwp uwp-xaml

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

\n\n

我可以通过这样做来做到这一点:

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

如果我这样做,我将添加 5 个以上的按钮,并且我必须为每个按钮编写属性。

\n\n

因此,我想使用 UserControl 并编写如下内容:

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

但我没能做到这一点,我找到了一些教程,但据我所知,所有这些都会让我写出这样的代码:

\n\n
<usercontrolvm:NavigationMenuButtonTemplate NavigateToPageCommand="{Binding NavigateToPageCommand}"/>\n
Run Code Online (Sandbox Code Playgroud)\n\n

大约 6 次,我不知道如何将 DataTemplate 的 x:DataType 作为我的属性列表。

\n\n

这是我的 UserControl.xaml.cs

\n\n
public sealed partial class NavigationMenuButtonTemplate : UserControl\n{\n    public ButtonInfo ButtonInfo => (DataContext as ButtonInfo);\n\n    public NavigationMenuButtonTemplate()\n    {\n        this.InitializeComponent();\n        Loaded += NavigationMenuButtonTemplate_Loaded;\n    }\n\n    private void NavigationMenuButtonTemplate_Loaded(object sender, RoutedEventArgs e)\n    {\n        Bindings.Update();\n    }\n\n    public DelegateCommand NavigateToPageCommand\n    {\n        get { return (DelegateCommand)GetValue(NavigateToPageCommandProperty); }\n        set { SetValue(NavigateToPageCommandProperty, value); }\n    }\n\n    // Using a DependencyProperty as the backing store for NavigateToPageCommand.  This enables animation, styling, binding, etc...\n    public static readonly DependencyProperty NavigateToPageCommandProperty =\n        DependencyProperty.Register("NavigateToPageCommand", \n            typeof(DelegateCommand), \n            typeof(NavigationMenuButtonTemplate), \n            new PropertyMetadata(0));\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是我的 ButtonInfo.cs

\n\n
public class ButtonInfo\n{\n    public string Symbol { get; set; }\n    public string FontFamily { get; set; }\n    public string MenuName { get; set; }\n    public string BenefitKind { get; set; }\n    public string Status { get; set; }        \n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是我的 UserControl.xaml

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

有人可以帮助我并指出正确的方向吗?\n我错过了什么?

\n

Jus*_* XL 5

你的问题中的方法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>
Run Code Online (Sandbox Code Playgroud)

考虑到上面的结构,您只需将这些属性公开为用户控件中的依赖属性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>
Run Code Online (Sandbox Code Playgroud)

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"));
        }));
}
Run Code Online (Sandbox Code Playgroud)

请注意,您需要在类PageType中包含一个属性ButtonInfo以用于导航目的。

public Type PageType { get; set; }
Run Code Online (Sandbox Code Playgroud)

我个人不喜欢在项目级别(即在类中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));
Run Code Online (Sandbox Code Playgroud)

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