peter
peter

Reputation: 13501

Stopping an item Being Selected in a listbox

I have a ListBox in silverlight. I want to validate what the user is doing, and stop them selecting a different item if the current item is not valid. This is because I am displaying other fields in an edit pane which correspond to the item selected in the ListBox.

How can I do this? This is what I currently have,

<ListBox SelectedItem="{Binding SelectedTemplate, Mode=TwoWay}" />
</ListBox>

The viewmodel looks like this,

public EmailTemplateEntity SelectedTemplate
    {
        get { return selectedTemplate; }
        set 
        {
            if (not valid)
            {
                RaisePropertyChanged(this, x => x.SelectedTemplate); // to reset it to the previous value
            }
            else
            {
                selectedTemplate = value;
            }
        }
    }

But it doesn't work. The getter is called if it drops into the not valid code, but the item selected is the one you selected rather than the previous one.

UPDATE:

So here I have written a WPF app,

<ListBox SelectedValuePath="Content" SelectedValue="{Binding SelectedItem, Mode=TwoWay}">
        <ListBoxItem>Test</ListBoxItem>
        <ListBoxItem>Test1</ListBoxItem>
        <ListBoxItem>Test2</ListBoxItem>
        <ListBoxItem>Test3</ListBoxItem>
        <ListBoxItem>Test4</ListBoxItem>
</ListBox>

And the viewmodel,

public class ViewModel : INotifyPropertyChanged
{
    public string SelectedItem
    {
        get
        {
            return "Test1";
        }
        set
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("SelectedItem"));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

Which I would expect to only allow the item Test1 to be selected, but that does the same thing.

The same applies if I make the items a string list in the viewmodel, and bind the itemssource to that list.

Using snoop I get a hint about the problem. The SelectedValue is set correctly, but the control has a list called 'SelectedItems', and it is this which is set incorrectly. This is a readonly field.

Upvotes: 1

Views: 244

Answers (2)

peter
peter

Reputation: 13501

It must be a timing issue, well more of an 'order' issue. If I do this,

<ListBox Name="ListBox" SelectedValuePath="Content" ItemsSource="{Binding Items}" SelectionChanged="ListBox_SelectionChanged">
</ListBox>

WIth code behind,

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    ListBox.SelectedItem = "Item2";
}

Then it works. The ListBox_SelectionChanged event fires after the setters and getters in the ViewModel if we are binding to SelectedValue. It must relate to us setting the SelectedItem right at the end after it has done all of the other internal things it is going to do.

Upvotes: 0

Ekk
Ekk

Reputation: 5715

You need to add validation before set value to your backing field then notify change to UI.

public EmailTemplateEntity SelectedTemplate
{
    get { return selectedTemplate; }
    set 
    {
        // if value is valid then assign the value to your backing field.
        if (IsValid(value))
        {
            selectedTemplate = value;
        }

        // notify changed back to UI, if value is value new selected value is apply, if value is invalid then the value of your backing field is not change and old value is notify to UI.
        RaisePropertyChanged(this, x => x.SelectedTemplate);
    }
}

private bool IsValue(EmailTemplateEntity entity)
{
    // do validation here.
}

Upvotes: 1

Related Questions