How to make part of TreeViewItem Header bold? - c#

I am trying to implement a simple search feature in SQL and wpf... I need to highlight only part of the next in results that has been entered in a TextBox.
So I do the search in SQL get the results and put them on a TreeViewItem that adds them to a TreeView. That all works but how would i go around making only a certain part of TreeViewItem Header bold?
I already know how to find where the part of the text I want bold is but i just need to make it bold.
TreeViewItem root_item = new TreeViewItem() { Header = "Users" };
FoundUsersTreeView.Items.Add(root_item);
while (sqlReader.Read())
{
TreeViewItem new_item = new TreeViewItem() { Header = sqlReader.GetString(0) };
root_item.Items.Add(new_item);
}

If you're going to use wpf for any substantial work, you should use MVVM.
Working directly with controls is OK for very simple stuff but the difficulty ramps up very quickly.
You should Bind data and template that into controls instead.
This is how WPF is intended to be used.
Work with the base data rather than controls.
If you take a look at this sample:
https://gallery.technet.microsoft.com/WPF-Highlight-Matching-71ad5a04
It works with a listview rather than treeview and highlights text by making the background red.
Not exactly what you need.
But the principle is the thing to look at.
You could easily change the listview used to a treeview.
Having said that, you only seem to have on level of items in your treeview, so you pretty much might as well use a listview anyhow.
Anyhow.
If you take a look, you'll see each item is split up using a regex so there's a separate RunHi viewmodel for each piece.
Matching pieces have IsMatch set to true on their RunHi.
These are templated into a horizontal listview - so it looks like one textblock but is in fact one or more arranged one after the other.
Each row of the listview is itself a listview.
You could of course make the header of each treeviewitem a listview if you particularly want a treeview.
A datatrigger is used to make the background yellow.
To make it bold instead you can just change that part:
<ControlTemplate TargetType="{x:Type ListViewItem}">
<TextBlock Text="{Binding Text}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding IsMatch}" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</ControlTemplate>

You can achieve this using HeaderTemplate of your TreeViewItem. As you're adding TreeViewItem from code behind, you can use the Tag property to differentiate which one need to be set as Bold.
You can add below DataTemplate to your Resources.
DataTemplate
<DataTemplate x:Key="headerTemplate">
<TextBlock Text="{Binding}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Tag, RelativeSource={RelativeSource AncestorType=TreeViewItem, Mode=FindAncestor}}"
Value="True">
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
Code Behind
TreeViewItem root_item = new TreeViewItem() { Header = "Users" };
treeView.Items.Add(root_item);
while (sqlReader.Read())
{
var new_item = new TreeViewItem { Header = sqlReader.GetString(0), Tag = true };
new_item.HeaderTemplate = Resources["headerTemplate"] as DataTemplate;
root_item.Items.Add(new_item);
}
You can set boolean value to Tag property to make that Node as Bold.

Related

How do I make the WPF ComboBox items visible, but non-selectable?

I am trying to make the items of my WPF comboBox visible (preferably greyed out) but not allow the user to select them using c# code.
I have tried the following:
comboBoxName.IsHitTestVisible = false
comboBoxName.Focusable = false
However, this prevents them seeing the contents of the comboBox all together. How would I make the contents visible but cannot be selected in c#?
Set an item container style that will disable each ComboBoxItem.
<ComboBox x:Name="comboBoxName" ItemsSource="{Binding Collection}">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="IsEnabled" Value="False"/>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
If you use code-behind, can define and apply the item container style like this.
var itemContainerStyle = new Style(typeof(ComboBoxItem));
var isEnabledSetter = new Setter(IsEnabledProperty, false);
itemContainerStyle.Setters.Add(isEnabledSetter);
comboBoxName.ItemContainerStyle = itemContainerStyle;

Change FontWeight of specific row of DevExpress GridControl in WPF

I want to Change the FontWeight of a specific row to bold. So i have a DataTable (MyDataTable):
Name Location
-------------------
Mark New-York
Julian Paris
Donald Moscow
which i bind to a DevExpress GridControl
<dxg:GridControl ItemsSource="{Binding MyDataTable}">
Now i would like to Change the FontWeight of the row where the Name is 'Julian'. How can i do this?
I thought using a DataTrigger like:
<dxg:GridControl.Resources>
<Style TargetType="{x:Type dxg:GridRow}">
<Style.Triggers>
<DataTrigger Binding="{Binding MyDataTable.Columns[0]}" Value="Name">
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
</Style.Triggers>
</Style>
</dxg:GridControl.Resources>
but this is not working. I tried several other Options, but did not find a working solution. Can someone please guide me in the right direction? I would very much prefer to do it directly in xaml and not in code behind, if this is possible.
Use FormatConditions Property to format row or cell with condition
<dxg:TableView.FormatConditions> <dxg:FormatCondition Expression="[Name] = 'Julian'" FieldName="Name" />
EDIT:
If you want formatting in code - Formatting in Code

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

How to create different ItemsPanelTemplate for a ListBox

I'm writing an IM program on Windows Phone 8. And I am currently dealing with the UI for chatting.
I want to create a ListBox that holds all the "chat bubbles" (like those in iPhone). The incoming messages appear on the left-hand side, and outgoing messages on the right-hand side. Like this:
So obviously, I need to set differnt alignment for each item.
I was trying to solve this by wrapping the bubble in a large Grid that expands all the space in the ItemsPanel, and align the chat bubble to the right (the parent of the chat bubble is the large Grid). But that didn't work because a grid in ItemsPanel won't fill up all the spaces automatically. And then I went for searching "how to fill up all spaces in ItemsPanel" and no luck.
So, I think the only way to do this is to set different ItemsPanelTemplate for each ItemsPanel, to either "Right" or "Left".
Please, help me.. Thank you!
So how do you create a selector for different ItemsPanelTemplate?
You just need to customize the itemContainer :
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Style.Triggers>
<DataTrigger Binding="{Binding IsAnswer}" Value="True">
<Setter Property="HorizontalAlignment" Value="Right"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ItemsControl.ItemContainerStyle>
In case you dont have style triggers, you can use binding and a bool to HorizontalAlignment converter :
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="HorizontalAlignment" Value="{Binding IsAnswer,Converter={StaticResource AlignmentConverter}}"/>
</Style>
</ItemsControl.ItemContainerStyle>
you only need 2 View's for your messages aka DataTemplate
one for MyMsg and one for Answer both inhire from the Message class or interface (your decision) lets call it Msg
so you can set your ItemsSource to List<Msg> or ObservableCollection<Msg> and you are done

Focus-dependent text change for TextBoxes in WPF

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?)

Categories