gpt4 book ai didi

wpf - 如何取消用户的 WPF TreeView 点击?

转载 作者:行者123 更新时间:2023-12-04 00:29:50 24 4
gpt4 key购买 nike

我有一个带有 Treeview 控件的 WPF 应用程序。

当用户单击树上的节点时,页面上的其他 TextBox、ComboBox 等控件将填充适当的值。

然后,用户可以更改这些值并通过单击“保存”按钮保存他或她的更改。

但是,如果用户选择了不同的 Treeview 节点而不保存他或她的更改,我想显示一个警告并有机会取消该选择。

MessageBox: Continue and discard your unsaved changes? OK/Cancel http://img522.imageshack.us/img522/2897/discardsj3.gif

XAML...

<TreeView Name="TreeViewThings"
...
TreeViewItem.Unselected="TreeViewThings_Unselected"
TreeViewItem.Selected="TreeViewThings_Selected" >

视觉基本...

Sub TreeViewThings_Unselected(ByVal sender As System.Object, _
ByVal e As System.Windows.RoutedEventArgs)
Dim OldThing As Thing = DirectCast(e.OriginalSource.DataContext, Thing)
If CancelDueToUnsavedChanges(OldThing) Then
'这里放取消代码
万一
结束子

子 TreeViewThings_Selected(ByVal 发件人作为 System.Object,_
ByVal e As System.Windows.RoutedEventArgs)
将 NewThing 调暗为 Thing = DirectCast(e.OriginalSource.DataContext, Thing)
PopulateControlsFromThing(NewThing)
结束子

如何取消那些取消选择/选择事件?

更新:我问了一个后续问题......
How do I properly handle a PreviewMouseDown event with a MessageBox confirmation?

最佳答案

您实际上不能将逻辑放入 OnSelectedItemChanged 方法中,如果存在逻辑,则 Selected Item 实际上已经更改。

正如另一张海报所建议的,PreviewMouseDown 处理程序是实现逻辑的更好位置,但是,仍然需要完成大量的工作。

下面是我的 2 美分:

首先是我实现的 TreeView:

public class MyTreeView : TreeView
{
static MyTreeView( )
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(MyTreeView),
new FrameworkPropertyMetadata(typeof(TreeView)));
}

// Register a routed event, note this event uses RoutingStrategy.Tunnel. per msdn docs
// all "Preview" events should use tunneling.
// http://msdn.microsoft.com/en-us/library/system.windows.routedevent.routingstrategy.aspx
public static RoutedEvent PreviewSelectedItemChangedEvent = EventManager.RegisterRoutedEvent(
"PreviewSelectedItemChanged",
RoutingStrategy.Tunnel,
typeof(CancelEventHandler),
typeof(MyTreeView));

// give CLR access to routed event
public event CancelEventHandler PreviewSelectedItemChanged
{
add
{
AddHandler(PreviewSelectedItemChangedEvent, value);
}
remove
{
RemoveHandler(PreviewSelectedItemChangedEvent, value);
}
}

// override PreviewMouseDown
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
{
// determine which item is going to be selected based on the current mouse position
object itemToBeSelected = this.GetObjectAtPoint<TreeViewItem>(e.GetPosition(this));

// selection doesn't change if the target point is null (beyond the end of the list)
// or if the item to be selected is already selected.
if (itemToBeSelected != null && itemToBeSelected != SelectedItem)
{
bool shouldCancel;

// call our new event
OnPreviewSelectedItemChanged(out shouldCancel);
if (shouldCancel)
{
// if we are canceling the selection, mark this event has handled and don't
// propogate the event.
e.Handled = true;
return;
}
}

// otherwise we want to continue normally
base.OnPreviewMouseDown(e);
}

protected virtual void OnPreviewSelectedItemChanged(out bool shouldCancel)
{
CancelEventArgs e = new CancelEventArgs( );
if (PreviewSelectedItemChangedEvent != null)
{
// Raise our event with our custom CancelRoutedEventArgs
RaiseEvent(new CancelRoutedEventArgs(PreviewSelectedItemChangedEvent, e));
}
shouldCancel = e.Cancel;
}
}

一些扩展方法来支持 TreeView 在鼠标下查找对象。
public static class ItemContainerExtensions
{
// get the object that exists in the container at the specified point.
public static object GetObjectAtPoint<ItemContainer>(this ItemsControl control, Point p)
where ItemContainer : DependencyObject
{
// ItemContainer - can be ListViewItem, or TreeViewItem and so on(depends on control)
ItemContainer obj = GetContainerAtPoint<ItemContainer>(control, p);
if (obj == null)
return null;

// it is worth noting that the passed _control_ may not be the direct parent of the
// container that exists at this point. This can be the case in a TreeView, where the
// parent of a TreeViewItem may be either the TreeView or a intermediate TreeViewItem
ItemsControl parentGenerator = obj.GetParentItemsControl( );

// hopefully this isn't possible?
if (parentGenerator == null)
return null;

return parentGenerator.ItemContainerGenerator.ItemFromContainer(obj);
}

// use the VisualTreeHelper to find the container at the specified point.
public static ItemContainer GetContainerAtPoint<ItemContainer>(this ItemsControl control, Point p)
where ItemContainer : DependencyObject
{
HitTestResult result = VisualTreeHelper.HitTest(control, p);
DependencyObject obj = result.VisualHit;

while (VisualTreeHelper.GetParent(obj) != null && !(obj is ItemContainer))
{
obj = VisualTreeHelper.GetParent(obj);
}

// Will return null if not found
return obj as ItemContainer;
}

// walk up the visual tree looking for the nearest ItemsControl parent of the specified
// depObject, returns null if one isn't found.
public static ItemsControl GetParentItemsControl(this DependencyObject depObject)
{
DependencyObject obj = VisualTreeHelper.GetParent(depObject);
while (VisualTreeHelper.GetParent(obj) != null && !(obj is ItemsControl))
{
obj = VisualTreeHelper.GetParent(obj);
}

// will return null if not found
return obj as ItemsControl;
}
}

最后但并非最不重要的是利用 RoutedEvent 子系统的自定义 EventArgs。
public class CancelRoutedEventArgs : RoutedEventArgs
{
private readonly CancelEventArgs _CancelArgs;

public CancelRoutedEventArgs(RoutedEvent @event, CancelEventArgs cancelArgs)
: base(@event)
{
_CancelArgs = cancelArgs;
}

// override the InvokeEventHandler because we are going to pass it CancelEventArgs
// not the normal RoutedEventArgs
protected override void InvokeEventHandler(Delegate genericHandler, object genericTarget)
{
CancelEventHandler handler = (CancelEventHandler)genericHandler;
handler(genericTarget, _CancelArgs);
}

// the result
public bool Cancel
{
get
{
return _CancelArgs.Cancel;
}
}
}

关于wpf - 如何取消用户的 WPF TreeView 点击?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/542392/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com