具有Bindable属性的自定义视图在Xamarin.Forms SAP上无法正确绑定

时间:2015-07-30 15:07:04

标签: c# mvvm xamarin xamarin.forms shared-project

我有一个复选框,它应该触发按钮的IsEnabled事件。但不知何故,应该这样做的命令永远不会被正确绑定并因此被执行。

这是CheckBox.xaml.cs(控件)中的可绑定属性:

// PART DEFINITION
ContentDefinitionManager.AlterPartDefinition("ProductPart", p => p

.WithDescription("Product part")

    // To select other contents ( on this example "ProductPresentation" content type )
.WithField("ProductPresentation", f => f
    .OfType("ContentPickerField")
    .WithDisplayName("Product presentation")
    .WithSetting("ContentPickerFieldSettings.Required", "True")
    .WithSetting("ContentPickerFieldSettings.Multiple", "True")
    .WithSetting("ContentPickerFieldSettings.ShowContentTab", "True")
    .WithSetting("ContentPickerFieldSettings.Hint", "Please select product's presentation")
    .WithSetting("ContentPickerFieldSettings.DisplayedContentTypes", "ProductPresentation")
)

// To select images
.WithField("ProductImageField", f => f
    .OfType("MediaLibraryPickerField")
    .WithDisplayName("Product image")
    .WithSetting("MediaLibraryPickerFieldSettings.Hint", "Please select product's image")
    .WithSetting("MediaLibraryPickerFieldSettings.Required", "True")
    .WithSetting("MediaLibraryPickerFieldSettings.Multiple", "False")

)

// To add a taxonomy field called "ProductLines"
.WithField("Category", fcfg => fcfg
    .OfType("TaxonomyField")
    .WithDisplayName("Category")
    .WithSetting("TaxonomyFieldSettings.Taxonomy", "ProductLines")
    .WithSetting("TaxonomyFieldSettings.LeavesOnly", "True")
    .WithSetting("TaxonomyFieldSettings.Required", "True")
    .WithSetting("TaxonomyFieldSettings.SingleChoice", "False")
    .WithSetting("TaxonomyFieldSettings.Autocomplete", "False")
    .WithSetting("TaxonomyFieldSettings.AllowCustomTerms", "False")
    .WithSetting("TaxonomyFieldSettings.Hint", "Please select product's category")
    )

.Attachable()
);


// CONTENT TYPE DEFINITION
ContentDefinitionManager.AlterTypeDefinition("Product", cfg => cfg
                .DisplayedAs("Product")
                .WithPart(
                    "CommonPart", c => c
                        .WithSetting("DateEditorSettings.ShowDateEditor", "False")
                        .WithSetting("OwnerEditorSettings.ShowOwnerEditor", "False")
                    )
                    .WithPart("ProductPart")
                    .WithPart("TitlePart", c => c.WithSetting("Hint", "Please enter the product name"))
                    .WithPart("BodyPart", c => c.WithSetting("Hint", "Please enter the product description"))
                    .WithPart("LocalizationPart")

                    .WithPart("AutoroutePart", partBuilder => partBuilder
                    .WithSetting("AutorouteSettings.AllowCustomPattern", "true")
                    .WithSetting("AutorouteSettings.AutomaticAdjustmentOnEdit", "true")
                    .WithSetting("AutorouteSettings.PatternDefinitions", "[{Name:'Product Title', Pattern: 'product/{Content.Slug}', Description: 'product/title-product'}]"))

                .Listable()
                .Draftable()
                .Creatable()
                .Securable()
                .Indexed()
                );

这就是我在ViewModel上的内容:

public static readonly BindableProperty CheckBoxCommandProperty =
       BindableProperty.Create<CheckBox, ICommand>(
       checkbox =>
           checkbox.CheckBoxCommand,
           null,
           propertyChanged: (bindable, oldValue, newValue) =>
               {
                   CheckBox checkbox = (CheckBox)bindable;
                   EventHandler<bool> eventHandler = checkbox.CheckedChanged;
                   if (eventHandler != null)
                   {
                       eventHandler(checkbox, checkbox.IsChecked);
                   }
               });

   public event EventHandler<bool> CheckedChanged;

   public ICommand CheckBoxCommand
   {
       get { return (ICommand)GetValue(CheckBoxCommandProperty); }
       set { SetValue(CheckBoxCommandProperty, value); }
   }

CheckBoxTapped方法永远不会被执行,因此我想要设置的按钮属性永远不会改变。

先谢谢大家!

2 个答案:

答案 0 :(得分:2)

您可以做的是将此问题的解决方案分为几个级别:

首先,为复选框创建一个可绑定属性,并将其命名为Checked。 我已经为它写了一个snippit,但没有真正编译它所以你可能想修改它,如果它不起作用

  public static readonly BindableProperty IsCheckedProperty = 
    BindableProperty.Create<CheckBox, bool> (w => w.IsChecked, false);

  public bool IsChecked{
    get { return GetValue (FooProperty); }
    set { SetValue (FooProperty, value); } 
  }

其次,在视图模型中创建一个具有更改通知的bool属性

private bool _isChecked;
public bool IsChecked
{
    get 
    { 
        return _isChecked;
    }
    set
    {
        _isChecked = value;
        RaisePropertyChanged("IsChecked");
    }
} 

第三步,将复选框“isChecked”的可绑定属性绑定到xaml视图模型中的属性:

<StackLayout>
    <Checkbox IsChecked = "{Binding IsChecked}"/>
</StackLayout>

第四,Xaml与MVVM中的按钮绑定命令。在这些命令中,有一个bool属性代表“CanExecute”,它基本上启用或禁用按钮。所以你在Xaml中要做的就是将按钮的命令绑定到View Model中的命令(让我们称之为ClickCommand)。 ClickCommand的CanExecute实际上只是一个返回“IsChecked”值的方法。 这将使我们修改“IsChecked”属性的setter,因此每次更改时都应该通知命令检查CanExecute属性。

所以最终的代码将是

public TermsAndConditionsViewModel()
   {
       NextCommand = new Command(ExecuteNextCommand,CanExecuteNextCommand);
       OnCheckBoxTapChanged = new Command(CheckBoxTapped);
   }


private bool _isChecked;
public bool IsChecked
{
    get { return _isChecked;}
    set
    {
         _isChecked = value;
    NextCommand.ChangeCanExecute(); //this will actually notify the command to enable/disable
        RaisePropertyChanged("IsChecked");
    }
}


public Command NextCommand {get;set;} // this type is available in Xamarin.Forms library
private bool CanExecuteNextCommand()
{
    return IsChecked;
}
private void ExecuteNextCommand()
{
    // your execution when the button is pressed    
}

而Xaml就像

<StackLayout>
    <Checkbox IsChecked = "{Binding IsChecked}"/>
    <Button Text= "Next" Command = "{Binding NextCommand}"/>
</StackLayout> 

答案 1 :(得分:1)

使用Xamarin.Forms.Behavior解决它。它允许多个绑定到控件。

例如&gt;

<Entry Placeholder="Enter password"
             Text= "{Binding TxtFirstPasswordInput}"
             IsPassword="true">
        <b:Interaction.Behaviors>
          <b:BehaviorCollection>
            <b:EventToCommand EventName="Unfocused" Command="{Binding entry_Finished}"/>
            <b:EventToCommand EventName="Focused" Command="{Binding entry_Focused}"/>
          </b:BehaviorCollection>
        </b:Interaction.Behaviors>
      </Entry>

在ViewModel&gt;

public PasswordInputViewModel()
        {
            entry_Finished = new Command(validateAndContinue);//unfocused
            entry_Focused = new Command(entryFocused); //focused
        }