【问题标题】:Can I disable a Button in my Xamarin ContentView custom control using a BindableProperty?我可以使用 BindableProperty 在我的 Xamarin ContentView 自定义控件中禁用按钮吗?
【发布时间】:2019-12-16 10:59:03
【问题描述】:

我希望能够在我的 Xamarin.Forms 应用程序中禁用自定义标头 ContentView 中的按钮,以便在离开包含数据的 ContentPage 之前警告用户他们有未保存的数据。

我为包含页面绑定其视图模型的 HeaderView 创建了一个 BindableProperty。我受到这篇文章的启发:Add Custom Controls with Binding Properties to Your Xamarin.Forms App ContentView 的 XAML 在这里

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
             x:Class="HeaderView"
             x:Name="HeaderRoot">


       <Grid RowSpacing="0">
        <Grid.RowDefinitions>
            <RowDefinition Height="80"/>
            <RowDefinition Height="5"/>
        </Grid.RowDefinitions>

        <Grid Grid.Row="0" Padding="20,20,20,0" ColumnSpacing="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="1.3*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

        <StackLayout Grid.Column="0">
                <FlexLayout HorizontalOptions="CenterAndExpand" VerticalOptions="Center">
                   <ImageButton x:Name="BackButton" TranslationY="-20" TranslationX="-20" BackgroundColor="Black"  HeightRequest="80" WidthRequest="80"  Source="angleleft.png" Padding="0,0,0,0" Margin="0,0,0,0" Clicked="OnBackClicked" IsEnabled="{Binding Source={x:Reference HeaderRoot}, Path=BindingContext.IsEnabled}" />
                </FlexLayout>
        </StackLayout>

        <FlexLayout Grid.Column="1" JustifyContent="Center" AlignItems="Center">
               <FlexLayout.TranslationY>
                <OnPlatform x:TypeArguments="x:Double">
                    <On Platform="Android" Value="-15"/>
                    <On Platform="iOS" Value="0"/>
                </OnPlatform>
            </FlexLayout.TranslationY>
           <Label x:Name="TitleLabel" FontFamily="{StaticResource TitleFont}" TextColor="White" FontSize="50" />
        </FlexLayout>

           </Grid>
    </Grid>
</ContentView>

ContentView 的相关代码在这里

    public partial class HeaderView : ContentView
    {
        public HeaderView()
        {
            InitializeComponent();

            if (DesignMode.IsDesignModeEnabled)
                return; // Avoid rendering exception in the editor.

            //Argument is null because the Header does not need navigation information.
            BindingContext = new HeaderViewModel(null);
        }
        public static BindableProperty CanNavigateProperty = 
                                 BindableProperty.Create(
            propertyName: "CanNavigate",
            returnType: typeof(bool),
            declaringType: typeof(HeaderView),
            defaultValue: true,
            defaultBindingMode: BindingMode.TwoWay,
            propertyChanged: HandleCanNavigatePropertyChanged);

        private static void HandleCanNavigatePropertyChanged(
            BindableObject bindable, 
            object oldValue, 
            object newValue)
        {
            HeaderView targetView = (HeaderView)bindable;

            if (targetView != null)
                targetView.BackButton.IsEnabled = (bool)newValue;
        }

//...

        public bool CanNavigate
        {
            get
            {
                return (bool)base.GetValue(CanNavigateProperty);
            }
            set
            {
                if(this.CanNavigate != value)
                {
                    base.SetValue(CanNavigateProperty, value);
                }
            }
        }


        protected void OnBackClicked(object sender, EventArgs e)
        {
            if (CanNavigate)
            {
                this.Navigation.PopAsync();
            }
        }

    }

编辑。 视图模型非常简单。

    public class HeaderViewModel : ViewModelBase
    {
        public HeaderViewModel(INavigationService navigationService)
            : base(navigationService)
        {
            UserDTO dto = (Prism.PrismApplicationBase.Current as App).CurrentUser;
            UserName = string.Format("{0} {1}", dto.FirstName, dto.LastName);
        }

        private string userName;
        public string UserName 
        { 
            get
            {
                return userName; 
            }
            set
            {
                    SetProperty<string>(ref userName, value);
            }
        }
    }

然后我在包含页面中有以下标记

<mdaViews:HeaderView CanNavigate="{Binding IsSaved}" Title="COLLECTIONS" Grid.Row="0" />

我已验证 IsSaved 属性确实改变了它的值。绑定在标签文本中使用时有效。

当我更改 IsSaved 属性的值时,Label 会按预期从“true”变为“false”。然而,这个相同的绑定似乎并没有改变我的自定义标题中的 CanNavigate 值。调试时,OnBackClicked 处理程序始终显示 CanNavigate == true 的值。永远不会输入 propertyChanged 事件 HandleCanNavigatePropertyChanged。如果我应该明确地调用它,我不知道如何。如果我遗漏了什么或使用了错误的方法,我想知道。

编辑 SO 中的一些帖子似乎暗示将 BindingContext 设置为视图模型可能是问题的一部分。

这是一个例子: BindableProperty in ContentView not working。我不确定应该如何处理视图模型,因为它按预期工作。

【问题讨论】:

  • 您好,不是太了解。如果要启用按钮,应将启用属性设置为按钮,但在 ContentView 中看不到按钮。
  • @JuniorJiang-MSFT 我为 HeaderView 添加了 XAML。带有 x:Name="BackButton" 的 ImageButton 是我试图动态禁用的。
  • 感谢更新,我会检查的。

标签: xamarin mvvm data-binding bindable bindableproperty


【解决方案1】:

我在评论中找到了答案,“使用 ContentView 的页面设置了它的 BindingContext,然后它将用于所有子元素,包括自定义 ContentView。如果您再次在内容视图中设置上下文,您将覆盖它。” @Krumelur,他正在回复这个答案https://stackoverflow.com/a/39989721/117995

当我在我的 ContentView 中设置 BindingContext 时,我覆盖了父页面中所有可用的内容。为了解决这个问题,我将所有 ViewModel 处理移到后面的代码中,并删除了我设置 BindingContext 的代码。

【讨论】:

    猜你喜欢
    • 2018-10-21
    • 2013-05-25
    • 2018-03-03
    • 2020-01-30
    • 1970-01-01
    • 2012-11-26
    • 1970-01-01
    • 1970-01-01
    • 2013-03-08
    相关资源
    最近更新 更多