Archive for category WPF
How do I cancel a databinding property set in WPF?
Posted by Brian Seekford in WPF on November 30, 2011
I have a combobox in WPF that I am using the SelectedItem property with a DataBinding and sometimes certain items shouldn’t be selected based on certain criteria. Mine was that two comboboxes couldn’t have the same value.
Yes, there are other ways, such as removing invalid values from other boxes, but here was my solution for preventing the invalid property set by cancelling the selection/property set.
WPF sucks in this manner as there isn’t an easy way to update it. You can’t raise the property updated event since the binding ignores those when setting, to avoid recursion issue I suppose. (Yes, developers could defend by not raising the events if the property doesn’t change)
Anyway, the solution is simply to raise the property changed after the operation, by simply posting it to the work queue on the UI thread right afterward.
Code: in C#
public MyHeaderType SelectedHeader
{
get { return this.selectedHeader; }
set
{
bool resetMe= validateValue(value);
var origVal = selectedHeader;//store for reset
selectedHeader = value;
RaisePropertyChanged(() => SelectedHeader);
if (resetMe)//Why do I need to set the value above? No idea. Doesn’t work unless I do it that way. Yes. I tried.
{
Application.Current.Dispatcher.BeginInvoke( //force a reenter to put it back……
new Action(() =>
{
SelectedHeader = origVal;//put me back to the correct value.
}),
DispatcherPriority.ContextIdle,
null
);
}
}
}
Happy Coding!
Silverlight and WPF Boolean Not Converter…To be or NOT to be
Posted by Brian Seekford in Silverlight, WPF on December 2, 2010
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
Posted by Brian Seekford in WPF on October 19, 2010
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
Posted by Brian Seekford in WPF on October 18, 2010
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
Posted by Brian Seekford in WPF on October 14, 2010
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.
Happy Coding!
Mouse Double Click for WPF in MVVM using a clean Behavior with Command Binding
Posted by Brian Seekford in WPF on August 31, 2010
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!