我正在开发一个应用程序,其中我们有一个主窗口,在不同的dock选项中有这么多的子窗口。因此,一个扩展坞具有一个属性面板窗口,允许用户修改所选实体的属性,并且在更改值后,用户必须单击控件底部的“应用”按钮。所以,我愿意提供某种功能,如果用户修改了某些值而不是单击“应用”,如果用户单击除了属性面板视图的子控件之外的其他位置,则应该向用户发出“请先点击”的消息申请保存您的更改“。为此,我在MainWindow的鼠标按下事件上编写了以下代码。
private void MainWindow_MouseDown(object sender, MouseButtonEventArgs e)
{
var hitObject = this.InputHitTest(e.GetPosition(this)) as DependencyObject;
if (hitObject.FindVisualAncestor<PropertyPanelUserControl>() == null)
{
MessageBox.Show("Please save your changes");
}
}
所以,逻辑就是这样,在主窗口的鼠标按下时,获取命中对象并检查它是否是属性面板控件的子控件,然后它将PropertyPanelUserControl作为其父级和其他控件而不是它们的一部分或者ChildPanelUserControl的子控件,然后会提示用户单击apply。
上面的代码工作非常棒...但是我发现了一个奇怪的问题,我在属性面板中有一个组合框,其中包含1到10个条目。因此,当用户尝试将值更改为其他值时,那么用户将不会被给出该消息,因为到目前为止用户正在单击属性面板控件,当我在组合框中选择项目后检查鼠标按下事件中的命中对象时,则命中对象是chromeButton或组合框。但是当我选择最后一个项目10时,然后命中对象作为具有属性面板控件的边框。
<Border><View:PropertyPanelControl/></Border>
及以上检查失败,因为border没有祖先作为属性面板控件,而border是控件的祖先。因此,即使只更改组合框值,用户也会收到消息,
此外,我已经确定我点击组合框项目不在外面,所以,现在问题是为什么wpf以这种奇怪的方式表现以及如何解决这个问题。
答案 0 :(得分:1)
你的第一个问题很奇怪:
为什么wpf以这种奇怪的方式表现
你描述了发生了什么,这对我来说似乎完全正常。用户点击ComboBoxItem
,HitTest
告诉您已点击ComboBoxItem
...我没有看到任何问题。
如何解决此问题
现在我想象一下,如果你已经拍摄了ComboBoxItem
并沿着视觉树向上移动,那么你就会找到你的PropertyPanelUserControl
控件。尝试这样的事情:
HitTestResult result = VisualTreeHelper.HitTest(this, e.GetPosition(this));
UIElement uIElement = result.VisualHit.GetParentOfType<PropertyPanelUserControl>();
if (uIElement != null)
{
// the user clicked inside the PropertyPanelUserControl control
}
GetParentOfType
方法是我创建的一种扩展方法,它在可视化树中查找特定类型的第一个元素...如果您愿意,可以轻松地将其重构为常规方法:
public static T GetParentOfType<T>(this DependencyObject element) where T : DependencyObject
{
Type type = typeof(T);
if (element == null) return null;
DependencyObject parent = VisualTreeHelper.GetParent(element);
if (parent == null && ((FrameworkElement)element).Parent is DependencyObject) parent = ((FrameworkElement)element).Parent;
if (parent == null) return null;
else if (parent.GetType() == type || parent.GetType().IsSubclassOf(type)) return parent as T;
return GetParentOfType<T>(parent);
}