xaml / c# stackpanel with background rectangle - c#

I have a list (ListBox) of items in XAML using a StackPanel- based element template. The layout is fine, but I would now like to have a rectangle as a background for each item - creating a box around each one.
I was thinking of using a Canvas somehow, but as each item's height varies (as well as the height of the items inside the StackPanel), I'm not sure how to do it (I'm new to C#/XAML). What would be the best composition for the template in this situation?

You can just specify it in an ItemTemplate and it will do what you want, something like;
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Border BorderBrush="Red" BorderThickness="2" Background="Blue"/>
<!-- Insert the rest of your Item template stuff here -->
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>

ListBox is a type of ItemsControl, which exposes several properties to control the appearance of the items. In this case, have a look at ItemContainerStyle (in the case of ListBox, the item containers are instances of ListBoxItem). You could, for instance, set the Background property in an ItemsContainerStyle to some color.

Related

hittesting on Listitems in a Listbox

I customized a Listbox to show a Pie-Chart (each Listitem is one slice of the Pie). To do this i used an Itemtemplate which (for now) only consists of a Shape. To make those shapes form a full circle, i calculated start/endangle for each piece and used a custom ItemsPanelTemplate to stack the Items on top of each other.
When I click anywhere near the Pie, the "last" item gets selected since it is located on top of the others. This is quite obvious, but I hoped since the ItemTemplate only contains a Shape, it would inherit the hit-testing from there and not assume that all items are represented by rectangles.
Where am I supposed to include the hittesting? I would like to set IsHitTestVisible="false" to everything inside my ItemTemplate, except for the shape - but since it doesn't actually contain anything except for my shape, i am stuck right now.
Edit:
I tried surrounding my Shape with a Grid with transparent background, on which i did set IsHitTestVisible="false". This still results in selecting the last element on each click while i would've assumed that nothing would be selected. I think i might be confused about how hittesting is supposed to work?
Code:
Since i am new to WPF i might have missed something during the implementation. I added the relevant codeparts of a minimal example:
My Shape-class:
public class PiePiece : Shape
{
protected override Geometry DefiningGeometry
{
get { return GetPieGeometry() }
}
//some DependencyProperties and helper methods.
private Geometry GetPieGeometry()
{
//calculations
}
}
XAML:
<Window [...] xmlns:Runner="clr-namespace:MyNamespace">
<Window.Resources>
<!-- some custom converters -->
<!-- ListBox-Style with the custom ControlTemplate for my Listbox -->
<ItemsPanelTemplate x:Key="ItemPanel">
<Grid/>
</ItemsPanelTemplate>
</Window.Resources>
<ListBox [...] ItemsPanel="{StaticResource ItemPanel}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Background="{x:Null}" IsHitTestVisible="False">
<Runner:PiePiece IsHitTestVisible="False" [...]>
<!-- Dependency Properties are set via Multibinding here -->
</Runner:PiePiece>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Window>
I finally found the reason why the hittesting did not work as desired:
The default template for the ListBoxItem-Style surrounds the ContentPresenter with a Border with transparent background. All click-events were caught and handled by that border, instead of my ContentPresenter. Writing my own style for the ListBoxItem and setting the Background to {x:null} as suggested by Gaz fixed the problem (as did removing the border, but I added another one by now for further customizations).

Using a HierarchicalDataTemplate to create a TreeView with child nodes of different UI Controls

I am trying to create a TreeView that allows child nodes of types textBlock and comboBox. Here is a picture of what this would look like:
I believe that this is an issue that can be solved by using a HierarchicalDataTemplate because the xaml is the area of the code that I would specify what UI control I cam using. So far I have tried implementing a StackPanel with my HierarchicalDataTemplate like so:
<HierarchicalDataTemplate DataType="{x:Type data:DataModel}" ItemsSource="{Binding Children}">
<StackPanel>
<TextBlock Text="{Binding DisplayName}" />
<ComboBox ItemsSource="{Binding CommandCollection}" />
</StackPanel>
</HierarchicalDataTemplate>
But I do not achieve the correct solution with this because StackPanel is basically setting up each node so that they contain both a textBlock and a comboBox. This is a problem because each child node is either a textBlock or a comboBox, never both. How do I set up a HierarchicalDataTemplate that allows TreeView child nodes to be either textBlocks or comboBoxes? Please let me know if you would like more details on how my TreeView is implemented, or would like to see more code.
Some background references to this question can be found here, and here.
Usually it is a good idea to template different types of data with respective data templates. This can be achieved implicitly by placing the templates in the TreeView.Resources and using the DataTemplate.DataType property.
Here is an example: [Link]
The only thing that differs is that you would use a hierarchical template and bind the ItemsSource of the template respectively to a property containing child items.

How to arrange the buttons vertically in RibbonControlGroup (wpf)

I have RibbonControlGroup with a few buttons.
<r:RibbonControlGroup>
<r:RibbonToggleButton Label="button1"/>
<r:RibbonToggleButton Label="button2"/>
</r:RibbonControlGroup>
On Ribbon buttons are arranged horizontally. Like (button1|button2).
How to arrange the buttons vertically?
I know, that I'm late to party, but may be this will help someone.
Since the RibbonControlGroup is an ItemsControl, the right way to go is to replace ItemsPanel like this:
<r:RibbonControlGroup>
<r:RibbonControlGroup.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</r:RibbonControlGroup.ItemsPanel>
<!-- Group items are listed below: -->
<r:RibbonToggleButton Label="button1"/>
<r:RibbonToggleButton Label="button2"/>
</r:RibbonControlGroup>
This approach conceptually differs from #Sajeetharan's answer, because he creates a group with a single child - StackPanel, while my sample still is an equivalent of the code, posted in the question: here's a group with two children of type RibbonToggleButton.
The difference will be meaningful with data binding scenarios, when items of group be populated dynamically through data binding expression.
You can keep these controls in a container and set its Orientation property to "Vertical"
For e.g. using StackPanel as a container
will place the buttons vertically
Use StackPanel and change the orientation to Vertical ,
<r:RibbonControlGroup>
<StackPanel Orientation="Vertical">
<r:RibbonToggleButton Label="button1"/>
<r:RibbonToggleButton Label="button2"/>
</StackPanel>
</r:RibbonControlGroup>

Why does this ComboBox ignore the DataTemplate when SelectedItem is a ContentControl?

In our application we have a screen design feature which is comprised of a custom ScreenDesignPanel and a Property Grid with a ComboBox at the top which points to the selected item on the ScreenDesignPanel. This allows the user to select the UIElement via the ComboBox or via the mouse to set its properties. We achieve this by binding the ItemsSource of the ComboBox to the ScreenDesignPanel's Children collection, then binding their SelectedItems together. This works great.
However, for whatever reason, if the SelectedItem is a ContentControl or a subclass like Button the ItemTemplate specified for the ComboBox is ignored for the 'selected item area' but it is applied when displaying the item in the dropdown list. If the SelectedItem is not a ContentControl, the template is used in both cases.
This also is seemingly specific to the ComboBox. If we use any other selector control: ListBox, ListView, ItemsControl... even third-party ComboBox controls... they all work as expected, properly applying the DataTemplate. ComboBox is doing something internally which no other control is doing.
Note: Below is an over-simplified example for illustrative purposes of the issue only. It is not how we're actually using it as described above.
Also of note: In the DataTemplate for the ComboBox.ItemTemplate, we are only using properties (i.e. Foreground in the example), and are not displaying the DataContext (i.e. the actual ContentControl) itself. This is important because again, the actual control already exists on the ScreenDesignPanel and therefore can't be used for display in the ComboBox's ItemTemplate as it would have two parents which isn't allowed. In other words, it is being used purely as data here.
One last thing... we have a working solution in our app, which was to wrap the Children before binding it to the ComboBox.ItemsSource. However, I'm still curious as to why the ComboBox behaves the way it does which is SPECIFICALLY what I'm asking. (In other words, I'm not looking for other solutions to this design. We already have a working one. I'm looking for clarity on the odd behavior of the ComboBox itself.)
On to the code!
In the first example below, note how the data template is applied to everything in the dropdown, but the selected item area only uses a template if the selected item is not a ContentControl.
<ComboBox>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="I am the template" Foreground="{Binding Foreground}" />
</DataTemplate>
</ComboBox.ItemTemplate>
<!-- Four 'Data' items for example only -->
<TextBlock Text="I am a Red TextBox" Foreground="Red"/>
<ListBox Foreground="Purple">
<ListBoxItem>I am a Purple ListBox</ListBoxItem>
</ListBox>
<ContentControl Content="I am a Blue ContentControl" Foreground="Blue" />
<Button Content="I am a Button with Green text" Foreground="Green" />
</ComboBox>
This second example shows that it is completely acceptable and fully supported to use a UIElement as the content of a ContentPresenter and still use a DataTemplate (via ContentTemplate) so you can use it in a purely-data role, allowing the template itself to define the visual appearance without displaying the UIElement itself, which is used purely as data here.
<ContentPresenter>
<ContentPresenter.ContentTemplate>
<DataTemplate>
<TextBlock Text="I am the ContentTemplate" Foreground="{Binding Foreground}" />
</DataTemplate>
</ContentPresenter.ContentTemplate>
<ContentPresenter.Content>
<Button Content="I am the button" Foreground="Green" />
</ContentPresenter.Content>
</ContentPresenter>
Again, the issue is specific to a ComboBox. I want to find out why the data template isn't applied in that single case, and how to force it to be applied, if possible.
Of note, ComboBox does define SelectionBoxItemTemplate which is separate from the regular ItemTemplate but the rub is that is read-only so you can't set it. We really don't want to re-template the ComboBox as that can mess up proper theming.
Have you tried explicitly setting the DataTemplate to the ContentControl.ContentTemplate property?:
<UserControl.Resources>
<DataTemplate x:Key="DataTemplate">
<TextBlock Text="{Binding Content,
StringFormat='Displayed via template: {0}'}" />
</DataTemplate>
</UserControl.Resources>
...
<ContentControl Content="ContentControl"
ContentTemplate="{StaticResource DataTemplate}" />

Make the children of DataTemplate inherit color of parents

I've got a DataTemplate for ListViewItems with some TextBoxes and Combos within. Something like this:
<DataTemplate x:Key="ListTemplate">
<Border Margin="2, 2, 4, 2" BorderThickness="2, 0, 0, 0">
<Grid>
(...)
<StackPanel Grid.Column="0" Grid.Row="0">
<TextBox VerticalAlignment="Bottom" Name="hoursField" Margin="5">
<TextBox.Text>
<Binding Path="Hours" />
</TextBox.Text>
</TextBox>
...
Now, I want to make the TextBox to inherit the background color of his container, in order to be draw with the same background color of the StackPanel, and change the Foreground of the TextBoxes to white every time ListView is selected.
Any clue on how I can obtain this?
If you don't want to mess around with anything other than the controls you are adding, set their background colour to be transparent.
Hacky, but will work.
Assuming your questions are :
a.) I want to make the TextBox to inherit the background color of his container.
Answer: you need to set a background color of the root grid for the ListBoxItem ControlTemplate. This will be inherited by the content presenters placed inside the ListBoxItem.
b.) change the Foreground of the TextBoxes to white every time ListView is selected
Answer: in the ListBoxItem ControlTemplate change the foreground of the root grid to be white in the selected state
If your background color of the parent changes, you can also use binding to explicitly tell the text box to bind the containing control, using the ElementName within the binding.

Categories