For a very specific reason I want to select ListViewItems on mouse button up, not actually on mouse button down. I want this behaviour to be embedded in the control. Is it possible to achieve this? can anyone give hint?
Yes it's definitely possible using attached properties. Define an attached property called SelectOnMouseUp and when it's set to true, hook to your ItemsContainerGenerator events to discover when a new item container is added. Then when you get an event for a new item container, hook into its PreviewMouseDown and ignore it (set e.Handled to true), and hook into its MouseUp event and perform the selection (set IsSelected to true).
Aviad P.'s answer is a good one and a clever use of attached properties, but I tend to use a different technique most of the time:
Subclass ListViewItem.
Override OnMouseLeftButtonDown and OnMouseRightButton to do nothing.
Override OnMouseLeftButtonUp / OnMouseRightButtonUp to call base.OnMouseLeftButtonDown / base.OnMouseRightButtonDown.
Subclass ListView.
Override GetContainerForItemOverride() to return your ListViewItem override
This seems easier to me than subscribing to ItemContainer events and adding handlers dynamically.
This is what it looks like:
public class MouseUpListViewItem : ListViewItem
{
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) {}
protected override void OnMouseRightButtonDown(MouseButtonEventArgs e) {}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
}
protected override void OnMouseRightButtonUp(MouseButtonEventArgs e)
{
base.OnMouseRightButtonDown(e);
}
}
public class MouseUpListView : ListView
{
protected override DependencyObject GetContainerForItemOverride()
{
return new MouseUpListViewItem();
}
}
I like this technique because there is less code involved.
Related
This is just example to learn from.
I want create custom control with completely different looks. Hence, according to https://learn.microsoft.com/en-us/dotnet/framework/wpf/controls/control-authoring-overview, I derive from FrameworkElement
and override OnRender method, also OverriderMesure and ArrangeOverride if needed.
Now I want implement mouse interaction, for example: on hover change color from red to blue. How I should do it?
public class Box : FrameworkElement
{
private static Color defaultColor = Colors.Red;
public static DependencyProperty ColorProperty = DependencyProperty.Register("Color", typeof(SolidColorBrush), typeof(Box),
new FrameworkPropertyMetadata(new SolidColorBrush(defaultColor), FrameworkPropertyMetadataOptions.AffectsRender));
public SolidColorBrush Color
{
get { return (SolidColorBrush)GetValue(ColorProperty); }
set { SetValue(ColorProperty, value); }
}
static Box()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Box), new FrameworkPropertyMetadata(typeof(Box)));
}
protected override void OnRender(DrawingContext drawingContext)
{
// It's just example, I know shape is wayyy too simple to involve custom render.
drawingContext.DrawRectangle(Color, null, new Rect(0, 0, ActualWidth, ActualWidth));
}
protected override void OnMouseEnter(MouseEventArgs e)
{
Color = new SolidColorBrush(Colors.Blue); // Set to color
}
protected override void OnMouseLeave(MouseEventArgs e)
{
Color = new SolidColorBrush(defaultColor); // Back to default
}
protected override Size MeasureOverride(Size constraint)
{
...
}
protected override Size ArrangeOverride(Size finalSize)
{
...
}
}
So far I deduce:
Normally, if I had derive from Control, I would have use VSM for this. Unfortunately VSM isn't available until ControlTemplate hierarchy tree, so controls which have Template property. So if I decided to draw my control by myself I need use for this Routed Events, in this particular example OnMouseEnter(MouseEventArgs), OnMouseLeave(MouseEventArgs) and some dependency property, like code above.
It this right approach? Please remember it's for learning purpose so FrameworkElement as base is obligatory.
I can see some drawbacks, becouse If we want control onHover color (in code above is harcoded to blue) I need mess around with code behind, or create another dependency property for this.
Unfortunately VSM isn't available until ControlTemplate hierarchy tree, so controls which have Template property.
This it not true.
You can use VSM normally, with some small changes. Read: https://msdn.microsoft.com/en-us/library/system.windows.visualstatemanager(v=vs.110).aspx#Examples. Take a closer look on example.
I have 2 controls on a form. One numericUpDown (from the Silverlight Toolkit) and a simple Rectangle.
On the MouseLeftButtonDown of the Rectangle I popup a MessageBox with the numericUpDown value.
If I use the arrows to change the value of the numericUpDown, everyting is fine. But if I edit the value manually (with the keyboard) and immediately click on the Rectangle it shows the previous value of the numericUpDown. If I click a sencond time on the rectangle it will show the new value.
The numericUpDown.ValueChanged event is raised after the Rectangle.MouseLeftButtonDown event.
Is that a Silverlight bug? Anybody knows a workaround for that?
(btw I cannot change my Rectangle controls or events)
As workaround I propose you to create your own control like:
public class MyNumericUpDown : NumericUpDown
{
private TextBox _textBox;
public void Sync()
{
ApplyValue(_textBox.Text);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_textBox = (TextBox)GetTemplateChild("Text");
}
}
Now you can use method Sync to syncronize display text with control Value property. You can call method from XAML declaratively or in code behind. In your case:
private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
myNumericUpDown.Sync();
MessageBox.Show(myNumericUpDown.Value.ToString());
}
I'm working in WPF to create a ListView component. The items in the list are based on another user control that reacts to MouseLeftDown events. The List also reacts to SelectionChanged events.
Right now, if I mouse down on any item on the list and move the cursor, the other items I pass along react to the SelectionChanged event (which is expected since the selection is changing as per the Mouse Down event in List view). I need to be able to disable this reaction when its down through a drag-to-scroll behavior, but to keep it active when the user selects an item on the list.
Does anyone have any ideas how this can be achieved?
Thanks everyone,
RK
I believe one of the ways that could help you is to implement your own handlers of MouseUp and MouseDown events of your items to select item on MouseUp instead of MouseDown. You could start from a sample like this:
public class MyListView : ListView
{
protected override DependencyObject GetContainerForItemOverride()
{
return new MyListViewItem();
}
}
public class MyListViewItem : ListViewItem
{
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
return;
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
}
}
I am making a very basic map editor. I'm halfway through it and one problem i hit is how to delete an object.
I would like to press delete but there appears to be no keydown event for pictureboxes and it will seem like i will have it only on my listbox.
What is the best solution for deleting an object in my editor?
You'll want the PictureBox to participate in the tabbing order and show that it has the focus. That takes a bit of minor surgery. Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox onto your form. Implement the KeyDown event.
using System;
using System.Drawing;
using System.Windows.Forms;
class SelectablePictureBox : PictureBox {
public SelectablePictureBox() {
this.SetStyle(ControlStyles.Selectable, true);
this.TabStop = true;
}
protected override void OnMouseDown(MouseEventArgs e) {
this.Focus();
base.OnMouseDown(e);
}
protected override void OnEnter(EventArgs e) {
this.Invalidate();
base.OnEnter(e);
}
protected override void OnLeave(EventArgs e) {
this.Invalidate();
base.OnLeave(e);
}
protected override void OnPaint(PaintEventArgs pe) {
base.OnPaint(pe);
if (this.Focused) {
var rc = this.ClientRectangle;
rc.Inflate(-2, -2);
ControlPaint.DrawFocusRectangle(pe.Graphics, rc);
}
}
}
i think this is the best methode:
http://felix.pastebin.com/Q0YbMt22
... 8 years after ...
An alternative to Hans Passant's code, which doesn't require you to create a new class just so your PictureBox is in the tab order, is to set TabStop to true, and call SetStyle() directly on the PictureBox, optimally after InitializeComponent() is called.
TabStop is public, so it's easily set, but SetStyle() is protected, so reflection comes to the rescue!
myPictureBox.TabStop = true;
typeof(PictureBox)
.GetMethod("SetStyle", BindingFlags.Instance | BindingFlags.NonPublic)
.Invoke(myPictureBox, new object[] { ControlStyles.Selectable, true });
This of course, doesn't do anything like getting the focus when the PictureBox is clicked, so you have to do that in its various events as you see fit.
I have a WPF Custom Control inherited from Button.
How do I programatically get the custom control to capture the Click Event (so that I can record the action and do some internal work)
(basically I want to catch the event and set a certain property to a certain value) and make this part of the classes standard functionality.
From my understanding the custom control should be able to catch it's own even and do some work.
Help appreciated
try one of the overrides
public class CustomButton : Button {
protected override void OnPreviewMouseDown(MouseButtonEventArgs e) {
base.OnPreviewMouseDown(e);
}
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) {
base.OnPreviewMouseLeftButtonDown(e);
}
}
I have realised why Ihad a problem.
I could not see the Click event
This was because I was not explicit enought in my class declaration:
I put
public class StateButton : Button
obviously picked the wrong button .. as
public class StateButton : System.Windows.Controls.Button
works
Then I just override the event
Thanks