WPF / MVVM将ListBoxItem模板中的CheckBox绑定到SelectedItem属性

时间:2013-07-26 08:07:44

标签: wpf mvvm listbox checkedlistbox

我正在构建一个WPF应用程序(.NET 4.0),我有以下情况:

<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>
  • ListBox的ItemSource绑定到ObservableCollection&lt;&gt;。
  • ListBox的SelectedItem绑定到SelectedItem属性 ViewModel。

但是,当ViewModel.SelectedItem更新时,会启动一些长时间运行(2-3s)的异步任务。 通过简单地在列表框中选择不同的项目来排队大量异步任务太简单了,所以我正在研究将ViewModel.SelectedItem绑定到CheckBox(包含在ItemTemplate中)。

我对WPF相当新,但是在表单中我会附加一个事件处理程序并编写一些冗长而丑陋的代码来取消检查除触发事件的所有项目,然后以编程方式更新属性。

在WPF中,我希望有一些更好的解决方案,我已经研究过如何使用ValueConverter,但我无法弄清楚如何绑定到父View-Model(具有ObservableCollection&lt;&gt;)。 / p>

如果有人遇到类似的要求,我真的很感激一些指示。

干杯!

./弗雷德里克

3 个答案:

答案 0 :(得分:0)

您好,您可以将CheckBox绑定到VM的命令,当选中/取消选中CheckBox时,命令将触发。

答案 1 :(得分:0)

您可以通过TemplateBinding将ListBoxItem的isselected属性绑定到checkbox。

答案 2 :(得分:0)

我想出了一个解决方案,它不会在代码隐藏中处理已检查的状态,所以我将把它记录下来以供后代使用。

第一个技巧是使用RadioButton来代替GroupName。同一组中的单选按钮将自动确保在任何给定时间仅检查其中一个,这避免了手动管理已检查状态的问题。

第二个技巧是将CommandParameter绑定到单选按钮DataContext

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

单击按钮命令会在每次点击时触发,而不仅仅是在检查时,但我们侥幸成功,因为与CheckBox不同,无法取消选中单选按钮,因此双击收音机按钮只会确认SelecedItem

如果SelectedItem属性触发PropertyChanged事件,建议让命令处理程序检查它是否实际上设置了一个新值,或者只是重复前一个值:

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