Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用Rx进行上下文菜单操作_C#_Contextmenu_System.reactive - Fatal编程技术网

C# 使用Rx进行上下文菜单操作

C# 使用Rx进行上下文菜单操作,c#,contextmenu,system.reactive,C#,Contextmenu,System.reactive,我想我应该尝试一下这个新系统,看看它是否能简化对上下文菜单点击列表视图中某个项目的响应执行操作。 到目前为止,所有的设置似乎都比较简单,但我正在努力以正确的方式组合两个事件流(项目选择和菜单单击) 这就是我目前所拥有的 (bookListView包含我的书籍,并显示菜单bookListContextMenu) private void frmBookList\u加载(对象发送方,事件参数e) { //筛选单击事件,以在包含实际书本的ListViewItem上单击鼠标右键 var rightcli

我想我应该尝试一下这个新系统,看看它是否能简化对上下文菜单点击列表视图中某个项目的响应执行操作。 到目前为止,所有的设置似乎都比较简单,但我正在努力以正确的方式组合两个事件流(项目选择和菜单单击)

这就是我目前所拥有的 (bookListView包含我的书籍,并显示菜单bookListContextMenu)

private void frmBookList\u加载(对象发送方,事件参数e)
{
//筛选单击事件,以在包含实际书本的ListViewItem上单击鼠标右键
var rightclicks=from点击可见。FromEventPattern(bookListView,“鼠标点击”)
其中click.EventArgs.Button==MouseButtons.Right&&
ClickedOnBook((ListView)click.Sender,click.EventArgs)!=null
选择“单击”;
//订阅单击以在单击的位置显示上下文菜单
rightclicks.Subscribe(单击=>bookListContextMenu.Show((控件)单击.Sender,单击.EventArgs.Location));
//再次订阅点击,将点击转换为点击图书
var rightclickedbook=rightclicks.Select(click=>ClickedOnBook((ListView)click.Sender,click.EventArgs));
//捕获上下文菜单单击,转换为操作枚举
var clickaction=Observable.FromEventPattern(bookListContextMenu,“ItemClicked”)
.Select(click=>GetAction(click.EventArgs.ClickedItem));
//将两个事件流合并,以获得一对Book和Action
//可以投影到匿名OUE类型,因为它将在此方法中使用
var bookaction=clickaction.CombineTest(rightclickedbook,(action,book)=>new{action=action,book=book});
//订阅操作并分支到特定于操作的方法
bookaction.Subscribe(doaction=>
{
开关(doaction.Action)
{
案例簿记操作。删除:
DeleteBookCommand(doaction.Book);
打破
案例书操作。编辑:
EditBookCommand(doaction.Book);
打破
}
});
}
公共枚举操作
{
无=0,
编辑=1,
删除=2
}
private BookAction GetAction(ToolStripItem项目)
{
如果(item==deleteBookToolStripMenuItem)返回BookAction.Delete;
else if(item==editBookToolStripMenuItem)返回BookAction.Edit;
否则返回BookAction.None;
}
私家书点击书本(列表视图lview,鼠标点击)
{
ListViewItem lvitem=lview.GetItemAt(单击.X,单击.Y);
返回lvitem!=null?lvitem.tagas Book:null;
}
私有void deletebook命令(Book selectedbook)
{
//删除一本书的代码
}
private void editbook命令(Book selectedbook)
{
//编辑一本书的代码
}
问题是组合函数。 如果我使用“CombineLatest”,那么在第一次使用上下文菜单后,每个后续的右键单击 对新选择再次调用上一个操作

如果我使用“Zip”然后右键单击一本书,但在上下文菜单之外而不是在它上面单击,那么下次我右键单击并实际单击菜单时,将在第一个选择上调用该操作,而不是在第二个选择上调用该操作

我尝试了各种形式的限时缓冲区、窗口和最新版本等,但通常只能在菜单出现时立即阻止,以便无法进行选择,或者在显示菜单但未单击任何项目时,获得关于空序列的异常

我相信一定有一个更简单的方法来做这件事,我错过了,但我不知道它是什么

也许是这个

//the menu may be closed with or without clicking any item
var contextMenuClosed = Observable.FromEventPattern(bookListContextMenu, "Closed");
var contextMenuClicked = Observable.FromEventPattern<ToolStripItemClickedEventArgs>(bookListContextMenu, "ItemClicked");

//combine the two event streams to get a pair of Book and Action
//which we can project to an anonymoue type as it will be consumed within this method
var bookaction = from mouseclick in rightclicks
                 let book = ClickedOnBook((ListView)mouseclick.Sender, mouseclick.EventArgs)
                 from menuclick in contextMenuClicked.Take(1).TakeUntil(contextMenuClosed)
                 let action = GetAction(menuclick.EventArgs.ClickedItem)
                 select new { Action = action, Book = book };
//可以通过单击或不单击任何项目来关闭菜单
var contextMenuClosed=Observable.FromEventPattern(bookListContextMenu,“Closed”);
var contextMenuClicked=Observable.FromEventPattern(bookListContextMenu,“ItemClicked”);
//将两个事件流合并,以获得一对Book和Action
//我们可以将其投影为匿名OUE类型,因为它将在该方法中使用
var bookaction=从鼠标右键单击
let book=ClickedOnBook((ListView)mouseclick.Sender,mouseclick.EventArgs)
从contextMenuClicked.Take(1.TakeUntil)(contextMenuClosed)中的menuclick
让action=GetAction(menuclick.EventArgs.ClickedItem)
选择新建{Action=Action,Book=Book};

解决这些问题的最简单方法是在整个可观察序列中携带引发元素(从ClickedOnBook中获得的元素)。一种方法是,每次有人单击书本时,创建上下文菜单的单独实例。差不多

IObservable<BookAction> WhenBookAction()
{
    return Observable.Defer(() => 
    {
       var menu = ContextMenuFactory.CreateMenu;
       return Observable
         .FromEventPattern<ToolStripItemClickedEventArgs>(
            menu, "ItemClicked")
         .Select(click => GetAction(click.EventArgs.ClickedItem));
    }
}
您可以保证这两本书中的书正是导致菜单出现的那本书——“from/from”AKA“SelectMany”AKA“Monad”解决了这个问题

编辑:这里有另一个很好的方法。我懒得复制上下文菜单,所以我的“测试套件”是一个有三个按钮的窗口,分别名为“firstBn”、“secondBn”和“actionBn”——这与问题中的模式相同。以下是我得到的:

    public MainWindow()
    {
        InitializeComponent();
        var actions = Observable
            .FromEventPattern<RoutedEventArgs>(actionBn, "Click");
        var firsts = Observable
            .FromEventPattern<RoutedEventArgs>(firstBn, "Click")
            .Select(x => firstBn);
        var seconds = Observable
            .FromEventPattern<RoutedEventArgs>(secondBn, "Click")
            .Select(x => secondBn);
        var buttons = firsts.Merge(seconds);
        var buttonActions = buttons
            .Select(x => actions.Select(_ => x))
            .Switch();
        buttonActions.Subscribe(x => Console.WriteLine(x.Name));
    }
public主窗口()
{
初始化组件();
var行动=可观察
.FromEventPattern(actionBn,“单击”);
var firsts=可观测
.FromEventPattern(第一个BN,“单击”)
.选择(x=>firstBn);
var秒=可观测
.FromEventPattern(第二个BN,“单击”)
.选择(x=>secondBn);
var按钮=第一次合并(秒);
var buttonActions=按钮
.Select(x=>actions.Select(=>x))
.开关();
Subscribe(x=>Console.WriteLine(x.Name));
}

一个可能的答案包括SelectMany、Take和TakeUntil,但我可以再发布5个小时。请看我答案中的第二个选项。
from book in rightclicks.Select(
  click => ClickedOnBook((ListView)click.Sender, click.EventArgs))
from action in WhenBookAction()
select book, action;
    public MainWindow()
    {
        InitializeComponent();
        var actions = Observable
            .FromEventPattern<RoutedEventArgs>(actionBn, "Click");
        var firsts = Observable
            .FromEventPattern<RoutedEventArgs>(firstBn, "Click")
            .Select(x => firstBn);
        var seconds = Observable
            .FromEventPattern<RoutedEventArgs>(secondBn, "Click")
            .Select(x => secondBn);
        var buttons = firsts.Merge(seconds);
        var buttonActions = buttons
            .Select(x => actions.Select(_ => x))
            .Switch();
        buttonActions.Subscribe(x => Console.WriteLine(x.Name));
    }