We started with the Infragistics XamMultiColumnComboEditor which isn't very satisfactory. The first things the designers don't like is that when you collapse it, you only see one column. They also don't like that you cannot turn the filter feature off. Here are a couple of screen prints showing these issues.
XamMultiColumnComboEditor shows all three columns when expanded... |
but only one when collapsed. |
Really need to be able to turn the filter feature off. |
We can override the default ItemTemplate for a ComboBox in XAML and use a style to disable selected rows. I came up with two UI designs, one with the column labels above the Combobox and one with them embedded using a converter. Let's take a look at both methods.
Note these designs are ideal for single use, but a custom control would be better when this functionality will be wide-spread. That's for another post.
Start a new WPF project called MultiColumnCombo using C# and any version of the Framework after 3.5.
The XAML (MainWindow.xaml) looks like this. It shows the two drop down lists described above.
<Window x:Class="MultiColumnCombo.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:MultiColumnCombo"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<local:PromptConverter x:Key="PromptConverter"/>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="100"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<TextBlock Text="Description" Margin="8,0,2,0" Width="200"></TextBlock>
<TextBlock Text="Setup" Margin="2,0,0,0" Width="35"></TextBlock>
<TextBlock Text="Post" Margin="2,0,0,0" Width="35"></TextBlock>
</StackPanel>
<ComboBox Grid.Row="1" HorizontalAlignment="Left" ItemsSource="{Binding RollTypes}" Width="300" SelectedValuePath="ID" SelectedItem="{Binding SelectedRollType}" Height="22">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Description}" Margin="2,0,2,0" Width="200"/>
<TextBlock Text="{Binding SetupObject}" Margin="2,0,0,0" Width="35"/>
<TextBlock Text="{Binding PostObject}" Margin="2,0,0,0" Width="35"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="IsEnabled" Value="{Binding IsEnabled}"/>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</Grid>
<ComboBox Grid.Row="2" HorizontalAlignment="Left" ItemsSource="{Binding RollTypes}" Width="380" SelectedValuePath="ID" SelectedItem="{Binding SelectedRollType}" Height="22">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Description}" Margin="2,0,2,0" Width="200"/>
<TextBlock Text="{Binding SetupObject, Converter={StaticResource PromptConverter}, ConverterParameter='Setup: '}" Margin="2,0,0,0" Width="80"/>
<TextBlock Text="{Binding PostObject, Converter={StaticResource PromptConverter}, ConverterParameter='Post: '}" Margin="2,0,0,0" Width="80"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="IsEnabled" Value="{Binding IsEnabled}"/>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</Grid>
</Window>
The code behind (MainWindow.xaml.cs) looks like this. It simply defines a list of objects we can bind to.
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
namespace MultiColumnCombo
{
public class cRollType
{
public int ID { get; set; }
public string
Description { get; set; }
public string
SetupObject { get; set; }
public string
PostObject { get; set; }
public bool
IsEnabled { get; set; }
}
public partial class MainWindow : Window, INotifyPropertyChanged
{
public List<cRollType> RollTypes { get; set; }
public cRollType SelectedRollType { get; set; }
public MainWindow()
{
RollTypes = new List<cRollType>();
RollTypes.Add(new cRollType() { ID = 0, Description =
"(SELECT)", SetupObject =
"", PostObject = "", IsEnabled = false });
RollTypes.Add(new cRollType() { ID = 1, Description =
"Accounts Receivable", SetupObject = "9229", PostObject = "9210", IsEnabled = true });
RollTypes.Add(new cRollType() { ID = 2, Description =
"Due from grantor government", SetupObject = "9299", PostObject = "9290", IsEnabled = false });
RollTypes.Add(new cRollType() { ID = 3, Description =
"Due from other funds", SetupObject = "9319", PostObject = "9310", IsEnabled = true });
SelectedRollType = RollTypes[0];
InitializeComponent();
}
public event
PropertyChangedEventHandler PropertyChanged;
public void
PropChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
using System;
using System.Globalization;
using System.Windows.Data;
namespace MultiColumnCombo
{
class PromptConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null ||
value.ToString() == "")
return "";
else
return parameter.ToString() + value.ToString();
}
public object
ConvertBack(object value,
Type targetType, object
parameter, CultureInfo culture)
{
throw new
NotImplementedException();
}
}
}
Initial collapsed state |
Expanded state - note the disabled item |
After selection |
The UI for the second list box (labels embedded in the items) looks like this.
Initial collapsed state |
Expanded state - note labels |
After selection |
No comments:
Post a Comment