#961 – A ListBox Has Three Available Selection Modes

By default, a user can select one item at a time in a ListBox.

961-001

You can use the SelectionMode property of the ListBox to allow the user to select multiple items.  By default, the SelectionMode property has a value of SelectionMode.Single, allowing the user to select a single item.

You can set SelectionMode to Extended, allowing a user to select multiple items, as follows:

  • A mouse left-click selects a single new item, unselecting all previously selected items
  • Control + left-click selects/unselects an additional item.  Previously selected items remain selected.
  • Shift + left-click selects all items between the most recently selected item and the one being clicked (inclusive).  Previously selected items not in this range are unselected.
  • Control + Shift + left-click selects all items within a range without unselecting previously selected items

961-002

Setting SelectionMode to Multiple allows selecting multiple items by left-clicking:

  • Left-clicking an item selects or unselects the item
Advertisement

#960 – A ListBox Can Store Objects of Different Types

You’ll most often bind the contents of a ListBox to a collection of items that are all of the same type.  You can, however, add different types of objects to the same ListBox.  Items in a ListBox can be either standard CLR objects or objects that derive from UIElement.

In the example below, we add several different types of objects to a ListBox.

    <ListBox Margin="15">
        <ListBoxItem>Simple string</ListBoxItem>
        <local:Actor FullName="Liam Neeson" BirthYear="1952" KnownFor="Schindler's List"/>
        <Button Content="Click Me"/>
        <TextBox Text="zzz" Width="100"/>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Username:"/>
            <TextBox Width="100" Margin="5,0"/>
        </StackPanel>
    </ListBox>

960-001
This example is not very typical, but points out that you can add any type of object that you like to a ListBox.  Note that the user can also select any item, whether the item is a string or a user interface element.

#959 – ListBox Basics

You can use a ListBox control to allow a user to select one or more items from a larger list of items.  The ListBox displays some subset of the items, with additional items visible by using scrollbars.

959-001

 

You typically populate a ListBox using data binding, setting its ItemsSource property.  Optionally, you can use the DisplayMemberPath property to indicate which property on the bound items is to be used in generating the text within the ListBox.

The Items property of the ListBox contains a collection of the items displayed in the list.  You typically use the SelectedItemSelectedItems, or SelectedIndex properties to access one or more items that a user has selected.

Instead of simple strings, each item in the ListBox can instead be displayed as a more complex user interface element.

959-002

#958 – Three Ways to Populate a List Control

There are three general ways that you can populate a list-based control with some content:

  • Add items in XAML
  • Add items in code
  • Use data binding  (preferred method, most flexible)

For example, to add several items to a ListBox from XAML:

    <ListBox>
        <ListBoxItem>Augustus</ListBoxItem>
        <ListBoxItem>Tiberius</ListBoxItem>
        <ListBoxItem>Caligula</ListBoxItem>
    </ListBox>

To add the same items from code:

    <ListBox Name="lbMyListBox"/>

 

            lbMyListBox.Items.Add("Augustus");
            lbMyListBox.Items.Add("Tiberius");
            lbMyListBox.Items.Add("Caligula");

Finally, to use data binding to add the items:

    <ListBox ItemsSource="{Binding Emperors}"/>

 

    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private string[] emperors;
        public string[] Emperors
        {
            get { return emperors; }
            set
            {
                if (value != emperors)
                {
                    emperors = value;
                    RaisePropertyChanged("Emperors");
                }
            }
        }

        public MainWindow()
        {
            this.InitializeComponent();
            this.DataContext = this;

            Emperors = new string[]
                {"Augustus",
                 "Tiberius",
                 "Caligula"};
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        private void RaisePropertyChanged(string propName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }

958-001

#957 – A Survey of Some List-Based Controls

WPF includes a variety controls that can display lists of items, all of which inherit from ItemsControl.  Below is a sampling of some of these controls.

ItemsControl is the base class for all of the list-based controls and provides basic support for storing a collection of items and displaying them in a simple list.

957-001

 

HeaderedItemsControl displays a list of items along with some sort of header (typically displayed above the items).

957-002

 

ToolBar contains a collection of items that a user can interact with.

957-003

 

Menu and MenuItem allow displaying a list of selectable items in a menu.

957-004

 

ComboBox allows selecting an item from a dropdown list.

957-005

 

ListBox allows selecting an item from a visible list.

957-006

 

DataGrid displays a collection of items in a tabular format.

957-007

 

TabControl groups user interface content into a set of selectable tabs.

957-008

 

TreeView displays a collection of items as a hierarchy.

957-009

#956 – PasswordBox Stores Password as a SecureString

When you use the PasswordBox control to let a user enter a password, the resulting password is stored in a SecureString.  SecureString allows storing confidential data in memory in a more secure manner than is possible with the string data type.

If the security of the string entered into a PasswordBox is important, you should avoiding converting the password into a managed type.  You can access the entered password as a SecureString using the SecurePassword property, which returns a SecureString.

You can also cause the password stored in a PasswordBox to be decrypted and stored as a string by using the Password property.  Since copying the confidential data into a managed type is not as secure as letting it remain stored on the unmanaged heap, within the SecureString, you should only use the Password property if the security of the data is not critical.

#955 – Getting Data Out of a SecureString

Confidential data stored in an instance of the SecureString type is stored in memory on the unmanaged heap, in an encrypted form.

If you need to work with the data in an unencrypted form, you can read the data out of the SecureString into an unmanaged string (BSTR).  Once you are finished working with the confidential string data, you should zero out the memory where it was stored.

Below is an example of using the Marshal.SecureStringToBSTR method to work with string data stored in a SecureString.

        private void DoSomethingWithSecureStringData(SecureString secStr)
        {
            // using System.Runtime.InteropServices
            IntPtr unmStr = Marshal.SecureStringToBSTR(secStr);

            try
            {
                // Do something with unmanaged confidential string here.
            }
            finally
            {
                Marshal.ZeroFreeBSTR(unmStr);
            }
        }

When you call the SecureStringToBSTR method, the SecureString object decrypts its data and copies it to a new BSTR, before re-encrypting it.

 

#954 – Store Confidential Data Only Within SecureString Instances

You can use the SecureString class to securely store confidential text-based data.

The most important guideline, for security purposes, when using the SecureString class is:

Never store confidential data in a managed object (other than an instance of a SecureString)

If you transfer data from a SecureString into some managed object (e.g. a string or a byte array), the data will be less secure, due to the security issues with storing data in managed objects.

If you must work with confidential data in memory within your application, the proper procedure is to extract and decrypt the string data, but to store it in an unmanaged data structure (e.g. a BSTR).  The data will be vulnerable while in memory within the unmanaged object, but you can then explicitly delete the data when done working with it, limiting the amount of time during which the data is vulnerable.

#953 – Use a SecureString Object to Store Confidential Text Data

There can be security issues with storing confidential data in the System.String type, given that the string exists in plaintext in memory and you can’t explicitly control the amount of time during the string is present in memory.

The SecureString class provides a more secure way of storing confidential string data in memory.  SecureString is more secure than the String data type because:

  • It stores the string data in memory in an encrypted form
  • The encrypted data is stored in unmanaged memory and therefore not visible to the garbage collector
  • It allows appending, inserting or removing characters, but re-encrypts the data after modifying it
  • It is mutable, avoiding the need to create extra copies when modifying the secure string
  • It zeros out the contents of the string when the SecureString object is disposed (or finalized)

#952 – Security Issues with Managed Strings

Confidential data stored in strings is vulnerable to attack during the time period that the string is stored in memory.

String data stored in managed strings in .NET is less secure than data stored in unmanaged strings.  Plaintext (non-encrypted) string data in managed strings has a longer period of time during which it is stored in memory.

Because managed strings exist on the garbage collected heap, you can’t explicitly destroy them.  The data will remain in memory until after the garbage collector has released the memory and it has been overwritten by some other object.

Since strings are immutable, you can’t overwrite the string data in a managed string object.  Writing new data results in a new instance being created.  The Garbage Collector may also create extra copies when it compacts memory.  The string data is less secure, due to the likelihood of there being multiple copies and its longer lifetime.