【问题标题】:Xamarin: Visual State Manager and custom propertiesXamarin:视觉状态管理器和自定义属性
【发布时间】:2020-02-18 14:28:55
【问题描述】:

我正在尝试使用 Visual State Manager 在自定义控件上设置自定义属性,但到目前为止我没有任何运气。我的自定义控件只是一个带有附加可绑定属性的标签。

public class SelectableLabel : Label
{
    public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create("IsSelected", typeof(bool), typeof(SelectableLabel), false);

    public bool IsSelected
    {
        get { return (bool)GetValue(IsSelectedProperty); }
        set
        {
            Console.WriteLine($"MDO: {Text}.IsSelected_set={value}");
            SetValue(IsSelectedProperty, value);
        }
    }

当控件进入Selected 视觉状态时,我在 CollectionView 中使用此控件来切换IsSelected 属性。

    <CollectionView
        x:Name="cv"
        ItemsSource="{Binding Names}"
        SelectionMode="Multiple"
        SelectedItems="{Binding SelectedNames, Mode=TwoWay}"
        VerticalOptions="Fill">
        <CollectionView.ItemTemplate>
            <DataTemplate>
                <local:SelectableLabel
                    x:Name="lblName"
                    Text="{Binding First}">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup
                            x:Name="CommonStates">
                            <VisualState
                                x:Name="Normal">
                                <VisualState.Setters>
                                    <Setter
                                        Property="IsSelected"
                                        Value="False" />
                                </VisualState.Setters>
                            </VisualState>
                            <VisualState
                                x:Name="Selected">
                                <VisualState.Setters>
                                    <Setter
                                        Property="IsSelected"
                                        Value="True" />
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                </local:SelectableLabel>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>

当我在 iOS 模拟器上运行它时,当视觉状态更改为 Selected 时,我没有看到 setter 被触发。如果我将 setter 中的属性更改为 BackgroundColorText,我会看到预期的行为。该问题似乎特定于自定义属性。我查看了Setter.Property 的文档,它指出Setter 可以应用于BindablePropertyIsSelected 是。是我做错了什么还是 VSM 不支持此功能?


编辑:此示例的 CollectionView 部分无关紧要。这段代码也会出现同样的问题。

    public class SelectableEntry : Entry
    {
        public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create("IsSelected", typeof(bool), typeof(SelectableEntry), false);

        public bool IsSelected
        {
            get { return (bool)GetValue(IsSelectedProperty); }
            set
            {
                Console.WriteLine($"MDO: {Text}.IsSelected_set={value}");
                var color = value ? Color.LightBlue : Color.LightPink;
                SetValue(IsSelectedProperty, value);
                SetValue(BackgroundColorProperty, color);
            }
        }
    }

这里是对应的 XAML。当第一个自定义 Entry 控件获得焦点而第二个没有获得焦点时,背景颜色会发生变化。我也没有在控制台中看到我的 WriteLine 语句。

        <local:SelectableEntry Text="First">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup
                    x:Name="CommonStates">
                    <VisualState
                        x:Name="Normal">
                        <VisualState.Setters>
                            <Setter
                                Property="BackgroundColor"
                                Value="LightBlue" />
                        </VisualState.Setters>
                    </VisualState>

                    <VisualState
                        x:Name="Focused">
                        <VisualState.Setters>
                            <Setter
                                Property="BackgroundColor"
                                Value="LightPink" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </local:SelectableEntry>
        <local:SelectableEntry Text="Second">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup
                    x:Name="CommonStates">

                    <VisualState
                        x:Name="Normal">
                        <VisualState.Setters>
                            <Setter
                                Property="IsSelected"
                                Value="False" />
                        </VisualState.Setters>
                    </VisualState>

                    <VisualState
                        x:Name="Focused">
                        <VisualState.Setters>
                            <Setter
                                Property="IsSelected"
                                Value="True" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </local:SelectableEntry>

【问题讨论】:

  • 您好,如果需要检测属性变化,可以使用propertyChangeddocs.microsoft.com/en-us/xamarin/xamarin-forms/xaml/…
  • @JuniorJiang-MSFT 我尝试像您链接的示例中那样添加propertyChanged 方法,但它没有被触发。我想这更能确认视觉状态管理器在视觉状态更改时不会更改属性。
  • 是的,没错。似乎 Visual State Manager 不支持自定义 Bindable Property 。

标签: xamarin xamarin.forms visualstatemanager


【解决方案1】:

我已尝试使用 Bindable Property 检查是否在 VisualStateManager 中调用了属性。很遗憾,即使在 propertyChanged 方法中也无法调用它。我想也许可绑定属性在VisualStateManager 中不起作用。

自定义Entry代码如下:

public class SelectableEntry : Entry
{
    public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create("IsSelected", typeof(bool), typeof(SelectableEntry), false ,propertyChanged:changedMethod);

    private static void changedMethod(BindableObject bindable, object oldValue, object newValue)
    {
        Console.WriteLine($"MDO: {oldValue}.IsSelected_set={newValue}");
    }

    public bool IsSelected
    {
        get { return (bool)GetValue(IsSelectedProperty); }
        set
        {
            Console.WriteLine($"MDO: {Text}.IsSelected_set={value}");
            var color = value ? Color.LightBlue : Color.LightPink;
            SetValue(IsSelectedProperty, value);
            SetValue(BackgroundColorProperty, color);
        }
    }
}

解决方案

但是,有一个 Attached Properties 可以在Style.Setters 中使用。然后您也可以在VisualState.Setters 中尝试使用它。它也可以工作。

附加属性类代码如下:

public class SelectableEntryStyle
{
    public static readonly BindableProperty IsSelectedProperty =  BindableProperty.CreateAttached("IsSelected", typeof(bool), typeof(SelectableEntryStyle), false,propertyChanged:onChangedMethod);

    private static void onChangedMethod(BindableObject bindable, object oldValue, object newValue)
    {
        Console.WriteLine($"MDO:IsSelected_set={newValue}");
        var color = (bool)newValue ? Color.LightBlue : Color.LightPink;
        var entry = bindable as Entry;
        entry.SetValue(Entry.BackgroundColorProperty, color);
    }

    public static bool GetIsSelected(BindableObject view)
    {
        return (bool)view.GetValue(IsSelectedProperty);
    }

    public static void SetIsSelected(BindableObject view, bool value)
    {
        view.SetValue(IsSelectedProperty, value);
    }

}

Xaml的代码如下:

<local:SelectableEntry FontSize="18" Placeholder="Bindable Property">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CommonStates">
            <VisualState x:Name="Normal">
                <VisualState.Setters>
                    <Setter Property="IsSelected"
                            Value="False" />
                </VisualState.Setters>
            </VisualState>

            <VisualState x:Name="Disabled">
                <VisualState.Setters>
                    <Setter Property="IsSelected"
                            Value="True" />
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</local:SelectableEntry>
<Entry Placeholder="Attached Property">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CommonStates">

            <VisualState x:Name="Normal">
                <VisualState.Setters>
                    <Setter Property="local:SelectableEntryStyle.IsSelected"
                            Value="False" />
                </VisualState.Setters>
            </VisualState>

            <VisualState x:Name="Focused">
                <VisualState.Setters>
                    <Setter Property="local:SelectableEntryStyle.IsSelected"
                            Value="True" />
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Entry>

EntryNormalFocused 时,控制台可以打印日志。

02-18 14:26:27.360 I/mono-stdout(26014): MDO:IsSelected_set=True

02-18 14:26:28.675 I/mono-stdout(26014): MDO:IsSelected_set=False

效果:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-02
    • 1970-01-01
    • 1970-01-01
    • 2023-02-14
    • 1970-01-01
    • 1970-01-01
    • 2011-06-17
    相关资源
    最近更新 更多