我正在努力学习更多关于反应式扩展的知识,但我发现很难找到一个真实世界的例子来训练自己。
几天前,我发现自己正在编写一些ToggleButton
鼠标输入、保持选中未选中的事件,现在我想知道是否可以使用反应式扩展来简化它。
目标是:
给定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;
}
}
我想要一个粗略的版本,但我真的不知道该怎么开始。
谢谢!
更新:
我确实想到了这个,但我不确定性能,如果切换按钮未选中,我似乎无法重复。
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;
});
});
这与我的想法非常接近。不过,我建议你,只要你觉得你应该订阅观察者中的一个可观察对象(注意你的嵌套subscribe调用),你就可以将这些可观察对象组合起来,然后订阅。
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;
}
);