WPF: Toggle multiple Buttons by dragging the mouse over them - wpf

Is it possible to toggle the state of multiple ToggleButtons by dragging the mouse over them (with the left mouse button hold down)?

There isn't anything in the box that would support this, but you should be able to subscribe to MouseMove and toggle the state on if the button is pressed.

<ToggleButton Content="ToggleButton" MouseEnter="ToggleButtonMouseEnter" Width="80" HorizontalAlignment="Left"/>
private void ToggleButtonMouseEnter(object sender, MouseEventArgs e)
{
System.Windows.Controls.Primitives.ToggleButton tb = (System.Windows.Controls.Primitives.ToggleButton)sender;
if(e.LeftButton == MouseButtonState.Pressed) tb.IsChecked = !tb.IsChecked;
}

Related

Keep submenu open when a new image is selected for display

Using WPF: A Simple Color Picker With Preview, Sacha Barber, 18 Apr 2012 ,
I created a custom control from it:
public class ColorCustomControl : Control
{....}
It is then used as:
<Menu....>
<MenuItem.....>
<pn:ColorCustomControl/>
</MenuItem>
</Menu>
This yields the following picture when the Brushes MenuItem is selected:
Selection of any item in the opened Brushes submenu results in the appropriate action being taken with the Brushes submenu REMAINING OPEN. This is the effect I want.
However, as shown below, selection of any of the three swatches results in a quick flicker of the new swatch -- it replaces the color pattern to the left of "Preview"--followed immediately by closure of the Brushes submenu.
If the Brushes menuitem is again chosen, the most recently selected swatch correctly appears.
I have tried all preview events (i.e., keyboard lost focus, left mouse down, etc.), to try stopping closure of the submenu when a swatch is chosen. Nothing I have found will stop the popup from closing.
How can closure of the Brushes submenu be prevented when selecting a swatch from the visual?
(I strongly suspect that redrawing of the visual, as in InvalidateVisual() when a new swatch image is selected, is forcing closure of the submenu).
Any ideas anybody?
TIA
My suggestion is to stop events propagation from your user control. So in your ColorCustomControl class first of all add a property (it can be a dependency one too if you need):
private bool propagateEvents = true;
public bool PropagateEvents
{
get
{
return propagateEvents;
}
set
{
propagateEvents = value;
}
}
Then add e.Handled = !PropagateEvents; at the end of every mouse event handler; in the end add a Swatch_MouseLeftButtonUp method (it has to handle the event raised by ImgSqaure1, ImgSqaure2 and ImgCircle1).
The result will be:
private void Swatch_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Image img = (sender as Image);
ColorImage.Source = img.Source;
e.Handled = !PropagateEvents;
}
private void Swatch_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
e.Handled = !PropagateEvents;
}
private void CanvImage_MouseDown(object sender, MouseButtonEventArgs e)
{
IsMouseDown = true;
e.Handled = !PropagateEvents;
}
private void CanvImage_MouseUp(object sender, MouseButtonEventArgs e)
{
IsMouseDown = false;
e.Handled = !PropagateEvents;
}
and in the user control XAML:
<Image x:Name="ImgSqaure1"
Height="20" Width="20"
Source="Images/ColorSwatchSquare1.png"
Margin="45,0,0,0"
ToolTip="Square swatch1"
MouseLeftButtonDown="Swatch_MouseLeftButtonDown"
MouseLeftButtonUp="Swatch_MouseLeftButtonUp"/>
<Image x:Name="ImgSqaure2"
Height="20" Width="20"
Source="Images/ColorSwatchSquare2.png" Margin="5,0,0,0"
ToolTip="Square swatch2"
MouseLeftButtonDown="Swatch_MouseLeftButtonDown"
MouseLeftButtonUp="Swatch_MouseLeftButtonUp"/>
<Image x:Name="ImgCircle1" Height="20" Width="20"
Source="Images/ColorSwatchCircle.png" Margin="5,0,0,0"
ToolTip="Circle swatch1"
MouseLeftButtonDown="Swatch_MouseLeftButtonDown"
MouseLeftButtonUp="Swatch_MouseLeftButtonUp" />
Now all you have to do is set the PropagateEvents property in your menu:
<Menu....>
<MenuItem.....>
<pn:ColorCustomControl PropagateEvents="False" />
</MenuItem>
</Menu>
I hope it can help you.

User control is not hiding in wpf

I created a UserControl like Popup which is displayed when user clicks on menu item.
If user clicks side that user control should be collapsed.
It works fine for me when user clicks side other than any control.
If I click on datagrid or listbox it is not hiding.
Here is my code:
<src:AddNewItemPopUp x:Name="PopUp" Margin="111,47,620,230" Panel.ZIndex="1" Visibility="Collapsed"/>
I took a button in click event I set PopUp visibility property to true
In my user control I have grid. In the mousedown event of grid I have written following code...
private void Grid_MouseDown_1(object sender, MouseButtonEventArgs e)
{
if (PopUp.Visibility == Visibility.Visible)
{
PopUp.Visibility = Visibility.Collapsed;
}
}
If I click on any control like a Button, DataGrid, ListBox that are placed in Grid Popup is not collapsed.
First Set Grid's Background Property, for example grid.Backgroung=Brushes.Transparent or in Xaml Backgroung = "Transparent"
Second Handle PreviewMouseDown event instead of MouseDown event.
The first one makes the mouse event to fire, when mouse is directly over the grid.
The second one makes the mouse event fire, when mouse is over an UIElement in the grid.
Try:
Visibility="Hidden"
that is:
private void Grid_MouseDown_1(object sender, MouseButtonEventArgs e)
{
if (PopUp.Visibility == Visibility.Visible)
{
PopUp.Visibility = Visibility.Hidden;
}
}
and also see:
http://msdn.microsoft.com/en-us/library/system.windows.visibility.aspx

Button on ListBox Item

I have a ListBox filled with items. Some of the items may have buttons or links within RichTextBlock inside. I want to fire different action either when the item is pressed or when the button is pressed. The problem is when I hit the button, also the action connected with the item itself is fired. How can I prevent fireing the event of list item when the button inside is pressed?
ListBox:
<ListBox x:Name="StripesList" SelectionChanged="StripesList_SelectionChanged">
</ListBox>
ListBox Items:
<Border x:Name="OuterBorder" Width="400">
<Image x:Name="ThumbnailBox" Width="100" Source="{Binding Thumbnail}" Tap="ThumbnailClick" />
</Border>
Code:
private void StripesList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (StripesList != null)
{
StripesList.SelectedIndex = -1;
}
}
private void ThumbnailClick(object sender, System.Windows.Input.GestureEventArgs e)
{
Image image = sender as Image;
// handle image click
}
private void ItemClick(object sender, EventArgs e)
{
// handle item click
}
I register item click event observers from code behind:
item.Tap += new EventHandler(ItemClick);
set e.Handled=true in the handler of all events . It will stop the Bubbleing of the event.

Allowing click-through with two hit testable controls

I have two controls stacked on top of each other as such:
Button1 is ZIndex 2, Button2 is ZIndex 1.
Both need to be hit testable, as I need to listen to Button1's MouseEnter event for other system functions. But I also need to be able to have Button2 be clickable. I'm not quite sure how I can get this functionality to pan out (since I can't just set the Button1 to IsHitTestableFalse). Is there some sort of way I can say, in Button1's Click event
if (hasElementBeneath):
click that element instead
If I understand you correctly the trick is rather to prevent the "click" from the inner button to be handled by the outer button too.
To accomplish this: In the click handler for the inner button set the Handled property of the supplied RoutedEventArgs to true.
Like this:
<Button Click="Button1_Click" HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel>
<TextBlock>Button 1</TextBlock>
<Button Click="Button2_Click" Margin="10">Button 2</Button>
</StackPanel>
</Button>
and:
private void Button1_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Button1 clicked!");
}
private void Button2_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Button2 clicked!");
e.Handled = true;
}

WPF: MouseEnter doesn't work on several buttons when mouse is pressed

I have a list of toggle-buttons in wpf and I want the user to be able to toggle several buttons by dragging over them. To do this, I used the MouseEnter-Event for each button. This does work, when I press the mousebutton outside the buttons and start dragging. But when I press the mousebutton on a button and start dragging, the MouseEnter-Event is only fired for the first button, where I pressed the mousebutton (also none of the other events like mouseover or mousemove are fired).
Here's the code:
public void AddButton()
{
ToggleButton btn = new ToggleButton();
btn.MouseEnter += VisibilityButton_Enter;
this.gridButtons.Children.Add(btn);
}
private void VisibilityButton_Enter(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed || e.RightButton == MouseButtonState.Pressed)
{
ToggleButton btn = sender as ToggleButton;
btn.IsChecked = !btn.IsChecked;
}
}
I found a solution to use "drag and drop" and the dragover-event, but I think there must be an easier solution?
As Kent mentioned, the ToggleButton captures the mouse. If we handle the PreviewMouseDown event ourselves we can prevent that. The rest is just keeping track of the mouse state so the we don't click twice during a single roll-over. Here is a behavior you can add to your button to enable roll-over clicking.
First add this namespace:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
and the corresponding reference to your project.
Then the XAML looks like this (notice the RollOverBehavior):
<Grid>
<ItemsControl>
<ItemsControl.ItemsSource>
<PointCollection>
<Point/>
<Point/>
<Point/>
<Point/>
<Point/>
</PointCollection>
</ItemsControl.ItemsSource>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton Width="25" Height="25">
<i:Interaction.Behaviors>
<local:RollOverBehavior/>
</i:Interaction.Behaviors>
</ToggleButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
and here is the behavior itself:
public class RollOverBehavior : Behavior<ToggleButton>
{
bool mouseOver;
bool clicked;
protected override void OnAttached()
{
AssociatedObject.PreviewMouseLeftButtonDown += (s, e) =>
{
AssociatedObject.IsChecked = !AssociatedObject.IsChecked;
e.Handled = true;
};
AssociatedObject.MouseEnter += (s, e) =>
{
mouseOver = true;
clicked = false;
};
AssociatedObject.MouseLeave += (s, e) =>
{
mouseOver = false;
};
AssociatedObject.MouseMove += (s, e) =>
{
if (mouseOver && !clicked && e.LeftButton == MouseButtonState.Pressed)
{
AssociatedObject.IsChecked = !AssociatedObject.IsChecked;
clicked = true;
}
};
}
}
The problem is that the default behavior of the ToggleButton is to capture the mouse when the left mouse button is clicked. Because the mouse is captured, all mouse events are sent to the first ToggleButton.
Sounds like what you want to do is override this default behavior such that the mouse isn't captured, but to be honest I couldn't really follow exactly what it is you're trying to achieve.
I had the same problem with normal Buttons. The solution, that worked for me, is to set e.Handled = true in the PreviewMouseButtonDown event (I implemented this too). It seems, that just by down-click with the mouse, the previous action is not fully handled until the mouse button is released, so the MouseEnter event is not able to raise.

Resources