wpf combobox padding - wpf

This is a simple question
How do you remove the space between the content of a combobox and the border of it. E.g. If the selection of a combobox is "Selection 1" then the "S" is drawn at the very top left of the ComboBox control with no whitespace spacing between it and top left portion of the control.
I did this
<ComboBox Padding="0"/>
Even this:
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="Padding" Value="0"/>
</Style>
</ComboBox.ItemContainerStyle>
The specified ComboBox above is within a ListView GridViewColumn. Maybe that's messing with something.
This doesn't remove the padding. Any ideas?

You can't. At least, not with the default template. You'd have to write your own. The default template includes this:
<DockPanel Margin="2">
<TextBox .../>
</DockPanel>
That'll be a hard-coded margin. About the best you could do with the default template is use a negative padding to offset the hard-coded margin:
<ComboBox Padding="-2">
<ComboBoxItem >Selected</ComboBoxItem>
</ComboBox>

In Expression Blend this is trivial:
Right-click the ComboBox and select Edit Control Parts (Template) - Edit A Copy.
Remove the Margin="2" from the beginning of the template.

Related

Binding to Template's parent's parent's child's property

I have an Expander style which applied template on both Header and Content
I wish to have one of the TextBlock inside content's template to match the Header's TextBlock's Foreground color
<Style TargetType="Expander">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Foreground="Blue"/> <!--Header TextBlock-->
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<ItemsControl>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock/> <!--Match Header TextBlock's Foreground-->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
I have tried ElemenName binding but it seems like the name scope is different since I am 2 template level deep.
I thought about TemplateBinding but I only want one of the column in the content to match the color of header instead of the whole expander.
I could apply the same trigger for the Header TextBlock on the Content TextBlock too but I am trying to see if there is a way to avoid duplicating the code.
ElementName can't work across templates; with a template, you could have multiple elements with the same name.
Anything with different template instances reaching out to grope each other via the visual tree is going to be fraught with nameless horrors, whatever you do.
Instead, I would suggest that they both get their brushes from the same source. This is much more in line with how WPF is happy doing things.
If the color won't change, use an appropriately-named Brush resource for both.
If it will change, bind both to a viewmodel Brush property (kinda squicky, but not the end of the world), or use triggers driven by some other viewmodel property which represents the state being indicated by the color. The triggers would reference any number of appropriately-named Brush resources: ErrorBrush, HappyBrush, SadBrush, etc. By "name" I mean x:Key of course:
<SolidColorBrush x:Key="HappyBrush">GreenYellow</SolidColorBrush>
...etc.

Why does my MenuItem have an Icon when I have overridden the DataTemplate?

I have successfully implement a WPF menu where the top-level items are drawn as large buttons and the lower level items are drawn as standard menu items (see my previous questions here and here).
In my original attempt at this my lower-level item template (SubItemTemplate in the example below) contained an image and a textblock. The result was something that looked like a normal menu item with an empty Icon area and the image next to the text in the text part of the menu item. I was not expecting to see the icon area in the visual display since I thought that the entire visual display would be determined by the contents of my template. The top-level template (TopLevelItemTemplate) does not have any empty icon area visible.
When I removed my image from teh lower-level template and replaced it with a style-setter for the Icon property, I got the display that I wanted.
I do not understand how and why the Icon property exists on my lower-level item DataTemplate.
Here's my code. The property HasParent is used to distinguish menu items that are not top-level (that is, the ones that are drawn with the SubItemTemplate). The section I don't understand is the DataTrigger.
Why is there an Icon property available inside that trigger?
<UserControl.Resources>
<Image x:Key="MenuIconResource16" Height="16" Width="16" Source="{Binding Icon32}" x:Shared="False" />
<HierarchicalDataTemplate x:Key="TopLevelItemTemplate" ItemsSource="{Binding Children}">
<StackPanel VerticalAlignment="Bottom" Orientation="Vertical">
<Image Width="32" Height="32" VerticalAlignment="Center" Source="{Binding Icon32}" ToolTip="{Binding UserHint}" />
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="SubItemTemplate" ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</UserControl.Resources>
<WrapPanel Height="Auto">
<Menu ItemsSource="{Binding DataContext.EventMenu.TopLevel, ElementName=UserControl}" ItemTemplateSelector="{StaticResource MenuItemTemplateSelector}">
<Menu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding Command}" />
<Setter Property="CommandParameter" Value="{Binding EventType}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding HasParent}" Value="true">
<Setter Property="Icon" Value="{StaticResource MenuIconResource16}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Menu.ItemContainerStyle>
</Menu>
</WrapPanel>
I thought that the entire visual display would be determined by the contents of my template.
#dkozl noted the difference between DataTemplate and Template -- that is the important distinction. A data template is a XAML fragment that the owning control uses as part of the overall control, which may or may not include other (customizable or hard-coded) visual elements, and/or other data templates. The control template is where this visual structure of the control is defined. If you set/override a control template, then your expectation of not seeing any other visual content, will hold true.
The top-level template (TopLevelItemTemplate) does not have any empty icon area visible.
The other thing to note here is that the default style for Menu defines multiple control templates for its MenuItems. These templates are applied depending on the role "TopLevelHeader", "TopLevelItem", "SubmenuHeader", and "SubmenuItem". So you will see different behavior for these different menu items. Take a look at the default styles/templates, which should be illuminating (although they are kind of complex).
Why is there an Icon property available inside that trigger?
A style trigger has the capability of modifying any dependency property of the control it is applied to. Since the style trigger in question is being applied to the MenuItem control, it can modify the Icon dependency property, which is owned by that control.

WPF how to make a listbox/listview unfocusable

I've been trying for a while to display some data in a listbox/listview that would be unfocusable (I mean not only the list, but also the items in it).
I tried with both types of list (listbox and listview), and I used their ItemTemplate and ItemContainerStyle. Everywhere I could, I set the Focusable property to false.
I don't see any other way than disabling the list, but then I have to change all its style, to make it appear not disabled.
Have I missed something? Is there a read-only type of list that I don't know about?
Thank you for your ideas :)
The problem you're probably seeing is that each individual item in the list is focusable. However, you can override that... Try adding this to your listbox:
<ListBox.ItemContainerStyle>
<Style TargetType="Control">
<Setter Property="Focusable" Value="False" />
</Style>
</ListBox.ItemContainerStyle>
Note however that this makes the items unselectable (by keyboard or by mouse). You can set the selected item programmatically, but it doesn't appear to be highlighted automatically any more - so really, this behaves almost the same as an ItemsControl.
Use an ItemsControl with TextBlocks instead of a ListBox
<ItemsControl ItemsSource="{Binding MyListBoxItemsSource}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding MyDisplayName}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

How do I apply a DataTemplate in a Dynamic Grid?

I have a Grid. The grid's columns are auto-generated at run-time based on the user's selection.
I need the cells in the grid to be red if the content is a negative number.
I have created a DataTemplateSelector. The DataTemplateSelector get's correctly called and returns my template if the cell is negative.
Since my columns are auto-generated, I cannot simply put the correct field in the binding in my template.
<DataTemplate x:Key="MontantNegatifTemplate">
<TextBlock Foreground="Red" Text="{Binding}" />
</DataTemplate>
If I do a Template like this the text is the name of the object the grid is bound on.
If I do something like:
<DataTemplate x:Key="MontantNegatifTemplate">
<TextBlock Foreground="Red" />
</DataTemplate>
The cell is empty since the Textblock seems to overwrite the standard auto-generated cell.
Is there a way to make this work? Should I use another approach?
I finally found the awnser to my question.
I needed to use a StyleSelector rather than a DataTemplateSelector.
In the same way I needed to define a Style instead of a DataTemplate in my Grid resources.
<style:NegativeStyleSelector x:Key="NegativeStyleSelector">
<style:NegativeStyleSelector.NegativeStyle>
<Style TargetType="GridViewCell">
<Setter Property="Foreground" Value="Red"/>
</Style>
</style:NegativeStyleSelector.NegativeStyle>
</style:NegativeStyleSelector>

Puzzle - Dynamically change data template control from another data template

I have a DataTemplate that contains an Expander with a border in the header. I want the header border to have round corners when collapsed and straight bottom corners when expanded. What would best practice be for achieving this (bonus points for code samples as I am new to XAML)?
This is the template that holds the expander:
<DataTemplate x:Key="A">
<StackPanel>
<Expander Name="ProjectExpander" Header="{Binding .}" HeaderTemplate="{StaticResource B}" >
<StackPanel>
<Border CornerRadius="0,0,2,2">
This is the expander datatemplate:
<DataTemplate x:Key="B">
<Border x:Name="ProjectExpanderHeader"
CornerRadius="{Binding local:ItemUserControl.ProjectHeaderBorderRadius, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}}}"
Background="{StaticResource ItemGradient}"
HorizontalAlignment="{Binding HorizontalAlignment,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}},
Mode=OneWayToSource}">
<local:ItemContentsUserControl Height="30"/>
</Border>
</DataTemplate>
Bind the CornerRadius property to the Expander.IsExpanded property and attach an IValueConverter that returns rounded corners when false and straight bottom corners when true. It's not the most elegant, but it will get the job done.
The other way to do this, if using MVVM, would be to expose a boolean property and bind it to the Expander.IsExpanded property. Then expose another property for the CornerRadius, which checks the boolean property and returns the appropriate values. This is definitely the "best practice" way to go about this.
Another way to do this is by editing the control template. The argument can be made that this is the best practice, though I'm not sure I'm ready to commit to that.
It's straightforward to do this if you have Expression Blend. An advantage of editing the control template is that it separates the behavior of the Expander from your data template, so that you can reuse it across different types of data. A disadvantage is that you end up embedding the properties of the header's Border in the control template, so you can't really change them for any individual instance of the control. (Other disadvantages: you have to have Expression Blend, and it produces a big bolus of XAML that you have to put in your resource dictionary.)
In Expression Blend, create an empty page and put an Expander on it. Right-click on the Expander and pick "Edit Template/Edit a Copy...". Give it a name like "ExpanderRoundedCorners".
This will add about 200 lines of XAML to Page.Resources, but most of this is used to create the graphics on the expand button. Switch to XAML view and search for the ToggleButton named "HeaderSite". This is the expand button. Note that its Content property is set to {TemplateBinding Header}. We'll want to fix that.
Delete the Content property, and add a child element to the ToggleButton like this:
<ToggleButton.Content>
<Border x:Name="HeaderBorder" BorderBrush="Red" BorderThickness="2">
<ContentPresenter Content="{TemplateBinding Header}"/>
</Border>
</ToggleButton.Content>
Now find the trigger that makes ExpandSite visible when the ToggleButton is pressed. Add this setter to it:
<Setter TargetName="HeaderBorder" Property="CornerRadius" Value="4"/>
That's it. Now every time you create an Expander with the ExpanderRoundedCorners style, the header content will be enclosed in a Border whose corners are rounded when the Expander is expanded.
You'll probably want to jigger around with this a little more when you've got it working. At the least, you'll want to remove the Border from the header template in your style, since it's now part of the control template.

Resources