Xamarin.Forms

时间:2018-10-15 20:16:22

标签: c# xaml xamarin xamarin.forms

我创建了一个ViewCell,可以在整个项目中重复使用它:

<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms" 
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
         xmlns:C="using:****.Converters"
         x:Class="****.Views.Settings.SettingCell">
<Grid BackgroundColor="{StaticResource BlueGray}">
    <Grid.Resources>
        <C:DebugConverter x:Key="debugConverter"/>
    </Grid.Resources>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="1*"/>
        <ColumnDefinition Width="2*"/>
    </Grid.ColumnDefinitions>
    <Image Grid.Column="0" Source="{Binding ImageSource}"/>
    <Label Grid.Column="1" 
           Text="{Binding Path=Title,
                          Converter={StaticResource debugConverter}, 
                          FallbackValue=Title}" 
           HorizontalOptions="Start" 
           VerticalOptions="Center"/>
    </Grid>
</ViewCell>

这是ViewModel:

public partial class SettingCell : ViewCell
{
    public SettingModel Model
    {
        get
        {
            return model;
        }
        set
        {
            model = value;
            BindingContext = value;
        }
    }
    public SettingModel model;

    public static readonly BindableProperty SettingTypeProperty = BindableProperty.Create(nameof(SettingType), typeof(Setting), typeof(SettingModel));
    public Setting SettingType
    {
        get
        {
            return (Setting)GetValue(SettingTypeProperty);
        }
        set
        {
            SetValue(SettingTypeProperty, value);
        }
    }

    public SettingCell()
    {
        InitializeComponent();

        switch (SettingType)
        {
            case Setting.Name:
                Model = new NameSettingModel();
                break;
            default:
                throw new NotImplementedException("Unknown Setting Type");
        }
    }
}

模型是通过类区分符选择的抽象类的子类型。这时该类非常简单,因为我只是将其连接起来,但这是基类以及on子类型:

public class NameSettingModel : SettingModel
{
    public NameSettingModel()
    {
        Title = "Name";
        IconSource = "";
    }

    public override void ClickCommand()
    {
        Debug.WriteLine("Setting Command Run");
    }
}

public abstract class SettingModel : BindableBase
{
    public string Title
    {
        get
        {
            return GetProperty<string>();
        }
        set
        {
            SetProperty(value);
        }
    }
    public string IconSource
    {
        get
        {
            return GetProperty<string>();
        }
        set
        {
            SetProperty(value);
        }
    }

    public abstract void ClickCommand();
}

BindableBase只是实现INotifyPropertyChanged的基本绑定类,并将属性值存储在字典中,因此我不必为每个属性都创建一个字段。

当我运行项目时;每次都会显示后备值。令我感到奇怪的是,当我在debugConverter中中断时,如下所示:

public class DebugConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }
}

我看到值“名称”通过转换器,但是UI仅显示后备值。有任何想法吗?绑定将获得正确值但不刷新以显示它的任何原因是什么?我在这里茫然。我很乐意发布更多可能有用的代码,请给我留言。

谢谢!

===========================编辑================ ============

情节变厚。现在,我有一个直接位于列表视图中的视单元,而我插入的模板只是一个网格。

<?xml version="1.0" encoding="UTF-8"?>
<Grid xmlns="http://xamarin.com/schemas/2014/forms" 
  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
  xmlns:Images="clr-namespace:MyApp.Images;assembly=MyApp"        
  xmlns:Converters="clr-namespace:MyApp.Views.Converters"
  x:Class="MyApp.Views.Templates.SettingTemplate" 
  BackgroundColor="White" VerticalOptions="Center">
<Grid.Resources>
     <Converters:SettingToIconConverter x:Key="SettingToIconConverter"/>
     <Converters:InverseBoolConverter x:Key="InverseBoolConverter"/>
</Grid.Resources>
<StackLayout Orientation="Horizontal" VerticalOptions="Center" HorizontalOptions="Center">
    <Images:VectorImage ResourceId="{Binding Converter={StaticResource SettingToIconConverter}}"
                        WidthRequest="30" HeightRequest="30" Margin="2"  VerticalOptions="Center"/>
    <Label Text="{Binding Name, FallbackValue=Name}" FontAttributes="Bold" FontSize="Medium" Margin="2" 
           VerticalOptions="Center"/>
    <ContentPresenter Content="{Binding BonusContent}" VerticalOptions="Center" Margin="2"/>
</StackLayout>
<Frame BackgroundColor="{StaticResource Slate}" Opacity="0.25" IsVisible="{Binding IsEnabled, UpdateSourceEventName=ValueChanged, Converter={StaticResource InverseBoolConverter}, FallbackValue=false}"/>

以下是包含两个模板的包含列表页面:

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="75"/>
            <RowDefinition Height="1"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Templates:PeripheralDetailsTemplate/>
        <Frame BackgroundColor="{StaticResource Slate}" Grid.Row="1"/>
        <Frame BackgroundColor="White" Grid.Row="2">
            <ListView x:Name="lvPeripheralSettings" ItemsSource="{Binding Settings}" 
                      SelectionMode="None" ItemTapped="Setting_Tapped" RowHeight="40"
                      ios:ListView.SeparatorStyle="FullWidth">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell IsEnabled="{Binding IsEnabled, UpdateSourceEventName=ValueChanged, Mode=TwoWay, Converter={StaticResource DebugConverter}}">
                            <Templates:SettingTemplate/>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </Frame>
    </Grid>

记下PeripheralDetailsTemplate:

   <Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="75"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="75"/>
    </Grid.ColumnDefinitions>
    <!--Icon--> 
    <Frame Padding="5">
         <Images:VectorImage ResourceId="{Binding HardwareType, Converter={StaticResource hardwareTypeToSVGPathConverter}}"
                             WidthRequest="150" HeightRequest="150" 
                             HorizontalOptions="Center" VerticalOptions="Center"/>
    </Frame>
    <Grid Grid.Column="1">
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <Frame>
            <Label Text="{Binding Name, FallbackValue=Peripheral Name}" FontSize="Medium" FontAttributes="Bold" HorizontalOptions="Start" VerticalOptions="Center"/>
        </Frame>
        <Frame Grid.Row="1">
            <Label Text="{Binding HardwareType, FallbackValue=Peripheral Type}" FontSize="Micro" HorizontalOptions="Start" VerticalOptions="Center"/>
        </Frame>
        <Frame Grid.Row="2">
            <Label Text="{Binding MacAddress, StringFormat='Mac: {0}', FallbackValue=000111222333}" FontSize="Micro" HorizontalOptions="Start" VerticalOptions="Center"/>
        </Frame>
        <Frame Grid.Row="3">
            <Label Text="{Binding FirmwareRevision, StringFormat='Firmware: {0}', FallbackValue=01AB}" FontSize="Micro" HorizontalOptions="Start" VerticalOptions="Center"/>
        </Frame>
    </Grid>
    <Frame Grid.Column="2">
        <Label Text="Conn" HorizontalOptions="Center" VerticalOptions="Center" TextColor="{Binding IsConnected, Converter={StaticResource BoolToColorConverter}, FallbackValue={StaticResource LynkdBlue}}"/>
    </Frame>
</Grid>

它必定与ViewCell完全一样!!!而且效果很好。我正在寻找差异,但尚未找到。我只知道我已经正确设置了绑定上下文,因为它一次绑定了数据,而且我知道我正在正确触发NotifyPropertyChanged,因为绑定到相同属性的另一个模板会按我的期望进行更新。我已经连接了一个debugconverter,它永远不会运行。我认为在两种情况下都使用ViewCell很有意思。这是两个具有相同问题的独立代码库。 :/

1 个答案:

答案 0 :(得分:0)

简单的答案;我绑定到基于另一个属性的模型中的只读属性。当其他属性更改时,我没有为只读属性触发OnPropertyChanged。