WPF: ComboBoxItem background - wpf

I have a ComboBox based on XML file data:
<Root>
<Node Background="Yellow" Foreground="Cyan" Image="1.ico" Property="aaaa" Value="28" />
<Node Background="SlateBlue" Foreground="Black" Image="2.ico" Property="bbbb" Value="2.5" />
<Node Background="Teal" Foreground="Green" Image="3.ico" Property="cccc" Value="4.0" />
<Node Background="Yellow" Foreground="Red" Image="4.ico" Property="dddd" Value="0" /></Root>
So, in this case, I need to create a compound ComboBoxItem when each item has a suitable background.
I tried to do something like this:
<UserControl.Resources>
<DataTemplate DataType="Node">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="20"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto" MinWidth="20"/>
</Grid.ColumnDefinitions>
<Border Background="{Binding XPath=#Background}" Grid.Column="0">
<Image Source="{Binding XPath=#Image}"
Width="16"
Height="16"
Margin="3" />
</Border>
<Border Background="{Binding XPath=#Background}" Grid.Column="1">
<TextBlock Foreground="{Binding XPath=#Foreground}"
Margin="3"
Text="{Binding XPath=#Property}" />
</Border>
<Border Background="{Binding XPath=#Background}" Grid.Column="2">
<TextBlock Foreground="{Binding XPath=#Foreground}"
Margin="3"
FontWeight="Bold"
Text="{Binding XPath=#Value}" />
</Border>
</Grid>
</DataTemplate>
<XmlDataProvider x:Key="xmlNodeList"
Source="/data/Combo.xml"
XPath="/Root/Node"/>
</UserControl.Resources>
<ComboBox Name="myComboBox"
ItemsSource="{Binding Source={StaticResource xmlNodeList}}"
SelectedIndex="0" />
but it's not looks good :-(
What solution you recommend?
Thanks in advance!

One thing is that you forgot to indicate which template to use:
<DataTemplate x:Key="Node">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="20"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto" MinWidth="20"/>
</Grid.ColumnDefinitions>
<Border Background="{Binding XPath=#Background}" Grid.Column="0">
<Image Source="{Binding XPath=#Image}"
Width="16"
Height="16"
Margin="3" />
</Border>
<Border Background="{Binding XPath=#Background}" Grid.Column="1">
<TextBlock Foreground="{Binding XPath=#Foreground}"
Margin="3"
Text="{Binding XPath=#Property}" />
</Border>
<Border Background="{Binding XPath=#Background}" Grid.Column="2">
<TextBlock Foreground="{Binding XPath=#Foreground}"
Margin="3"
FontWeight="Bold"
Text="{Binding XPath=#Value}" />
</Border>
</Grid>
</DataTemplate>
And then your ComboBox:
<ComboBox Name="myComboBox"
ItemsSource="{Binding Source={StaticResource xmlNodeList}}"
ItemTemplate="{StaticResource Node}"
SelectedIndex="0" />
The "dataType" system works with typed object, I'm not sure you can make it work with XML data. This will work.
Update:
Before you ask, you should also define a Style for the items so that they cove the width of the list, otherwise your columns are going to be uneven:
<ComboBox Name="myComboBox"
ItemsSource="{Binding Source={StaticResource xmlNodeList}}"
ItemTemplate="{StaticResource Node}"
SelectedIndex="0">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="HorizontalContentAlignment"
Value="Stretch" />
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
This will stretch the individual items to cover the whole width of the list.

Related

How to center UserControl in a TabControl

My MainWindow is built with TabContol containing in each tab UserControl in xaml files. Opening specific UserControl is not a problem, but aligning it is. I was able to horizontally center content of tab but struggle to vertically do this same. I found out that the root problem is that UserControl don't take the whole free space (height) in the Tab. I tried to make main grid VerticalAlignment="Stretch" and "Center" but that didn't help. I could use margin with specific number or define row fixed hight but that will not work on every resolution and I don't want to write method in code behind but use the power of xaml. How can I force UserControl to take whole height in Tab and then vertically center it (it's important to do it for specific UserControl because others should have default position)?
ps. I'm using MetroWindow from MahApps.Metro.
MainWindow main Grid:
<Grid>
<StackPanel>
<TabControl ItemsSource="{Binding Tabs}"
SelectedIndex="0">
<TabControl.Resources>
<Style TargetType="{x:Type TabPanel}">
<Setter Property="HorizontalAlignment"
Value="Center" />
</Style>
<DataTemplate DataType="{x:Type VMod:LoginViewModel}">
<Pages:LoginView />
</DataTemplate>
<DataTemplate DataType="{x:Type VMod:AdminViewModel}">
<Pages:AdminView />
</DataTemplate>
<DataTemplate DataType="{x:Type VMod:ProductsViewModel}">
<Pages:ProductsView />
</DataTemplate>
<DataTemplate DataType="{x:Type VMod:DistributionViewModel}">
<Pages:DistributionView />
</DataTemplate>
<DataTemplate DataType="{x:Type VMod:SummaryViewModel}">
<Pages:SummaryView />
</DataTemplate>
<DataTemplate DataType="{x:Type VMod:SettingsViewModel}">
<Pages:SettingsView />
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemTemplate>
<DataTemplate DataType="{x:Type inter:ITab}">
<TextBlock>
<Run Text="{Binding TabName}" />
</TextBlock>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
</StackPanel>
</Grid>
UserControl main Grid:
<Grid Background="LightBlue"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Height="300"
Width="300"
Grid.Row="2"
BorderBrush="LightGray"
BorderThickness="1">
<StackPanel HorizontalAlignment="Center">
<iconPacks:PackIconRPGAwesome Kind="Honeycomb"
HorizontalAlignment="Center"
Width="60"
Height="60"
Margin="0, 0, 0, 0"/>
<TextBlock HorizontalAlignment="Center"
Text="DistributionTool"
FontSize="20"
FontWeight="Bold"
Margin="5" />
<Grid Width="200">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0"
Margin="5"
TextAlignment="Left"
FontSize="15"/>
<iconPacks:PackIconMaterial Grid.Column="1"
Kind="AccountTie"
Width="20"
Height="20"
VerticalAlignment="Center"/>
</Grid>
<Grid Width="200">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<PasswordBox Grid.Column="0"
Margin="5"
HorizontalContentAlignment="Left"
FontSize="15"
Style="{StaticResource Win8MetroPasswordBox}" />
<iconPacks:PackIconMaterial Grid.Column="1"
Kind="Key"
Width="20"
Height="20"
VerticalAlignment="Center" />
</Grid>
<Button Content="LOGIN"
Width="80"
metro:ControlsHelper.ContentCharacterCasing="Normal"
Margin="5"
Style="{StaticResource AccentedSquareButtonStyle}" />
</StackPanel>
</Border>
</Grid>
From what I gather, what you could try would be:
Remove the StackPanel in your MainWindow Grid. Unless you intend to have more than 1 child inside the stack panel (Other than your TabControl), it is useless.
Add VerticalAlignement="Stretch" to your TabControl. This will allow it to take up all the space it can vertically.
Then you should be pretty much set to go.
The reason why you shouldn't use a StackPanel unless you intend to stack items inside, as in
<StackPanel>
<Child1/>
<Child2/>
</StackPanel>
is that the StackPanel.Orientation property affects how things will appear inside, including the Alignement of each child.
So Orientation="Vertical" (the default), affects the VerticalAlignement of its children. Same idea with Horizontal.

Listbox last element incorrect rendering

I got trouble with the listbox. Please, check the screenshot down there. The last element is kind of "eaten" by the listbox external border (I defined appropriate MaxHeight). Can someone help me?
<DataTemplate x:Key="QCTemplate">
<Grid>
<Expander x:Name="expander" Header="{Binding}">
<Expander.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBox Name="ComponentNameTextBlock" Style="{StaticResource BorderlessTextBoxStyle}" Text="{Binding ComponentName, Mode=TwoWay}" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Margin="1">Количество цитат:</TextBlock>
<TextBlock Name="ComponentVolumeTextBlock" Grid.Column="1" Margin="1" Text="{Binding Volume}" />
</Grid>
</StackPanel>
</DataTemplate>
</Expander.HeaderTemplate>
<!-- Контекстное меню экспандера -->
<Expander.ContextMenu>
<ContextMenu>
<MenuItem Header="Оригинал 'My Clippings.txt'">
<MenuItem Header="Удалить из оригинала..."
Command="{StaticResource ResourceKey=DeleteFromMyClippingsCommand}"
CommandParameter="{Binding}" />
</MenuItem>
</ContextMenu>
</Expander.ContextMenu>
<!-- Внутреннее содержание экспандера -->
<Grid Name="ExpanderContentContainer"
Height="{Binding ElementName=ComponentChildsListBox, Path=ActualHeight}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Rectangle Grid.Column="0" Grid.Row="0"
Width="2" Height="{Binding Path=ActualHeight}"
Fill="Black"
Margin="2"
/>
<StackPanel Orientation="Vertical"
Grid.Column="1" Grid.Row="0">
<TextBox Name="ComponentCommentTextBox"
Text="{Binding Comment, Converter={StaticResource ResourceKey=QCCCommentConvrtr}, Mode=TwoWay}"
BorderThickness="0"
GotFocus="ComponentCommentTextBox_GotFocus"
Margin="1"
/>
<ListBox Name="ComponentChildsListBox"
BorderBrush="Transparent"
ItemsSource="{Binding ChildsCollection}"
ScrollViewer.CanContentScroll="False"
MaxHeight="300"
Margin="1"
Style="{StaticResource LibraryViewListBoxStyle}"
/>
</StackPanel>
</Grid>
</Expander>
</Grid>
</DataTemplate>
Screenshot

Bind Button Command in ControlTemplate to SelectedItem from Element in DataTemplate

I have done some googling and searches and find many questions on StackOverFlow that come close to helping me but all the ideas from them still give me binding expression errors in one form or another with most always mentioning it cannot find the source.
Cannot find source for binding with reference 'ElementName=filesList'.
View that calls control template:
<Expander
DockPanel.Dock="Top"
SnapsToDevicePixels="True"
Grid.Column="1" Grid.ColumnSpan="1" Grid.Row="3" Grid.RowSpan="1"
Header="Files"
IsExpanded="True"
ExpandDirection="Down"
Background="{DynamicResource DynamicFrmBG}" Foreground="{DynamicResource DynamicFrmFG}"
>
<ContentControl
SnapsToDevicePixels="True"
Template="{StaticResource filesTemplate}"
/>
</Expander>
Control Template Code Snippet (Comment in this code is another example of different things I have tried):
<ControlTemplate x:Key="filesTemplate">
<Grid
SnapsToDevicePixels="True"
>
<Grid.RowDefinitions>
<RowDefinition Height="5" />
<RowDefinition Height="Auto" />
<RowDefinition Height="1*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="5" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="5" />
</Grid.ColumnDefinitions>
<ContentControl
SnapsToDevicePixels="True"
Grid.Column="1" Grid.ColumnSpan="1" Grid.Row="2" Grid.RowSpan="1"
Margin="0,0,0,0"
Content="{Binding Files}"
ContentTemplate="{StaticResource filesListTemplate}"
/>
<StackPanel
SnapsToDevicePixels="True"
Grid.Column="1" Grid.ColumnSpan="1" Grid.Row="3" Grid.RowSpan="1"
Orientation="Horizontal"
>
<Button
SnapsToDevicePixels="True"
Foreground="{DynamicResource DynamicFrmFG}"
Margin="0,5,5,5"
Content="Download"
Command="{Binding SelectedItem.Content.DownloadCommand, ElementName=filesList}"
MinWidth="50"
>
<!--Command="{Binding SelectedItem.Content.DownloadCommand, Source={StaticResource ResourceKey=filesListTemplate}, ElementName=filesList}"-->
<Button.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="{DynamicResource DynamicFrmBGColor}" Offset="0"/>
<GradientStop Color="{DynamicResource DynamicFrmFGColor}" Offset="2"/>
</LinearGradientBrush>
</Button.Background>
</Button>
</StackPanel>
</Grid>
Code snippet for the DataTemplate (The ListView datasource is set to an ObservableCollection and the FilesViewModel contains a Download command):
<DataTemplate x:Key="filesListTemplate">
<ListView
x:Name="filesList"
SnapsToDevicePixels="True"
IsTextSearchEnabled="False"
ItemsSource="{Binding }"
HorizontalContentAlignment="Stretch"
BorderBrush="{DynamicResource DynamicFrmFG}" Foreground="{DynamicResource DynamicFrmFG}" Background="{DynamicResource DynamicFrmBG}"
ItemContainerStyle="{DynamicResource ListViewItemStyle_Gray}"
>
<ListView.View>
<GridView
AllowsColumnReorder="False"
ColumnHeaderContainerStyle="{DynamicResource SpecialityHeader}"
>
<GridViewColumn
Width="200" Header="ID">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock
SnapsToDevicePixels="True"
FontFamily="Consolas" FontSize="14"
Text="{Binding ID}"
/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn
Width="200" Header="File Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock
SnapsToDevicePixels="True"
FontFamily="Consolas" FontSize="14"
Text="{Binding Filename}"
/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn
Width="250" Header="Uploaded By">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock
SnapsToDevicePixels="True"
FontFamily="Consolas" FontSize="14"
Text="{Binding Role}"
/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn
Width="200" Header="Uploaded When">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock
SnapsToDevicePixels="True"
FontFamily="Consolas" FontSize="14"
Text="{Binding UploadedWhen}"
/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</DataTemplate>
What I am trying to do is this; Bind the button in my control template to the selected FileViewModel, from the ListView, download command. This command, however, is located up in a DataTemplate. Can someone please assist me in doing this successfully?
Edit at 1705EST: Added the View that calls the control template.

ListView fill the width of parent, screen or whatever [duplicate]

This question already has answers here:
ListViewItem won't stretch to the width of a ListView
(2 answers)
Closed 7 years ago.
I am trying to display some data from an Observable Collection to a ListView.
Binding is working fine. My only problem I cannot fix is the layout of the ListView.I use a Grid with 2 rows to split my View. The ListView is one the second row. I only try to use * for setting Columns and Rows as suggested in most sources. The code for the ListView is this.
<Grid Grid.Row="1" Margin="10,0,10,0" HorizontalAlignment="Stretch">
<ListView ItemsSource="{Binding Collection}" HorizontalAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Center" Text="{Binding Period}" Foreground="{StaticResource ColorBrush}" FontFamily="{StaticResource Family}" FontSize="20"/>
<TextBlock Grid.Column="1" HorizontalAlignment="Center" Text="{Binding Currency}" Foreground="{StaticResource ColorBrush}" FontFamily="{StaticResource Family}" FontSize="20"/>
<TextBlock Grid.Column="2" HorizontalAlignment="Center" Text="{Binding Date}" Foreground="{StaticResource ColorBrush}" FontSize="20" FontFamily="{StaticResource Family}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
When I use HorizontalAlignment="Stretch" for the Grid that contains the ListView and the ListView itself the data is displayed on the left side without getting the whole width of parent View.
When I explicitly set Width to some value (i.e.380) it displays OK.
<Grid Grid.Row="1" Margin="10,0,10,0">
<ListView ItemsSource="{Binding Collection}" Width="380">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Width="380">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Center" Text="{Binding Period}" Foreground="{StaticResource ColorBrush}" FontFamily="{StaticResource Family}" FontSize="20"/>
<TextBlock Grid.Column="1" HorizontalAlignment="Center" Text="{Binding ValueInCurrency}" Foreground="{StaticResource ColorBrush}" FontFamily="{StaticResource Family}" FontSize="20"/>
<TextBlock Grid.Column="2" HorizontalAlignment="Center" Text="{Binding Date}" Foreground="{StaticResource ColorBrush}" FontSize="20" FontFamily="{StaticResource Family}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
But I want to know a better way to not use implicit values, but *.
Try this. Add the following jus after </ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>

TextBlock TextWrapping not wrapping #2

OK... so this solution doesn't help
XAML is here
<ListBox ItemsSource="{Binding Path=ContentItems}" Background="White" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="2" Height="Auto" Width="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<Label VerticalAlignment="Center" Margin="0,0,0,5">Start</Label><svl:TimeEditor Value="{Binding Path=FormatedStart}" Width="87" HorizontalAlignment="Left" Margin="2,8" Name="dtpStart" FontSize="12" Height="25" VerticalAlignment="Center" />
<Label VerticalAlignment="Center" Margin="0,0,0,5">End</Label><svl:TimeEditor Value="{Binding Path=FormatedEnd}" Width="87" HorizontalAlignment="Left" Margin="2,8" Name="dtpEnd" FontSize="12" Height="25" VerticalAlignment="Center" />
</StackPanel>
<TextBlock Grid.Row="1" TextWrapping="Wrap" Name="tbText" Text="{Binding Path=Data}"></TextBlock>
</Grid>
<Grid Grid.Column="1" Visibility="Collapsed">
</Grid>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The following will helps for text wrapping:
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled">
Well your TextBlock does not need to wrap since your specifying Width as Auto for it's ColumnDefinition which allows it to take all the Width it needs to fit Content even at the cost of overflowing. You either need to set the Column's Width to "*" to allow the TextWrapping to kick in when requested width exceeds allowable or manually force a MaxWidth on it using a Binding like
<TextBlock Name="tbText" Grid.Row="1" MaxWidth="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=ActualWidth}" Text="{Binding Path=Data}" TextWrapping="Wrap" />

Resources