我正在尝试在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='‘'}"
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>
请有人帮助我,并指出我正确的方向。 我错过了什么?
答案 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
将同时定义ButtonInfoCollection
和NavigateToPageCommand
-
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文件中重复代码,但它也是一个不错的选择。
希望你喜欢我的回答我认为它可以被我们许多人使用,并且可以用你的想象力来应用于许多其他控件。