语境

我正在try 为我的Xamarin Forms Shell应用程序创建一个可定制、可重复使用的标题视图模板.我所说的"标题视图"指的是出现在页面顶部的标题栏.I've mostly implemented it, but I'm struggling to make some bindings work.

这个 idea 很简单.我想要以如下形式结束,一个非常标准的标题栏模板,我可以在其中逐页填充空白:

enter image description here

我希望在我的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,不能再设置了.

推荐答案

TitleViewButtonInfo的BindingContext不是该页的ViewModel.因此,您可以为其设置绑定源.请考虑以下代码:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
         ...
         x:Name="this">

<Shell.TitleView>
    <tv:CustomAppShellTitleView>
        <tv:CustomAppShellTitleView.LeftButton>
            <tv:TitleViewButtonInfo Command="{Binding BindingContext.LeftButtonCommand,Source={x:Reference this}}" ... />
        </tv:CustomAppShellTitleView.LeftButton>

希望它能起作用.

Csharp相关问答推荐

如何打印已添加到List的Linq值,而不是C#中的:System.Collections.Generic.List ' 1[System.Int32]?

PredicateBuilder不是循环工作,而是手动工作

如何从泛型方法返回一个可为空的T,其中T:notnull?

一种安全的方式来存储SSH凭证(MAUI/C#应用程序)

最新的Mediatr和具有同步方法的处理程序Handle:并非所有代码路径都返回值"

使用可信第三方的Iext8.Net pdf签名

如何在实体框架中添加包含列表?

C#阻塞调用或await calling inside calling方法

如何在ASP.NET Core8中启用REST应用程序的序列化?

当试图限制EF Select 的列时,如何避免重复代码?

如果是,我怎么才能让这个加75,如果不是,我怎么才能减go 100?

从Base64转换为不同的字符串返回相同的结果

try 创建一个C#程序,该程序使用自动实现的属性、覆盖ToString()并使用子类

Xamarin.Forms-如何创建可 Select 的显示alert 或弹出窗口?

当`JToken?`为空时?

WPF:如何从DatagridHeader的内容模板绑定到词典项

如何对正方形格线进行对角分组

C#LINQ多行条件

自定义ConsoleForMatter中的DI/Http上下文

使用';UnityEngineering.Random.Range()';的IF语句仅适用于极高的最大值