views:

289

answers:

5

I have a listbox and I want to prevent changing of ListBox's selection if user has not finished certain tasks, this is the best explanation i can provide at this time, in WinForms there used to be selection changing and it has cancellable event arguement, where in we could trap and cancel even of changing the selection.

I thought I will inherit listbox and do something but internally all functionalities in Selector class are hidden that I can see in reflector but there is no way i can inherit and override any methods !!

A: 

I know this doesn't directly answer your question, but in most cases (I'd need to be convinced of a reason not to), I would simply not enable to control until the criteria for selection is met.

This simple step removes most of the complexity of figuring out that the value changed, and if it was a valid change, etc. If you allow the comboxbox to be edited (i.e. a value typed in), that adds another level of complexity.

Otherwise, here is a related discussion: http://stackoverflow.com/questions/314503/how-to-prevent-cancel-a-comboboxs-value-change-in-c

Wonko the Sane
I was using exact same solution till date but its not very great and now my code became so complex its just giving me more and more problems so i thought i will try something else better, anyway thanks for your answer.
Akash Kava
It's tough to tell your design from the information given. However, in most cases, you can bind the IsEnabled property of the control to some property in your code-behind, be it right in the Window's class, or (better yet) in the ViewModel in a MVVM application. This property that you define would then simply be defined by your business rules as to when you can change the selection in that combobox. You have to define these rules at some point, anyway, and it is easier in most cases to define these ahead of time, rather than in validating the control. [Continued in next comment]
Wonko the Sane
[Part Two]In other words, its probably easier to say, "I have done A and B, so now I can do C," rather than "I am trying to do C. Have I done A? Yes, so have I done B? No? So undo C."If your code is getting too complex because of that, take a step back and look at the design. In my experience, if you feel it is getting too complex, you are probably right. Think of it again without thinking of code - draw pictures or diagrams if it helps. Usually, you will find clarity if you think of it in this way, and then you just code to your picture.Hope that makes sense, and helps...
Wonko the Sane
MVVM doesnt help, its good but I cant use it in my application, second, even if I will try to use MVVM, ListBox already displays the new value selected even if I try to control from viewmodel. However I intercepted mouse event to fire my custom event requesting cancellation of selection change, that works as of now.
Akash Kava
A: 

One solution would be to make the ListBox and ListBoxItems not focusable until you are ready for the user to change them. Here is a quick mock-up that accomplished this:

XAML:

<StackPanel>
        <ListBox x:Name="LB">
            <ListBoxItem Focusable="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=Focusable}"  Content="item 1"/>
            <ListBoxItem Focusable="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=Focusable}" Content="item 2"/>
            <ListBoxItem Focusable="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=Focusable}" Content="item 3"/>
            <ListBoxItem Focusable="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=Focusable}" Content="item 4"/>
            <ListBoxItem Focusable="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=Focusable}" Content="item 5"/>
            <ListBoxItem Focusable="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=Focusable}" Content="item 6"/>
        </ListBox>
        <Button Content="Lock/Unlock" Click ="Button_Click"/>
    </StackPanel>

Code:

   private void Button_Click(object sender, RoutedEventArgs e)
    {
        if (LB.Focusable == true)
            LB.Focusable = false;
        else
            LB.Focusable = true;
    }
Ben Collier
Nice suggestion but cant use it in my current environment as i need to alert user when they are trying to change it, if i block the changing functionality then they will think that program stalled !!
Akash Kava
A: 

Bind IsSelected to a property in your view model class, and handle the case in the property's setter, e.g.:

public bool IsSelected
{
   get { return _IsSelected; }
   set
   {
       if (value && DisableSelection)
       {
          AlertUser();
       }
       else
       {
          _IsSelected = value;
       }
       OnPropertyChanged("IsSelected");
   }
}

Note that you raise the PropertyChanged event even if the property didn't change, because from the view's perspective it actually did change.

Robert Rossney
This doesnt work because ListBox already shows new selection, and that is what we want to prevent, and I am not using MVVM.
Akash Kava
Oh, then what you want to do is handle the `PreviewMouseDown` event on the ListBox and set `Handled` to `true`.
Robert Rossney
Yes I did the same, but it looks like a workaround, however I did it differently, I have my own custom control derived from ListBox and have my own container item which handles mouse down and raises selection changing event.
Akash Kava
A: 

I derived a class MyListBox from ListBox and added event called SelectionChanging which is cancellable event. Then I used MyListBoxItem as ItemContainer in MyListBox which handles Preview Left Mouse Up event and raises Selection Changing event, on cancel value, I mark event as handled, which prevents new selection as well as it allows me to notify user to do someting.

Akash Kava