Friday, November 8, 2019

Disabling previous used values in WPF combo boxes

One common problem we have is when our design team decides to make a lookup option unavailable. For example, let's suppose we have a table of "Customer Types" and we decide we want to remove one of them. We don't want customer maintenance to be able to select that customer type for new customers, but we don't want to do data cleanup on all the existing customers of that type.

We need to change the UI to hide or disable that customer type in the customer type drop down. Normally this is a problem because if we remove that entry from the drop down we still have customers that need to show that entry. In WPF there are two solutions that both work well. We can disable the entry or we can hide it in the drop down list. Because in MVVM then view and the viewmodel are separate we can keep the entry in the viewmodel, but remove it from the view.

Here's an example of both disabling and hiding one entry from the drop down list, showing how the UI looks when displaying a data record that contains the obsolete value.

Start a new WPF C# project called HiddenComboItem. The framework does not matter. Change MainWindow.xaml to look like this. It defines two combo boxes, the first disables the obsolete value and the second hides it completely.


<Window x:Class="HiddenComboItem.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:HiddenComboItem"
        mc:Ignorable="d"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Title="MainWindow" Height="450" Width="800">
    <StackPanel Orientation="Horizontal">
        <ComboBox ItemsSource="{Binding Things}" SelectedItem="{Binding SelectedThing}" DisplayMemberPath="Name" IsEditable="False" Height="40" FontSize="20">
            <ComboBox.ItemContainerStyle>
                <Style TargetType="ComboBoxItem">
                    <Setter Property="IsEnabled" Value="{Binding IsEnabled}"/>
                </Style>
            </ComboBox.ItemContainerStyle>
        </ComboBox>
        <ComboBox ItemsSource="{Binding Things}" SelectedItem="{Binding SelectedThing}" DisplayMemberPath="Name" IsEditable="False" Height="40" FontSize="20">
            <ComboBox.ItemContainerStyle>
                <Style TargetType="ComboBoxItem">
                    <Setter Property="Visibility" Value="Visible"/>
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsEnabled}" Value="False">
                            <Setter Property="Visibility" Value="Collapsed"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ComboBox.ItemContainerStyle>
        </ComboBox>
    </StackPanel>
</Window>

The code behind looks like this. It defines a class with an enabled property, a list of objects with one disabled, and a selected property that references the disabled Thing.


using System.Collections.Generic;
using System.Windows;

namespace HiddenComboItem
{
    public class cThing
    {
        public string Name { get; set; }
        public bool IsEnabled { get; set; }
    }

    public partial class MainWindow : Window
    {
        private List<cThing> _Things = new List<cThing>()
        {   new cThing() {Name="Alpha", IsEnabled=true },
            new cThing() {Name="Beta", IsEnabled=false },
            new cThing() {Name="Gamma", IsEnabled=true }
        };

        public List<cThing> Things
        {
            get { return _Things; }
            set { _Things = value; }
        }

        private cThing _SelectedThing;
        public cThing SelectedThing
        {
            get { return _SelectedThing; }
            set { _SelectedThing = value; }
        }
        public MainWindow()
        {
            SelectedThing = Things[1];
            InitializeComponent();
        }
    }
}

When you run this you see two combo boxes. Drop the first and you see Beta is disabled. Drop the second and you see Beta is missing from the list. In both cases we can still display Beta in the text box part but we cannot select it from the list. If a different selection is made, we cannot get back to Beta without refreshing the page in some way. This is the functionality we want.



So much simpler to implement than in a web browser.

No comments:

Post a Comment