2

我有一个弹出面板(如下图所示),当鼠标离开面板区域时,如果未停靠,它应该是不可见的。

弹出面板

但是,如果发生以下任何一种情况,我不希望面板关闭:

1) 用户打开一个ContextMenu

2) 用户选择ComboBox面板下方的项目(如上图所示)

3)由于用户操作(例如删除项目DataGrid)而出现的确认对话框

ContextMenuOpening跟踪上下文菜单操作(和事件)来处理第一种情况很容易ContextMenuClosing,但我还没有找到任何好的方法来处理其他两种情况,特别是正在打开的跟踪对话框。

有任何想法吗?

我的弹出面板只是一个网格,其可见性和内容由后面的代码确定:

<Grid Name="UndockedGrid" ContextMenuOpening="Grid_ContextMenuOpening" ContextMenuClosing="Grid_ContextMenuClosing" MouseLeave="Grid_MouseLeave">
    <!-- Toolbox (undocked) -->
    <ScrollViewer Name="ToolBoxUndockedViewer">
        <StackPanel Name="ToolBoxUndockedPanel" />
    </ScrollViewer>
</Grid>
4

1 回答 1

0

RoutedEvent对这个问题采取了一种方法,因为我的视图模型在这个版本中不直接处理对话工作流。

为了获得我想要的数据网格组合框的行为,我扩展DataGrid添加了我想要跟踪的路由事件:

public class RoutableDataGrid : DataGrid
{
    public static readonly RoutedEvent ElementOpenedEvent = EventManager.RegisterRoutedEvent("ElementOpened", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(RoutableDataGrid));

    public event RoutedEventHandler ElementOpened
    {
        add { AddHandler(ElementOpenedEvent, value); }
        remove { RemoveHandler(ElementOpenedEvent, value); }
    }

    public static readonly RoutedEvent ElementClosedEvent = EventManager.RegisterRoutedEvent("ElementClosed", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(RoutableDataGrid));

    public event RoutedEventHandler ElementClosed
    {
        add { AddHandler(ElementClosedEvent, value); }
        remove { RemoveHandler(ElementClosedEvent, value); }
    }

    public void RaiseElementOpened()
    {
        RaiseEvent(new RoutedEventArgs(RoutableDataGrid.ElementOpenedEvent, this));
    }

    public void RaiseElementClosed()
    {
        RaiseEvent(new RoutedEventArgs(RoutableDataGrid.ElementClosedEvent, this));
    }
}

并且DataGridComboBoxColumn扩展为触发新的路由事件:

public class BindableDataGridComboBoxColumn : DataGridComboBoxColumn
{
    protected RoutableDataGrid ParentGrid { get; set; }

    protected FrameworkElement Element { get; set; }

    protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
    {
        Element = base.GenerateEditingElement(cell, dataItem);
        Element.MouseEnter += new System.Windows.Input.MouseEventHandler(element_MouseEnter);
        Element.MouseLeave += new System.Windows.Input.MouseEventHandler(element_MouseLeave);
        CopyItemsSource(Element);
        return Element;
    }

    void element_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
    {
        if (ParentGrid != null)
        {
            ParentGrid.RaiseElementClosed();
        }
    }

    void element_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
    {
        if (ParentGrid != null)
        {
            ParentGrid.RaiseElementOpened();
        }
    }
}

更多的黑客攻击,因为MessageBox是一个密封类,我必须构建一个包装类来使用 a 触发路由事件MessageBox(并将这个元素的一个实例放在 xaml 中,以便它在可视树中):

public class RoutedEventPlaceHolder : UIElement
{
    public static readonly RoutedEvent ElementOpenedEvent = EventManager.RegisterRoutedEvent("ElementOpened", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(RoutedEventPlaceHolder));

    public event RoutedEventHandler ElementOpened
    {
        add { AddHandler(ElementOpenedEvent, value); }
        remove { RemoveHandler(ElementOpenedEvent, value); }
    }

    public static readonly RoutedEvent ElementClosedEvent = EventManager.RegisterRoutedEvent("ElementClosed", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(RoutedEventPlaceHolder));

    public event RoutedEventHandler ElementClosed
    {
        add { AddHandler(ElementClosedEvent, value); }
        remove { RemoveHandler(ElementClosedEvent, value); }
    }

    public void RaiseElementOpened()
    {
        RaiseEvent(new RoutedEventArgs(RoutedEventPlaceHolder.ElementOpenedEvent, this));
    }

    public void RaiseElementClosed()
    {
        RaiseEvent(new RoutedEventArgs(RoutedEventPlaceHolder.ElementClosedEvent, this));
    }

    public MessageBoxResult ShowMessageBox(string text, string caption, MessageBoxButton button)
    {
        RaiseElementOpened();
        MessageBoxResult result = MessageBox.Show(text, caption, button);
        RaiseElementClosed();
        return result;
    }
}

最后我可以在弹出面板中订阅新的路由事件:

        <Grid Name="UndockedGrid" lib:RoutedEventPlaceHolder.ElementOpened="Grid_ElementOpened" lib:RoutableDataGrid.ElementOpened="Grid_ElementOpened" ContextMenuOpening="Grid_ContextMenuOpening" ContextMenuClosing="Grid_ContextMenuClosing" MouseLeave="Grid_MouseLeave">
            <!-- Toolbox (undocked) -->
            <ScrollViewer Grid.Row="0" Grid.Column="0" Name="ToolBoxUndockedViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Visibility="Collapsed" MouseLeave="ToolBoxUndockedViewer_MouseLeave">
                <StackPanel Name="ToolBoxUndockedPanel" MinWidth="200" Background="{StaticResource ControlBackgroundBrush}" />
            </ScrollViewer>
        </Grid>

这不是一个理想的解决方案。我会接受任何其他更优雅的答案。

于 2011-07-23T05:51:48.097 回答