How to set StyleSheets for ComboBoxItems in XAML - xaml

<ComboBox
Foreground="Black"
BorderBrush="Black"
HorizontalAlignment="Left" Margin="108,280,0,0" VerticalAlignment="Top" Width="200" Style="{StaticResource ComboBoxStyl}"><ComboBoxItem Content="One" IsSelected="True" Style="{StaticResource ComboBoxItemStyle1}"/>
<ComboBoxItem Content="Two" Style="{StaticResource ComboBoxItemStyle1}"/>
<ComboBoxItem Content="Three" Style="{StaticResource ComboBoxItemStyle1}"/>
<ComboBoxItem Content="Four" Style="{StaticResource ComboBoxItemStyle1}"/>
<ComboBoxItem Content="Five" Style="{StaticResource ComboBoxItemStyle1}"/>
</ComboBox>
Here I have referred to Style sheet for Every ComboBoxItem. I want to refer to stylesheets only once(with respect to ComboBoxItem).So that styles will be applied automatically when a dynamic data item is added to it.

You'll want to use something like this:
<ComboBox x:Name="combobox1" ItemsSource="{Binding ItemList}">
<ComboBox.ItemTemplate>
<DataTemplate>
<!-- define data template and/or style, example: -->
<TextBlock Style="{StaticResource TextBlockItemStyle}" Text="{Binding ItemText}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Also, since you want to add/remove items dynamically, it'd be better to bind the items source to a list or collection which you can easily edit in c#. You might want to create a class like:
public class ComboBoxListItem
{
public string ItemText {get; set;}
//any other useful property
}
Then in your page create a List<ComboBoxListItem> ItemList and in the page's constructor, initialize the list with whatever data you want to. Then in your XAML DataTemplate, simply insert "{Binding ItemText}" wherever you want the text to appear (like I've done in the text block).

<ComboBox
SelectedIndex="0"
Foreground="Black"
ItemContainerStyle="{StaticResource ComboBoxItemStyle1}"
BorderBrush="Black"
HorizontalAlignment="Left" Margin="108,280,0,0" VerticalAlignment="Top" Width="200" Style="{StaticResource ComboBoxStyl}">
<ComboBoxItem Content="One" />
<ComboBoxItem Content="Two" />
<ComboBoxItem Content="Three" />
<ComboBoxItem Content="Four" />
<ComboBoxItem Content="Five" />
</ComboBox>
Using the "ItemContainerStyle" refering to the sylesheet we created for ComboBoxItems we can easily change the Styles of ComboBoxItems whether it is declared statically or dynamically.

Related

UWP Bind to ObservableCollection declaratively

I have a simple UWP page; there is a public ObservableCollection in the page code-behind:
public ObservableCollection<Book> MyObservableColl{ get; } = new ObservableCollection<Book>();
(note the collection consists of a single item)
I would like to bind to the collection; here is what I tried:
<StackPanel x:Name="stackPanel"
Grid.Row="2"
Margin="50"
DataContext="{x:Bind MyObservableColl, Mode=OneWay}">
<TextBox x:Name="txtTitle"
TextWrapping="Wrap"
Text="{x:Bind Title, Mode=OneWay}" />
</StackPanel>
The visual studio designer complains "the property Title was not found".
I appreciate any help to bind my text boxes to the Observable Collection.
the property Title was not found
txtTitle TextBox can't access Book item where in the MyObservableColl collection directly, you need place txtTitle under items control's ItemTemplate.
For example
<ListView ItemsSource="{x:Bind MyObservableColl, Mode=OneWay}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Book">
<StackPanel>
<TextBox Text="{x:Bind Title}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
For more info please refer to listview document.
Update
For single item please refer to this xaml
<StackPanel
x:Name="stackPanel"
Grid.Row="2"
Margin="50"
DataContext="{x:Bind MyObservableColl[0], Mode=OneWay}">
<TextBox Text="{Binding Title}"/>
</StackPanel>

Controls show through ComboBox dropdown on Windows Phone 8.1

I'm just getting started working with XAML using VS2013 and Windows Phone SDK 8. I've got a HubSection with a few ComboBox controls in a Grid. When you open a ComboBox dropdown, it shows controls in the dropdown that should be behind it.
Any suggestions on how to fix this? Even if I can open the dropdown separately (I have another ComboBox with 13 items that will show full-screen automatically if it is opened).
Thanks for any help.
screenshot http://i112.photobucket.com/albums/n182/capellanx/wp_ss_20140704_0002_zps877f0a6a.jpg
<HubSection x:Uid="CharacterInfo" Header="Character Information" DataContext="{Binding Groups}" HeaderTemplate="{ThemeResource HubSectionHeaderTemplate}">
<DataTemplate>
<Grid>
<TextBlock HorizontalAlignment="Left" Margin="10,0,0,0" TextWrapping="Wrap" Text="Character Name:" VerticalAlignment="Top" FontSize="18"/>
<TextBox HorizontalAlignment="Left" Margin="10,20,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="321" Height="10"/>
<TextBlock HorizontalAlignment="Left" Margin="10,60,0,0" TextWrapping="Wrap" Text="Breed:" VerticalAlignment="Top" FontSize="18"/>
<ComboBox HorizontalAlignment="Left" Margin="10,80,0,0" VerticalAlignment="Top" Width="321">
<ComboBoxItem Tag="HOMID" IsSelected="True">Homid</ComboBoxItem>
<ComboBoxItem Tag="METIS">Metis</ComboBoxItem>
<ComboBoxItem Tag="LUPUS">Lupus</ComboBoxItem>
</ComboBox>
<TextBlock HorizontalAlignment="Left" Margin="10,150,0,0" TextWrapping="Wrap" Text="Auspice:" VerticalAlignment="Top" FontSize="18"/>
<ComboBox HorizontalAlignment="Left" Margin="10,170,0,0" VerticalAlignment="Top" Width="321">
<ComboBoxItem Tag="RAGABASH" IsSelected="True">Ragabash (New Moon)</ComboBoxItem>
<ComboBoxItem Tag="THEURGE">Theurge (Crescent Moon)</ComboBoxItem>
<ComboBoxItem Tag="PHILODOX">Philodox (Half Moon)</ComboBoxItem>
<ComboBoxItem Tag="GALLIARD">Galliard (Gibbous Moon)</ComboBoxItem>
<ComboBoxItem Tag="AHROUN">Ahroun (Full Moon)</ComboBoxItem>
</ComboBox>
<TextBlock HorizontalAlignment="Left" Margin="10,240,0,0" TextWrapping="Wrap" Text="Tribe:" VerticalAlignment="Top" FontSize="18"/>
<ComboBox HorizontalAlignment="Left" Margin="10,260,0,0" VerticalAlignment="Top" Width="321">
<ComboBoxItem Tag="BLACKFURIES" IsSelected="True">Black Furies</ComboBoxItem>
<ComboBoxItem Tag="BONEGNAWERS">Bone Gnawers</ComboBoxItem>
<ComboBoxItem Tag="CHILDRENOFGAIA">Children of Gaia</ComboBoxItem>
<ComboBoxItem Tag="FIANNA">Fianna</ComboBoxItem>
<ComboBoxItem Tag="GETOFFENRIS">Get of Fenris</ComboBoxItem>
<ComboBoxItem Tag="GLASSWALKERS">Glass Walkers</ComboBoxItem>
<ComboBoxItem Tag="REDTALONS">Red Talons</ComboBoxItem>
<ComboBoxItem Tag="SHADOWLORDS">Shadow Lords</ComboBoxItem>
<ComboBoxItem Tag="SILENTSTRIDERS">Silent Striders</ComboBoxItem>
<ComboBoxItem Tag="SILVERFANGS">Silver Fangs</ComboBoxItem>
<ComboBoxItem Tag="STARGAZERS">Stargazers</ComboBoxItem>
<ComboBoxItem Tag="UKTENA">Uktena</ComboBoxItem>
<ComboBoxItem Tag="WENDIGO">Wendigo</ComboBoxItem>
</ComboBox>
</Grid>
</DataTemplate>
</HubSection>
The problem is that the Controls are inside a Grid, this causes the Controls to overlay each other unless you use different rows/columns. But the easiest way to change this is to just use a StackPanel, which causes the elements to automatically stack horizontally or vertically. This means you don't need to use manual margins and alignments to get a nice layout.
Here is the modified XAML, I also added a ScrollViewer around to incase the ComboBox expands out of the view:
<HubSection x:Uid="CharacterInfo" Header="Character Information" DataContext="{Binding Groups}">
<DataTemplate>
<ScrollViewer>
<StackPanel>
<TextBlock TextWrapping="Wrap" Text="Character Name:" FontSize="18"/>
<TextBox TextWrapping="Wrap" Text="TextBox"/>
<TextBlock TextWrapping="Wrap" Text="Breed:" FontSize="18"/>
<ComboBox>
<ComboBoxItem Tag="HOMID" IsSelected="True">Homid</ComboBoxItem>
<ComboBoxItem Tag="METIS">Metis</ComboBoxItem>
<ComboBoxItem Tag="LUPUS">Lupus</ComboBoxItem>
</ComboBox>
<TextBlock TextWrapping="Wrap" Text="Auspice:" FontSize="18"/>
<ComboBox>
<ComboBoxItem Tag="RAGABASH" IsSelected="True">Ragabash (New Moon)</ComboBoxItem>
<ComboBoxItem Tag="THEURGE">Theurge (Crescent Moon)</ComboBoxItem>
<ComboBoxItem Tag="PHILODOX">Philodox (Half Moon)</ComboBoxItem>
<ComboBoxItem Tag="GALLIARD">Galliard (Gibbous Moon)</ComboBoxItem>
<ComboBoxItem Tag="AHROUN">Ahroun (Full Moon)</ComboBoxItem>
</ComboBox>
<TextBlock TextWrapping="Wrap" Text="Tribe:" FontSize="18"/>
<ComboBox>
<ComboBoxItem Tag="BLACKFURIES" IsSelected="True">Black Furies</ComboBoxItem>
<ComboBoxItem Tag="BONEGNAWERS">Bone Gnawers</ComboBoxItem>
<ComboBoxItem Tag="CHILDRENOFGAIA">Children of Gaia</ComboBoxItem>
<ComboBoxItem Tag="FIANNA">Fianna</ComboBoxItem>
<ComboBoxItem Tag="GETOFFENRIS">Get of Fenris</ComboBoxItem>
<ComboBoxItem Tag="GLASSWALKERS">Glass Walkers</ComboBoxItem>
<ComboBoxItem Tag="REDTALONS">Red Talons</ComboBoxItem>
<ComboBoxItem Tag="SHADOWLORDS">Shadow Lords</ComboBoxItem>
<ComboBoxItem Tag="SILENTSTRIDERS">Silent Striders</ComboBoxItem>
<ComboBoxItem Tag="SILVERFANGS">Silver Fangs</ComboBoxItem>
<ComboBoxItem Tag="STARGAZERS">Stargazers</ComboBoxItem>
<ComboBoxItem Tag="UKTENA">Uktena</ComboBoxItem>
<ComboBoxItem Tag="WENDIGO">Wendigo</ComboBoxItem>
</ComboBox>
</StackPanel>
</ScrollViewer>
</DataTemplate>
</HubSection>

Binding from multi object in to one value in XAML

I have a ListView which have a DataTemplate like this:
<DataTemplate x:Key="FilterDataTemplate">
<StackPanel Orientation="Horizontal" Background="White" Height="50" HorizontalAlignment="Left">
<ComboBox x:Name="TermsItemComboBox" Width="160"
ItemsSource="{Binding ItemList}" Tag="{Binding}"
DisplayMemberPath="Key" SelectionChanged="AddTermsItem_SelectionChanged"
Background="#FFD1D1D1" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" />
<TextBox x:Name="TermsInputTxt1" Text="{Binding FilterText, Mode=TwoWay}"
BorderBrush="#FF727272" Background="#FFD1D1D1" HorizontalAlignment="Left"
Width="200" FontSize="16" VerticalAlignment="Center"
Visibility="{Binding IsTxtForm, Converter={StaticResource BooleanToVisibilityConverter}}"
Height="45"/>
<TextBox x:Name="TermsInputTxt2" Text="{Binding FilterText, Mode=TwoWay}"
BorderBrush="#FF727272" Background="#FFD1D1D1" HorizontalAlignment="Left"
Width="200" FontSize="16" VerticalAlignment="Center"
Visibility="{Binding IsTxtForm, Converter={StaticResource BooleanToVisibilityConverter}}"
Height="45"/>
<Button x:Name="TrashBtn" HorizontalAlignment="Left" VerticalAlignment="Stretch"
BorderBrush="#FF575757" Foreground="#FF494949" BorderThickness="2" Tapped="TrashBtn_Tapped"
Style="{StaticResource DiscardAppBarButtonStyle}" Height="45" Width="55"
RenderTransformOrigin="0.5,0.5">
<Button.RenderTransform>
<CompositeTransform ScaleX="-1" />
</Button.RenderTransform>
</Button>
</StackPanel>
It's have a combobox and two TextBox. At default, the combobox don's show anything, just a blank item, I want when user type some text to the TermsInputTxt1 or TermsInputTxt2, the combobox will select the first item.
I try to bind the selectedindex of combobox with the lenght of those two textbox with a converter but look like XAML doesn't support multi binding like that.
Any suggest? Thank you!
So, this is a bit of a difficult situation. You have a couple of ways of going about it:
Bind the TermsInputTxt1 and TermsInputTxt2 to the ViewModel, with the Setter on the ViewModel controlling an ObservableCollection, adding and removing items as they get set in the property.
Create a Model for each entry with a Value field (string) and bind the Terms... to accessors in the ViewModel. Then, the ComboBox items will automatically change.
I suggest doing the first one. You'll have to have a SelectedItem/SelectedIndex property in the ViewModel which the ComboBox will bind to. You may also want to change the method by which the binding on the TextBoxs are updated, either so that they are updated immediately (lots of processing) or after it loses focus (less processing, but won't update the UI immediately).

Are there are shorter ways to write this XAML?

Are there perhaps any shorter ways of writing this, like using the property ItemTemplate in the ComboBox declaration? I hate looking at my code and seeing this big blob of code.
<ComboBox Grid.Row="0" Grid.Column="1" Margin="3" ItemsSource="{Binding Accounts}" SelectedItem="{Binding SelectedAccount}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<ComboBoxItem Content="{Binding Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
If you only want to display the Name of the items you can use the DisplayMemberPath-Property of the ComboBox. Then you define the ComboBox as:
<ComboBox Grid.Row="0"
Grid.Column="1"
Margin="3"
ItemsSource="{Binding Accounts}"
SelectedItem="{Binding SelectedAccount}"
DisplayMemberPath="Name"/>

Using different databinding sources within ListBox and ContextMenus

Here is the XAML:
<ListBox ItemsSource="{Binding Documents}" BorderBrush="{x:Null}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Title}" FontSize="12" FontWeight="Bold" />
<TextBlock Text="{Binding ID}" FontSize="10" FontStyle="Italic" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ContextMenu>
<ContextMenu ItemsSource="{Binding CategoryList}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Command="{Binding AddDocumentToCategoryContextMenuCommand}" Header="{Binding Category.Name}" />
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
Ok so the ListBox's ItemSource is bound to the Documents collection in the VM and properly renders the Titles and IDs
The Context Menu's ItemSource is bound to the CategoryList collection in the VM and properly renders the list of categories.
The problem I have is with the Command Binding:
Command="{Binding AddDocumentToCategoryContextMenuCommand}"
Since the ItemSource for the ContextMenu is already set, it tries to get the AddDocumentToCategoryContextMenuCommand from CategoryList. Obviously the command is not there, it is a member of the VM.
I do not want any references to the VMs or Models in the XAML. Everything is constructed using Unity and VM-View is associated in App.xaml:
<Application.Resources>
<DataTemplate DataType="{x:Type vms:FeedViewModel}">
<views:FeedView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vms:DocumentsViewModel}">
<views:DocumentsView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vms:ManagementViewModel}">
<views:ManagementView/>
</DataTemplate>
<DataTemplate DataType="{x:Type dev:DevelopmentViewModel}">
<dev:DevelopmentView />
</DataTemplate>
</Application.Resources>
How can I databind to a member of the VM from within the ContextItem.
Thanks.
UPDATED edit #1 starts Here
Here is the updated xaml (but still not working but some insight gained):
<ListBox ItemsSource="{Binding Documents}" x:Name="Results" BorderBrush="{x:Null}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Title}" FontSize="12" FontWeight="Bold" />
<TextBlock Text="{Binding ID}" FontSize="10" FontStyle="Italic" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ContextMenu>
<ContextMenu ItemsSource="{Binding CategoryList}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Command="{Binding ElementName=Results, Path=DataContext.AddDocumentToCategoryContextMenuCommand}" Header="{Binding Category.Name}" />
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
I have this example working for a simple example that does not use a ContextMenu. It appears that the ContextMenu (even though attached to the ListBox) is not part of the user control visual tree. The binding always comes back null / not found. I think the ContextMenu, because it is a floating "window" is constructed in its own tree and therefore cannot find the ListBox call "Results" in order to access the ListBox's DataContext.
Any thoughts on this? Any recommendations on how deal with?
Edit #2 Starts Here
In case you are are wondering, figured out the answer to the binding question:
This binding works:
Command="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.DataContext.AddDocumentToCategoryContextMenuCommand}
Hope this helps others with the same question.
One last update for completeness.
In order for the command to know which context menu item was clicked on, I had to change the xaml slightly (silly oversight):
<ListBox.ContextMenu>
<ContextMenu x:Name="Context" ItemsSource="{Binding CategoryList}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Command="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.DataContext.AddDocumentToCategoryContextMenuCommand}"
CommandParameter="{Binding Category.ID}"
Header="{Binding Category.Name}" />
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</ListBox.ContextMenu>
Again, hope this helps others.
Use the ElementName property of the binding to specify that. You'd end up with something like this:
Command="{Binding ElementName=ViewModelObject
Path=AddDocumentToCategoryContextMenuCommand}"