How to select an object in canvas wpf - wpf

I am dropping ListBox items (items here are textbox, checkbox, radio buttons when user drops onto canvas we are creating controls dynamic and adding to canvas) to Canvas. Now when user clicks on any item in the canvas, want to show properties on that control.
How to get the selected control from the canvas?

To get UI element under mouse on click you can perform hit testing. In XAML define MouseDown event handler:
<Canvas Mouse.MouseDown="Canvas_MouseDown">
and implement it:
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
var canvas = sender as Canvas;
if (canvas == null)
return;
HitTestResult hitTestResult = VisualTreeHelper.HitTest(canvas, e.GetPosition(canvas));
var element = hitTestResult.VisualHit;
// do something with element
}

Related

Dynamically create ContextMenu in Silverlight 5

I have just started to use Silverlight this few days.
Currently I have generated some panel dynamically in a canvas. Each panel will have a shared MouseLeftButtonUp event which will display a ContextMenu.
The problem now is when I click on a first panel, the ContextMenu is able to show but when I click on a second panel, the first ContextMenu shown up instead of the second. The second panel will show its ContextMenu only when I click another time on the second panel.
Below is my code to generate the panel and the context menu:
void generatePanel()
{
StackPanel panel = new StackPanel();
panel.MouseLeftButtonUp += panel_MouseLeftButtonUp;
canvas.Children.Add(panel)
}
void panel_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
ContextMenu menu = new ContextMenu();
menu.IsOpen = true;
}
Hopefully my problem is clear enough. Is there any way to solve the problem? Or if there are any event that are fired when the menu is hidden, so that I can make sure the previous context menu is disposed or cleared?
Thanks.

WPF MouseDown event on FrameworkElement object

I have a WPF Application that receive FrameworkElement objects from 3rd party API.
I would like to register events on those objects.
Is this possible? This not working:
public void DisplayControl(FrameworkElement control)
{
control.MouseEnter += new MouseEventHandler(Control_MouseEnter);
control.MouseDown += new MouseButtonEventHandler(Control_MouseDownFromElement);
VideoGrid.Children.Add(control);
}
void Control_MouseDownFromElement(object sender, EventArgs e)
{
lblOutput.Content = string.Format("Sender is: " + sender.ToString());
}
void Control_MouseEnter(object sender, EventArgs e)
{
(sender as FrameworkElement).Focus();
}
One possible reason is the control provider is intentionally blocking that event... you can try adding a control(say grid) on the top of the original control with 0.01 opacity means virtually the control we have added is not visible to the user and we can write all the events on the invisible control...
Update
Something like this... create a grid with opacity 0.01 add events to that grid and add the grid to the video grid after adding your control... so in the video grid there will be control and on the top of the control there will be grid which is invisible because of its opacity and your events will work on the grid... make sure to give same height and width to the grid that match with your control height and width....
Grid grd = new Grid();
grd.Opacity = 0.01;
grd.MouseDown += new MouseButtonEventHandler(Grid_MouseDown_1);
VideoGrid.Children.Add(control);
VideoGrid.Children.Add(grd)

WPF Adorner appear on mouseover animation - what's the best pattern?

An Adorner is defined over part of an Image. The required behavior is as follows:
When the mouse is over the image area, including the Adorner area, the Adorner appears.
When the mouse leaves the image and Adorner area, the Adorner dissapears.
Adorner appearing and disappearing is to be through a fade in / out animation, accordingly.
A click on the Adorner area must raise event AdornerClicked
A click on the area over the Image which is not hidden by the adorner, must rais ImageClicked.
A naive implementation
Attach an animation on the Adorner opacity on the Image's MouseEnter and MouseLeave events, and attach Click events for each. This however causes the Adorner to disappear when the mouse is directly above it (as a MouseLeave is triggered on the Image below), violating requirement number 1.
A possible amendment to the naive implementation is to set IsHitTestVisible=false on the Adorner. However, no clicks are then captured by the Adorner, violating requirement number 4.
What is the correct pattern which will fulfill the requirements?
A bit old question but I've just had the same problem and could not find an answer so here's what I've come up with.
So the problem is that the control and its adorner are overlapping and setting the adorner to visible triggers a MouseLeave on the adorned control because it is now covered by the adorner.
The solution is to react on every MouseEnter and MouseLeave on both the adorned control and its adorner(s) and do a hit test manually. If any of them are hit then the adorner(s) should be visible otherwise collapsed.
So you need to be able to get the adorners from the adorned control and vica versa. Getting the adorned control from the adorner is no problem (use the AdornedElement property) but getting the adorners for a control is not provided by the framework (AFAIK) so I use a dictionary that maps my controls to a list of their adorners.
Here's the code inside my Panel-derived class (that contains and arranges my controls and their adorners):
private readonly Dictionary<Control, List<Adorner>> _controlToAdornersMap;
...
private void CreateMyControl()
{
var control = new MyControl();
control.MouseEnter += OnMyControlMouseEnterOrLeave;
control.MouseLeave += OnMyControlMouseEnterOrLeave;
Children.Add(control);
AddAdorners(control);
}
private void AddAdorners(Control control)
{
var myAdorner = new MyAdorner(control);
myAdorner.MouseEnter += OnMyAdornerMouseEnterOrLeave;
myAdorner.MouseLeave += OnMyAdornerMouseEnterOrLeave;
var adornerLayer = AdornerLayer.GetAdornerLayer(control);
adornerLayer.Add(myAdorner);
_controlToAdornersMap[control] = new List<Adorner> {myAdorner};
}
private void OnMyControlMouseEnterOrLeave(object sender, MouseEventArgs e)
{
HitTestAndSetAdornersVisibility((MyControl)sender, e);
}
private void OnMyAdornerMouseEnterOrLeave(object sender, MouseEventArgs e)
{
var adorner = (Adorner)sender;
HitTestAndSetAdornersVisibility((MyControl)adorner.AdornedElement, e);
}
private void HitTestAndSetAdornersVisibility(MyControl control, MouseEventArgs e)
{
var adorners = _controlToAdornersMap[control];
var hitTestSubjects = new List<UIElement> { control }.Concat(adorners);
var hit = hitTestSubjects.Any(i => VisualTreeHelper.HitTest(i, e.GetPosition(i)) != null);
SetAdornersVisibility(adorners, hit ? Visibility.Visible : Visibility.Collapsed);
}
private static void SetAdornersVisibility(IEnumerable<Adorner> adorners, Visibility visibility)
{
if (adorners != null)
foreach (var adorner in adorners)
adorner.Visibility = visibility;
}

POPUP on Button right click + WPF

I have a ListBox that is bound to a list of items. The ListBoxItem is bound to a datatemplate of type Button.
On the click of button, I do some action (another window is shown). So i have bound to the Command of the button.
Now my requirement is that i show a POPUP (with some buttons in popup) to the right click of the button.
How would i be able to do this in MVVM ?
Girija
You can simply catch MouseUp event from ListBox.ItemTemplate and set Popup.IsOpen there:
private void SomeTemplateElement_MouseUp(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Right)
puMyPopup.IsOpen = true;
}
Popup is a view element, so I don`t think there`s a reason to open it through viewmodel commands.

WPF drag and drop from a ListBox that has SelectionMode=Extended

I have a ListBox and want the selection-mode to be extended. Also I want have to implement drag and drop functionality. The problem now is, that if the mouse is clicked on a selected item, it will be immediately be selected as single selection instead of waiting to the mouse-up-event for doing this.
Due to this behaviour, start dragging multiple items is for the user quasi impossible because always he clicks on the selection to start dragging, the selection changes to the item that is under the mouse and starts the drag-operation with this item.
Is there a good workaround for this problem or does even exists an official solution?
Here's what I've done. In your DragDrop code, subscribe to the PreviewMouseLeftButtonDown. If the item you are already clicking on is selected, then set e.Handled to true.
In my sample below, I identify a part of the list box item as a drag grip (with bumps) so that I can distinguish between the item and a drag surface. I just had to get the list box item data template and the drag and drop behavior to agree on a name of the drag grip element.
The PreviewMouseLeftButtonDown from my work in progress:
private void ItemsControl_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
dragStartPoint = e.GetPosition(null);
ItemsControl itemsControl = this.AssociatedObject as ItemsControl;
if (itemsControl != null)
{
this.sourceItemContainer = itemsControl.ContainerFromElement((Visual)e.OriginalSource) as FrameworkElement;
}
// If this is an multiple or extended selection list box, and on a drag grip, then ensure the item being hit is selected
// This prevents the ItemsControl from using this MouseDown to change selection, except over a selected item's drag grip.
if ((this.IsMultipleSelectionListBox() == true) && (this.IsOriginalSourceDragGrip(e) != false) && (this.IsSourceListBoxItemSelected() == true))
{
e.Handled = true;
}
}
The easiest workaround i can think of would be to change the ListBoxItem to select on MouseUp not Down like so and change the ContainerGenerator to serve your custom ListBoxItems:
public class CustomListBoxItem : ListBoxItem
{
protected override void OnMouseLeftButtonDown( MouseButtonEventArgs e )
{
//do nothing
}
protected override void OnMouseLeftButtonUp( MouseButtonEventArgs e )
{
base.OnMouseLeftButtonDown( e );
}
}
You might need some MouseLeave/LeftButtonDown logic if you want to prevent different items selecting when moving through the List while holding the mouse button down.
Use PreviewMouseLeftButtonDown to add the selected items for the drag operation.

Resources