我希望能够在我的 Xamarin.Forms 应用程序中禁用自定义标头 ContentView 中的按钮,以便在离开包含它的 ContentPage 之前警告用户他们有未保存的数据。
我为包含页面绑定其视图模型的 HeaderView 创建了一个 BindableProperty。我受到这篇文章的启发:将具有绑定属性的自定义控件添加到您的 Xamarin.Forms 应用程序 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 属性的值时,标签将按预期从“true”更改为“false”。然而,这个相同的绑定似乎并没有改变我的自定义标题中的 CanNavigate 值。调试时,OnBackClicked 处理程序始终显示 CanNavigate == true 的值。永远不会输入 propertyChanged 事件 HandleCanNavigatePropertyChanged。如果我应该明确地调用它,我不知道如何。如果我遗漏了什么或使用了错误的方法,我想知道。
编辑 SO中的一些帖子似乎表明将 BindingContext 设置为视图模型可能是问题的一部分。
这是一个这样的例子: ContentView 中的 BindableProperty not working。我不确定应该如何处理视图模型,因为它按预期工作。