以编程方式切换时会触发 Switch Toggled 事件

问题描述 投票:0回答:3
<StackLayout BackgroundColor="White">
    <ListView x:Name="ListViewMenu" ItemsSource="{Binding Menus}"
          HasUnevenRows="True"
          BackgroundColor="White"
          SeparatorVisibility="None"
          VerticalOptions="FillAndExpand"
          ItemTapped="Handle_ItemTapped"
          ItemSelected="Handle_ItemSelected"
          IsGroupingEnabled = "true"
          SeparatorColor="White">
        <ListView.GroupHeaderTemplate>
            <DataTemplate>
                <ViewCell>
                    <ViewCell.View>
                        <StackLayout BackgroundColor="LightSkyBlue" HeightRequest="25">
                            <Label Text="{Binding Key}"  FontAttributes="Bold"  LineBreakMode="NoWrap" Margin="10,0,0,0">
                            </Label>
                        </StackLayout>
                    </ViewCell.View>
                </ViewCell>
            </DataTemplate>
        </ListView.GroupHeaderTemplate>
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <ViewCell.View>
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"></RowDefinition>
                                <RowDefinition Height="Auto"></RowDefinition>
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="6*"></ColumnDefinition>
                                <ColumnDefinition Width="Auto"></ColumnDefinition>
                            </Grid.ColumnDefinitions>
                            <Label Text="{Binding article_description}"
                                       FontAttributes="Bold" FontSize="13"  Margin="10,5,0,-6" Grid.Row="0" LineBreakMode="NoWrap"/>
                            <Label Text="{Binding dish_name}" 
                                   FontSize="13" Margin="10,0,0,2" Grid.Row="1" Grid.Column="0"/>
                            <Label Grid.Row="0" Grid.Column="0" x:Name="LabelReserved"  Text="{Binding reserved}" IsVisible="false" LineBreakMode="NoWrap"/> 
                            <Switch Grid.Row="0" Grid.RowSpan="2" Grid.Column="1"  HorizontalOptions="Start" VerticalOptions="Center" IsEnabled="False" Toggled="SwitchMenu_OnToggled" >
                                <Switch.Triggers>
                                    <DataTrigger TargetType="Switch" Binding="{Binding Source={x:Reference LabelReserved},
                                   Path=Text.Length}" Value="7">
                                        <Setter Property="IsToggled" Value="true" />
                                    </DataTrigger>
                                </Switch.Triggers>
                            </Switch>
                        </Grid>
                    </ViewCell.View>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</StackLayout>

我上面有一个列表视图,它有一个开关,如果 labelreserved 的长度为 7,我有一个触发器来切换开关,但我不希望只有当用户单击开关时才触发 Toggled 事件。 可以做我想做的事吗?

listview xamarin.forms xamarin.android
3个回答
3
投票

注意: 这个解决方案是我的一个实验 - 所以我建议,如果你决定实现这个,请谨慎使用。

基本上,目的是创建一个仅查看的解决方案,能够跟踪如何设置

IsToggled
属性 - 无论是通过触发器、绑定上下文还是点击操作(类似于维护的 属性上下文)对于
BindingContext
BindableObject
)

假设我们有一个自定义事件,仅当用户点击开关时才会触发 - 这个问题应该得到解决。简单地向

Switch
添加点击识别器似乎不起作用。我们只剩下两个选择:

  1. 创建您自己的自定义控件,提供与

    Switch
    类似的功能,但仅在捕获点击手势时触发切换事件 - 强烈推荐此选项。

  2. 或者,您可以使用自定义事件扩展现有

    Switch
    控件,并通过提供其自己的一组可绑定属性来跟踪
    IsToggled
    属性的设置方式。

例如:

public class CustomSwitch : Switch
{
    internal enum ToggledSetFlags
    {
        None = 0,
        FromCode = 1 << 0,
    }

    ToggledSetFlags _toggleSetStatus = ToggledSetFlags.None;
    public event EventHandler<ToggledEventArgs> UserToggled;

    public static readonly BindableProperty ToggledStateFromCodeProperty =
        BindableProperty.Create(
            "ToggledStateFromCode", typeof(bool), typeof(CustomSwitch),
            defaultBindingMode: BindingMode.TwoWay,
            defaultValue: default(bool), propertyChanged: OnToggledStateFromCodeChanged);

    public bool ToggledStateFromCode
    {
        get { return (bool)GetValue(ToggledStateFromCodeProperty); }
        set { SetValue(ToggledStateFromCodeProperty, value); }
    }

    private static void OnToggledStateFromCodeChanged(BindableObject bindable, object oldValue, object newValue)
    {
        ((CustomSwitch)bindable).OnToggledStateFromCodeChangedImpl((bool)oldValue, (bool)newValue);
    }

    protected virtual void OnToggledStateFromCodeChangedImpl(bool oldValue, bool newValue)
    {
        if (ToggledStateFromCode != IsToggled)
        {
            _toggleSetStatus = ToggledSetFlags.FromCode;
            IsToggled = ToggledStateFromCode;
        }
    }

    protected override void OnPropertyChanged(string propertyName = null)
    {
        base.OnPropertyChanged(propertyName);

        if (propertyName == nameof(IsToggled))
        {
            ToggledStateFromCode = IsToggled;
            if (_toggleSetStatus == ToggledSetFlags.None)
                UserToggled?.Invoke(this, new ToggledEventArgs(IsToggled));
            else
                _toggleSetStatus = ToggledSetFlags.None;
        }
    }
}

并且,示例用法如下所示:

<local:CustomSwitch 
       Grid.Row="0" Grid.RowSpan="2" Grid.Column="1" 
       HorizontalOptions="Start" VerticalOptions="Center" 
       ToggledStateFromCode="{Binding IsSwitchOn}" 
       UserToggled="SwitchMenu_OnToggled">
    <Switch.Triggers>
        <DataTrigger TargetType="{x:Type local:CustomSwitch}" 
                     Binding="{Binding Source={x:Reference LabelReserved},
                     Path=Text.Length}" Value="7">
            <Setter Property="ToggledStateFromCode" Value="true" />
        </DataTrigger>
    </Switch.Triggers>
</local:CustomSwitch>

编辑1:在恢复自定义切换属性状态时错过了在

else
方法中添加
OnPropertyChanged
。此外,仅在当前切换值不同时添加检查以设置标志。

编辑2: 将可绑定属性转换为跟踪状态,而不是像以前一样无状态。这确保了能够在不触发事件的情况下处理绑定更改。


0
投票

您可以通过使用属性

IsEnabled
禁用 Switch 并将其设置为 false 来防止用户切换开关。


0
投票

这个问题很旧,但我找到了一个简单(有点不正确)的解决方案,我用它来从已接受的答案中节省大量额外的工作。 当我以编程方式切换开关时,我将 Tag 属性设置为 true。

ToggleSwitch.Tag = true;
ToggleSwitch.IsOn = true (or false);

然后在我的 Toggled 事件中,我检查 Tag 属性是否为 null 并执行我的操作。这样,事件被触发的唯一时间就是用户切换开关时。

private void ToggleSwitch_Toggled(object sender, RoutedEventArgs e)
{
    ToggleSwitch toggleSwitch = (ToggleSwitch)e.OriginalSource;
    if (toggleSwitch.Tag == null)
    {
        // Switch was toggled by user, do some action.
    }
    else
    {
        // Switch was toggled programmatically, set Tag null.
        toggleSwitch.Tag = null;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.