Xamarin的.表单:相当于CSS:last-of-type选择器
本文关键字:last-of-type 选择器 CSS 相当于 表单 Xamarin | 更新日期: 2023-09-27 18:12:25
我目前正在重新设计一个在Xamarin中显示联系人信息的页面。该页面将显示部分列表(地址,电话号码,电子邮件地址等),每个部分都有一个图标和相关信息。各部分之间应该用一条线隔开,但第一部分的上方和最后一部分的下方不能有线。此外,空部分根本不显示。
标记基本上是这样的:
<ScrollView>
<StackLayout>
<Label Text="{Binding Contact.Name}" />
<controls:ContactSection Icon="address.png">
<!-- address-type stuff -->
</controls:ContactSection>
<controls:ContactSection Icon="phone.png">
<!-- phone numbers -->
</controls:ContactSection>
<!-- further sections -->
</StackLayout>
</ScrollView>
我已经让它工作的大部分,除了行。(我只是用BoxView
, HeightRequest
为1。)为了使它们正常工作,我需要告诉渲染器在每个可见部分下面画一条线,除了最后一个。从本质上讲,我需要一个css3风格的:not(:last-of-type)
选择器(或:not(:first-of-type)
选择器)。
在XAML中最好的方法是什么?
你刚刚提醒我,我想要这个已经有一段时间了,所以我写了一个(带有片段,这是一个十分钟的工作)。让我知道如何/如果这与Xamarin工作;我不能用它来测试。
更新:我今天一定是半睡半醒。我读"StackLayout"作为"StackPanel"。OP将其改编为Xamarin,并将其工作代码作为另一个答案发布。
using System;
using System.Windows;
using System.Windows.Controls;
namespace HollowEarth.AttachedProperties
{
public static class PanelBehaviors
{
public static void UpdateChildFirstLastProperties(Panel panel)
{
for (int i = 0; i < panel.Children.Count; ++i)
{
var child = panel.Children[i];
SetIsFirstChild(child, i == 0);
SetIsLastChild(child, i == panel.Children.Count - 1);
}
}
#region PanelExtensions.IdentifyFirstAndLastChild Attached Property
public static bool GetIdentifyFirstAndLastChild(Panel panel)
{
return (bool)panel.GetValue(IdentifyFirstAndLastChildProperty);
}
public static void SetIdentifyFirstAndLastChild(Panel panel, bool value)
{
panel.SetValue(IdentifyFirstAndLastChildProperty, value);
}
/// <summary>
/// Behavior which causes the Panel to identify its first and last children with attached properties.
/// </summary>
public static readonly DependencyProperty IdentifyFirstAndLastChildProperty =
DependencyProperty.RegisterAttached("IdentifyFirstAndLastChild", typeof(bool), typeof(PanelBehaviors),
// Default MUST be false, or else True won't be a change in
// the property value, so PropertyChanged callback won't be
// called, and nothing will happen.
new PropertyMetadata(false, IdentifyFirstAndLastChild_PropertyChanged));
private static void IdentifyFirstAndLastChild_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Panel panel = (Panel)d;
((Panel)d).LayoutUpdated += (s, e2) => UpdateChildFirstLastProperties(panel);
}
#endregion PanelExtensions.IdentifyFirstAndLastChild Attached Property
#region PanelExtensions.IsFirstChild Attached Property
public static bool GetIsFirstChild(UIElement obj)
{
return (bool)obj.GetValue(IsFirstChildProperty);
}
public static void SetIsFirstChild(UIElement obj, bool value)
{
obj.SetValue(IsFirstChildProperty, value);
}
/// <summary>
/// True if UIElement is first child of a Panel
/// </summary>
public static readonly DependencyProperty IsFirstChildProperty =
DependencyProperty.RegisterAttached("IsFirstChild", typeof(bool), typeof(PanelBehaviors),
new PropertyMetadata(false));
#endregion PanelExtensions.IsFirstChild Attached Property
#region PanelExtensions.IsLastChild Attached Property
public static bool GetIsLastChild(UIElement obj)
{
return (bool)obj.GetValue(IsLastChildProperty);
}
public static void SetIsLastChild(UIElement obj, bool value)
{
obj.SetValue(IsLastChildProperty, value);
}
/// <summary>
/// True if UIElement is last child of a Panel
/// </summary>
public static readonly DependencyProperty IsLastChildProperty =
DependencyProperty.RegisterAttached("IsLastChild", typeof(bool), typeof(PanelBehaviors),
new PropertyMetadata(false));
#endregion PanelExtensions.IsLastChild Attached Property
}
}
使用例子:
<StackPanel
xmlns:heap="clr-namespace:HollowEarth.AttachedProperties"
heap:PanelBehaviors.IdentifyFirstAndLastChild="True"
HorizontalAlignment="Left"
Orientation="Vertical"
>
<StackPanel.Resources>
<Style TargetType="Label">
<Setter Property="Content" Value="Blah blah" />
<Setter Property="Background" Value="SlateGray" />
<Setter Property="Margin" Value="4" />
<Style.Triggers>
<Trigger Property="heap:PanelBehaviors.IsFirstChild" Value="True">
<Setter Property="Background" Value="DeepSkyBlue" />
<Setter Property="Content" Value="First Child" />
</Trigger>
<Trigger Property="heap:PanelBehaviors.IsLastChild" Value="True">
<Setter Property="Background" Value="SeaGreen" />
<Setter Property="Content" Value="Last Child" />
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<Label />
<Label />
<Label />
<Label />
</StackPanel>
在Ed Plunkett为WPF提供解决方案后,我决定发布Xamarin。我用他的代码构建了一个等价的表单。
namespace Foo.Behaviors
{
using System.Linq;
using Xamarin.Forms;
/// <summary>
/// Identifies the first and last child of a <see cref="Layout{View}"/>.
/// </summary>
public class FirstAndLastChildBehavior
{
/// <summary>
/// Identifies the first and last child of the given <see cref="Layout{View}"/>.
/// </summary>
/// <param name="layout">The <see cref="Layout{View}"/>.</param>
public static void UpdateChildFirstLastProperties(Layout<View> layout)
{
// This is just here to provide a convenient place to do filtering, e.g. .Where(v => v.IsVisible).
var children = layout.Children;
for (var i = 0; i < children.Length; ++i)
{
var child = children[i];
SetIsFirstChild(child, i == 0);
SetIsLastChild(child, i == children.Length - 1);
}
}
#region PanelExtensions.IdentifyFirstAndLastChild Attached Property
/// <summary>
/// Gets a value that controls whether the child-identifying functionality is enabled for the given <see cref="Layout{View}"/>.
/// </summary>
/// <param name="layout">The <see cref="Layout{View}"/>.</param>
/// <returns><c>True</c> if functionality has been enabled, <c>false</c> otherwise.</returns>
public static bool GetIdentifyFirstAndLastChild(Layout<View> layout)
{
return (bool)layout.GetValue(IdentifyFirstAndLastChildProperty);
}
/// <summary>
/// Sets a value that controls whether the child-identifying functionality is enabled for the given <see cref="Layout{View}"/>.
/// </summary>
/// <param name="layout">The <see cref="Layout{View}"/>.</param>
/// <param name="value">The value.</param>
public static void SetIdentifyFirstAndLastChild(Layout<View> layout, bool value)
{
layout.SetValue(IdentifyFirstAndLastChildProperty, value);
}
/// <summary>
/// Identifies the <see cref="IdentifyFirstAndLastChild"/> property.
/// </summary>
/// <remarks>
/// The behavior can't be turned off; once the value is set to <c>true</c> the behavior will stick even if it's set back to
/// <c>false</c> later.
/// </remarks>
public static readonly BindableProperty IdentifyFirstAndLastChildProperty = BindableProperty.CreateAttached(
"IdentifyFirstAndLastChild",
typeof(bool),
typeof(FirstAndLastChildBehavior),
false,
BindingMode.OneWay,
null,
IdentifyFirstAndLastChildPropertyChanged);
/// <summary>
/// Gets called when IdentifyFirstAndLastChildProperty changes.
/// </summary>
/// <param name="bindable">The object we're bound to.</param>
/// <param name="oldValue">This parameter is not used.</param>
/// <param name="newValue">This parameter is not used.</param>
private static void IdentifyFirstAndLastChildPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var layout = (Layout<View>)bindable;
((Layout<View>)bindable).LayoutChanged += (a, b) => UpdateChildFirstLastProperties(layout);
}
#endregion PanelExtensions.IdentifyFirstAndLastChild Attached Property
#region PanelExtensions.IsFirstChild Attached Property
/// <summary>
/// Gets a value that determines whether the given <see cref="View"/> is the first child of its parent.
/// </summary>
/// <param name="obj">The <see cref="View"/>.</param>
/// <returns><c>True</c> if the <see cref="View"/> is the first child, <c>false</c> otherwise.</returns>
public static bool GetIsFirstChild(View obj)
{
return (bool)obj.GetValue(IsFirstChildProperty);
}
/// <summary>
/// Sets a value that determines whether the given <see cref="View"/> is the first child of its parent.
/// </summary>
/// <param name="obj">The <see cref="View"/>.</param>
/// <param name="value">The value.</param>
public static void SetIsFirstChild(View obj, bool value)
{
obj.SetValue(IsFirstChildProperty, value);
}
/// <summary>
/// Identifies the <see cref="IsFirstChild"/> property.
/// </summary>
public static readonly BindableProperty IsFirstChildProperty = BindableProperty.CreateAttached(
"IsFirstChild",
typeof(bool),
typeof(FirstAndLastChildBehavior),
false);
#endregion PanelExtensions.IsFirstChild Attached Property
#region PanelExtensions.IsLastChild Attached Property
/// <summary>
/// Gets a value that determines whether the given <see cref="View"/> is the last child of its parent.
/// </summary>
/// <param name="obj">The <see cref="View"/>.</param>
/// <returns><c>True</c> if the <see cref="View"/> is the last child, <c>false</c> otherwise.</returns>
public static bool GetIsLastChild(View obj)
{
return (bool)obj.GetValue(IsLastChildProperty);
}
/// <summary>
/// Sets a value that determines whether the given <see cref="View"/> is the last child of its parent.
/// </summary>
/// <param name="obj">The <see cref="View"/>.</param>
/// <param name="value">The value.</param>
public static void SetIsLastChild(View obj, bool value)
{
obj.SetValue(IsLastChildProperty, value);
}
/// <summary>
/// Identifies the <see cref="IsLastChild"/> property.
/// </summary>
public static readonly BindableProperty IsLastChildProperty = BindableProperty.CreateAttached(
"IsLastChild",
typeof(bool),
typeof(FirstAndLastChildBehavior),
false);
#endregion PanelExtensions.IsLastChild Attached Property
}
}