受け入れられた回答(およびこのページの他の回答)は、元のポスターが持つ特定の問題を解決しますが、タイトルに書かれた質問に適切な答えを与えません。つまり、コントロールが見えるかどうかを判断する方法ユーザー。問題は、他のコントロールでカバーされているコントロールはレンダリングすることはできますが、他のコントロールが解決しているコンテナの境界内にあるにもかかわらず、は表示されません。ユーザーによる
AAコントロールを使用すると、時々、WPFのUIElementがクリッカブル(またはPC上で到達可能なマウス)であるかどうかを判断のことができるようにする必要がユーザーに表示されるかどうかを決定する
私はときに、この問題が発生しました私はボタンがマウスでクリックできるかどうかをチェックしようとしていました。私に迷惑をかけた特別なシナリオは、ボタンが実際にユーザーに見えるが、マウスクリックを防ぐ透明レイヤー(または半透明レイヤーまたは非透明レイヤー)で覆われているということでした。そのような場合、コントロールはユーザーには見えるが、ユーザーにはアクセスできません。ユーザーには表示されないようなものです。
私は自分の解決策を考えなければなりませんでした。
EDIT - オリジナルの投稿には、InputHitTestメソッドを使用した別のソリューションがありました。しかし、それは多くの場合にうまくいかず、私はそれを再設計しなければならなかった。このソリューションははるかに堅牢で、偽の否定や否定がなくてもうまく機能しているようです。
ソリューション:
- は、アプリケーションのメインウィンドウ
- コール(左上、左下、右上、右下)、全ての角
- 上へのオブジェクトの絶対位置を取得する私たちオブジェクトを呼び出す完全にクリック可能なから取得したオブジェクトが元のオブジェクトまたはすべての角の視覚的な親と等しい場合は部分的に1つまたは複数のコーナーにはをクリックできます。
#1の点に注意してください。完全にクリッカブルまたは部分的に クリッカブルのここでの定義は正確ではありません - 私たちは オブジェクトのすべての四隅がクリック可能ですチェックしています。たとえば、ボタンにクリック可能なコーナーが4つありますが、 の中心にクリック可能なスポットがある場合は、それでも 完全にクリック可能と見なされます。指定されたオブジェクト内のすべての点をチェックするには、無駄な もあります。
#2の点に注意してください。私たちはそれを
を見つけることを希望する場合、時々(ただし、これは多くの一般的な コントロールのデフォルト値です)
真にオブジェクト
IsHitTestVisible
プロパティを設定する必要がありその後
private bool isElementClickable<T>(UIElement container, UIElement element, out bool isPartiallyClickable)
{
isPartiallyClickable = false;
Rect pos = GetAbsolutePlacement((FrameworkElement)container, (FrameworkElement)element);
bool isTopLeftClickable = GetIsPointClickable<T>(container, element, new Point(pos.TopLeft.X + 1,pos.TopLeft.Y+1));
bool isBottomLeftClickable = GetIsPointClickable<T>(container, element, new Point(pos.BottomLeft.X + 1, pos.BottomLeft.Y - 1));
bool isTopRightClickable = GetIsPointClickable<T>(container, element, new Point(pos.TopRight.X - 1, pos.TopRight.Y + 1));
bool isBottomRightClickable = GetIsPointClickable<T>(container, element, new Point(pos.BottomRight.X - 1, pos.BottomRight.Y - 1));
if (isTopLeftClickable || isBottomLeftClickable || isTopRightClickable || isBottomRightClickable)
{
isPartiallyClickable = true;
}
return isTopLeftClickable && isBottomLeftClickable && isTopRightClickable && isBottomRightClickable; // return if element is fully clickable
}
private bool GetIsPointClickable<T>(UIElement container, UIElement element, Point p)
{
DependencyObject hitTestResult = HitTest< T>(p, container);
if (null != hitTestResult)
{
return isElementChildOfElement(element, hitTestResult);
}
return false;
}
private DependencyObject HitTest<T>(Point p, UIElement container)
{
PointHitTestParameters parameter = new PointHitTestParameters(p);
DependencyObject hitTestResult = null;
HitTestResultCallback resultCallback = (result) =>
{
UIElement elemCandidateResult = result.VisualHit as UIElement;
// result can be collapsed! Even though documentation indicates otherwise
if (null != elemCandidateResult && elemCandidateResult.Visibility == Visibility.Visible)
{
hitTestResult = result.VisualHit;
return HitTestResultBehavior.Stop;
}
return HitTestResultBehavior.Continue;
};
HitTestFilterCallback filterCallBack = (potentialHitTestTarget) =>
{
if (potentialHitTestTarget is T)
{
hitTestResult = potentialHitTestTarget;
return HitTestFilterBehavior.Stop;
}
return HitTestFilterBehavior.Continue;
};
VisualTreeHelper.HitTest(container, filterCallBack, resultCallback, parameter);
return hitTestResult;
}
private bool isElementChildOfElement(DependencyObject child, DependencyObject parent)
{
if (child.GetHashCode() == parent.GetHashCode())
return true;
IEnumerable<DependencyObject> elemList = FindVisualChildren<DependencyObject>((DependencyObject)parent);
foreach (DependencyObject obj in elemList)
{
if (obj.GetHashCode() == child.GetHashCode())
return true;
}
return false;
}
private IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
private Rect GetAbsolutePlacement(FrameworkElement container, FrameworkElement element, bool relativeToScreen = false)
{
var absolutePos = element.PointToScreen(new System.Windows.Point(0, 0));
if (relativeToScreen)
{
return new Rect(absolutePos.X, absolutePos.Y, element.ActualWidth, element.ActualHeight);
}
var posMW = container.PointToScreen(new System.Windows.Point(0, 0));
absolutePos = new System.Windows.Point(absolutePos.X - posMW.X, absolutePos.Y - posMW.Y);
return new Rect(absolutePos.X, absolutePos.Y, element.ActualWidth, element.ActualHeight);
}
(例えば)ボタンがクリック可能であるかどうかを確認するために必要なことすべてを呼び出すことです:
if (isElementClickable<Button>(Application.Current.MainWindow, myButton, out isPartiallyClickable))
{
// Whatever
}
私はかつて同様の問題を抱えていました。コントロールが表示されているかどうかを検出するコードを作成した後、実際に隠しコントロールを更新するよりも検出するコードが遅いことが判明しました。それが価値がないかもしれないので、ベンチマークしてください。 –