Posts Tagged ‘behavior’

Unhandling previously handled events in Silverlight

What?

You may well find yourself wanting to attach to an event which has already been handled inside a control with no way to override and prevent the event from being handled. As seen in my prior post to this, you can make use of the AddHandler method. I am going to use the Backspace key down in a TextBox as an example, the event is only raised and not handled when the TextBox is empty. (This can be seen in the sample application in the output coming from the behavior)

Read more

Double Click behavior, mvvm compliant

Often when creating an application you will want a secondary mechanism for executing a command, the primary mechanism will often be a button click (e.g. Opening a record). In MVVM the backing ViewModel will expose an ICommand which is bound to the Button’s Command. This behavior executes the same command when a double click occurs.

Sample Application:

Install Microsoft Silverlight

How:

  • Register to the Mouse Up event on the AssociatedObject, we use the Mouse Up event so that we can attach the behavior to DataGrid / ListBox templates as the Mouse Down events are swallowed by these.
  • Create a dependancy property for the ICommand and the ClickInterval (this will commonly be hard coded by exists for demonstration purposes)
  • Set up a DispatcherTimer with the desired interval, also attach the Tick event and stop the timer.
  • When Mouse Up occurs event occurs the first time we start the DispatcherTimer.
  • For a double click to occur the Mouse Up event must be raised while the timer is active, if it is then we execute the Command and stop the timer.

Code:

public class DoubleClickBehavior : Behavior<UIElement>
{
    private readonly DispatcherTimer _timer = new DispatcherTimer();

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.MouseLeftButtonUp += AssociatedObjectMouseLeftButtonUp;
        _timer.Tick += new EventHandler(_timerTick);
        _timer.Interval = TimeSpan.FromSeconds(ClickInterval);
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.MouseLeftButtonUp -= AssociatedObjectMouseLeftButtonUp;
    }

    private void _timerTick(object sender, EventArgs e)
    {
        _timer.Stop();
    }

    private void AssociatedObjectMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        if (!_timer.IsEnabled)
        {
            // If the timer is not already running then start it.
            _timer.Start();
        }
        else
        {
            _timer.Stop();
            if(CommandToExecute != null)
            {
                // If the timer is active there has been a second event so execute the command.
                CommandToExecute.Execute(this);

            }
        }
    }

    public static readonly DependencyProperty IntervalProperty =
        DependencyProperty.Register("ClickInterval",
        typeof(double),
        typeof(DoubleClickBehavior),
        new PropertyMetadata(0.25,
            new PropertyChangedCallback(OnClickIntervalChanged)));

    private static void OnClickIntervalChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        var doubleClick = (DoubleClickBehavior)sender;
        doubleClick._timer.Interval = TimeSpan.FromSeconds(doubleClick.ClickInterval);
    }

    public double ClickInterval
    {
        get { return (double)GetValue(IntervalProperty); }
        set { SetValue(IntervalProperty, value); }
    }

    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.Register("CommandToExecute",
        typeof(ICommand),
        typeof(DoubleClickBehavior),
        new PropertyMetadata(null));

    public ICommand CommandToExecute
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }
}

Update:

xaml

Xaml

Source

Download solution

public class DoubleClickBehavior : Behavior<UIElement>
{
private readonly DispatcherTimer _timer = new DispatcherTimer();protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.MouseLeftButtonUp += AssociatedObjectMouseLeftButtonUp;
_timer.Tick += new EventHandler(_timerTick);
_timer.Interval = TimeSpan.FromSeconds(ClickInterval);
}protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.MouseLeftButtonUp -= AssociatedObjectMouseLeftButtonUp;
}private void _timerTick(object sender, EventArgs e)
{
_timer.Stop();
}private void AssociatedObjectMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (!_timer.IsEnabled)
{
// If the timer is not already running then start it.
_timer.Start();
}
else
{
if(CommandToExecute != null)
{
// If the timer is active there has been a second event so execute the command.
CommandToExecute.Execute(this);
}
}
}public static readonly DependencyProperty IntervalProperty =
DependencyProperty.Register(“ClickInterval”,
typeof(double),
typeof(DoubleClickBehavior),
new PropertyMetadata(0.25,
new PropertyChangedCallback(OnClickIntervalChanged)));

private static void OnClickIntervalChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
var doubleClick = (DoubleClickBehavior)sender;
doubleClick._timer.Interval = TimeSpan.FromSeconds(doubleClick.ClickInterval);
}

public double ClickInterval
{
get { return (double)GetValue(IntervalProperty); }
set { SetValue(IntervalProperty, value); }
}

public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(“CommandToExecute”,
typeof(ICommand),
typeof(DoubleClickBehavior),
new PropertyMetadata(null));

public ICommand CommandToExecute
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
}

Behavior to process an Image Drop from file system to Image Source

This behavior is used to set the source of a silverlight image control when an image is dropped from the file system onto a UIElement in the Silverlight application.
Sample Application:

Install Microsoft Silverlight

How:

  • Register to the Drop event on the AssociatedObject.
  • The dropped file is processed to a bitmap image from a filestream. I took advantage of using the extension method for processing a file drop which can be seen here.
  • Set the Source of the TargetImage to be the dropped image.

Code:

public class ImageDropBehavior : Behavior<UIElement>
    {
        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.Drop +=
                new DragEventHandler(AssociatedObject_Drop);
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.Drop -=
                new DragEventHandler(AssociatedObject_Drop);
        }

        private void AssociatedObject_Drop(object sender, DragEventArgs e)
        {
            Func<FileStream, BitmapImage> func = (stream) =>
            {
                BitmapImage bitmapImage = new BitmapImage();
                bitmapImage.SetSource(stream);

                return bitmapImage;
            };

            var droppedImage =
                e.ProcessDragEventArgsTo<BitmapImage>(func, _ => { });
            if (droppedImage != null)
            {
                TargetImage.Source = droppedImage;
            }
        }

        public static readonly DependencyProperty TargetImageProperty =
            DependencyProperty.Register("TargetImage",
            typeof(Image),
            typeof(ImageDropBehavior),
            new PropertyMetadata(null));

        public Image TargetImage
        {
            get { return (Image)GetValue(TargetImageProperty); }
            set { SetValue(TargetImageProperty, value); }
        }
    }
}

Using the behavior:

  • Attach the behavior to a UIElement.
  • The AllowDrop property needs to be set to true on the UIElement the behavior is attached to else the Drop event will never be raised.
  • Element bind the TargetImage property on the behavior to an Image.
  • See the behavior being used in blend:

Notes:

  • If the target image has data binding, this behavior will remove the binding when it sets the image source.
  • Will only work for Silverlight supported images. At the point of writing these are jpg and png.
public class ImageDropBehavior : Behavior<UIElement>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Drop += new DragEventHandler(AssociatedObject_Drop);
}

protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.Drop -= new DragEventHandler(AssociatedObject_Drop);
}

private void AssociatedObject_Drop(object sender, DragEventArgs e)
{
Func<FileStream, BitmapImage> func = (stream) =>
{
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(stream);

return bitmapImage;
};

var droppedImage = e.ProcessDragEventArgsTo<BitmapImage>(func, _ => { });
if (droppedImage != null)
{
TargetImage.Source = droppedImage;
}
}

public static readonly DependencyProperty TargetImageProperty =
DependencyProperty.Register(“TargetImage”,
typeof(Image),
typeof(ImageDropBehavior),
new PropertyMetadata(null));

public Image TargetImage
{
get { return (Image)GetValue(TargetImageProperty); }
set { SetValue(TargetImageProperty, value); }
}
}

Return top