I am just wondering if there is a wpf combobox control that can contain multiple columns?
And if not, what XAML I need to use to achieve this?
I am just looking for a basic two column combobox if is possible,
Thanks
Please Refer these links for Multiple Column Combobox which is implemented by editing combox and comboboxitem Default template/style.
1)Link1
2)Link2
Xaml code : Please take a look at commented Trigger IsHighlighted in ComboboxItem style
<Grid>
<ComboBox Height="30" Margin="5" ItemsSource="{Binding}" HorizontalContentAlignment="Stretch">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Margin="2" Text="{Binding Name}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid x:Name="gd" TextElement.Foreground="Black">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Margin="5" Grid.Column="0" Text="{Binding Name}"/>
<TextBlock Margin="5" Grid.Column="1" Text="{Binding State}"/>
<TextBlock Margin="5" Grid.Column="2" Text="{Binding Population}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ComboBoxItem.IsSelected" Value="True">
<Setter TargetName="gd" Property="Background" Value="Gray"></Setter>
<Setter TargetName="gd" Property="TextElement.Foreground" Value="White"></Setter>
</Trigger>
<Trigger Property="ComboBoxItem.IsMouseOver" Value="True">
<Setter TargetName="gd" Property="Background" Value="Blue"></Setter>
<Setter TargetName="gd" Property="TextElement.Foreground" Value="White"></Setter>
</Trigger>
<!--IsHighlighted and IsMouseOver is showing same effect but IsHighlighted is used for showing logical focus( for understanding check using tab key)-->
<!--<Trigger Property="ComboBoxItem.IsHighlighted" Value="True">
<Setter TargetName="gd" Property="Background" Value="Yellow"></Setter>
<Setter TargetName="gd" Property="TextElement.Foreground" Value="Black"></Setter>
</Trigger>-->
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</Grid>
c# code
public partial class MainWindow : Window
{
private ObservableCollection<City> cities = new ObservableCollection<City>();
public MainWindow()
{
InitializeComponent();
cities.Add(new City() { Name = "Mumbai", State = "Maharashtra", Population = 3000000 });
cities.Add(new City() { Name = "Pune", State = "Maharashtra", Population = 7000000 });
cities.Add(new City() { Name = "Nashik", State = "Maharashtra", Population = 65000 });
cities.Add(new City() { Name = "Aurangabad", State = "Maharashtra", Population = 5000000 });
DataContext = cities;
}
}
class City
{
public string State { get; set; }
public string Name { get; set; }
public int Population { get; set; }
}
Output
Because I found, Heena, that your Xaml does not provide selected dropped down items to be highlighted I modified your code as follows:
Xaml
<ComboBox Name="cbCities" Height="30" Margin="5" HorizontalContentAlignment="Left" HorizontalAlignment="Stretch" ItemsSource="{Binding}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="2" Text="{Binding Name}"/>
<TextBlock Margin="2" Text="{Binding State}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
<Border Name="templateBorder" Padding="2" SnapsToDevicePixels="true">
<ContentPresenter>
<ContentPresenter.Content>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Margin="5" Grid.Column="0" Text="{Binding Name}"/>
<TextBlock Margin="5" Grid.Column="1" Text="{Binding State}"/>
<TextBlock Margin="5" Grid.Column="2" Text="{Binding Population}"/>
</Grid>
</ContentPresenter.Content>
</ContentPresenter>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="True">
<Setter Property="Foreground" Value="{x:Static SystemColors.HighlightTextBrush}"/>
<Setter TargetName="templateBorder" Property="Background" Value="{x:Static SystemColors.HighlightBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
C#
private void Window_Loaded(object sender, RoutedEventArgs e)
{
cities.Add(new City() { Name = "Boston", State = "MA", Population = 3000000 });
cities.Add(new City() { Name = "Los Angeles", State = "CA", Population = 7000000 });
cities.Add(new City() { Name = "Frederick", State = "MD", Population = 65000 });
cities.Add(new City() { Name = "Houston", State = "TX", Population = 5000000 });
cbCities.DataContext = cities;
}
class City
{
public string State { get; set; }
public string Name { get; set; }
public int Population { get; set; }
}
Output
I know im late but this is how you do it in a simplified way, After the DataTemplate tag you can put anything depending on how you want your lay out to look like.
<ComboBox.ItemTemplate>
<DataTemplate >
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="{StaticResource ForegroundMainBrush}"
Margin="5 0"
FontFamily="{StaticResource LatoBold}"
VerticalAlignment="Center">
<Run Text="Code :" />
<Run Text="{Binding ActivityCode,Mode=OneWay}" />
</TextBlock>
<TextBlock Foreground="{StaticResource ForegroundDarkBrush}"
Margin="5 0"
Text="|"
FontFamily="{StaticResource LatoBold}"
VerticalAlignment="Center" />
<TextBlock Foreground="{StaticResource ForegroundMainBrush}"
Margin="5 0"
FontFamily="{StaticResource LatoBold}"
VerticalAlignment="Center">
<Run Text="Rate :" />
<Run Text="{Binding Rate,Mode=OneWay}" />
</TextBlock>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
Result
Sample Result
Or Use a readonly property in your DataModel as shown on the code below and set your combobox DisplayMemberPath to DisplayMemberPath="CodeRate"
public string ActivityCode { get; set; }
public string Rate { get; set; }
public string CodeRate => string.Format("Code: {0} | Rate:
{1}",ActivityCode,Rate);
I just use StackPanels in mine. Maybe kind of redundant per item, but it got me exactly the solution I wanted without getting too deep into things.
<ComboBox Name="cboTask">
<StackPanel Orientation="Horizontal">
<ComboBoxItem Name="someTask" Content="Doing Some Task" /><Button Name="cmdDetails" Content="..." />
</StackPanel>
</ComboBox>
Related
I have 3 RadioButtons in my app:
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Margin="91,206,0,24">
<TextBlock Text="Title Language:" VerticalAlignment="Top" FontSize="20" FontWeight="Bold" HorizontalAlignment="Left" Margin="0,0,15,0" />
<RadioButton x:Name="Rad_TitleNameRomaji" Content="Romaji" FontSize="20" Margin="0,0,10,0" Checked="TitleSettingsChanged"/>
<RadioButton x:Name="Rad_TitleNameEnglish" Content="English" FontSize="20" Margin="0,0,10,0" Checked="TitleSettingsChanged"/>
<RadioButton x:Name="Rad_TitleNameJapanese" Content="Japanese" FontSize="20" Checked="TitleSettingsChanged" />
</StackPanel>
There is a DataTemplate for my ListViewItems:
<DataTemplate x:Key="ItemTemplate_ListViewItems" >
<Grid Width="213" Height="326">
...
<TextBlock Text="{Binding WhatShouldIPutHere}) />
...
</Grid>
</DataTemplate>
The ListView's ItemsSource is a List<CustClass>.
CustClass:
public class CustClass : INotifyPropertyChanged
{
public string RomajiTitle { get; set; }
public string EnglishTitle { get; set; }
public string JapaneseTitle { get; set; }
...
public event PropertyChangedEventHandler PropertyChanged;
}
Now what i want is when I checked the "English" RadioButton, the Text of the TextBlock inside the DataTemplate will be bind to EnglishTitle. And so for the other two.
How can i approach this?
three DataTriggers should do the trick
<DataTemplate x:Key="ItemTemplate_ListViewItems" >
<Grid Width="213" Height="326">
<TextBlock >
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Rad_TitleNameRomaji,Path=IsChecked}" Value="True" >
<Setter Property="Text" Value="{Binding RomajiTitle}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=Rad_TitleNameEnglish,Path=IsChecked}" Value="True" >
<Setter Property="Text" Value="{Binding EnglishTitle}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=Rad_TitleNameJapanese,Path=IsChecked}" Value="True" >
<Setter Property="Text" Value="{Binding JapaneseTitle}"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
</DataTemplate>
I have a special requirement which need to implement a combobox which list data in groups and I could do it as below
the XAML file
<Window x:Class="GroupComboBox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ComboBox x:Name="comboBox" Width="100">
<ComboBox.Resources>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" Orientation="Horizontal" Width="150" Height="Auto" >
<!-- add scroll bar -->
</WrapPanel>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="Width" Value="50" />
</Style>
</ComboBox.Resources>
<ComboBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="2">
<TextBlock Text="{Binding Name}" HorizontalAlignment="Stretch" Background="YellowGreen"/>
</Border>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ComboBox.GroupStyle>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Item}" Width="40"/>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="IsEnabled" Value="{Binding Available}"/>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</Grid>
</Window>
The code-behind file
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<CategoryItem<string>> items = new List<CategoryItem<string>>();
for (int i = 0; i < 18; ++i)
{
items.Add(new CategoryItem<string> { Item = string.Format("{0:D2}", i), Available = (i > 9), Category = "Group A" });
}
for (int i = 0; i < 4; ++i)
{
items.Add(new CategoryItem<string> { Item = string.Format("{0:D2}", i), Available = (i > 2), Category = "Group B" });
}
//Need the list to be ordered by the category or you might get repeating categories
ListCollectionView lcv = new ListCollectionView(items.OrderBy(w => w.Category).ToList());
//Create a group description
lcv.GroupDescriptions.Add(new PropertyGroupDescription("Category"));
this.comboBox.ItemsSource = lcv;
}
}
public class CategoryItem<T>
{
public T Item { get; set; }
public bool Available { get; set; }
public string Category { get; set; }
}
Now I want to make the combobox to be a custom control, then it can be reused easily, but I am new for creating custom control and how should I do?
Currently I have created a WPF custom control library and change the base class of the custom control to be 'ComboBox' , but I do not know how to move the styles and templates to the resource dictionary file correctly
I can offer the following variant. Move all the styles and templates in resources:
<!-- Main style for ComboBox -->
<Style x:Key="MyComboBox" TargetType="{x:Type ComboBox}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Width" Value="100" />
<Setter Property="Height" Value="25" />
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" Orientation="Horizontal" Width="150" Height="Auto" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding Item}" Width="40"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Style for ComboBoxItem -->
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="Width" Value="50" />
</Style>
<!-- Style for ItemContainerStyle -->
<Style x:Key="ComboBoxItemContainerStyle" TargetType="{x:Type ComboBoxItem}">
<Setter Property="IsEnabled" Value="{Binding Available}" />
</Style>
<!-- DataTemplate for HeaderTemplate -->
<DataTemplate x:Key="MyHeaderTemplate">
<Border BorderBrush="Black" BorderThickness="2">
<TextBlock Text="{Binding Name}" HorizontalAlignment="Stretch" Background="YellowGreen" />
</Border>
</DataTemplate>
Using of ComboBox with our styles:
<ComboBox x:Name="MyComboBox1" Style="{StaticResource MyComboBox}" IsSynchronizedWithCurrentItem="False" ItemContainerStyle="{StaticResource ComboBoxItemContainerStyle}">
<ComboBox.GroupStyle>
<GroupStyle HeaderTemplate="{StaticResource MyHeaderTemplate}" />
</ComboBox.GroupStyle>
</ComboBox>
<ComboBox x:Name="MyComboBox2" Style="{StaticResource MyComboBox}" IsSynchronizedWithCurrentItem="False" ItemContainerStyle="{StaticResource ComboBoxItemContainerStyle}">
<ComboBox.GroupStyle>
<GroupStyle HeaderTemplate="{StaticResource MyHeaderTemplate}" />
</ComboBox.GroupStyle>
</ComboBox>
And set the data in code:
this.MyComboBox1.ItemsSource = lcv;
this.MyComboBox2.ItemsSource = lcv;
Set styles for you control need to change Type and write your control name:
<Style x:Key="MyControlComboBox" TargetType="{x:Type local:MyControlComboBox}">
</Style>
I have a ListView in which the ListView Items have button and textblock....
Senario :
I am able to click the button with out selecting the ListView Item i.e is the selection the last Item and then if i try to click the button of the first item the first time is not selected (In DataGrid it does select).
I Cannot use DataGrid as i am using CustomView in ListView.
If you need my code for reference of the problem i'll post it..
Any help in this regard would be great
My ListView :
<ListView Name="lv"
Grid.Row="1"
DisplayMemberPath="Name"
IsTextSearchEnabled="True"
ItemsSource="{Binding}"
KeyboardNavigation.DirectionalNavigation="Cycle"
SelectionMode="Single"
TextSearch.TextPath="{Binding Path=Person.Name}"
View="{Binding Path=SelectedItem,
ElementName=viewComboBox}" />
My DataTemplates for CustomViews :
<Style x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type CustomView:PlainView},
ResourceId=ImageView}"
BasedOn="{StaticResource {x:Type ListBox}}"
TargetType="{x:Type ListView}">
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="BorderThickness" Value=".5" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="ItemContainerStyle" Value="{Binding (ListView.View).ItemContainerStyle, RelativeSource={RelativeSource Self}}" />
<Setter Property="ItemTemplate" Value="{Binding (ListView.View).ItemTemplate, RelativeSource={RelativeSource Self}}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border Name="bd"
Margin="{TemplateBinding Margin}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer Margin="{TemplateBinding Padding}">
<WrapPanel KeyboardNavigation.DirectionalNavigation="Cycle"
Width="{Binding ActualWidth,
RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"
MinWidth="{Binding (ListView.View).MinWidth,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ListView}}}"
IsItemsHost="True"
ItemWidth="{Binding (ListView.View).ItemWidth,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ListView}}}" Orientation="Vertical"
Height="{Binding ActualHeight,
RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type CustomView:PlainView},
ResourceId=ImageViewItem}"
BasedOn="{StaticResource {x:Type ListBoxItem}}"
TargetType="{x:Type ListViewItem}">
<Setter Property="Padding" Value="3" />
<Setter Property="Margin" Value="5" />
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="BorderThickness" Value="2" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
<DataTemplate x:Key="centralTile">
<StackPanel Width="80" Height="40" KeyboardNavigation.AcceptsReturn="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button x:Name="tempabc" Command="{Binding Path=Launch}" KeyboardNavigation.AcceptsReturn="True" >
<TextBlock Text="{Binding Path=Name}" FocusManager.IsFocusScope="True"></TextBlock>
</Button>
<Image Grid.Column="1" Source="Water lilies.jpg"/>
</Grid>
<TextBlock
HorizontalAlignment="Center"
FontSize="13"
Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
<CustomView:PlainView x:Key="plainView"
ItemTemplate="{StaticResource ResourceKey=centralTile}"
ItemWidth="100" />
<GridView x:Key="myGridView">
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button>
<TextBlock Text="{Binding Path=Name}" />
</Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
As with most things, there are a number of ways to do this. Here's one I just threw together in a minute...
Given the following model:
public sealed class ItemModel
{
public string Name { get; set; }
}
I wish to display a collection of them to the user and select one via a button. This means I need three things in my ViewModel:
A collection of ItemModels
A "SelectedItem" property to hold the currently selected instance
An ICommand implementation to bind to the buttons in the View
I create my ViewModel and add these items to it. Please note, I prefer making my ViewModels extend DependencyObject rather than mess with INPC.
public sealed class ViewModel : DependencyObject
{
// 1. A collection of ItemModels
public ObservableCollection<ItemModel> ItemModels { get; private set; }
// 2. A "SelectedItem" property to hold the currently selected instance
public static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.Register(
"SelectedItem",
typeof(ItemModel),
typeof(ViewModel),
new UIPropertyMetadata(null));
public ItemModel SelectedItem
{
get { return (ItemModel)GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
// 3. An ICommand implementation to bind to the buttons in the View
public Command SelectItem { get; private set; }
public ViewModel()
{
ItemModels = new ObservableCollection<ItemModel>();
ItemModels.Add(new ItemModel { Name = "One" });
ItemModels.Add(new ItemModel { Name = "Two" });
ItemModels.Add(new ItemModel { Name = "Three" });
SelectItem = new Command
{
ExecuteAction = x => SelectedItem = x as ItemModel
};
}
}
Lastly, I slap together my UI with a rudimentary ListView.
<Window
x:Class="q_7635202.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="WindowRoot">
<ListView
SelectedItem="{Binding SelectedItem}"
ItemsSource="{Binding ItemModels}">
<ListView.View>
<GridView>
<GridViewColumn
DisplayMemberBinding="{Binding Name}"
Header="Name" />
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button
Content="Select"
Command="{Binding DataContext.SelectItem,
ElementName=WindowRoot}"
CommandParameter="{Binding}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Window>
Its all pretty straight forward. I'm leaving out the ICommand implementation as it is trivial.
Requirement:
Need to display an error message when the user types a forlder name that doesn't exist as shown below:
Problem: I am able to display the UI but not able to call a method in the view model when the user clicks on the button "CreateNew"
View Model Code:
public string this[string columnName]
{
get { return "The entered folder name doesn't exist."; }
}
RelayCommand createNewFolder;
public RelayCommand CreateNewFolder
{
get
{
if (createNewFolder == null)
createNewFolder = new RelayCommand(param => this.OnCreateNewFolder());
return createNewFolder;
}
}
public void OnCreateNewFolder()
{
MessageBox.Show("CreateNewFolder");
}
RelayCommand.cs can be downloaded at: http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mag200902MVVM&DownloadId=4357
Xaml Code:
<Window.Resources>
<ControlTemplate x:Key="validationTemplate">
<DockPanel LastChildFill="True">
<Border Margin="5,5,0,0" DockPanel.Dock="Bottom" Background="Red">
<StackPanel>
<TextBlock Name="ErrorText" Foreground="White" Background="Red"
FontSize="12" Padding="2" FontFamily="Trebuchet MS"
TextWrapping="Wrap"
Text="{Binding [0].ErrorContent}" ></TextBlock>
<StackPanel Margin="0" Orientation="Horizontal">
<Button Content="Create New" Command="{Binding Path=CreateNewFolder}" Margin="10" Padding="5"></Button>
<Button Content="Cancel" Margin="10" Padding="5" ></Button>
</StackPanel>
</StackPanel>
</Border>
<AdornedElementPlaceholder Name="ErrorTextBox" />
</DockPanel>
</ControlTemplate>
<Style x:Key="ValidationStyle" TargetType="{x:Type ComboBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="BorderBrush" Value="Red" />
<Setter Property="BitmapEffect">
<Setter.Value>
<BitmapEffectGroup>
<OuterGlowBitmapEffect GlowColor="Red" GlowSize="3" Noise="0.6"></OuterGlowBitmapEffect>
</BitmapEffectGroup>
</Setter.Value>
</Setter>
<Setter Property="DataContext"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},Path=DataContext}">
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<AdornerDecorator >
<ComboBox IsEditable="True" FontSize="11" Margin="10" Width="250"
VerticalAlignment="Center"
Text="{Binding Path=StrText, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"
Validation.ErrorTemplate="{StaticResource validationTemplate}"
Style="{StaticResource ValidationStyle}"></ComboBox>
</AdornerDecorator>
</Grid>
Please note that i set the DataContext property in the style:
<Setter Property="DataContext" Value="{Binding RelativeSource={x:Static
RelativeSource.Self},Path=DataContext}">
</Setter>
Please let me know how to bind the method to a button in the validation template.
You could reference the DataContext for the AdornerDecorators Child in the Binding. I think something like this will work
<Button Content="Create New"
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type AdornerDecorator}},
Path=Child.DataContext.CreateNewFolder}"
Margin="10" Padding="5"></Button>
This line looks suspicious:
createNewFolder = new RelayCommand(param => this.OnCreateNewFolder());
Maybe you should replace it by:
createNewFolder = new RelayCommand(OnCreateNewFolder);
So, the following is easy enough in WPF, but how would you do it in Silverlight?
Please note that the trick here is to display both Groups, and Entries on the same level.
Additonally you dont know how deep the entries are nested, they might be on the first, or the nth level.
This is hard in Silverlight because you lack the DataType="{x:Type local:Group}" property in the H.DataTemplate (or any DataTemplate). Building my own custom DataTempalteSelector also didnt work, because the Hierarchial ItemsSource gets lost. (Which just gave me a new idea which I will investigate shortly)
Example:
Group1
--Entry
--Entry
Group2
--Group4
----Group1
------Entry
------Entry
----Entry
----Entry
--Entry
--Entry
Group3
--Entry
--Entry
Your Classes:
public class Entry
{
public int Key { get; set; }
public string Name { get; set; }
}
public class Group
{
public int Key { get; set; }
public string Name { get; set; }
public IList<Group> SubGroups { get; set; }
public IList<Entry> Entries { get; set; }
}
Your xaml:
<TreeView Name="GroupView" Grid.Row="0" Grid.Column="0" ItemsSource="{Binding}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Group}" ItemsSource={Binding Items}">
<TextBlock Text="{Binding Path=Name}" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:Entry}" >
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</TreeView.Resources>
</TreeView>
The TreeView control from the Silverlight toolkit supports hierarchical data templates.
Check out this article for sample usage, but it looks identical to me to the WPF built in one.
You can download the Silverlight toolkit here.
Here is an example of using the HierarchicalDataTemplate with a HeaderedItemsControl in Silverlight (Songhay.Silverlight.BiggestBox.Views.ClientView.xaml):
<UserControl x:Class="Songhay.Silverlight.BiggestBox.Views.ClientView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:sdk="clr-namespace:System.Windows;assembly=System.Windows.Controls"
xmlns:sdkctrls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
xmlns:uriMapper="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation"
xmlns:v="clr-namespace:Songhay.Silverlight.BiggestBox.Views"
xmlns:m="clr-namespace:Songhay.Silverlight.BiggestBox.ViewModels">
<UserControl.Resources>
<Style x:Key="StackPanelRoot" TargetType="StackPanel">
<Setter Property="Background" Value="Seashell" />
<Setter Property="Height" Value="598" />
<Setter Property="Width" Value="1024" />
</Style>
<Style x:Key="GridRoot" TargetType="Grid">
<Setter Property="Height" Value="570" />
</Style>
<Style x:Key="ClientGridSplitter" TargetType="sdkctrls:GridSplitter">
<Setter Property="Background" Value="#FFE0EEE0" />
<Setter Property="Height" Value="8" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
<m:ClientViewModel x:Key="ClientViewModelDataSource" d:IsDataSource="True"/>
<Style TargetType="sdkctrls:HeaderedItemsControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="sdkctrls:HeaderedItemsControl">
<StackPanel>
<ItemsPresenter Margin="10,0,0,0" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollViewerIndexItems" TargetType="ScrollViewer">
<Setter Property="Margin" Value="10" />
<Setter Property="VerticalScrollBarVisibility" Value="Auto" />
</Style>
<Style x:Key="StackPanelIndexItems" TargetType="StackPanel">
<Setter Property="Background" Value="#ff9" />
<Setter Property="Orientation" Value="Horizontal" />
</Style>
</UserControl.Resources>
<UserControl.DataContext>
<Binding Source="{StaticResource ClientViewModelDataSource}"/>
</UserControl.DataContext>
<Border BorderBrush="Black" BorderThickness="1" VerticalAlignment="Center">
<StackPanel x:Name="RootPanel" Style="{StaticResource StackPanelRoot}">
<Grid Style="{StaticResource GridRoot}">
<Grid.RowDefinitions>
<RowDefinition MinHeight="128" MaxHeight="360" Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="1.5*" />
</Grid.RowDefinitions>
<v:HeaderView Grid.Row="0" />
<sdkctrls:GridSplitter Grid.Row="1" Style="{StaticResource ClientGridSplitter}" />
<StackPanel Grid.Row="2"
Orientation="Horizontal"
Style="{StaticResource StackPanelIndexItems}">
<ScrollViewer Style="{StaticResource ScrollViewerIndexItems}">
<sdkctrls:HeaderedItemsControl
Header="{Binding IndexTitle}"
ItemsSource="{Binding Outlines}">
<sdkctrls:HeaderedItemsControl.HeaderTemplate>
<DataTemplate>
<TextBlock FontSize="24" FontWeight="Bold" Text="{Binding}" />
</DataTemplate>
</sdkctrls:HeaderedItemsControl.HeaderTemplate>
<sdkctrls:HeaderedItemsControl.ItemTemplate>
<sdk:HierarchicalDataTemplate>
<StackPanel>
<TextBlock FontSize="12" FontWeight="Bold" Margin="0,10,0,0" Text="{Binding Text}" />
<sdkctrls:HeaderedItemsControl ItemsSource="{Binding Outlines}" Margin="10,0,10,0">
<sdkctrls:HeaderedItemsControl.ItemTemplate>
<sdk:HierarchicalDataTemplate>
<HyperlinkButton
ClickMode="Press"
Command="{Binding IndexItemCommand, Source={StaticResource ClientViewModelDataSource}}"
CommandParameter="{Binding Url}"
FontSize="12">
<HyperlinkButton.Content>
<TextBlock Text="{Binding Text}" />
</HyperlinkButton.Content>
</HyperlinkButton>
</sdk:HierarchicalDataTemplate>
</sdkctrls:HeaderedItemsControl.ItemTemplate>
</sdkctrls:HeaderedItemsControl>
</StackPanel>
</sdk:HierarchicalDataTemplate>
</sdkctrls:HeaderedItemsControl.ItemTemplate>
</sdkctrls:HeaderedItemsControl>
</ScrollViewer>
<navigation:Frame x:Name="IndexFrame" Width="685">
</navigation:Frame>
</StackPanel>
</Grid>
<v:FooterView Height="30" />
</StackPanel>
</Border>
</UserControl>