0

[introduction] I have sample WPF application. If I click a button, new window is opened. I need to wait some time for data to be loaded inside it. Rather than passively wait, I want to do some other stuff in the meantime. I can for example open some context menu. This situation is illustrated on the screen below:

enter image description here

This wait-for-me window, just after the loading is completed (data is ready to show), fires an event where focus is set to the grid:

void DataLoaded(object sender, EventArgs e)
{             
    grid.Focus();
    grid.SelectedIndex = 0;
}

[current issue] Unfortunately, in the very same moment, our recently opened context menu has just disappeared. The focus has been forcefully stolen from it. Annoying final effect is shown below:

enter image description here

[desired effect] What would be the happy end? It would be no automatic focus, if user just changed it to any other element (like context menu). In the other words - do not steal the focus.

enter image description here

The code modification could be:

void DataLoaded(object sender, EventArgs e)
{
    if (Magic.FocusNotChanged)
    {                
        grid.Focus();
        grid.SelectedIndex = 0;
    }
}

But, what is the Magic? Some global publish subscribe mechanism which allows or denies automatic focus changes? Some handler which is spying focus changes?

BTW: This particular application shown above is just artificially extracted from much wider context. Do not pay much attention to the layout implemented here. Some generic mechanism has to be invented, not related to this specific button or context menu. Any clues? Regards.

4

1 回答 1

0

解决方案是平淡无奇的 - 以非侵入性方式集中注意力,检查窗口是否在那个时候处于活动状态:

void DataLoaded(object sender, EventArgs e)
{
    if (this.IsActive)
    {                
        grid.Focus();
        grid.SelectedIndex = 0;
    }
}

一些进一步的增强:

假设我们想要更通用的解决方案。如果我们想从某个窗口托管的特定控件中设置焦点,而不是从窗口本身(缺少IsActive属性)怎么办?我们需要找到它的父窗口,以检查它是否仍然处于活动状态。更重要的是,假设这个控件包含一堆子控件,我们想将焦点设置到某个特定的子控件。看这个:

void DataLoaded(object sender, EventArgs e)
{
    var window = this.GetParent<Window>();
    if (window.IsActive)
    {         
        var grid = this.GetChild<DataGrid>();
        grid.Focus();
    }
}

您可以看到两个辅助方法的用法。它们的实现如下:

public static T GetParent<T>(this DependencyObject child) where T : DependencyObject
{
    if (child == null) return null;

    // get parent item
    var parentObject = VisualTreeHelper.GetParent(child);
    // we’ve reached the end of the tree
    if (parentObject == null) return null;
    // check if the parent matches the type we’re looking for
    var parent = parentObject as T;
    // return parent if match or use recursion to proceed with next level
    return parent ?? GetParent<T>(parentObject);            
}

public static T GetChild<T>(this DependencyObject parent) where T : DependencyObject
{
    if (parent == null) return null;
    T result = null;

    var childrenCount = VisualTreeHelper.GetChildrenCount(parent);
    for (var i = 0; i < childrenCount; i++)
    {
        var childObject = VisualTreeHelper.GetChild(parent, i);
        var child = childObject as T;
        if (child == null)
            result = childObject.GetChild<T>();
        else
        {
            result = (T) childObject;
            break;
        }
    }   
    return result;
}
于 2013-11-08T10:10:37.340 回答