当鼠标不超过两个元素时,Wpf Reactive Extensions会做出反应

Zap*_*ila 1 wpf mouseevent system.reactive

我正在尝试更多地了解反应性扩展,但我发现很难找到一个真实世界的例子,所以我可以训练自己.

我几天前发现自己写了一些ToggleButtonMouse Enter,Leave Checked Unchecked事件,现在我想知道我是否可以使用被动扩展来简化它.

这是目标:

给定a ToggleButton,当悬停并且未检查时,弹出窗口应该显示,如果鼠标没有超过按钮或弹出窗口,弹出窗口应该关闭

如果我按下切换按钮(选中),弹出窗口应保持打开状态,直到取消选中该按钮(忽略鼠标输入离开事件),之后鼠标悬停行为应再次启动.

如果弹出窗口外部关闭,则应自动取消选中切换按钮.(我知道这可以使用一些绑定和数据触发器实现,但我想练习我的反应式扩展逻辑)

现在我有以下内容:

    private void ToggleButton_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
    {
        if (!ToggleButton.IsChecked ?? false)
            Popup.IsOpen = true;
    }

    private void ToggleButton_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
    {
        if (!Popup.Child.IsMouseOver && !(TaskManagerTab.IsChecked ?? false))
        {
            Popup.IsOpen = false;
            return;
        }

        popup.Child.MouseLeave +=  Popup_MouseLeave;
    }

    void Popup_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
    {
        Popup.Child.MouseLeave -=  Popup_MouseLeave;

        if (!ToggleButton.IsMouseOver && !(ToggleButton.IsChecked ?? false))
        {
            Popup.IsOpen = false;
            return;
        }
    }

    private void ToggleButton_CheckedChanged(object sender, System.Windows.RoutedEventArgs e)
    {
        Popup.IsOpen = ToggleButton.IsChecked ?? false;

        if (Popup.IsOpen)
            Popup.Closed += Popup_Closed;
    }

    void Popup_Closed(object sender, System.EventArgs e)
    {
        Popup.Closed -= Popup_Closed;

        ToggleButton.IsChecked = false;
    }
}
Run Code Online (Sandbox Code Playgroud)

我会粗略的版本,但我真的不知道如何开始.

谢谢!

更新:

我确实拿出了这个,但我不确定性能,如果未选中切换按钮,我似乎无法重复.

var mouseEnterSaveBtn = Observable.FromEventPattern<MouseEventHandler, MouseEventArgs>(h => SaveBtn.MouseEnter += h,
                                                                       h => SaveBtn.MouseEnter -= h);

        var mouseLeaveList = Observable.FromEventPattern<MouseEventHandler, MouseEventArgs>(h => popup.MouseLeave += h,
                                                                       h => popup.MouseLeave -= h);

        var toggleBtnChecked =
            Observable.FromEventPattern<RoutedEventHandler, RoutedEventArgs>(h => SaveBtn.Checked += h,
                                                                            h => SaveBtn.Checked -= h);

        var allCloseEvents = mouseLeaveList.Merge(mouseLeaveList);

        mouseEnterSaveBtn.TakeUntil(toggleBtnChecked).Subscribe(pattern =>
                                                                    {
                                                                        popup.Visibility = Visibility.Visible;

                                                                        allCloseEvents.TakeUntil(toggleBtnChecked).
                                                                            Subscribe(eventPattern =>
                                                                                          {
                                                                                              if (!popup.IsMouseOver && !popup.IsMouseOver)
                                                                                                  popup.Visibility = Visibility.Collapsed;
                                                                                          });

                                                                    });
Run Code Online (Sandbox Code Playgroud)

And*_*mes 5

这与我的工作非常接近.但我建议的一点是,无论何时你觉得你应该订阅观察者中的一个observable(注意你的嵌套订阅调用),你可以组合这些observable 然后订阅.

var mouseIn = Observable.FromEventPattern<MouseEventHandler, MouseEventArgs>
    (
        h => SaveBtn.MouseEnter += h,
        h => SaveBtn.MouseEnter -= h
    );

var mouseOut = Observable.FromEventPattern<MouseEventHandler, MouseEventArgs>
    (
        h => popup.MouseLeave += h,
        h => popup.MouseLeave -= h
    );

var isMouseOver = mouseIn
    .Select((o,e) => true)
    .Merge(mouseOut
        .Select((o,e) => false));

var toggleBtnChecked = Observable.FromEventPattern<RoutedEventHandler, RoutedEventArgs>
    (
        h => SaveBtn.Checked += h,
        h => SaveBtn.Checked -= h
    )
    .Select((o,e) => (o as ToggleButton).Checked);

var shouldShow = isMouseOver
    .DistinctUntilChanged()
    .CombineLatest(toggleBtnChecked, (mouse, pressed) => pressed || mouse);

shouldShow.Subscribe
(
    shouldBeVisible =>
    {
        popup.Visibility = shouldBeVisible ? Visibility.Visible : Visibility.Collapsed;
    }
);
Run Code Online (Sandbox Code Playgroud)

  • 安德森通过使用CombineLatest获得了它的关键.请记住,您可以使用ViewModel的+绑定完全完成所有这些操作,而不依赖于控件.仅供参考. (2认同)