【问题标题】:Deselect ListBoxItem with delay延迟取消选择 ListBoxItem
【发布时间】:2019-10-26 20:35:47
【问题描述】:

我想实现一种效果,其中ListBoxItem 被选中(突出显示)几秒钟,然后被取消选中。尝试使用淡入淡出效果实现简单的控制突出显示,但为了使事情正常进行,我需要相应地更改一个属性。

我有一个IsSelected 属性绑定到我的视图模型属性:

<Style TargetType="{x:Type ListBoxItem}">
    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</Style>

我的财产是这样的:

public bool IsSelected
{
    get => _isSelected;
    set
    {
        // Update value
        _isSelected = value;

        // Raise property changed
        OnPropertyChanged(nameof(IsSelected));
    }
}

我尝试过使用延迟绑定:

<ControlTemplate TargetType="{x:Type ListBoxItem}">
    <ControlTemplate.Triggers>
        <!--  Deselect after 5 seconds  -->
        <DataTrigger Binding="{Binding IsSelected, Delay=5000}" Value="True">
            <Setter Property="IsSelected" Value="False" />
        </DataTrigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

我也尝试过使用故事板:

<ControlTemplate TargetType="{x:Type ListBoxItem}">
    <ControlTemplate.Triggers>
        <!--  Deselect after 5 seconds  -->
        <DataTrigger Binding="{Binding IsSelected}" Value="True">
            <DataTrigger.EnterActions>
                <BeginStoryboard>
                    <Storyboard>
                        <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsSelected">
                            <DiscreteBooleanKeyFrame KeyTime="00:00:05" Value="False" />
                        </BooleanAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </DataTrigger.EnterActions>
        </DataTrigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

不幸的是,上述方法似乎都没有更新我的IsSelected 属性,ListBoxItem 仍然被选中并突出显示。

我希望以 XAML(或扩展)、MVVM 样式、没有代码和浪费的计时器来完成此操作 - 这可能吗? 如果是这样,我怎样才能正确取消选择 ListBoxItem 并延迟?

【问题讨论】:

  • 为什么要在 XAML 中实现类似的东西?它应该是控制逻辑的一部分,而 XAML 是一种标记语言。是什么让您认为计时器比Storyboard 更浪费。看起来你已经把自己画到了这些要求的角落里。 MVVM 肯定不是要消除与视图相关的代码并在 XAML 中实现行为。
  • @mm8 使其成为控制逻辑的一部分需要为每个控件创建一个计时器。一种解决方案是将单个计时器放入列表视图模型中,但是我很确定这不是最好的解决方案。我认为这可以使用附加属性(标记扩展)来完成,这将是 100% 有效的解决方案,但我现在没有想法。
  • 附加行为并非“在 XAML 中完成”,因此您可能需要稍微重新表述一下您的问题。
  • @mm8 对。现在在我的问题中确实提到了这一点。

标签: c# wpf xaml properties triggers


【解决方案1】:

这是一个附加行为的示例,应该或多或少地做你想做的事:

public class DeselectBehavior
{
    public static bool GetIsEnabled(ListBox listBox)
    {
        return (bool)listBox.GetValue(IsEnabledProperty);
    }

    public static void SetIsEnabled(ListBox listBox, bool value)
    {
        listBox.SetValue(IsEnabledProperty, value);
    }

    public static readonly DependencyProperty IsEnabledProperty =
        DependencyProperty.RegisterAttached(
        "IsEnabled",
        typeof(bool),
        typeof(DeselectBehavior),
        new UIPropertyMetadata(false, OnChanged));

    private static void OnChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ListBox listBox = d as ListBox;
        if((bool)e.NewValue)
        {
            listBox.AddHandler(ListBoxItem.SelectedEvent, (RoutedEventHandler)OnListBoxItemSelected, true);
        }
        else
        {
            listBox.RemoveHandler(ListBoxItem.SelectedEvent, (RoutedEventHandler)OnListBoxItemSelected);
        }
    }

    private static async void OnListBoxItemSelected(object sender, RoutedEventArgs e)
    {
        await Task.Delay(2000);
        ListBoxItem listBoxItem = e.OriginalSource as ListBoxItem;
        if (listBoxItem != null)
            listBoxItem.IsSelected = false;
    }
}

XAML:

    <ListBox ... local:DeselectBehavior.IsEnabled="True">
    ...

【讨论】:

  • local:DeselectBehavior.IsEnabled="True" 我如何通知使用 this 只能用于 ListBox 。比如说我有另一个attached behavior,它只能在一个按钮上使用。然后当一些在其他任何东西上使用时,设计如何通知他们。还是让编译失败成为可能?
猜你喜欢
  • 2011-06-29
  • 2015-07-03
  • 2015-09-10
  • 1970-01-01
  • 1970-01-01
  • 2011-07-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-16
相关资源
最近更新 更多