I'm using attached behavior to add sorting to GridView columns from here: http://www.thomaslevesque.com/2009/08/04/wpf-automatically-sort-a-gridview-continued/
It is working fine, if I don't use following code:
<ListView.Style>
<Style TargetType="ListView">
<Style.Triggers>
<Trigger Property="HasItems" Value="False">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListView">
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ListView.Style>
Problem appears, using this sequence of steps:
1) fill list with items, click on header to sort it, sorting glyph appears
2) clear list
3) fill list again, sorting glyph is not visible
I subscribed to SizeChanged event in attached behavior, to catch the moment, when list goes from empty to full, to redraw sorting glyph, but GetAdornerLayer(columnHeader) returns null, I guess it is not rendered yet and does not have adorner layer yet.
Question is, how to catch right moment to redraw missing glyph (or to get adorner layer, when it exists)?
I've sorted it out, problem was, that GridViewSort had property SortedColumnHeaderProperty which was holding reference to sorted column header.
So when list would be cleared and would be filled again, column headers were recreated and that reference was not used in rendering anymore.
Related
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.
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.
How do you set the Design Time Width and Height of a custom control?
I have created a custom ItemsControl, i.e. (contents of generic.xaml)
<Style TargetType="{x:Type MyItemsControl}" >
<Setter Property="Height" Value="24" />
<Setter Property="Width" Value="160" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyItemsControl}" >
<Grid>
...
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
...
</Style>
And it works all nicely and all, however if I drag the control from the ToolBox onto my window the default size of my control is: Height = 100 and Width = 200. How do I set the design time size so that when I drag the control from the Toolbox to window the default size is 24 and 160 respectively?
May b it helps u..........
for that firstly u have to make ur own controls by inheriting it with
original controls and set Hieght,width and whatever you want in your
custom control .........after this when u drag ur own made control
form toolbox to ur form it will set by ur way whatever u wanted.......
This is a setting within Visual Studio itself, and there doesn't seem to be a way to change it, nor is Microsoft planning on changing it.
Source: A user reported this issue to Microsoft online and a Microsoft employee responded and marked the issue as "Won't Fix".
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
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?)