语境
我正在try 为我的Xamarin Forms Shell应用程序创建一个可定制、可重复使用的标题视图模板.我所说的"标题视图"指的是出现在页面顶部的标题栏.I've mostly implemented it, but I'm struggling to make some bindings work.个
这个 idea 很简单.我想要以如下形式结束,一个非常标准的标题栏模板,我可以在其中逐页填充空白:
我希望在我的ContentPages
个人中的任何一个人都能像这样创造它.我已经对它进行了修改,这样我只需要告诉按钮它们的图像源和命令是什么,其余的将为我格式化:
<ContentPage
x:DataType="viewmodels:MyViewModel"
... >
<Shell.TitleView>
<tv:CustomAppShellTitleView>
<tv:CustomAppShellTitleView.LeftButton>
<tv:标题查看按钮信息 Command="{Binding SomeCommandHere}" Source="{StaticResource SomeIconHere}" />
</tv:CustomAppShellTitleView.LeftButton>
<tv:CustomAppShellTitleView.Title>SomeTitle</tv:CustomAppShellTitleView.Title>
<tv:CustomAppShellTitleView.RightButton1>
<tv:标题查看按钮信息 Command="{Binding SomeCommandHere}" Source="{StaticResource SomeIconHere}" />
</tv:CustomAppShellTitleView.RightButton1>
<tv:CustomAppShellTitleView.RightButton2>
<tv:标题查看按钮信息 Command="{Binding SomeCommandHere}" Source="{StaticResource SomeIconHere}" />
</tv:CustomAppShellTitleView.RightButton2>
<tv:CustomAppShellTitleView.RightButton3>
<tv:标题查看按钮信息 Command="{Binding SomeCommandHere}" Source="{StaticResource SomeIconHere}" />
</tv:CustomAppShellTitleView.RightButton3>
</tv:CustomAppShellTitleView>
</Shell.TitleView>
...
我所有的ContentPages
个人都使用视图模型,我想使用其中的数据来配置标题栏行为(例如,按钮命令、可视化等).
标题查看按钮信息
你会注意到我用了一个叫做标题查看按钮信息
的东西.我想既然我有4个可能的按钮,我可以通过将它们的可绑定属性放在一个漂亮的小对象中来减少代码重复,如下所示:
using System.Windows.Input;
using Xamarin.Forms;
namespace MyNamespace.Views.TitleViews
{
public class 标题查看按钮信息 : BindableObject
{
public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(标题查看按钮信息), default(ICommand));
public ICommand Command
{
get => (ICommand)GetValue(CommandProperty);
set => SetValue(CommandProperty, value);
}
public static readonly BindableProperty SourceProperty = BindableProperty.Create(nameof(Source), typeof(ImageSource), typeof(标题查看按钮信息), default(ImageSource));
public ImageSource Source
{
get => (ImageSource)GetValue(SourceProperty);
set
{
SetValue(SourceProperty, value);
OnPropertyChanged(nameof(IsVisible));
}
}
public bool IsVisible => Source != null;
}
}
CustomAppShellTitleView
最后,我拿到了我的actual CustomAppShellTitleView
.为简单起见,我将省略右侧的按钮:
XAML
<ContentView
x:Class="MyNamespace.Views.TitleViews.CustomAppShellTitleView"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyNamespace.Views.TitleViews"
x:Name="customAppShellTitleView"
x:DataType="local:CustomAppShellTitleView">
<ContentView.Resources>
<ResourceDictionary>
<x:Double x:Key="ButtonSize">32</x:Double>
</ResourceDictionary>
</ContentView.Resources>
<ContentView.Content>
<Grid
Padding="0,0,10,0"
RowSpacing="0"
VerticalOptions="CenterAndExpand">
<Grid.ColumnDefinitions>
<!-- Left-side Button -->
<ColumnDefinition Width="Auto" />
<!-- Title -->
<ColumnDefinition Width="*" />
<!-- Right-side Buttons -->
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- Left-side Button -->
<ImageButton
Grid.Column="0"
Command="{Binding LeftButton.Command, Source={x:Reference Name=customAppShellTitleView}}"
HeightRequest="{StaticResource ButtonSize}"
HorizontalOptions="Start"
IsVisible="{Binding LeftButton.IsVisible, Source={x:Reference Name=customAppShellTitleView}}"
Source="{Binding LeftButton.Source, Source={x:Reference Name=customAppShellTitleView}}"
WidthRequest="{StaticResource ButtonSize}" />
<!-- Title -->
<Label
Grid.Column="1"
HorizontalOptions="StartAndExpand"
LineBreakMode="TailTruncation"
MaxLines="1"
Text="{Binding Title, Source={x:Reference Name=customAppShellTitleView}}"
VerticalOptions="CenterAndExpand" />
<!-- Right-side Buttons -->
<StackLayout
Grid.Column="2"
Orientation="Horizontal"
Spacing="10">
<!-- Buttons 1, 2 and 3 here -->
</StackLayout>
</Grid>
</ContentView.Content>
</ContentView>
代码隐藏
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace MyNamespace.Views.TitleViews
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CustomAppShellTitleView : ContentView
{
// LeftButton
public static readonly BindableProperty LeftButtonProperty = BindableProperty.Create(
nameof(LeftButton),
typeof(标题查看按钮信息),
typeof(CustomAppShellTitleView),
new 标题查看按钮信息());
public 标题查看按钮信息 LeftButton
{
get => (标题查看按钮信息)GetValue(LeftButtonProperty);
set => SetValue(LeftButtonProperty, value);
}
// Same thing for RightButton1, 2 and 3
#region Title Property
public static readonly BindableProperty TitleProperty = BindableProperty.Create(nameof(Title), typeof(string), typeof(CustomAppShellTitleView), default(string));
public string Title
{
get => (string)GetValue(TitleProperty);
set => SetValue(TitleProperty, value);
}
#endregion
public CustomAppShellTitleView()
{
InitializeComponent();
Binding语境 = this;
}
}
}
问题所在
这种设置似乎在很大程度上是有效的.一切看起来都很好.标题和按钮图像源在运行时被正确设置,主要是因为它们是在我的页面的XAML中设置Shell.TitleView
时的exist的静态值.然而,Bindings才是问题所在.例如,尽管按钮的Command
个属性绑定到我的视图模型中的ICommand
个属性,但按钮在被按下时什么也不做.当我将该命令绑定到我的视图中的常规按钮时,该命令可以很好地工作,因此它不是由于我的XAML和视图模型之间的某些不匹配造成的.
很明显,这里有一些基本的事情我不明白.
我try 过的东西
我在标题查看按钮信息.CommandProperty
和我的视图模型的构造函数中设置了断点,在那里分配命令.由于在将视图模型设置为Binding语境(甚至是现有的)之前对视图进行了初始化,因此这是有意义的--但是一旦视图模型实际设置了CommandProperty
的setter,它就再也不会被击中了.显然,第一次命中时,该值将为空,因为视图模型尚未初始化.因此,即使在我的视图模型中设置了ICommand is,标题视图也听不到它.我试着在绑定的命令上触发OnPropertyChanged
,但没有起作用.
当我的视图模型中的命令被设置时,有没有办法将其设置为hear?肯定有什么明显的地方是我做错了,以至于这个标题视图的属性只能设置为once,不能再设置了.