首页 > 解决方案 > Xamarin 基于同一 Grid.Row 中的多个绑定属性在 Grid 内设置按钮的 IsVisible 而不编辑原始模型

问题描述

我有一个可以出现在网格的每一行中的按钮。
如果“行”中的任何绑定属性为空,我需要隐藏按钮。
这是使用 MVVM 模式,因此 ViewModel 具有 ObservableCollection。

非常简化的例子:

public class TestClass
{
    public int? Prop1 { get; set; }
    public int? Prop2 { get; set; }
}

public class TestViewModel
{
    private ObservableCollection<TestClass> _TestClasses;
    public ObservableCollection<TestClass> TestClasses
    {
        get { return _TestClasses; }
        set { _TestClasses = value; OnPropertyChanged(nameof(TestClasses)); }
    }

    // LOAD TEST DATA IN CONSTRUCTOR
    public TestViewModel()
    {
        var testClasses = new List<TestClass>();
        testClasses.Add(new TestClass { Prop1 = 1, Prop2 = 1 };
        testClasses.Add(new TestClass { Prop1 = 2, Prop2 = null };
        testClasses.Add(new TestClass { Prop1 = null, Prop2 = 2 };

        TestClasses = new ObservableCollection<TestClass>(testClasses);
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        var changed = PropertyChanged;
        if (changed == null)
            return;

        changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class NullBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value == null ? false : true;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

当“Prop1”为空时,以下 XAML 将隐藏按钮,但如果“EITHER”Prop1 或 Prop2 为空,我需要隐藏按钮。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:converters="clr-namespace:TestProject.Converters"
             x:Class="TestProject">

    <ContentPage.Resources>
        <ResourceDictionary>
            <converters:NullBooleanConverter x:Key="NullBooleanConverter"/>
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout>
        <ListView ItemsSource="{Binding TestClasses}" 
                  SelectionMode="Single"
                  HasUnevenRows="True" >
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout>
                            <Grid>

                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                </Grid.RowDefinitions>

                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>

                                <StackLayout Grid.Column="0">
                                    <Label Text="{Binding Prop1}"/>                                    
                                </StackLayout>

                                <StackLayout Grid.Column="1">
                                    <Label Text="{Binding Prop2}"/>                                    
                                </StackLayout>

                                <StackLayout Grid.Column="2">
                                    <Button Text="Do Something" 
                                            IsVisible="{Binding Path=Prop1, Converter={StaticResource NullBooleanConverter}}" />
                                </StackLayout>

                            </Grid>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>

</ContentPage>

更新 1
我无法编辑原始模型,因为它位于其他几个项目中使用的共享库中。
我可以创建模型的部分类,但似乎过于复杂,因为在我们所有其他项目中,这在 UI 中或使用 IMultiValueConverter 很容易实现,但在 Xamarin 中不支持。

更新 2
我在 NullBooleanConverter 中找到了一种“hack”方法。

public class NullBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is TestClass)
        {
            TestClass testClass = (TestClass)value;

            if (testClass.Prop1 == null || testClass.Prop2 == null)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        else
        {
            return value;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

标签: xamarin.forms

解决方案


您还可以将属性IsVisible绑定到 ViewModel

<StackLayout Grid.Column="2">
   <Button Text="Do Something" 
           IsVisible="{Binding isVisible}" />
</StackLayout>

在模型

public class TestClass
{
  public string? Prop1 { get; set; }
  public string? Prop2 { get; set; }      
  public bool isVisible { get; private set; }

  public TestClass(string? p1,string?p2)
  {
      if(p1==null||p2==null)
      {
        isVisible = false;
      }
      else
      {
        isVisible = true;
      }
  }

}

在 ViewModel 中

var testClasses = new List<TestClass>();
testClasses.Add(new TestClass("1","1") );
testClasses.Add(new TestClass(null,"2") );
testClasses.Add(new TestClass("1",null));
TestClasses = new ObservableCollection<TestClass>(testClasses);

另外,文本的类型是 string 而不是 int 。

更新:

我认为你的方式是明智的(不是黑客方式)。你只需要设置

<Button Text="Do Something" IsVisible="{Binding , Converter={StaticResource NullBooleanConverter}}" />

否则,您也可以创建Button的子类并定义两个BindableProperties,然后将它们绑定到Prop1Prop2。它会很复杂,我不建议你选择它。


推荐阅读