I have 2 object types which display on tabs within the same tab. I am using a DataTrigger and a DataTypeConverter to display the content. The content displays correctly but I receive the following errors in the output window:
System.Windows.Data Error: 40 : BindingExpression path error: 'Taste' property not found on 'object' ''MySmellObject' (HashCode=30266853)'. BindingExpression:Path=Taste; DataItem='MySmellObject' (HashCode=30266853); target element is 'TextBox' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Error: 40 : BindingExpression path error: 'Smell' property not found on 'object' ''MyTasteObject' (HashCode=36404074)'. BindingExpression:Path=Smell; DataItem='MyTasteObject' (HashCode=36404074); target element is 'TextBox' (Name=''); target property is 'Text' (type 'String')
Here's the XAML:
<Window x:Class="ControlTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ControlTest"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:DataTypeConverter x:Key="DataTypeConverter" />
</Window.Resources>
<StackPanel Orientation="Vertical" Width="150">
<TabControl Name="tab" Height="200px"
ItemsSource="{Binding MyObjects}"
SelectedValuePath="Id"
SelectedItem="{Binding MyObject}"
>
<TabControl.ContentTemplate>
<DataTemplate>
<ContentControl>
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=tab,Path=SelectedItem, Converter={StaticResource DataTypeConverter}}" Value="{x:Type local:MyTasteObject}">
<Setter Property="Content">
<Setter.Value>
<TextBox Text="{Binding Taste}" ></TextBox>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=tab,Path=SelectedItem, Converter={StaticResource DataTypeConverter}}" Value="{x:Type local:MySmellObject}">
<Setter Property="Content">
<Setter.Value>
<TextBox Text="{Binding Smell}" ></TextBox>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</StackPanel>
</Window>
Here's the code behind:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace ControlTest
{
public partial class MainWindow : Window
{
public List<MyObject> MyObjects { get; set; }
public int MyObjectId { get; set; }
public MyObject MyObject { get; set; }
public MainWindow()
{
MyObject obj0 = new MySmellObject() { Id = 0, Smell = "Pleasent" };
MyObject obj1 = new MyTasteObject() { Id = 1, Taste = "Mild" };
MyObjects = new List<MyObject> { obj0, obj1 };
MyObjectId = 0;
MyObject = obj0;
DataContext = this;
InitializeComponent();
}
}
public class MyObject
{
public int Id { get; set; }
}
public class MyTasteObject : MyObject
{
public string Taste { get; set; }
public override string ToString()
{
return Taste;
}
}
public class MySmellObject : MyObject
{
public String Smell { get; set; }
public override string ToString()
{
return Smell;
}
}
public class DataTypeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
return value.GetType();
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Does anyone know why I'm getting these errors and how to fix the code?
The problem here is the ContentTemplate is applied against all items in the TabControl. Initially it's applied only on the SelectedItem. But after switching to the new item, it's then applied to all loaded items.
When the SelectedItem is changed, the ContentTemplate with a ContentControl having new Content updated, this is then applied on all items. But because the underlying items are of different concrete types (deriving from the same base type). So once the template is applied on item of mismatched type, the Binding error will be reported silently.
In fact we have a better way to achieve what you want without using Triggers at all. That's what the so-called DataTemplate provides you. Just set the DataType to the item type, then it will be automatically replaced with the corresponding template, something like this:
<TabControl.ContentTemplate>
<DataTemplate>
<ContentControl Content="{TemplateBinding Content}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:MySmellObject}">
<TextBox Text="{Binding Smell}" ></TextBox>
</DataTemplate>
<DataTemplate DataType="{x:Type local:MyTasteObject}">
<TextBox Text="{Binding Taste}" ></TextBox>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</DataTemplate>
</TabControl.ContentTemplate>
Related
I have am attempting to build a tree view where:
1. The TreeViewItems are generated by a list in my model.
2. Each TreeViewItem contains a ComboBox, and a dynamic element whose template I want to change based on the value selected in the ComboBox.
Here is my current xaml code.
<Window x:Class="MyTestWPF.MainWindow"
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"
xmlns:local="clr-namespace:MyTestWPF"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<local:NodeTypeToTemplateConverter x:Key="NodeTypeToTemplateConverter"/>
<DataTemplate x:Key="Template1">
<TextBlock Text="Template 1" />
</DataTemplate>
<DataTemplate x:Key="Template2">
<TextBlock Text="Template 2" />
</DataTemplate>
<Style x:Key="MyNodeTemplate" TargetType="ContentPresenter">
<Setter Property="ContentTemplate" Value="{StaticResource Template1}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=NodeType}">
<DataTrigger.Value>
<local:NodeTypesEnum>Type1</local:NodeTypesEnum>
</DataTrigger.Value>
<Setter Property="ContentTemplate" Value="{Binding Converter={StaticResource NodeTypeToTemplateConverter}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
<HierarchicalDataTemplate DataType="{x:Type local:MyTreeNode}"
ItemsSource="{Binding Nodes}">
<StackPanel Orientation="Horizontal">
<ComboBox ItemsSource="{Binding Path=GetAvailableNodeType}"
SelectedItem="{Binding Path=NodeType}" />
<ContentPresenter Style="{StaticResource MyNodeTemplate}" Content="{Binding}" />
</StackPanel>
</HierarchicalDataTemplate>
</Window.Resources>
<TreeView x:Name="MyTree" ItemsSource="{Binding MyTreeModel}" />
</Window>
And its code-behind:
using System.Windows;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new
{
MyTreeModel = new MyTreeNode[] {
new MyTreeNode() { Name = "1", Nodes = new MyTreeNode[] { new MyTreeNode() { Name= "2" } } }
}
};
}
}
The tree node type:
namespace MyTestWPF
{
public class MyTreeNode
{
public string Name { get; set; }
public NodeTypesEnum NodeType { get; set; }
public MyTreeNode[] Nodes { get; set; }
public NodeTypesEnum[] GetAvailableNodeType()
{
return new NodeTypesEnum[] { NodeTypesEnum.Type1, NodeTypesEnum.Type2 };
}
}
public enum NodeTypesEnum
{
Type1 = 0,
Type2 = 1
}
}
The Converter (NodeTypeToTemplateConverter) receives the whole ViewModel, and returns the name of the relevant template based on values in the model.
using System;
using System.Globalization;
using System.Windows.Data;
namespace MyTestWPF
{
public class NodeTypeToTemplateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if((value as MyTreeNode).NodeType == NodeTypesEnum.Type1)
{
return "Template1";
} else
{
return "Template2";
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
The problem is that the above code causes a stack overflow exception. The first item in the TreeView endlessly calls NodeTypeToTemplateConverter's Convert method.
I figured it had to do with the DataTrigger.Value. Setting that to a value different from the default NodeType allows the page to load without overflow, but the moment any ComboBox is set to NodeType1, stack overflow.
I attempted to simply remove the DataTrigger.Value element, but that causes the Converter to never be called at all...
How can I dynamically build the template name based on the value selected by its neighboring ComboBox?
You probably want to use a DataTemplateSelector rather than a converter.
public class ComboBoxItemTemplateSelector : DataTemplateSelector
{
public DataTemplate Template1 { get; set; }
public DataTemplate Template2 { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
//Logic to select template based on 'item' value.
if (item == <template1Value>) return Template1; //TODO: replace <template1Value>
else if (item == <template2Value>) return Template2; //TODO: replace <template2Value>
else return new DataTemplate();
}
}
<local:ComboBoxItemTemplateSelector x:Key="ComboBoxItemTemplateSelector">
<local:ComboBoxItemTemplateSelector.Template1>
<DataTemplate>
<TextBlock Text="" />
</DataTemplate>
</local:ComboBoxItemTemplateSelector.Template1>
<local:ComboBoxItemTemplateSelector.Template2>
<DataTemplate>
<TextBlock Text="" />
</DataTemplate>
</local:ComboBoxItemTemplateSelector.Template2>
</local:ComboBoxItemTemplateSelector>
<ContentPresenter Content="{Binding NodeType}" ContentTemplateSelector="{StaticResource ComboBoxItemTemplateSelector}"/>
I have not fully tested this code, so let me know if you have any issues.
EDIT:
The template selector is only executed when the content changes so this won't work if you use {Binding}. A workaround for this would be to have the DataTemplate content bind to the parent's DataContext.
<DataTemplate>
<TextBlock Text="" DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=ContentPresenter}}"/>
</DataTemplate>
If this workaround is not acceptable, there are other ways to do this as well.
I have a working solution to convert boolean value into a xaml-image wrapped inside <Viewbox> by using <ContentControl> as follows:
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentControl Content="{Binding Recommended, Converter={StaticResource BoolImageConverter}}" Height="20"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
But with the above solution the converted image is only shown in the first cell.
How can I properly use <ControlTemplate> or <Control> in this
case?
I have looked into this answer but I'm unable to reproduce a working solution with the Converter.
Example of the xaml-image
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Viewbox x:Key="Symbols.StarIcon">
<Canvas Width="46" Height="44" >
...
</Canvas>
</Viewbox>
</ResourceDictionary>
The Converter idea is from this post:
public class BoolToImage : IValueConverter
{
public Viewbox TrueImage { get; set; }
public Viewbox FalseImage { get; set; }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!(value is bool))
{
return null;
}
bool b = (bool)value;
if (b)
{
return this.TrueImage;
}
else
{
return this.FalseImage;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Your ViewBox is a control with a key. And control can have only one visual parent. So the first cell monopolizes ViewBox, and others can't use it.
In your case it is better to use CellTemplateSelector property.
First, create custom DataTemplateSelector:
public class TrueFalseSelector : DataTemplateSelector
{
public DataTemplate TrueTemplate { get; set; }
public DataTemplate FalseTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item == null) return null;
var isSomething = ((CustomObjectType) item).CustomBoolProperty;
return isSomething ? this.TrueTemplate
: FalseTemplate;
}
}
Then use it in XAML. Add Selector in Resources somewhere:
<local:TrueFalseSelector x:Key="trueFalseSelector">
<local:TrueFalseSelector.TrueTemplate>
<DataTemplate>
<!-- your true template here -->
</DataTemplate>
</local:TrueFalseSelector.TrueTemplate>
<local:TrueFalseSelector.FalseTemplate>
<DataTemplate>
<!-- your false template here -->
</DataTemplate>
</local:TrueFalseSelector.FalseTemplate>
</local:TrueFalseSelector>
And voila:
<DataGrid.Columns>
<DataGridTemplateColumn CellTemplateSelector="{StaticResource trueFalseSelector}" />
</DataGrid.Columns>
EDIT: you can place DataTemplates in the same dictionary where your ViewBox is right now. Give them a key and just use like this:
<local:TrueFalseSelector x:Key="trueFalseSelector"
FalseTemplate="{StaticResource falseTemplate}"
TrueTemplate="{StaticResource trueTemplate">
Here is just another way you can do this (pure xaml):
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentControl Style="{StaticResource RecommendedStyle}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<Style TargetType="ContentControl" x:Key="RecommendedStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ViewBox x:Key="True"/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Recommended}" Value="False">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ViewBox x:Key="False"/><!--This is image for false-->
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style>
In my application I would like you highlight an index based on the value. for example:
ArrayList itemsList = new ArrayList();
private void button_Click(object sender, RoutedEventArgs e)
{
itemsList.Add("Coffie");
itemsList.Add("Tea");
itemsList.Add("Orange Juice");
itemsList.Add("Milk");
itemsList.Add("Mango Shake");
itemsList.Add("Iced Tea");
itemsList.Add("Soda");
itemsList.Add("Water");
listBox.ItemsSource = itemsList;
ApplyDataBinding();
}
private void ApplyDataBinding()
{
listBox.ItemsSource = null;
listBox.ItemsSource = itemsList;
}
It does not matter where in the listbox "Orange Juice" is I would like to highlight it based on its value. If the Position change it should be still highlighted. (Not based on the selected index)
If you want to highlight an item based on it's value, then you need to define your own datatemplate for an item and use a converter to provide appropriate brush for the background. Something like that:
<Window.Resources>
<local:TextToBrushConverter x:Key="TextToBrushConverter" />
</Window.Resources>
<Grid>
<ListBox Name="listBox" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Background="{Binding ., Converter={StaticResource TextToBrushConverter}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Converter
class TextToBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((value as String) == "Orange Juice")
{
return Brushes.Orange;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I would recommend that you place the items into a class, think Object Oriented design and then work off of properties (as flags) to give different states.
Then by using Xaml styles to key off those different properties to achieve the affect you are looking for.
Say for example we have an Order class with these properties
public class Order
{
public string CustomerName { get; set; }
public int OrderId { get; set; }
public bool InProgress { get; set; }
}
When an order is marked as in progress (InProgress = true) we want to show red in our list box say for "Alpha" and "Omega" which are in progress:
ListBox Xaml
Here is the Xaml which binds to our data (how you bind is up to you) and shows how to work with Style(s), DataTemplate, and DataTrigger(s) to achieve that:
<ListBox ItemsSource="{StaticResource Orders}"
x:Name="lbOrders">
<ListBox.Resources>
<DataTemplate DataType="{x:Type model:Order}">
<TextBlock Text="{Binding Path=CustomerName}" />
</DataTemplate>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=InProgress}"
Value="True">
<Setter Property="Foreground"
Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
</ListBox>
Here is the data setup in the pages's resource Xaml to do that, but it could be created in code behind:
<Window.Resources>
<model:Orders x:Key="Orders">
<model:Order CustomerName="Alpha"
OrderId="997"
InProgress="True" />
<model:Order CustomerName="Beta"
OrderId="998"
InProgress="False" />
<model:Order CustomerName="Omega"
OrderId="999"
InProgress="True" />
<model:Order CustomerName="Zeta"
OrderId="1000"
InProgress="False" />
</model:Orders>
</Window.Resources>
This should give you enough to start on and create a full featured UI.
I am trying to prepare template for DataGridColumnHeader. Template should be really simple.
Attached dependency property csdpp:CalendarProperties.EnumDay should only specific day that DataGridColumnHeader belong to and converter should then just return right label for that day.
If I set AncestorType to DataGridTextColumn (that is what I want) and leave the code like this:
<Style TargetType="DataGridColumnHeader" x:Key="DayHeaderStyle">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBox Text="{Binding
RelativeSource={RelativeSource FindAncestor, AncestorType=DataGridTextColumn}, Mode=OneWay,
Path=(csdpp:CalendarProperties.EnumDay),
Converter={StaticResource IndexToDayLabelConverter}}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
nothing happen. Converter is not even getting called.
But if I change code to this:
<Style TargetType="DataGridColumnHeader" x:Key="DayHeaderStyle">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBox Text="{Binding
RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}, Mode=OneWay,
Path=(csdpp:CalendarProperties.EnumDay),
Converter={StaticResource IndexToDayLabelConverter}}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
(DatagridTextColumn switched by DataGrid, DataGrid has attached property too (below))
Converter is getting called and as value is passed attached property from DataGrid. Why is that working for DataGrid and not for DataGridTextColumn? Please help.
Code with DataGrid and DataGridTextColumn:
<DataGrid Grid.Row="1" Grid.Column="1"
x:Name="_shiftDataGrid"
ItemsSource="{Binding ElementName=Root, Path=PersonShiftgroupings.ShiftPersons}"
DataContext="{Binding ElementName=Root, Path=PersonShiftgroupings.ShiftPersons}"
AutoGenerateColumns="False"
csdpp:CalendarProperties.EnumDay="Fri">
<DataGrid.Columns>
<DataGridTextColumn
csdpp:CalendarProperties.EnumDay="Wed"
HeaderStyle="{StaticResource DayHeaderStyle}">
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
Any help would be appreciated.
Like i stated in my comment above DataGridColumnHeader is in the VisualTree of DataGrid via
DataGridColumnHeaderPresenter and not in the VisualTree of DataGridColumn.
You can reach the Column through DataGridColumnHeader's Column property
Column
I didn't want to get into your implementation and logic because i'm sure there's a cleaner way of doing what ever it is you need done.
Here's a sample of what you need to get it working :
CS:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
public List<SomeItem> MyItems
{
get { return new List<SomeItem> { new SomeItem() , new SomeItem() , new SomeItem() , new SomeItem() }; }
}
}
public class SomeItem
{
public int First { get { return 1; } }
public int Second { get { return 2; } }
public int Third { get { return 3; } }
public int Forth { get { return 4; } }
}
public static class ASample
{
public static string GetMyProperty(DependencyObject obj)
{
return (string)obj.GetValue(MyPropertyProperty);
}
public static void SetMyProperty(DependencyObject obj, string value)
{
obj.SetValue(MyPropertyProperty, value);
}
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.RegisterAttached("MyProperty", typeof(string), typeof(ASample));
}
public class ColumnHeaderConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return string.Empty;
DataGridColumn c = (DataGridColumn)value;
string header = ASample.GetMyProperty(c);
return header;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
XAML :
<Window.Resources>
<local:ColumnHeaderConverter x:Key="colConverter"/>
<Style TargetType="DataGridColumnHeader" x:Key="DayHeaderStyle">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBox Text="{Binding
RelativeSource={RelativeSource AncestorType=DataGridColumnHeader}, Mode=OneWay,
Path=Column , Converter={StaticResource colConverter} }"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<DataGrid AutoGenerateColumns="False" ColumnHeaderStyle="{StaticResource DayHeaderStyle}"
ItemsSource="{Binding MyItems}" local:ASample.MyProperty="DataGrid" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding First}" local:ASample.MyProperty="11"/>
<DataGridTextColumn Binding="{Binding Second}" local:ASample.MyProperty="22"/>
<DataGridTextColumn Binding="{Binding Third}" local:ASample.MyProperty="33"/>
<DataGridTextColumn Binding="{Binding Forth}" local:ASample.MyProperty="44"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
DataGridTextColumn is no ancestor of DataGridColumnHeader
I have a List< Versions> where Version, amongst others has the properties VersionUUID, Label, SKU and IsSelected. I would like to bind this to a Combobox and have the selected item just select the IsSelected flag (unselected any previous set flag).
Note:The combobox is in a template, used inside a datagrid cell, so I can not just bind a SelectedItem to the model!
What I have so far is working, the datagrid updates the DB as expected, however the initial value is not set onLoad. If one version already has a IsSelected=true, I would like to have that showing int the Combobox, but it is always empty unless i Select one from the list.
<DataTemplate x:Key="dtDatagridVersionSelector">
<ComboBox Margin="0" Width="90" Style="{StaticResource DatagridComboBox}"
ItemsSource="{Binding Path=Versions, Mode=OneTime}">
<ComboBox.ItemTemplate >
<DataTemplate >
<RadioButton Focusable="false" IsEnabled="true"
GroupName="{Binding VersionUUID}"
IsChecked="{Binding IsSelected, Mode=TwoWay}">
<StackPanel Orientation="Horizontal" >
<TextBlock Margin="3,0,0,0" Text="{Binding Label}"/>
<TextBlock Foreground="Red" Margin="3,0,0,0"
Text="{Binding SKU}"/>
</StackPanel>
</RadioButton>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="IsSelected"
Value="{Binding IsSelected, Mode=OneWay}" />
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</DataTemplate>
Also, the use of the Radiobox is not written in stone, if there is a better solution to achieve this so only one item isSelected, I'm all open for it
Thanx for any pointers
Andreas
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:SelectedItemConverter x:Key="selectedItemConverter"/>
</Window.Resources>
<Grid>
<ComboBox ItemsSource="{Binding Students}" SelectedItem="{Binding Students, Converter={StaticResource selectedItemConverter}}" DisplayMemberPath="Name"/>
</Grid>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Students = new ObservableCollection<Student>();
Students.Add(new Student() { Name = "HArish", RollNo = 1, IsSelected = false });
Students.Add(new Student() { Name = "Arev", RollNo = 2, IsSelected = false });
Students.Add(new Student() { Name = "Pankaj", RollNo = 3, IsSelected = true });
Students.Add(new Student() { Name = "Deepak", RollNo = 4, IsSelected = false });
DataContext = this;
}
public ObservableCollection<Student> Students { get; set; }
}
public class Student
{
public string Name { get; set; }
public int RollNo { get; set; }
public bool IsSelected { get; set; }
}
public class SelectedItemConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null && value is IEnumerable<Student>)
return ((IEnumerable<Student>)value).Where(s => s.IsSelected).FirstOrDefault();
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
I hope this will help.