Focus-dependent text change for TextBoxes in WPF - c#

I'm writing an application in WPF using the MVVM-pattern and will really often use TextBoxes.
I don't want to use labels for the user to know user what the text box is for, i.e. I don't want something like this:
<TextBlock> Name: </TextBlock>
<TextBox />
Instead, I would like the TextBox to contain its own label. Statically, you would express it like this:
<TextBox>Name</TextBox>
If the cursor is displayed in the textbox, i.e. the TextBox gains focus, I want the description text to disappear. If the TextBox is left empty and it loses the focus, the description text should be shown again. It's similar to the search textbox of StackOverflow or the one of Firefox. (please tell me if your not sure what I mean).
One TextBox's label may change at runtime, dependending on e.g. a ComboBox's selected element or a value in my ViewModel. (It's like in Firefox's search TextBox, if you select google from the search engins' menu, the TextBox's label changes to "Google", if you select "Yahoo" its set to "Yahoo"). Thus I want to be able to bind the label's content.
Consider that I may already have a Binding on the Text-Property of the TextBox.
How can implement such a behaviour and make it reusable for any of my TextBox's? Code is welcome but not needed; a description of what to do is enough.
Thank you in advance.

Here is a style I think is exactly what you are looking for, and it's pure XAML.
<Style x:Key="WatermarkTextBox" TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<Border x:Name="BorderBase" Background="White" BorderThickness="1.4,1.4,1,1" BorderBrush="Silver">
<Label x:Name="TextPrompt"
Content="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Tag}"
Background="{TemplateBinding Background}" Visibility="Collapsed"
Focusable="False" Foreground="Silver"/>
</Border>
<ScrollViewer Margin="0" x:Name="PART_ContentHost" Foreground="Black"/>
</Grid>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsFocused" Value="False"/>
<Condition Property="Text" Value=""/>
</MultiTrigger.Conditions>
<Setter Property="Visibility" TargetName="TextPrompt" Value="Visible"/>
</MultiTrigger>
<Trigger Property="IsFocused" Value="True">
<Setter Property="BorderBrush" TargetName="BorderBase" Value="Black"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="DimGray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Usage is:
<TextBox Style="{StaticResource WatermarkTextBox}" Tag="Full Name"/>
where Tag is the help message you want to show.
You could clean up this style for your own use, but the most important part is the which controls hiding/showing the helper text.
It's worth noting as well, there is already a DependencyObject available for storing the helper text, so you don't need to create your own with this method.
FrameworkElement.Tag is available for holding arbitrary information about this element. That's why we set the Tag property:
http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.tag.aspx

You could derive from TextBox and implement your behaviour. The TextBox offers the events GotFocus/LostFocus (or the methods OnGotFocus/OnLostFocus respectively) which should help. You also should consider offering a new DepedencyProperty, so you can define the default text in xaml and bind it to other controls/resources etc.

To amplify on my suggestion about using an adorner.
An Adorner is basically an element, rendered on its own layer, that appears over/around another element. For instance, if you implement validation in a binding, the red box that decorates an invalid control is an adorner - it's not part of the control, and it can be (and is) applied to all kinds of controls. See the Adorners section of the WPF docs for a simple but clear example.
I thought of an Adorner for a couple of reasons. The principal one is that the behavior you're describing might not necessarily be confined to a TextBox. You might, for instance, want to have a ComboBox exhibit the same behavior. Implementing an Adorner would give you a consistent way to implement this functionality across multiple controls (though it doesn't make sense in, say, a CheckBox or a ProgressBar). A second is that you wouldn't have to do anything to the underlying control more elaborate than implementing triggers to display and hide the Adorner in response to focus events. Adorners are a bit of a pain in the butt to implement, but it's worth knowing how to.
All that said, I like mattjf's answer a lot more than I like mine. The only disadvantages I see with that approach are 1) It only works with the TextBox; you need to implemnent a new version of the style every time you want to use the approach on another control, 2) I may just be engaging in magical thinking, but every time I ever used the Tag property in WinForms it told me (once I learned to listen) that I was building something fragile. I don't know for sure that this is also true in WPF, but I bet it is.
My comment on using the bound Text property probably needs amplification. If you use the Text property to store the field label, then you've got a number of hard-to-solve problems. First, since it's a bound property, changing its value in the TextBox will change it in the source. So now your source needs to know a lot of information about the state of the UI - does the control currently have the focus? If the value of the Text property is Foo, does that mean that the label is Foo, or the user typed in Foo? There are probably ways that you can manage this, but the best way to manage it is to not have to.
(One other problem with this paradigm: What should be the behavior be if the user wants the value of the TextBox to be the empty string?)

Related

WPF Treeview is not Collapsing Rows Even with Visibility Collapsed [duplicate]

I've been trying to just hide items from a TreeView. I'm using a custom data type as source (called SettingsMenuItem) which inherits from FrameworkElement (currently FrameworkContentElement, because otherwise the TreeView renders them wrong).
My goal is by setting the VisibilityProperty of these FrameworkElements to either Collapsed or Visible that I'm able to hide certain items (including their children). I know that this can be done by deleting items from the source collection. But that's not what I want. It would mean that I have to mirror each collection in order to keep track of it's actual items, bind to each one in order to be notified about Visibility-changes and create a new collection each time one changes. A lot of overhead for this.
Right now I have no clue how I could accomplish that. I figure it's related to the ItemsGenerator, but I haven't seen any possibility to override it's behaviour. I thought TreeView would be able to detect Visibility, but obviously it doesn't. As alternative I thought of a custom TreeViewItem (maybe even TreeView if necessary) - but at this point the abstraction of this whole system overwhelms me. I don't know where to start and what is actually necessary to solve the problem.
Tips what I have to change or implement by myself would be more than enough. A complete solution would be nice.
You can do this using a data trigger bound to a property (e.g. "IsVisible") in you tree data nodes:
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsVisible}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
While this technically answers your question I would be wary of actually doing it. User3690202's comment is correct, it's the sort of thing you would normally do via filtering in your view model.
For alternate solution using code behind xaml.cs:
To Remove a specific TreeViewItem from a TreeView which is created from a code behind.
TreeViewItem treeViewItem1 = new TreeViewItem
{
Visibility = Visibility.Collapsed,
};
use the code with TreeViewItem you want to hide in a if condition to hide specific TreeViewItem Header let say "Cars" and you want to hide it and use the code with if condition to hide "Cars" TreeViewItem.

usercontrol (?) for WPF reusable menu

I am a beginner at WPF so please excuse me if this question is too simple :)
I have a listbox which I would like to filter by various filter conditions. This listbox I fill with instances of a particular type. Each filter condition is associated with one of the listbox items' properties. (They are like: this or that string property starts with string XXX.)
For this I would need a menu for each property from which users can select the filter conditions they want to filter the items with. Each property of the same type will have the very same set of menu items with the various filter conditions. (For strings: starts with, ends with... for ints: lower than, higher than, etc.)
The menus require some code behind too so I don't want to program these for each property separately.
My problem is that I don't know in what way could I program these. I cannot program them as UserControls because all what I need is MenuItems in a Menu. But I cannot program them as MenuItem derived classes because I would need the XAML for designing them for each type. Could I create a MenuItem derived class with a XAML somehow? Or do you have any other suggestions?
In WPF, we work with data elements whose public properties are data bound to the properties of various UI controls via DataTemplates. Please see the Data Templating Overview page on MSDN for the full story.
In order to do this, we develop custom classes that contain all of the necessary properties that we need to display and then we declare one or more DataTemplates that define the binding connections between the classes and the UI controls, or MenuItems in your case.
The benefit of this is that in order to display a Menu in the UI, you just need to data bind one of your custom menu class objects to a control in the UI and let the DataTemplate do the rest. So if you want to change the menu contents, you just need to change the data item that is data bound to the Menu.
So to answer your question directly, a Menu control would be most suitable for you to use, but you don't store the Menu properties in your code behind... you store the property values in your custom classes that will be data bound to the Menu control properties:
<Menu ItemsSource="{Binding CollectionOfYourCustomClassItems}" ... />
It is worth pointing out that you may need to set the child MenuItem properties in a Style and not a DataTemplate as usual (taken from the accepted answer to the WPF MenuItem : Mix databound items and static content question (which I recommend that you read) here on Stack Overflow):
<MenuItem Header="_Recent Files" ItemsSource="{Binding Commands,Mode=OneWay}">
<MenuItem.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Header" Value="{Binding Path=ShortName}" />
<Setter Property="ToolTip" Value="{Binding Path=FileName}" />
<Setter Property="Command" Value="{Binding Path=OpenCommand}" />
<Setter Property="CommandParameter" Value="{Binding Path=OpenParameter}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSeparator}" Value="true">
<Setter Property="MenuItem.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MenuItem}">
<Separator Style="{DynamicResource {x:Static MenuItem.SeparatorStyleKey}}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
You will find many more tutorials and related questions regarding data binding to MenuItems online, so I won't go over everything again here. Please see the following article to start with:
Binding menus using HeirarchicalDataTemplates

Border thickness for Telerik's RadMaskedInputBaseStyle in Silverlight when content is invalid

How do I increase border thickness for RadMaskedInputBaseStyle (or RadMaskedDateTimeInput by Telerik) in Silverlight only WHEN it is red indicating that the input contains invalid entry.
My XAML looks like this
<Style TargetType="telerik:RadMaskedDateTimeInput">
<Setter Property="IsValidationHintVisible" Value="True" />
</Style>
In general, if a style isn't available as a property of the control, then you will find it buried somewhere in the control template (as Chris W alludes to in the comments).
To see the source for a proprietary control template like one of Telerik's, open up Expression Blend and click "Edit Template" on an instance of the control. If you do that for the RadMaskedDateTimeInput, you will notice the validation-related visual states making reference to an element named "ErrorElement". Scroll down, in the control template source, and you will see that is declared as follows:
<Telerik_Windows_Controls_Chromes:ValidationTooltip x:Name="ErrorElement" Opacity="0" TooltipPlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}" telerik:StyleManager.Theme="{StaticResource Theme6}" TooltipContent="{TemplateBinding DisplayErrorMessage}" TooltipContentTemplate="{TemplateBinding ErrorMessageTemplate}" />
Ok, so it's another control called ValidationTooltip. This control does have a BorderThickness property exposed, so if you like, you should be able to simply set that property in a targeted global style. Something like this should go in your resource dictionary:
<Style xmlns:Telerik_Windows_Controls_Chromes="clr-namespace:Telerik.Windows.Controls.Chromes;assembly=Telerik.Windows.Controls"
TargetType="Telerik_Windows_Controls_Chromes:ValidationTooltip">
<Setter Property="BorderThickness" Value="2" />
</Style>

WPF: How do I handle an event from a Model to dynamically update xaml in MVVM

I've hit a bit of a dead end in trying to figure this one out... Using the MVVM pattern in WPF, our C# Model fires an event to say something has happened. I want to be able handle that event in my ViewModel and then either kick of a storyboard or change the visibility of a hidden panel on the current Xaml Page. This has to be handled with no Code Behind.
I can sync for the event in my ViewModel, update a property to say what the name of that event is and fire a NotifyPropertyChanged even but how do I get that to either kick off a storyboard or map to a boolean true/false on the Visibility property of my Grid? The property I bind to hs to be the event name as different grids may be shown based on different events so I need a way of mapping this to a boolean. However the ideal solution would be to kick off a storyboard. I've looked at DataTriggers but they all seem to be linked to styles and not to actual pages.
Any ideas of how I can achieve this?
Thanks!
I've used this in the past to kick off a storyboard in code-behind
Storyboard animation = (Storyboard)this.FindResource("ShowPanelStoryboard");
animation.Begin();
This code goes behind the View, not in the ViewModel. Personally, I don't mind some code behind my View providing it is only related the View. In the project I used this in, I added a listener to the VisibilityChanged event and when it got changed to Visible, I ran the storyboard.
As for showing your popup, there's a few ways. One of my favorites was just adding an IsPopupShown property to the ViewModel, binding my panel's visibility to it, and setting it to true anytime the popup should be shown. The ViewModel then handles the events that trigger the popup being shown or not.
An alternative as suggested by Dave White is to use a converter. If your value is not always true/false then you could create a converter that checks if a bound value is equal to the ConverterParameter, and return a Visibility value.
From your comment, it seems to me like what you may want to do is expose an Event property of type object in your view model. When the view model receives an event, it sets Event to an object of a type appropriate for that event. In your XAML, you have this:
<ContentControl Content="{Binding Event}"/>
and in the resource dictionary define a DataTemplate for each specific type of event you want to display. If Event is null, nothing gets displayed. If Event contains an object that you've defined a DataTemplate for, it gets displayed using that template.
Yes, you'll need to create a class for each type of event (if you don't already have one).
Another way is to implement the poor man's template selector:
<TextBlock Text="This is displayed if Foo contains 'BAR'">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Property="Foo" Value="BAR">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBlock Text="This is displayed if Foo contains 'BAZ'">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Property="Foo" Value="BAZ">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
It's kind of stupidly verbose, but it's an easy way to handling a lot of mutually-exclusive display options.
Bind the Visibility property on your grid, in Xaml, to the boolean property on your ViewModel.
<Grid Visibility="{Binding Path=VisiblePropertyOnViewModel}">
Now do whatever you need in your ViewModel and set the property. As long as it does INotifyPropertyChanged or is a DependencyProperty, it will work.
I'd have to do more digging to figure out how to kick off a Storyboard, but I have no doubt it would be almost as easy. Storyboards can be kicked off by PropertyTriggers as well I believe. I'll leave this to get you started.

C# wpf question custom checkbox

I just started getting deeper into C# and WPF design, so dont mind if I ask for some basics.
I am trying to port one of our internet applications to a c# application and having some difficulties.
I need 4 checkboxes which look like this. If you click them they should look like the second one.
http://frauneder.com/checkbox_example.jpg
I was able to do it with images which change on click but there I miss the ischecked property.
The second question:
I want to check/uncheck the checkboxes using the 1-4 keys on my keyboard. How do I do this?
Thanx very much in advance!
I'm not sure I fully understand your questions, but let me try. It all matters how deep you want to go here, too. There are many ways to skin this cat.
1 - I think you're asking how to use the IsChecked property to influence the look of the CheckBox? The way to do this is re-template the CheckBox and use a trigger in the template. Something like this:
<CheckBox>
<CheckBox.Template>
<ControlTemplate TargetType="CheckBox">
<StackPanel Orientation="Horizontal">
<Image x:Name="_image" Source="Unchecked.jpg"/>
<ContentControl Content="{Binding Content}"/>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="_image" Property="Source" Value="Checked.jpg"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</CheckBox.Template>
</CheckBox>
There is more to consider here, but that should get you started.
2 - You can use InputBindings to execute a command when some input is received by the control. So you can define a command that checks or unchecks the appropriate CheckBox based on the parameter passed to the command. Then you can do something like this:
<CheckBox>
<CheckBox.InputBindings>
<KeyBinding Key="1" Command="{x:Static local:Commands.YourCommand}" CommandParameter="1"/>
</CheckBox.InputBindings>
</CheckBox>
Again, there are many ways to solve your problems here. Hopefully this steers you in the right direction.

Categories