This blog has, IMO, some great resources. Unfortunately, some of those resources are becoming less relevant. I'm still blogging, learning tech and helping others...please find me at my new home on http://www.jameschambers.com/.
Showing posts with label ComboBox. Show all posts
Showing posts with label ComboBox. Show all posts

Friday, May 29, 2009

Setting Template Properties on a ComboBox

In WPF the ComboBox is a tricky little control that doesn’t easily allow you to adjust properties on the inner controls of the template.

If you try to override the template you will find very quickly that you might get into the trap of having to override the entire visual tree, thus having to recreate the entire control from scratch.

Below is a way to get at the controls from the template, per my answer to a question on the MSDN forums. In particular, the question was about getting the TextBox (actually, in his case, the TextBlock) to have underlined text.

cboTest.Loaded += delegate {
if (cboTest.IsEditable)
{
TextBox textEditPart = ((TextBox)cboTest.Template.FindName("PART_EditableTextBox", cboTest));
textEditPart.TextDecorations = TextDecorations.Underline;
}
else
{
Grid layoutGrid = VisualTreeHelper.GetChild(cboTest, 0) as Grid;
ContentPresenter nonEditPart = VisualTreeHelper.GetChild(layoutGrid, 2) as ContentPresenter;
TextBlock textNonEditPart = VisualTreeHelper.GetChild(nonEditPart, 0) as TextBlock;
textNonEditPart.TextDecorations = TextDecorations.Underline;
}
};


Man, code on this blog is hard to read.  :o/



Okay, so what’s going on is basically that we have to hunt down the TextBox or TextBlock, depending on if the ComboBox is set to be editable or not.



After finding that, we simply set the TextDecorations property to the pre-defined Underline text decoration. Paste that code into your code-behind after InitializeComponent and you should be good to go.



I found the elements in question by using Mole.  When we have an object that is named, we can use the Template.FindName to get the control loaded up locally.  When we don’t, we’ll need to use VisualTreeHelper’s static GetChild method to dig.



Side note: this won’t work in a big way if you’ve otherwise edited your template.  This is fairly hard-coded against the VisualTree provided by ComboBox out-of-the-box (but could easily be adapted to be a little less tightly coupled).

Wednesday, May 13, 2009

Adding a Hint to a Search Textbox in WPF

Are you running Vista?  Good.  Press the start key (or click on the Vista orb).  See how it says, “Start Search”?

It’s a nice effect: it’s contextual, it gives the user direction and it disappears the instant you start typing something.

If you want to give your users a similar experience with minimal effort, here’s how you add a hint (or help text) to a textbox or similar control in WPF.  I am added the hint to a combobox, so adjust your code as needed.

The approach we’re going to take here is similar to using a reflection surface in WPF, in that we’ll use a VisualBrush.  A couple of quick things: first, we set Stretch and TileMode to None (it would look a little weird, if not); second, we apply a slight transform to pad out the text (otherwise it hugs the border).

<VisualBrush x:Key="SearchHint" TileMode="None" Stretch="None" AlignmentX="Left">
<
VisualBrush.Transform>
<
TranslateTransform X="5" Y="0" />
</
VisualBrush.Transform>
<
VisualBrush.Visual>
<
Grid>
<
TextBlock FontStyle="Italic"
Foreground="Black"
Opacity="0.3"
Text="Enter search text…"/>
</
Grid>
</
VisualBrush.Visual>
</
VisualBrush>



You’ll need to add this visual brush to the window or control resources, or put it in a resource file.



Next, we want to use a trigger so that the background is changed from it’s default when the string is empty to be the SearchHint instead.  WPF takes care of changing it back for us when there is text in the box.



I have this as code in my ComboBox tag:




<ComboBox.Style>
<
Style TargetType="ComboBox">
<
Style.Triggers>
<Trigger Property="Text" Value="">
<
Setter Property="Background" Value="{StaticResource SearchHint}"/>
</
Trigger>
</Style.Triggers>
</
Style>
</
ComboBox.Style>




There you have it.  You may want to add multiple brushes, or even an image or anything (I used a grid for this purpose in the Visual, but you can set this to any single element you like).  If you’re presenting data or there is a chance you could get a null in there you may wish to handle that Trigger condition as well.



Man, alive…I really need to do something about this blog template so my code doesn’t look like arse.



edit: Here is the original article I based my work off of. 

Tuesday, May 12, 2009

Getting at the Text of a ComboBox in WPF – Part 2

- You all finished?
- Yeup, it compiles!

At the end of the day yesterday I thought I had made a bit of progress with my filtered-combo box. Unfortunately, though it compiles, I’ve found that I can’t get my app loaded and binding to that event at run-time gives me an exception.

However, in looking for a solution, I found the DependencyPropertyDescriptor object, which allows us to access dependency properties from code.  Using this object I can now observe the text for changes and add my event handler as such:

public Window1()
{
InitializeComponent();

DependencyPropertyDescriptor comboText;
comboText = DependencyPropertyDescriptor.FromProperty(ComboBox.TextProperty, typeof(ComboBox));
comboText.AddValueChanged(this, this.ComboTextChanged);
}

private void ComboTextChanged(object sender, EventArgs e)
{
// ...
}

Monday, May 11, 2009

Getting at the Text of a ComboBox in WPF

I am writing a small wrapper for WPF’s ComboBox and want to hook up (optionally) a delegate that filters the list of items, based on what the user has typed already into the text box portion of the control.

I have achieved this with the help of Mole and the FindName method on the Template object.

TextBox input = ((TextBox)comboBox1.Template.FindName("PART_EditableTextBox",comboBox1));
input.TextChanged += new TextChangedEventHandler(input_TextChanged);

FindName allows us to walk across a templated control and search for a child element by the name we pass in.  This allows us to get at some of the innards for some of the existing controls and, in my case as above, attach to events or check properties and the like.