سؤال

I am building a WPF application (.NET 4.0), and I have the following situation:

<ListBox
    ItemsSource="{Binding Path=Items}"
    SelectedItem="{Binding Path=SelectedItem}">
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="Height" Value="48"/>
        </Style>
    </ListBox.ItemContainerStyle>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <DockPanel>
                <!-- ... -->
                <CheckBox>
                    <CheckBox.IsChecked>
                        <!-- Something here that behaves like SelectedItem binding -->
                    </CheckBox.IsChecked>
                </CheckBox>
            </DockPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
  • The ItemSource of the ListBox is bound to an ObservableCollection<>.
  • The SelectedItem of the ListBox is bound to a SelectedItem property of the ViewModel.

However, when the ViewModel.SelectedItem is updated, a bit of a long-running (2-3s) asynchronous task is kicked off. It is way too easy to queue up a large numer of asynchronous task by simply selecting different items in the list box, so I am looking into binding ViewModel.SelectedItem to a CheckBox instead (included in the ItemTemplate).

I am fairly new to WPF, but in Forms I would have attached an event handler and written some long and ugly code to de-check all items but the one that triggered the event, then update the property programmatically.

In WPF I am hoping that there is some nicer solution, I have looked into using a ValueConverter, but I can't figure out how to bind to the parent View-Model (that has the ObservableCollection<>).

If anyone has encountered similar requirements, I would really appreciate some pointers.

Cheers!

./Fredrik

هل كانت مفيدة؟

المحلول 3

I figured out a solution that doesn't resort to processing the checked states in code-behind, so I'm going to document it for posterity.

The first trick is to use RadioButton instead, with and associated GroupName. Radio buttons within the same group will automatically ensure that only one of them is checked at any given time, which avoids the issue with manually managing the checked states.

The second trick is to bind a CommandParameter to the radio buttons DataContext.

<RadioButton
    Name="rdbSelected"
    GroupName="itemsRadioGroup"
    Command="{Binding 
        RelativeSource={RelativeSource AncestorType=UserControl},
        Path=DataContext.SelectItemCommand}" 
    CommandParameter="{Binding 
        RelativeSource={RelativeSource Self}, 
        Path=DataContext}"/>

The radio buttons command fires on every click, not just when it is checked, but we get away with this because unlike CheckBoxit is not possible to un-check a radio button, so double-clicking the radio button will only confirm the SelecedItem.

If the SelectedItem property fires a PropertyChanged event, it may be advisable to have the command handler check whether it is in fact setting a new value, or just repeating the previous one:

RelayCommand<object> cmd = new RelayCommand<object>(
    (o) =>
    {
       if (this.SelectedItem != o)
           this.SelectedItem = o;
    });

نصائح أخرى

Hi You can Bind the CheckBox to the Command to VM and the command will Fire when CheckBox is Selected/DeSelected.

You can bind isselected property of ListBoxItem to checkbox through TemplateBinding.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top