vladeck's junkyard

designer wannabe

SearchTextBox Behavior

Damn, this was a tricky one – a bit of coding, a sprinkle of XAML and here it is. And it works. You can set this Behavior to any TextBox and turn it into Windows 7 search box like thingy. You can define your own Search and Clear icons (ImageSource) and (if you don’t want search-as-you-type) Search command (ICommand). The good thing is that it doesn’t affect the style/template you set for the TextBox, as it is implemented as Adorner.

Download here (rename .DOC to .RAR – wordpress limitation).

1 Comment »

Button Popup Behavior

Another behavior that I wrote for my project. The code is simple and there aren’t many things to configure, but it is a good starting point for a nice button popup (many other examples I’ve seen are coded as custom controls; the same can be accomplished using this behavior):

namespace Foo
{
    public class ButtonPopupBehavior : Behavior<Button>
    {
        private readonly Popup popup_;

        public static DependencyProperty PopupProperty =
            DependencyProperty.Register(
                "Popup",
                typeof(UIElement),
                typeof(ButtonPopupBehavior),
                null
            );

        public ButtonPopupBehavior()
        {
            popup_ = new Popup() { StaysOpen = false };
        }

        public UIElement Popup
        {
            get { return (UIElement)GetValue(PopupProperty); }
            set { SetValue(PopupProperty, value); }
        }

        protected override void OnAttached()
        {
            base.OnAttached();
            
            AssociatedObject.Click += OnClick;
            AssociatedObject.IsVisibleChanged += OnIsVisibleChanged;

            popup_.PlacementTarget = AssociatedObject;
            popup_.Child = Popup;
        }

        protected override void OnDetaching()
        {
            AssociatedObject.Click -= OnClick;
            AssociatedObject.IsVisibleChanged -= OnIsVisibleChanged;
            
            base.OnDetaching();
        }

        private void OnClick(object sender, RoutedEventArgs e)
        {
            popup_.IsOpen = true;
        }

        private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (!(bool)e.NewValue)
                popup_.IsOpen = false;
        }
    }
}

2 Comments »

Conditional referencing in .NET

If you ever happen to stumble upon a problem of having the need to support multiple versions of the same assembly in your .NET project, read on… Take these two assemblies for example:

Foo.dll (v1.0)

namespace Foo
{
    class Bar
    {
        public void Do()
        {
            Console.WriteLine("Hello, from v1.0 of Bar");
        }
    }
}

Foo.dll (v2.0)

namespace Foo
{
    class Bar
    {
        public void Do(string parameter)
        {
            Console.WriteLine("Hello, from v2.0 of Bar with parameter: {0}", parameter);
        }
    }
}

So, now we have two Foo.dll assemblies that are of different version and we want to use them in our project. First, copy these assemblies to project directory and put them under v1 and v2 directories (at the same level as the .csproj file); then, open the .csproj file and add the following configurations (I’ll do this for DEBUG versions – just copy DEBUG that is already there and modify it; the RELEASE is similar):

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug - v1|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <OutputPath>bin\Debug\v1\</OutputPath>
    <DefineConstants>TRACE;DEBUG;V_ONE</DefineConstants>
    <DebugType>full</DebugType>
    <PlatformTarget>AnyCPU</PlatformTarget>
    <ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug - v2|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <OutputPath>bin\Debug\v2\</OutputPath>
    <DefineConstants>TRACE;DEBUG;V_TWO</DefineConstants>
    <DebugType>full</DebugType>
    <PlatformTarget>AnyCPU</PlatformTarget>
    <ErrorReport>prompt</ErrorReport>
</PropertyGroup>

And here comes the good part, just below previous modification:

<Choose>
    <When Condition=" '$(Configuration)' == 'Debug - v1'">
      <ItemGroup>
        <Reference Include="Foo">
          <SpecificVersion>False</SpecificVersion>
          <HintPath>v1\Foo.dll</HintPath>
        </Reference>
      </ItemGroup>
    </When>
    <When Condition=" '$(Configuration)' == 'Debug - v2'">
      <ItemGroup>
        <Reference Include="Foo">
          <SpecificVersion>False</SpecificVersion>
          <HintPath>v2\Foo.dll</HintPath>
        </Reference>
      </ItemGroup>
    </When>
</Choose>

Now you are ready to choose your build configuration, and have code support multiple version of the same assembly:

var b = new Foo.Bar();

#if (V_ONE)
   b.Do();
#elif (V_TWO)
   b.Do("Hello");
#endif

No Comments »

Animated ErrorInfo Behavior

Ever since I wrote Animated Height Behavior, I wanted to create Behavior that will give me nice eye-candy for all my IDataErrorInfo validation needs. You can see the result in the video below, as well as the code of the Behavior. Please note that the image I’m using here is from the Resources (just add 16×16 png image to Resources and name it Error16). GetBitmapSource() is Extension that I wrote for converting System.Drawing.Bitmap to BitmapSource.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace Foo
{
    public class AnimatedErrorInfoBehavior : Behavior<FrameworkElement>
    {
        private readonly TextBlock textBlock_;
        private Grid errorGrid_;

        private readonly DoubleAnimation increaseHeightAnimation_;
        private readonly Storyboard increaseHeightStoryboard_;

        private readonly DoubleAnimation showAnimation_;
        private readonly Storyboard showStoryboard_;

        private readonly DoubleAnimation decreaseHeightAnimation_;
        private readonly Storyboard descreaseHeightStoryboard_;

        private readonly DoubleAnimation hideAnimation_;
        private readonly Storyboard hideStoryboard_;

        private readonly Dictionary<string, int> errors_;

        public AnimatedErrorInfoBehavior()
        {
            errors_ = new Dictionary<string, int>();
            textBlock_ = new TextBlock();

            increaseHeightAnimation_ = new DoubleAnimation(
                0.0,
                23.0,
                TimeSpan.FromMilliseconds(200)
            );

            increaseHeightAnimation_.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
            increaseHeightStoryboard_ = new Storyboard();

            Storyboard.SetTarget(increaseHeightAnimation_, errorGrid_);
            Storyboard.SetTargetProperty(increaseHeightAnimation_, new PropertyPath(FrameworkElement.HeightProperty));
            increaseHeightStoryboard_.Children.Add(increaseHeightAnimation_);

            showAnimation_ = new DoubleAnimation(0.0, 1.0, TimeSpan.FromMilliseconds(200));
            showAnimation_.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseIn };
            showStoryboard_ = new Storyboard();

            Storyboard.SetTarget(showAnimation_, textBlock_);
            Storyboard.SetTargetProperty(showAnimation_, new PropertyPath(UIElement.OpacityProperty));
            showStoryboard_.Children.Add(showAnimation_);

            decreaseHeightAnimation_ = new DoubleAnimation(
                23.0,
                0.0,
                TimeSpan.FromMilliseconds(100)
            );

            descreaseHeightStoryboard_ = new Storyboard();

            Storyboard.SetTarget(decreaseHeightAnimation_, errorGrid_);
            Storyboard.SetTargetProperty(decreaseHeightAnimation_, new PropertyPath(FrameworkElement.HeightProperty));
            descreaseHeightStoryboard_.Children.Add(decreaseHeightAnimation_);

            hideAnimation_ = new DoubleAnimation(1.0, 0.0, TimeSpan.FromMilliseconds(100));
            hideAnimation_.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };

            hideStoryboard_ = new Storyboard();

            Storyboard.SetTarget(hideAnimation_, textBlock_);
            Storyboard.SetTargetProperty(hideAnimation_, new PropertyPath(UIElement.OpacityProperty));
            hideStoryboard_.Children.Add(hideAnimation_);
        }

        protected override void OnAttached()
        {
            var parent = VisualTreeHelper.GetParent(AssociatedObject) as Grid;

            if (parent == null)
                return;

            var row_index = Grid.GetRow(AssociatedObject);
            var row_span = Grid.GetRowSpan(AssociatedObject);

            var column_index = Grid.GetColumn(AssociatedObject);
            var column_span = Grid.GetColumnSpan(AssociatedObject);

            parent.Children.Remove(AssociatedObject);

            var grid = new Grid();
            grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
            grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });

            Grid.SetRow(grid, row_index);
            Grid.SetRowSpan(grid, row_span);

            Grid.SetColumn(grid, column_index);
            Grid.SetColumnSpan(grid, column_span);

            grid.Children.Add(AssociatedObject);
            Grid.SetRow(AssociatedObject, 0);

            errorGrid_ = new Grid();
            errorGrid_.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
            errorGrid_.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });

            errorGrid_.Height = 0;

            var image = new Image();
            image.Source = Resources.Error16.GetBitmapSource();
            image.Margin = new Thickness(0,0,2,7);

            errorGrid_.Children.Add(image);
            Grid.SetColumn(image, 0);

            textBlock_.Foreground = Brushes.Red;

            errorGrid_.Children.Add(textBlock_);
            Grid.SetColumn(textBlock_, 1);

            grid.Children.Add(errorGrid_);
            Grid.SetRow(errorGrid_, 1);

            parent.Children.Add(grid);

            Validation.AddErrorHandler(AssociatedObject, OnError);
            Validation.SetErrorTemplate(AssociatedObject, null);

            base.OnAttached();
        }

        private void OnError(object sender, ValidationErrorEventArgs e)
        {
            var error_msg = e.Error.ErrorContent.ToString();

            if (e.Action == ValidationErrorEventAction.Added)
            {
                if (errors_.ContainsKey(error_msg))
                    errors_[error_msg]++;
                else
                    errors_.Add(error_msg, 1);

                if (errors_[error_msg] == 1)
                {
                    textBlock_.Text = e.Error.ErrorContent.ToString();

                    increaseHeightStoryboard_.Begin(errorGrid_);
                    showStoryboard_.Begin(textBlock_);
                }
            }

            if (e.Action == ValidationErrorEventAction.Removed)
            {
                errors_[error_msg]--;

                if (errors_[error_msg] == 0)
                {
                    descreaseHeightStoryboard_.Begin(errorGrid_);
                    hideStoryboard_.Begin(textBlock_);
                }
            }
        }
    }
}

No Comments »

System.Drawing.Bitmap GetBitmapSource() Extension – Convert System.Drawing.Bitmap to BitmapSource

If you are like me, you probably keep bitmaps (png files) of your WPF project in Resources. Since Resources uses System.Drawing.Bitmap for storing bitmaps, I wrote (some code modifications were done by Bojan) this little extension that will convert bitmap resource to BitmapSource.

using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace Foo
{
    public static class BitmapExtension
    {
        public static BitmapSource GetBitmapSource(this Bitmap image)
        {
            var rect = new Rectangle(0, 0, image.Width, image.Height);
            var bitmap_data = image.LockBits(rect, ImageLockMode.ReadOnly, image.PixelFormat);

            try
            {
                BitmapPalette palette = null;
                
                if (image.Palette.Entries.Length > 0)
                {
                    var palette_colors = image.Palette.Entries.Select(entry => System.Windows.Media.Color.FromArgb(entry.A, entry.R, entry.G, entry.B)).ToList();
                    palette = new BitmapPalette(palette_colors);
                }

                return BitmapSource.Create(
                    image.Width,
                    image.Height,
                    image.HorizontalResolution,
                    image.VerticalResolution,
                    ConvertPixelFormat(image.PixelFormat),
                    palette,
                    bitmap_data.Scan0,
                    bitmap_data.Stride * image.Height,
                    bitmap_data.Stride
                );
            }
            finally
            {
                image.UnlockBits(bitmap_data);
            }
        }

        private static System.Windows.Media.PixelFormat ConvertPixelFormat(System.Drawing.Imaging.PixelFormat sourceFormat)
        {
            switch (sourceFormat)
            {
                case System.Drawing.Imaging.PixelFormat.Format24bppRgb:
                    return PixelFormats.Bgr24;

                case System.Drawing.Imaging.PixelFormat.Format32bppArgb:
                    return PixelFormats.Bgra32;

                case System.Drawing.Imaging.PixelFormat.Format32bppRgb:
                    return PixelFormats.Bgr32;
            }

            return new System.Windows.Media.PixelFormat();
        }
    }
}

No Comments »

Animated Height Behavior

On one project that I’m working on, I had a need to animate height (simulating Visible/Not Visible state of ‘overlay’ and edit dialogs) of FrameworkElement. So I wrote this little behavior that does just that. You can use IsVisible to control (using binding) ‘Visibility’, as well as ShowDuration and HideDuration to control duration of animation.

using System;
using System.Windows;
using System.Windows.Interactivity;
using System.Windows.Media.Animation;

namespace Foo
{
    public class AnimatedHeightBehavior : Behavior<FrameworkElement>
    {
        private static DoubleAnimation showAnimation_;
        private static readonly Storyboard showStoryboard_ = new Storyboard();

        private static DoubleAnimation hideAnimation_;
        private static readonly Storyboard hideStoryboard_ = new Storyboard();

        public static DependencyProperty IsVisibleProperty =
            DependencyProperty.Register(
                "IsVisible",
                typeof(bool),
                typeof(AnimatedHeightBehavior),
                new PropertyMetadata(false, OnShowChanged)
            );

        public static DependencyProperty ShowDurationProperty =
            DependencyProperty.Register(
                "ShowDuration",
                typeof(int),
                typeof(AnimatedHeightBehavior),
                new PropertyMetadata(200)
        );

        public static DependencyProperty HideDurationProperty =
            DependencyProperty.Register(
                "HideDuration",
                typeof(int),
                typeof(AnimatedHeightBehavior),
                new PropertyMetadata(50)
        );

        public bool IsVisible
        {
            get { return (bool)GetValue(IsVisibleProperty); }
            set { SetValue(IsVisibleProperty, value); }
        }

        public int ShowDuration
        {
            get { return (int)GetValue(HideDurationProperty); }
            set { SetValue(HideDurationProperty, value); }
        }

        public int HideDuration
        {
            get { return (int)GetValue(ShowDurationProperty); }
            set { SetValue(ShowDurationProperty, value); }
        }

        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.Loaded += OnLoaded;
        }

        protected override void OnDetaching()
        {
            AssociatedObject.Loaded -= OnLoaded;
            base.OnDetaching();
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            if (!IsVisible)
                AssociatedObject.Height = 0.0;

            showAnimation_ = new DoubleAnimation(
                0.0,
                AssociatedObject.ActualHeight,
                TimeSpan.FromMilliseconds((int)GetValue(ShowDurationProperty))
            );

            showAnimation_.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };

            Storyboard.SetTarget(showAnimation_, AssociatedObject);
            Storyboard.SetTargetProperty(showAnimation_, new PropertyPath(FrameworkElement.HeightProperty));
            showStoryboard_.Children.Add(showAnimation_);

            hideAnimation_ = new DoubleAnimation(
                AssociatedObject.ActualHeight,
                0.0,
                TimeSpan.FromMilliseconds((int)GetValue(HideDurationProperty))
            );

            Storyboard.SetTarget(hideAnimation_, AssociatedObject);
            Storyboard.SetTargetProperty(hideAnimation_, new PropertyPath(FrameworkElement.HeightProperty));
            hideStoryboard_.Children.Add(hideAnimation_);
        }

        private static void OnShowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var element = ((AnimatedHeightBehavior)d).AssociatedObject;

            if ((bool)e.NewValue)
                showStoryboard_.Begin(element);
            else
                hideStoryboard_.Begin(element);
        }
    }
}

No Comments »

GymDo TextBox (WPF Style)

TextBox style that you can use in WPF 3.5 and WPF 4. Do note that the provided Resource Dicitionary has SelectedBrush defined which must be removed if you intend to use this style in WPF 3.5 (WPF 4 only property).

Download here (rename .DOC to .RAR – wordpress limitation).

No Comments »

GymDo Button (WPF Style)

Here are some button styles I’ve been working on for one of my personal projects. Styles are compatible with both WPF 3.5 and WPF 4 – I used only triggers. There are blue, green and red styles, as you can see in the screenshot below:

Download here (rename .DOC to .RAR – wordpress limitation).

No Comments »

Publishing Multi-Page DWF from Mechanical Desktop (MDT) using ACAD API

This is one of those problems that I couldn’t solve for so long… I’m posting a small code example of how it can be done without the need for user interaction – great for batch type of Addin. In the following example, adoc is AcadDocument, path is absolute path to where you want your DWF to be published.

Dim dsd_path = path + ".dsd"
Dim dwf_path = path + ".dwf"

Dim dsd_stream = File.Open(dsd_path, FileMode.Create)
Dim dsd_writer As New StreamWriter(dsd_stream)

dsd_writer.WriteLine("[DWF6Version]")
dsd_writer.WriteLine("Ver=1")

For Each layout As Object In adoc.Layouts

    Dim sheet_line As String = "[DWF6Sheet:" + layout.Name + "]"
    dsd_writer.WriteLine(sheet_line)

    Dim dwg_line As String = "DWG=" + adoc.Path
    dsd_writer.WriteLine(dwg_line)

    Dim layout_line As String = "Layout=" + layout.Name
    dsd_writer.WriteLine(layout_line)

Next

    dsd_writer.WriteLine("[Target]")
    dsd_writer.WriteLine("Type=1")

    Dim dwf_line As String = "DWF=" + dwf_path
    dsd_writer.WriteLine(dwf_line)

    dsd_writer.WriteLine("PWD=")
    dsd_writer.Close()
                
    Dim dsd_data As New DsdData()
    dsd_data.ReadDsd(dsd_path)

    dsd_data.ProjectPath = Path.GetDirectoryName(path)
    dsd_data.LogFilePath = path + ".log"
    dsd_data.NoOfCopies = 1
    dsd_data.SheetType = SheetType.MultiDwf
    dsd_data.SheetSetName = "PublisherSet"
    dsd_data.WriteDsd(dsd_path)

    Dim reader As New StreamReader(dsd_path)
    Dim content = reader.ReadToEnd()

    reader.Close()
    content = content.Replace("PromptForDwfName=TRUE", "PromptForDwfName=FALSE")
    
    Dim writer As New StreamWriter(dsd_path)
    writer.Write(content)
    writer.Close()

    Dim final_dsd As New DsdData()
    final_dsd.ReadDsd(dsd_path)

    Dim plot_cfg As PlotConfig

    For Each cfg_info As PlotConfigManager.Devices

        If cfg_info.DeviceName.Contains("DWF") Then
            plot_cfg = PlotConfigManager.SetCurrentConfig(cfg_info.DeviceName)
            Exit For
        End If
    Next

    Dim publisher = Application.Publisher
    publisher.PublishExecute(final_dsd, plot_cfg)

No Comments »

GraySky ToggleButton (WPF Style)

Here is the style for the ToggleButton.

GraySky_ToggleButton_Preview

Download here (rename .DOC to .RAR – wordpress limitation).

No Comments »

Follow

Get every new post delivered to your Inbox.