Silverlight and WPF Boolean Not Converter…To be or NOT to be

So you have an IsReadOnly flag on your viewmodel, but you want to set the IsEnabled property on control. A conundrum for a binding, right.

Well, simple solution to an annoying problem. Use the converter below on your binding and it becomes opposite day.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
 
namespace Seekford{
   
public class BooleanNotConverter : IValueConverter
    {
       
//easy peezy.
 
       
/// <summary>
       
/// Converts a value.
       
/// </summary>
       
/// <param name="value">The value produced by the binding source.</param>
       
/// <param name="targetType">The type of the binding target property.</param>
       
/// <param name="parameter">The converter parameter to use.</param>
       
/// <param name="culture">The culture to use in the converter.</param>
       
/// <returns>
       
/// A converted value. If the method returns null, the valid null value is used.
       
/// </returns>
       
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
           
return !(bool)value;
        }
 
       
/// <summary>
       
/// Converts a value.
       
/// </summary>
       
/// <param name="value">The value that is produced by the binding target.</param>
       
/// <param name="targetType">The type to convert to.</param>
       
/// <param name="parameter">The converter parameter to use.</param>
       
/// <param name="culture">The culture to use in the converter.</param>
       
/// <returns>
       
/// A converted value. If the method returns null, the valid null value is used.
       
/// </returns>
       
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
           
return !(bool)value;
        }
 
        
    }
}

 

Happy Coding!

WPF LinkButton – Easy as pie

Where in the world is the LinkButton? I am sure its there somewhere but I just didn’t find it. So, what’s a guy to do? Get some style, that’s what.

WPF makes restyling controls incredibly easy. So much, I switched gears from a WinForms project to use WPF to make the interface look great without resorting to a million third party controls.

I assume you are familiar with WPF and know how to apply a style to a control. Well, apply this to a Button. Just paste the code below in your UserControl.Resources or Window.Resources section and then apply the Style={StaticResource LinkButton} to the button.

Note: I hate underlined links. You can add the underline by changing the TextFormatter on the TextBlock wrapping the content presenter.

 

  <Style x:Key="LinkButton" TargetType="Button">

            <Setter Property="Template">

                <Setter.Value>

                    <ControlTemplate TargetType="Button">

                        <TextBlock>

                    <ContentPresenter />

                        </TextBlock>

                    </ControlTemplate>

                </Setter.Value>

            </Setter>

            <Setter Property="Foreground" Value="Blue" />

            <Setter Property="Cursor" Value="Hand" />

            <Style.Triggers>

                <Trigger Property="IsMouseOver" Value="true">

                    <Setter Property="Foreground" Value="Red" />

                </Trigger>

            </Style.Triggers>

        </Style>

Happy Coding!

Bind to an ICommand on ViewModel with objects in an ItemsControl in WPF

I spent a few minutes beating my head on binding a command to a button that I had in an ItemsControl. Mainly, was creating a list of “link” buttons and wanted them to pass their binding argument to my command on the main view model.

Well, since the DataContext to the content is not the main view model but the individual data item that is in the ItemSource for the ItemsControl, you have to get creative.

Enter the RelativeSource binding. This great tool allows you to search up in the visual hierarchy and grab different data contexts. Simply put, I use the FindAncestor to search for my main UserControl instance, and then go off its DataContext to grab the command. Nice and easy.

Below is the code. Should be easy to follow:

<Window x:Class="SSI.Views.SelectorView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
              mc:Ignorable="d"
             xmlns:views="clr-namespace:SSI.I8N.LanguagePackEditor.Views"
        Title="SSI">
                <ItemsControl Margin="0" ItemsSource="{Binding Folders}">
<ItemsControl.ItemTemplate>
<DataTemplate>
 <Button Content="{Binding}" Command="{Binding DataContext.FolderCommand,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type views:SelectorView}}}" CommandParameter="{Binding}"/>
                </DataTemplate>
           </ItemsControl.ItemTemplate>
</ItemsControl></Window>

Happy coding!

WPF not compiling: program does not contain a static ‘Main’ method

I decided to create a new WPF application. I started the project out intending to use WinForms, but then I hit a limitation(pain) that prompted me to switch to WPF. A list of link buttons, easily accomplished in WPF, but annoying in WinForms.

So, I created an App.xaml, deleted my Programs.cs and Main and went compile.

Boom! Error, no Main method. hmmmm… I stared at another one of my WPF projects and didn’t see the magic missing setting. Finally, it dawned on. The compile options for the App.xaml.

Set the compile option to Application Definition and away you go. So simple, yet so non-obvious.

image

Happy Coding!

Multiselect on GridView in WPF ListView loses selection on mouse click

We overrode the ListViews View using a GridView so that we could display the data in the format our users required. The issue that we encountered was that after we introduced MultiSelect, our drag and drop didn’t work as expected.

You could select multiple rows, but when you then clicked on the selection area to “drag” them, then it would unselect everything but the one you specifically clicked on.

Not the greatest of behaviors.

So the trick is rather simple, yet strange. Override the ListViewItem class, and use it to override the generated items.

Your new ListView

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
using System.Windows;
using System.Collections.ObjectModel;
using System.Collections;
using System.Collections.Specialized;
using System.Windows.Controls.Primitives; 

namespace Seekford{
    public class MyListView: ListView    {
        protected override DependencyObject GetContainerForItemOverride()
        {            return new MyListItem();
       }
     protected override bool IsItemItsOwnContainerOverride(object item)
      { 
           return item is MyListItem;
       } 

     }
}

Your new ListViewItem

using System;
using System.Windows.Controls;
using System.Windows.Input;
using System.ComponentModel;

namespace Seekford{
      public class MyListItem : ListViewItem	{

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            if (IsSelected)
                return;
            base.OnMouseLeftButtonDown(e);
       }

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            if(IsSelected)
                base.OnMouseLeftButtonDown(e);
        }
 }
}

Nice and easy! Kludgy, but seems to work.

Happy Coding!

How to put bound data (Binding) into a Grid View Header or List View Header.

This is another seemingly simple task. It actually is, but you may go down the route of setting the GridViewHeader.Template and wondering why it doesn’t work.

Well, it’s as simple as putting a GridViewHeader into the GridViewColumn definition and setting content to it.

<GridViewColumn  Width="Auto">
    <GridViewColumnHeader>
        <Grid HorizontalAlignment="Right" >
                <Grid.RowDefinitions>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <TextBlock Text="{Binding Title, Mode=OneWay}" Grid.Row="0" HorizontalAlignment="Right" />
             </Grid>
    </GridViewColumnHeader>
</GridViewColumn>

See. Nice and easy right? Just fill in the different UI controls you want to make it fit your needs and away you go.

Happy Coding!

How to left align or right align the header in a ListView or GridView in WPF

So you have this great ListView or GridView in your fancy WPF application, but everything is centered. Maybe you like that, and all is good. Or, like most of us, you want the data aligned to the left or right. I like the left for most data, makes more sense. You looked for the property, and hmm… not to be found.

It turns out this seemingly simple task is, well, actually quite simple. It is really easy to spend a number of hours looking for the “magic” tag, property, etc. to do this. You will find out though, it’s all about having style.

You simply need to set the HorizontalContentAlignment on the style for the header to align everything however you want to.

Take a look at the following code:

<GridViewColumn  Width="Auto"  >
 <GridViewColumn.HeaderContainerStyle>
    <Style  TargetType="{x:Type GridViewColumnHeader}">
            <Setter Property="HorizontalContentAlignment" Value="Right" />
    </Style>    
 </GridViewColumn.HeaderContainerStyle>
</GridViewColumn>

What we are doing is setting the HorizontalContentAlignment to right aligned. This will cause the contents of the header to all shift to the right. If you are using your own template, make sure to right align the textblocks and other controls as well. Otherwise, it probably won’t look right.

Nice and easy, right?

Happy Coding!

Mouse Double Click for WPF in MVVM using a clean Behavior with Command Binding

I wanted to capture the double click event, which is actually the MouseLeftButtonDown with the e.ClickCount ==2.

Since I transitioned to a new WPF project, handed off the Silverlight work, I have been trying to keep the same MVVM pattern. I wanted to get the double click off of my TreeViewItem so the child node could invoke the ViewModel to execute a Command.

Here is the behavior I wrote to handle this simple task.

Snippet

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Controls;

namespace Seekford.Behaviors
{
    public static class MouseDoubleClickBehavior
    {
        /// <summary>
        /// Hooks up a weak event against the source Selectors MouseDoubleClick
        /// if the Selector has asked for the HandleDoubleClick to be handled
        ///�
        /// If the source Selector has expressed an interest in not having its
        /// MouseDoubleClick handled the internal reference
        /// </summary>
        private static void OnHandleDoubleClickCommandChanged(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            FrameworkElement ele = d as FrameworkElement;
            if (ele != null)
            {
                ele.MouseLeftButtonDown -= OnMouseDoubleClick;
                if (e.NewValue != null)
                {
                    ele.MouseLeftButtonDown += OnMouseDoubleClick;
                }
            }
        }

        /// <summary>
        /// TheCommandToRun : The actual ICommand to run
        /// </summary>
        public static readonly DependencyProperty DoubleClickCommandProperty =
            DependencyProperty.RegisterAttached("DoubleClickCommand",
                typeof(ICommand),
                typeof(MouseDoubleClickBehavior),
                new FrameworkPropertyMetadata((ICommand)null,
                    new PropertyChangedCallback(OnHandleDoubleClickCommandChanged)));

        /// <summary>
        /// Gets the TheCommandToRun property. �
        /// </summary>
        public static ICommand GetDoubleClickCommand(DependencyObject d)
        {
            return (ICommand)d.GetValue(DoubleClickCommandProperty);
        }

        /// <summary>
        /// Sets the TheCommandToRun property. �
        /// </summary>
        public static void SetDoubleClickCommand(DependencyObject d, ICommand value)
        {
            d.SetValue(DoubleClickCommandProperty, value);
        }

        #region Handle the event

        /// <summary>
        /// Invoke the command we tagged.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            //check for double clicks.
            if (e.ClickCount != 2)
                return;
            FrameworkElement ele = sender as FrameworkElement;

            DependencyObject originalSender = e.OriginalSource as DependencyObject;
            if (ele == null || originalSender == null)
                return;

            ICommand command = (ICommand)(sender as DependencyObject).GetValue(DoubleClickCommandProperty);

            if (command != null)
            {
                if (command.CanExecute(null))
                    command.Execute(null);
            }
        }
        #endregion
    }

}

Hopefully this helps you.

Oh, how to use. Almost forgot:

Snippet

xmlns:infraBehaviors="clr-namespace:Seekford.Behaviors;assembly=Seekford"

Snippet

 <Grid infraBehaviors:MouseDoubleClickBehavior.DoubleClickCommand="{Binding MyCommand}"  HorizontalAlignment="Stretch" >
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>       �
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition></RowDefinition>
                </Grid.RowDefinitions>
                <TextBlock Text="{Binding Name}" TextWrapping="Wrap" FontWeight="Bold"  Grid.Column="0"  />
            </Grid>

Of course, make your own namespace and correct accordingly. But you already knew that.

Happy Coding!