Xamarin MultiBinding 需要更高祖先级别的 BindingContext 或 XAML 树中的命名项

Xamarin MultiBinding Needs BindingContext from higher ancestor level or named Items in XAML tree

我正在构建一个由同类按钮组成的矩形网格,其中包含要在运行时设置的动态行和列。代码在 Xamarin 中。所有最新版本等。 整个项目可以在这里下载:https://github.com/BicycleMark/XamSweeper 我遇到的问题是 XAML 的多绑定部分。任何评论或建议都会非常好

我使用 Nested StackPanels 创建了这样的网格:

我成功地创建了一个 MultiValueConverter 用于调整大小 正确显示的按钮。我已经用单元测试测试了转换器,它按预期运行。 [R,C] 打印在每个按钮的测试中。这些是从正确绑定的模型中提取的

我遇到的问题是将 MultiBinding 链接到 3 个项目,我需要计算按钮的大小:

每个Button的宽度是用这三个参数计算出来的

  1. 按住按钮的框架的实际宽度
  2. 模型按钮的 列数
  3. 每个按钮之间的间距或填充
  4. 如果任何 [1..3] 为空 return 50 <--- 这就是我 return 因为我的绑定不起作用

每个Button的高度是用这三个参数计算出来的

  1. 按住按钮的框架的实际高度
  2. 模型按钮的行数
  3. 每个按钮之间的间距或填充
  4. 如果任何 [1..3] 为空 return 50 <--- 这就是我 return 因为我的绑定不起作用

这是描述的转换器:

    public class SizeConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values == null || values.Length <3 || values[2] == null || values[1] == null || values[0] == null)
            return 50;
        int numItems = (int)values[2];
        int separatorSize = (int)values[1]; 
        double frameSize = System.Convert.ToDouble(values[0]) ;
        
        int totalSeparatorSize = (numItems - 1) * separatorSize;
        int remainingArea = System.Convert.ToInt32(frameSize) - totalSeparatorSize;
        return remainingArea / numItems;
    }
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

及其通过的单元测试:

 [DataRow(100, 2, 4)]
    [DataTestMethod]
    public void Test_Piece_Sizing(double frameSize, int separatorSize, int numItems)
    {
        var sizeConverter = new SizeConverter();
        object[] values = new object[] { frameSize, separatorSize, numItems };
        Assert.AreNotEqual(0,sizeConverter.Convert(values, typeof(int), null, System.Globalization.CultureInfo.CurrentCulture));
    }

手头的问题是当我在 Xamarin 中绑定我的值时,我的转换器从我的 XAML 中获取 Null 这是 XAML

    <?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:prism="http://prismlibrary.com"
    prism:ViewModelLocator.AutowireViewModel="True"
    xmlns:local="clr-namespace:Sweeper.Controls;assembly=Sweeper"
    xmlns:cvt="clr-namespace:Sweeper.Views.Converters;assembly=Sweeper"
    x:Class="Sweeper.Views.GamePage"    
    Title="Game"
    x:Name="page">
    <ContentPage.Resources>
        <cvt:SizeConverter  x:Key="SizeConverter" />
        <cvt:CoordinateConverter x:Key="CoordinateConverter" />
    </ContentPage.Resources>
    <Frame BackgroundColor="DarkSeaGreen" CornerRadius="15" Padding="15">
        <Grid RowDefinitions="*,3*">
            <Frame Grid.Row="0" Padding="0">
                <Grid ColumnDefinitions="*,*,*" Padding="0" >
                    <Frame Grid.Column="0">
                        <Label HorizontalOptions="Center" VerticalOptions="Center">
                            <Label.Text>
                                <MultiBinding Converter="{StaticResource CoordinateConverter}">
                                    <Binding Path="Board.Rows" />
                                    <Binding Path="Board.Columns" />
                                </MultiBinding>
                            </Label.Text>
                        </Label>
                    </Frame>
                    <Frame Grid.Column="1">
                        <Button Text="Ok"></Button>
                    </Frame>
                    <Frame Grid.Column="2">
                        <Label HorizontalOptions="Center" VerticalOptions="Center" Text="{Binding Game.Time}"/>
                    </Frame>
                </Grid>
            </Frame>
            <Frame Grid.Row="1" x:Name="frameButtons" Padding="4" HasShadow="True" >
                <StackLayout HorizontalOptions="FillAndExpand" Orientation="Vertical" Spacing="4" 
                             BindableLayout.ItemsSource="{Binding Board.RowItems}">
                    <BindableLayout.ItemTemplate>
                        <DataTemplate>
                            <StackLayout BindableLayout.ItemsSource="{Binding}" Orientation="Horizontal" HorizontalOptions="Center">
                                <BindableLayout.ItemTemplate>
                                    <DataTemplate>
                                        <Frame Padding="0"  HasShadow="False" BackgroundColor="LightBlue" >
                                            <Button  Text="{Binding Name}" FontSize="Body" HorizontalOptions="Center" TextColor="Navy"/>
                                            <Frame.WidthRequest>
                                                <MultiBinding Converter="{StaticResource SizeConverter}" >
                                                    <MultiBinding.Bindings>
                                                        <Binding Source="x:Reference frameButtons" Path="ActualWidth" />
                                                        <Binding Source="x:Reference frameButtons" Path="Padding" />
                                                        <Binding Source="x:Reference frameButtons" Path="BindingContext.Board.Columns" />
                                                    </MultiBinding.Bindings>
                                                </MultiBinding>
                                            </Frame.WidthRequest>
                                            <Frame.HeightRequest>
                                                <MultiBinding Converter="{StaticResource SizeConverter}" >
                                                    <MultiBinding.Bindings>
                                                        <Binding Source="x:Reference frameButtons" Path="ActualHeight"/>
                                                        <Binding Source="x:Reference frameButtons" Path="Padding" />
                                                        <Binding Source="x:Reference frameButtons" Path="BindingContext.Board.Rows" />
                                                    </MultiBinding.Bindings>
                                                </MultiBinding>
                                            </Frame.HeightRequest>
                                        </Frame >
                                    </DataTemplate>
                                </BindableLayout.ItemTemplate>
                            </StackLayout>
                        </DataTemplate>
                    </BindableLayout.ItemTemplate>
                </StackLayout>
            </Frame>
        </Grid>
    </Frame>
</ContentPage>

正在调用转换器,但我每次都传递 3 个空值。这是我要修复的绑定错误

整个项目可以在这里下载:https://github.com/BicycleMark/XamSweeper

The Converter is Getting Called but I am passing 3 nulls each time.

您可以尝试将 BindingContext 设置为 Frame,例如:

<Frame Padding="0"  HasShadow="False" BackgroundColor="LightBlue" BindingContext="{x:Reference frameButtons}">
   <Button  Text="{Binding Name}" FontSize="Body" HorizontalOptions="Center" TextColor="Navy" Clicked="Button_Clicked"/>
   <Frame.WidthRequest>
      <MultiBinding Converter="{StaticResource SizeConverter}" >

         <MultiBinding.Bindings>
           <Binding Path="ActualWidth" />
           <Binding Path="Padding" />
           <Binding Path="BindingContext.Board.Columns" />
         </MultiBinding.Bindings>
      </MultiBinding>
   </Frame.WidthRequest>
   <Frame.HeightRequest>
      <MultiBinding Converter="{StaticResource SizeConverter}" >
         <MultiBinding.Bindings>
           <Binding Path="ActualHeight" />
           <Binding Path="Padding" />
           <Binding Path="BindingContext.Board.Rows" />
         </MultiBinding.Bindings>
      </MultiBinding>
    </Frame.HeightRequest>
 </Frame >

然后你可以在你的 Converter.

中获取值

但是 ActualWidth 似乎不是现有的可绑定 属性。