[英]Dragging Adorner does not work when TextBox text is selected
I have a custom adorner that is added to controls when they are selected. 选择控件时,我将其添加到控件中。 The issue is, I also have a custom global event registered to automatically select all text in a textbox when it is focused. 问题是,我还注册了一个自定义全局事件,以便在焦点集中时自动选择文本框中的所有文本。
The issue I have is that my adorner does not work when I try to use it on a textbox with selected text. 我的问题是,当我尝试在具有选定文本的文本框中使用它时,装饰器不起作用。 For some reason it tries to drag the selected text instead. 由于某种原因,它尝试拖动选定的文本。 The weird thing is I can drag the selected text and then after that drop is completed I can then use my adorner. 奇怪的是,我可以拖动选定的文本,然后完成拖放操作,然后可以使用我的装饰器。 I am not sure why or how to fix it. 我不确定为什么或如何解决它。
I have tried cancelling the drag command on the individual textboxes but that also prevents the adorner from working. 我尝试取消单个文本框上的拖动命令,但这也使装饰器无法正常工作。
Is there a way I can give the adorner a higher priority over the selected text? 有没有一种方法可以使装饰器的优先级高于所选文本?
Here is my custom adorner 这是我的定制装饰品
public class DraggingAdorner : Adorner
{
Thumb draggingIcon = null;
Thumb resizeThumb = null;
Border border = null;
VisualCollection visualChildren;
public DraggingAdorner(UIElement adornedElement)
: base(adornedElement)
{
visualChildren = new VisualCollection(this);
BuildBorder();
BuildDraggingIcon();
BuildResizer();
draggingIcon.DragDelta += DraggingIcon_DragDelta;
resizeThumb.DragDelta += Resize;
resizeThumb.MouseDoubleClick += ResizeThumb_MouseDoubleClick;
}
private void ResizeThumb_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
FrameworkElement adornedElement = this.AdornedElement as FrameworkElement;
Thumb hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null) return;
FrameworkElement parentElement = adornedElement.Parent as FrameworkElement;
var tb = adornedElement as TextBox;
if (tb == null) return;
tb.Height = Double.NaN;
tb.Width = Double.NaN;
e.Handled = true;
}
private void BuildBorder()
{
if (border != null) return;
border = new Border();
border.BorderBrush = new SolidColorBrush(Colors.Black);
border.BorderThickness = new Thickness(1);
border.Opacity = .5;
visualChildren.Add(border);
}
private void BuildDraggingIcon()
{
if (draggingIcon != null) return;
draggingIcon = new Thumb();
draggingIcon.Cursor = Cursors.Hand;
draggingIcon.Height = draggingIcon.Width = 12;
draggingIcon.Opacity = 0.40;
draggingIcon.Background = new SolidColorBrush(Colors.Black);
visualChildren.Add(draggingIcon);
}
private void BuildResizer()
{
if (resizeThumb != null) return;
resizeThumb = new Thumb();
// Set some arbitrary visual characteristics.
resizeThumb.Cursor = Cursors.ScrollAll;
resizeThumb.Height = resizeThumb.Width = 10;
resizeThumb.Opacity = 0.40;
resizeThumb.Background = new SolidColorBrush(Colors.Red);
visualChildren.Add(resizeThumb);
}
private void DraggingIcon_DragDelta(object sender, DragDeltaEventArgs e)
{
FrameworkElement adornedElement = this.AdornedElement as FrameworkElement;
Thumb hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null) return;
FrameworkElement parentElement = adornedElement.Parent as FrameworkElement;
var left = e.HorizontalChange + Canvas.GetLeft(adornedElement);
if (left <= 0)
{
left = 1;
}
else if (left + adornedElement.ActualWidth >= parentElement.ActualWidth)
{
left = parentElement.ActualWidth - adornedElement.ActualWidth - 1;
}
var top = e.VerticalChange + Canvas.GetTop(adornedElement);
if (top <= 0)
{
top = 1;
}
else if (top + adornedElement.ActualHeight >= parentElement.ActualHeight)
{
top = parentElement.ActualHeight - adornedElement.ActualHeight - 1;
}
Canvas.SetLeft(adornedElement, left);
Canvas.SetTop(adornedElement, top);
}
// Handler for resizing from the bottom-right.
private void Resize(object sender, DragDeltaEventArgs e)
{
FrameworkElement adornedElement = this.AdornedElement as FrameworkElement;
Thumb hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null) return;
FrameworkElement parentElement = adornedElement.Parent as FrameworkElement;
// Ensure that the Width and Height are properly initialized after the resize.
EnforceSize(adornedElement);
var left = Canvas.GetLeft(adornedElement);
var top = Canvas.GetTop(adornedElement);
var newWidth = Math.Max(adornedElement.Width + e.HorizontalChange, hitThumb.DesiredSize.Width);
var newHeight = Math.Max(e.VerticalChange + adornedElement.Height, hitThumb.DesiredSize.Height);
if (left + newWidth >= parentElement.ActualWidth)
{
newWidth = parentElement.ActualWidth - left;
}
if (top + newHeight >= parentElement.ActualHeight)
{
newHeight = parentElement.ActualHeight - top;
}
adornedElement.Width = newWidth;
adornedElement.Height = newHeight;
}
private void EnforceSize(FrameworkElement adornedElement)
{
if (adornedElement.Width.Equals(Double.NaN))
adornedElement.Width = adornedElement.DesiredSize.Width;
if (adornedElement.Height.Equals(Double.NaN))
adornedElement.Height = adornedElement.DesiredSize.Height;
FrameworkElement parent = adornedElement.Parent as FrameworkElement;
if (parent != null)
{
adornedElement.MaxHeight = parent.ActualHeight;
adornedElement.MaxWidth = parent.ActualWidth;
}
}
protected override Size ArrangeOverride(Size finalSize)
{
double desiredWidth = AdornedElement.DesiredSize.Width;
double desiredHeight = AdornedElement.DesiredSize.Height;
double adornerWidth = this.DesiredSize.Width;
double adornerHeight = this.DesiredSize.Height;
draggingIcon.Arrange(new Rect(-adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight));
resizeThumb.Arrange(new Rect(desiredWidth - adornerWidth / 2, desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight));
border.Arrange(new Rect(0, 0, adornerWidth, adornerHeight));
return finalSize;
}
protected override int VisualChildrenCount { get { return visualChildren.Count; } }
protected override Visual GetVisualChild(int index) { return visualChildren[index]; }
}
Here is my code to apply the adorner 这是我应用装饰者的代码
private void OnPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
e.Handled = AdornSelectedElement(sender as UIElement);
}
private bool AdornSelectedElement(UIElement element)
{
if (element == null) return false;
RemoveSelectedElement();
if (Canvas.GetLeft(element) < 0)
Canvas.SetLeft(element, 1);
var aLayer = AdornerLayer.GetAdornerLayer(element);
if ((aLayer.GetAdorners(element)?.Length ?? 0) > 0) return false;
aLayer.Add(new DraggingAdorner(element));
selectedElement = element;
return true;
}
private void RemoveSelectedElement()
{
if (selectedElement == null) return;
var aLayer = AdornerLayer.GetAdornerLayer(selectedElement);
if ((aLayer.GetAdorners(selectedElement)?.Length ?? 0) < 1) return;
aLayer.Remove(aLayer.GetAdorners(selectedElement)[0]);
selectedElement = null;
}
Here is my global event handler 这是我的全局事件处理程序
protected override void OnStartup(StartupEventArgs e)
{
EventManager.RegisterClassHandler(typeof(TextBox), TextBox.GotKeyboardFocusEvent, new RoutedEventHandler(OnTextBoxFocus));
EventManager.RegisterClassHandler(typeof(TextBox), TextBox.GotFocusEvent, new RoutedEventHandler(OnTextBoxFocus));
base.OnStartup(e);
}
private void OnTextBoxFocus(object sender, RoutedEventArgs e)
{
var tb = sender as System.Windows.Controls.TextBox;
if (tb == null) return;
if (!String.IsNullOrWhiteSpace(tb.Text))
tb.SelectAll();
}
Lastly, here is the code to cancel the internal drag on the selected text that did not work 最后,这是用于取消对选定文本无效的内部拖动的代码
DataObject.AddCopyingHandler(tb, (s, e) =>
{
if (e.IsDragDrop)
{
e.CancelCommand();
}
});
I will be more than happy to add any more code that may be necessary. 我将很乐意添加任何可能必要的代码。
EDIT: I do not think it is just because of the selected text in the TextBox. 编辑:我不认为这仅仅是因为在文本框中选择了文本。 I think there is just something weird about my adorner and the textbox, but I am not sure what. 我认为我的装饰器和文本框有些奇怪,但是我不确定是什么。 I have a custom Image control that works fine. 我有一个自定义的图像控件,可以正常工作。
SECOND EDIT: It looks like I actually can't do anything at all (IE Close the main window, click on other controls, etc) after selecting the textbox. 第二编辑:似乎在选择文本框后,我实际上根本无法执行任何操作(即,关闭主窗口,单击其他控件,等等)。 For some reason there is something weird happening where the selection must be handled improperly and it doesn't exit this weird drag text mode. 出于某种原因,发生了一些不可思议的事情,其中必须对选择进行不正确的处理,并且它不会退出此奇怪的拖动文本模式。 I need to drag and drop the text and after that I can do whatever I want again. 我需要拖放文本,然后我可以再次做我想做的事情。
I sort of figured out the issue. 我有点想通了。 Turns out this method 原来这个方法
private void OnPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
e.Handled = AdornSelectedElement(sender as UIElement);
}
Was causing the issues with textboxes. 导致文本框出现问题。 I have a custom image control that requires e.Handled be set to true for this selection to even fire properly, but on TextBoxes this causes the wierd selected text drag issue. 我有一个自定义图像控件,该控件需要将e.Handled设置为true才能使此选择正确触发,但是在TextBoxes上,这会导致选择文本拖拽的问题。 I changed the 我改变了
return true;
at the end of my 在我的结尾
AdornSelectedElement
routine to read 例行阅读
return element is ImageBox;
and that fixed it. 并解决了它。 If anyone knows why this is I can provide the custom control's Xaml and we can discuss why this might have happened. 如果有人知道这是为什么,我可以提供自定义控件的Xaml,我们可以讨论为什么会发生这种情况。
Thanks! 谢谢!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.