I created an Attached Property which registers the drag and drop events and requests the operations: move, link, copy.
UIElement dragablecontrol = d as UIElement;
if (dragablecontrol != null)
{
dragablecontrol.AllowDrop = true;
dragablecontrol.DragEnter += Dragablecontrol_DragEnter;
dragablecontrol.DragStarting += Dragablecontrol_DragStarting;//does not get fired
dragablecontrol.DragOver += Dragablecontrol_DragOver; //e.AcceptedOperation got move, link, copy
dragablecontrol.Drop += Dragablecontrol_Drop; //e.DataView.RequestedOperation is set none
}
Anyway the starting drag event is not fired and my RequestedOperation are ignored because e.Data is null in drag enter.
Therefore (I guess) the event argument parameter e.DataView.RequestedOperation is set to None in the drop event. The file attributes I get with var filesAndFolders = await e.DataView.GetStorageItemsAsync(); are set to ReadOnly.
What can I do about that. I need to rename the dragged files. I created a demo project on GitHub.
Related
I made a simple button, but when i click outside of win form my button getting a black border. By the way i set BorderSize to "0" and it works great while i clicking inside of my form.
this.button.FlatAppearance.BorderSize = 0;
That's how it looks like.
it seems a focus problem. Try to reset the focus when the cursor leave the control.
Add these lines of code to your forms load event.
btn.FlatStyle = FlatStyle.Flat;//You can also use the popup flat style
btn.FlatAppearance.BorderColor = btn.Parent.BackColor;
btn.FlatAppearance.BorderSize = 0;
One simple workaround is to set the FlatAppearance.BorderColor of the Button to its Parent.BackColor:
this.button1.FlatAppearance.BorderColor = this.button1.Parent.BackColor;
You could set this Property subscribing to the ParentChanged event (or overriding OnParentChanged, if it's a Custom Control) if the Control can be assigned to another parent at some point.
You can also perform the same operation in batch, using the HandleCreated event and have all the Buttons (with FlatStyle = FlatStyle.Flat) subscribe to the event in the Form's constructor:
public Form1()
{
InitializeComponent();
foreach (Button button in this.Controls.OfType<Button>().Where(btn => btn.FlatStyle == FlatStyle.Flat))
{
button.HandleCreated += (s, e) => {
button.FlatAppearance.BorderColor = button.Parent.BackColor;
};
}
}
I have a WPF CheckBox inside a Popup, and I'm finding if it is inside the item template of a TreeView, then the CheckBox does not respond to user input. If it is outside of the TreeView, then there are no problems.
I have created a relatively minimal mock-up here:
https://github.com/logiclrd/TestControlsInPopupsNotWorking
Does anyone know why the CheckBox controls popped up from within the TreeView cannot be checked?
I think this is an oversight in the design of the TreeView. Take a look at this:
Note: Some code excerpts were tidied up to avoid wrapping.
// This method is called when MouseButonDown on TreeViewItem and also listen
// for handled events too. The purpose is to restore focus on TreeView when
// mouse is clicked and focus was outside the TreeView. Focus goes either to
// selected item (if any) or treeview itself
internal void HandleMouseButtonDown()
{
if (!this.IsKeyboardFocusWithin)
{
if (_selectedContainer != null)
{
if (!_selectedContainer.IsKeyboardFocused)
_selectedContainer.Focus();
}
else
{
// If we don't have a selection - just focus the TreeView
this.Focus();
}
}
}
This method is called from TreeViewItem.OnMouseButtonDown, which we can see is a class-level handler that's configured to receive handled events too:
EventManager.RegisterClassHandler(
typeof(TreeViewItem),
Mouse.MouseDownEvent,
new MouseButtonEventHandler(OnMouseButtonDown),
/* handledEventsToo: */ true);
I have verified with the debugger that Handled is set to true by the time the event makes it to the TreeViewItem.
When you press down on the left mouse button over the CheckBox, the CheckBox begins a speculative 'click' operation and marks the event as handled. Normally, an ancestor element wouldn't see a handled event bubble up, but in this case it explicitly asked for them.
The TreeView sees that this.IsKeyboardFocusWithin resolves to false because the focused element is in another visual tree (the popup). It then gives focus back to the TreeViewItem.
Now, if you look in ButtonBase:
protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
base.OnLostKeyboardFocus(e);
if (ClickMode == ClickMode.Hover)
{
// Ignore when in hover-click mode.
return;
}
if (e.OriginalSource == this)
{
if (IsPressed)
{
SetIsPressed(false);
}
if (IsMouseCaptured)
ReleaseMouseCapture();
IsSpaceKeyDown = false;
}
}
We see that IsPressed is set to false when focus is lost. If we then go to OnMouseLeftButtonUp, we see this:
bool shouldClick = !IsSpaceKeyDown && IsPressed && ClickMode == ClickMode.Release;
With IsPressed now false, the click operation never completes, all because the TreeViewItem stole focus away from you when you tried to click the button.
As a work-around, I have had success so far with using the NuGet library Ryder (which looks like a freely-usable open-source (MIT license) version of Microsoft Detours) to intercept the HandleMouseButtonDown method in TreeView.
The Ryder library can be found in the NuGet library, and the code behind it can be found here:
https://github.com/6A/Ryder
Hooking the HandleMouseButtonDown method is pretty simple:
var realMethod = typeof(System.Windows.Controls.TreeView).GetMethod("HandleMouseButtonDown", BindingFlags.Instance | BindingFlags.NonPublic);
var replacementMethod = typeof(Program).GetMethod(nameof(TreeView_HandleMouseButtonDown_shim), BindingFlags.Static | BindingFlags.NonPublic);
Redirection.Redirect(realMethod, replacementMethod);
The shim that replaces the method can basically do what the real method does but with a fix that detects the cross-visual-tree focus situation:
static void TreeView_HandleMouseButtonDown_shim(TreeView #this)
{
// Fix as seen in: https://developercommunity.visualstudio.com/content/problem/190202/button-controls-hosted-in-popup-windows-do-not-wor.html
if (!#this.IsKeyboardFocusWithin)
{
// BEGIN NEW LINES OF CODE
var keyboardFocusedControl = Keyboard.FocusedElement;
var focusPathTrace = keyboardFocusedControl as DependencyObject;
while (focusPathTrace != null)
{
if (ReferenceEquals(#this, focusPathTrace))
return;
focusPathTrace = VisualTreeHelper.GetParent(focusPathTrace) ?? LogicalTreeHelper.GetParent(focusPathTrace);
}
// END NEW LINES OF CODE
var selectedContainer = (System.Windows.Controls.TreeViewItem)TreeView_selectedContainer_field.GetValue(#this);
if (selectedContainer != null)
{
if (!selectedContainer.IsKeyboardFocused)
selectedContainer.Focus();
}
else
{
// If we don't have a selection - just focus the treeview
#this.Focus();
}
}
}
Some reflection is needed since this interacts with a private field that is not otherwise exposed from the TreeView class, but as work-arounds go, this is a lot less invasive than what I tried at first, which was importing the entirety of the TreeView class (and related types) from Reference Source into my project in order to alter the one member. :-)
I have downloaded Kinect SDK 1.7, toolkit and have played with following samples.
ControlBasics WPF
InteractionGallery WPF.
I figured out that Kinect Toolkit internally uses the interaction frame to detect the hand position/gesture and accordingly maps it with the Kinect Controls.
I have a requirement where I want to capture a grip event on a Kinect Tile Button. Since the default KinectTileButton does not provide a Grip event. I added a grip event handler on my button.
KinectRegion.AddHandPointerGripHandler(kinectButton, OnHandPointerCaptured);
private void OnHandPointerCaptured(object sender, HandPointerEventArgs handPointerEventArgs)
{
// Add code here
}
I placed a debug breakpoint inside the OnHandPointerCaptured method and was able to receive proper hits when I grip on the KinectTileButton. But for some reason I do not see the KinectCursor image change to a grip as it happens on the KinectScrollViewer control.
I tried setting up the isGripTarget property in the KinectButtonBase class but it doesn't help.
private void InitializeKinectButtonBase()
{
KinectRegion.AddHandPointerPressHandler(this, this.OnHandPointerPress);
KinectRegion.AddHandPointerGotCaptureHandler(this, this.OnHandPointerCaptured);
KinectRegion.AddHandPointerPressReleaseHandler(this, this.OnHandPointerPressRelease);
KinectRegion.AddHandPointerLostCaptureHandler(this, this.OnHandPointerLostCapture);
KinectRegion.AddHandPointerEnterHandler(this, this.OnHandPointerEnter);
KinectRegion.AddHandPointerLeaveHandler(this, this.OnHandPointerLeave);
// Use the same OnHandPointerPress handler for the grip event
KinectRegion.AddHandPointerGripHandler(this, this.OnHandPointerPress);
//Set Kinect button as Grip target
// KinectRegion.SetIsPressTarget(this, true);
KinectRegion.SetIsGripTarget(this, true);
}
How do I change the KinectCursor image from openhand icon to grip, and also the size.
Here's what i found-
1) Cursor Image and Size - Both these samples use Microsoft.Kinect.Toolkit.Controls project that defines the Custom Controls (KinectTileButton,KinectScrollViwer,KinectRegion etc.) used in these samples. The Kinect Cursor image and size is defined as a resource in
Microsoft.Kinect.Toolkit.Controls ->Themes->Generic.xaml. Search for following in the file -
<Style TargetType="{x:Type local:KinectCursor}">
You can modify this as per your need. Wasn't able to find any properties/hooks exposed to control this directly from the UI.
2) Grip event on Tile Button - Kinect Button Supports various events which can be subsribed to and acted upon on your desire. see this
Hand over button event in Kinect SDK 1.7
3) Change Cursor image to Grip on Tile Button -
Microsoft.Kinect.Toolkit.Controls project uses KinectCursorVisualizer.cs and KinectCursor.cs to render the virtual hand cursor on the UI. The Open Hand/Grip visual state is controlled via this Dependency Property defined in KinectCursor.cs.
public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register(
"IsOpen",
typeof(bool),
typeof(KinectCursor),
new UIPropertyMetadata(true, (o, args) => ((KinectCursor)o).EnsureVisualState()));
A quick find all references on the property IsOpen tells that the only place where this property is set is in KinectCursorVisualizer.cs-> OnHandPointersUpdated method. Line- 229
// Set open state
cursor.IsOpen = !pointer.IsInGripInteraction;
And this pointer.IsInGripInteraction property is set at KinectAdapter.cs Line 678
handPointer.IsInGripInteraction = newIsInGripInteraction;
If you look at the code just above this line you'll find that this property is only set to true if the target element has a QueryInteractionStatusHandler defined and it sets
args.Handled , args.IsInGripInteraction property to true.
Since KinectScrollViewer has this handler defined you see a grip image.
private void InitializeKinectScrollViewer()
{
KinectRegion.AddHandPointerGotCaptureHandler(this, this.OnHandPointerCaptured);
KinectRegion.AddHandPointerLostCaptureHandler(this, this.OnHandPointerLostCapture);
KinectRegion.AddHandPointerEnterHandler(this, this.OnHandPointerEnter);
KinectRegion.AddHandPointerMoveHandler(this, this.OnHandPointerMove);
KinectRegion.AddHandPointerPressHandler(this, this.OnHandPointerPress);
KinectRegion.AddHandPointerGripHandler(this, this.OnHandPointerGrip);
KinectRegion.AddHandPointerGripReleaseHandler(this, this.OnHandPointerGripRelease);
//This is the QueryInteractionStatusHandler
KinectRegion.AddQueryInteractionStatusHandler(this, this.OnQueryInteractionStatus);
KinectRegion.SetIsGripTarget(this, true);
this.scrollMoveTimer.Tick += this.OnScrollMoveTimerTick;
this.scrollViewerInertiaScroller.SlowEnoughForSelectionChanged += this.OnSlowEnoughForSelectionChanged;
// Create KinectRegion binding
this.kinectRegionBinder = new KinectRegionBinder(this);
this.kinectRegionBinder.OnKinectRegionChanged += this.OnKinectRegionChanged;
}
but KinectTileButton (extends KinectButtonBase) does not have this handler defined
private void InitializeKinectButtonBase()
{
KinectRegion.AddHandPointerPressHandler(this, this.OnHandPointerPress);
KinectRegion.AddHandPointerGotCaptureHandler(this, this.OnHandPointerCaptured);
KinectRegion.AddHandPointerPressReleaseHandler(this, this.OnHandPointerPressRelease);
KinectRegion.AddHandPointerLostCaptureHandler(this, this.OnHandPointerLostCapture);
KinectRegion.AddHandPointerEnterHandler(this, this.OnHandPointerEnter);
KinectRegion.AddHandPointerLeaveHandler(this, this.OnHandPointerLeave);
KinectRegion.SetIsPressTarget(this, true);
}
How to define this handler ? - Simple add following to your UI. Can be added to constructor
//Add the handler
KinectRegion.AddQueryInteractionStatusHandler(kinectButton, OnQuery);
Define the Handler
//Variable to track GripInterationStatus
bool isGripinInteraction = false;
private void OnQuery(object sender, QueryInteractionStatusEventArgs handPointerEventArgs)
{
//If a grip detected change the cursor image to grip
if (handPointerEventArgs.HandPointer.HandEventType == HandEventType.Grip)
{
isGripinInteraction = true;
handPointerEventArgs.IsInGripInteraction = true;
}
//If Grip Release detected change the cursor image to open
else if (handPointerEventArgs.HandPointer.HandEventType == HandEventType.GripRelease)
{
isGripinInteraction = false;
handPointerEventArgs.IsInGripInteraction = false;
}
//If no change in state do not change the cursor
else if (handPointerEventArgs.HandPointer.HandEventType == HandEventType.None)
{
handPointerEventArgs.IsInGripInteraction = isGripinInteraction;
}
handPointerEventArgs.Handled = true;
}
You may have to tweak this as per your requirement. Happy Kinecting :)
I'm using the SilverLight Toolkit to implement some drag/drop functionality in a Silverlight 4 web application. My drag source is a listbox, and I've got eighteen potential drop targets. I need to allow/disallow dropping based on a string value on the dragged object.
I have no problem doing the comparison and determining whether or not the item is allowed to be dropped on the target, however, I'm having trouble figuring out what the best event is to handle, and how to make it not accept the drop.
I've looked at the DragEnter event, and that looks like the best place to handle this, but I'm not quite sure what I need to do to make it not drop. Here's a snippet of some of the code that I've tried, but it doesn't prevent the drop:
lbDragDrop.DragEnter += (src, e) =>
{
VaultSocketViewModel vm = this.DataContext as VaultSocketViewModel;
ListBoxDragDropTarget target = src as ListBoxDragDropTarget;
ObservableCollection<ItemModel> listBoxBinding = vm.Slots[target.Name];
object data = e.Data.GetData(e.Data.GetFormats()[0]);
ItemDragEventArgs eventArgs = data as ItemDragEventArgs;
SelectionCollection coll = eventArgs.Data as SelectionCollection;
ItemModel newItem = coll.Select(t => t.Item).OfType<ItemModel>().FirstOrDefault();
if (!target.Name.StartsWith(newItem.ItemSlot)) // don't allow drop
{
e.Effects = Microsoft.Windows.DragDropEffects.None;
e.Handled = true;
}
else
{
}
};
just change the Effects to None (like you're doing) should be enough - a good example is some of the internal code in the treeview drag drop target in the toolkit itself (the SetEffects method)
http://silverlight.codeplex.com/SourceControl/changeset/view/57505#779753
Well, I was close. As #James Manning said in his answer, "just change the Effects to None ... should be enough."
So, true, as long as you do it in the right place. I had put my code to handle this in the DragEnter event handler, when it should have been done in the DragOver event handler. Changing the effects in DragEnter are like Rainier Wolfcastle's Radioactive Man goggles-- they do nothing.
So, the code that works is as follows:
lbDragDrop.DragOver += (src, e) =>
{
VaultSocketViewModel vm = this.DataContext as VaultSocketViewModel;
ListBoxDragDropTarget target = src as ListBoxDragDropTarget;
ObservableCollection<ItemModel> listBoxBinding = vm.Slots[target.Name];
object data = e.Data.GetData(e.Data.GetFormats()[0]);
ItemDragEventArgs eventArgs = data as ItemDragEventArgs;
SelectionCollection coll = eventArgs.Data as SelectionCollection;
ItemModel newItem = coll.Select(t => t.Item).OfType<ItemModel>().FirstOrDefault();
if (!target.Name.StartsWith(newItem.ItemSlot)) // don't allow drop
{
e.Effects = Microsoft.Windows.DragDropEffects.None;
e.Handled = true;
}
else
{
}
};
I am building a canvas control. This root canvas has several overlapping children (canvas as well). This is done so each child can handle its own drawing and I can then compose the final result with any combination of children to get the desired behavior.
This is working very well as far as rendering is concerned. This does not work so well with mouse events however. The way mouse events works are as follow (using previewmousemove as an example):
1- If root canvas is under mouse, fire event
2- Check all children, if one is under mouse, fire event and stop
As such, only the first child I add will receive the mouse move event. The event is not propagated to all children because they overlap.
To overcome this, I attempted the following:
1- Override mouse events in the root canvas
2- For every event, find all children that want to handle the event using VisualTreeHelper.HitTest
3- For all children that returned a valid hit test result (ie: under mouse and willing to handle the event (IsHitTestVisible == true)), ???
This is where I am stuck, I somehow need to send the mouse event to all children, and stop the normal flow of the event to make sure the first child doesn't receive it twice (via handled = true in the event).
By using RaiseEvent with the same event passed on the children, things seem to work but somehow it raises the event on the parent (root canvas) as well. To bypass this I needed to create a copy of the event and set force set the source though it appears to be more of a hack than a solution. Is there a proper way to do what I am trying to do? Code example follows.
public class CustomCanvas : Canvas
{
private List<object> m_HitTestResults = new List<object>();
public new event MouseEventHandler MouseMove;
public CustomCanvas()
{
base.PreviewMouseMove += new MouseEventHandler(CustomCanvas_MouseMove);
}
private void CustomCanvas_MouseMove(object sender, MouseEventArgs e)
{
// Hack here, why is the event raised on the parent as well???
if (e.OriginalSource == this)
{
return;
}
Point pt = e.GetPosition((UIElement)sender);
m_HitTestResults.Clear();
VisualTreeHelper.HitTest(this,
new HitTestFilterCallback(OnHitTest),
new HitTestResultCallback(OnHitTest),
new PointHitTestParameters(pt));
MouseEventArgs tmpe = new MouseEventArgs(e.MouseDevice, e.Timestamp, e.StylusDevice);
tmpe.RoutedEvent = e.RoutedEvent;
tmpe.Source = this;
foreach (object hit in m_HitTestResults)
{
UIElement element = hit as UIElement;
if (element != null)
{
// This somehow raises the event on us as well as the element here, why???
element.RaiseEvent(tmpe);
}
}
var handlers = MouseMove;
if (handlers != null)
{
handlers(sender, e);
}
e.Handled = true;
}
private HitTestFilterBehavior OnHitTest(DependencyObject o)
{
UIElement element = o as UIElement;
if (element == this)
{
return HitTestFilterBehavior.ContinueSkipSelf;
}
else if (element != null && element.IsHitTestVisible && element != this)
{
return HitTestFilterBehavior.Continue;
}
return HitTestFilterBehavior.ContinueSkipSelfAndChildren;
}
private HitTestResultBehavior OnHitTest(HitTestResult result)
{
// Add the hit test result to the list that will be processed after the enumeration.
m_HitTestResults.Add(result.VisualHit);
// Set the behavior to return visuals at all z-order levels.
return HitTestResultBehavior.Continue;
}
I think you should use the preview events because those are RoutingStrategy.Tunnel from Window to the most high control in Z-Order, and normal events are RoutingStrategy.Bubble.
In this RoutedEvents there are a property Handle when it's true the system will stop to traverse the visual tree because someone used this event.
I found your code example interesting so I gave it a try... but I had to make a small modification for it to work properly in my stuff.
I had to change the 2nd "if" in the HitTestFilter method as follow:
if (element == null || element.IsHitTestVisible)
As you can see I removed the useless "element != this" at the end (you already tested that condition in the 1st "if") and I added "element == null" at the beginning.
Why? Because at some point during the filtering the parameter type was System.Windows.Media.ContainerVisual which doesn't inherit from UIElement and so element would be set to null and ContinueSkipSelfAndChildren would be returned. But I don't want to skip the children because my Canvas is contained inside its "Children" collection and UIElements I want to hittest with are contained in Canvas.
Just as #GuerreroTook said, you should solve this by using WPF's RoutedEvents (more information here.