【问题标题】:Xamarin MultiBinding Needs BindingContext from higher ancestor level or named Items in XAML treeXamarin MultiBinding 需要来自更高祖先级别的 BindingContext 或 XAML 树中的命名项
【发布时间】:2020-12-08 02:31:20
【问题描述】:

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

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

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

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

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

  1. 按住按钮的框架的实际宽度
  2. 模型按钮的列数
  3. 每个按钮之间的间距或填充
  4. 如果任何 [1..3] 为空 返回 50

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

  1. 按住按钮的框架的实际高度
  2. 模型按钮的行数
  3. 每个按钮之间的间距或填充
  4. 如果任何 [1..3] 为空 返回 50

这里是转换器描述:

    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

【问题讨论】:

    标签: c# xamarin mvvm multibinding


    【解决方案1】:

    转换器正在被调用,但我每次都传递 3 个空值。

    您可以尝试将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 似乎不是现有的可绑定属性。

    【讨论】:

    • 是的,它开始将值发送到我的转换器中。我将不得不找出 AcutalWidth/ActualHeight 的替代方案。找到其余答案后,我会将其标记为答案。在实际...嗯也许是一个标记???
    • @MarkWardell 你想平均帧数吗?如果是,可能是设备屏幕的宽度。
    • 好吧,我睡着了,回来时精神焕发。 ActualWidth/Height 缺乏可用性使我的美中不足...另一点需要注意的是,我正在附加到 Padding 并且我应该附加到 Padding 的一个字段。在 WPF 中,我们可以绑定到 ActualWidth/AcutaulHeight。
    • 我可能想考虑覆盖布局或布局
    • 平均问题...我希望每个子框架都具有统一大小。在 WPF 中,我们从 UniformGrid 执行此操作。
    猜你喜欢
    • 2017-06-04
    • 1970-01-01
    • 2013-03-17
    • 2022-06-28
    • 1970-01-01
    • 2016-12-26
    • 1970-01-01
    • 2015-04-02
    • 1970-01-01
    相关资源
    最近更新 更多