列表框中DataTemplate的数据绑定:如何判断项是否被选中?

3
我将尝试简单地将我的类中的IsSelected字段与IsSelected属性进行数据绑定。但是在我更改代码的值之后,它并没有改变属性,点击ListBoxItem也无法改变字段的值。
XAML:
<FlipView ItemsSource="{Binding Source={StaticResource itemsViewSource}}" ... >
    <FlipView.ItemTemplate>
        <DataTemplate>
            <UserControl Loaded="StartLayoutUpdates" 
                Unloaded="StopLayoutUpdates">
                <!-- other controls -->
                <ListBox Grid.Row="1" Grid.ColumnSpan="3"
                    SelectionMode="Multiple" VerticalAlignment="Center" 
                    ItemsSource="{Binding Answers}">
                    <ListBox.Resources>
                        <local:LogicToText x:Key="logToText" />
                    </ListBox.Resources>

                     <!-- bind IsSelected only in one way from 
                         code to content --> 
                     <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <ListBoxItem 
                              IsSelected="{Binding IsSelected, Mode=TwoWay, Converter={StaticResource logToText}}" 
                              Content="{Binding IsSelected, Mode=TwoWay, Converter={StaticResource logToText}}">

                            </ListBoxItem>

                        </DataTemplate>
                    </ItemsControl.ItemTemplate>


                    <!-- not working at all
                    <ListBox.Resources>
                        <Style TargetType="ListBoxItem">
                            <Setter Property="IsSelected" 
                                Value="{Binding IsSelected, Mode=TwoWay}"/>
                            <Setter Property="Content" 
                                Value="{Binding IsSelected, Mode=TwoWay}"/>
                        </Style>
                    </ListBox.Resources>-->

                </ListBox>
            </UserControl>
        </DataTemplate>
    </FlipView.ItemTemplate>
</FlipView>

代码:

答案

private ObservableCollection<PrawoJazdyDataAnswer> _answers = 
    new ObservableCollection<PrawoJazdyDataAnswer>();
public ObservableCollection<PrawoJazdyDataAnswer> Answers 
{ 
    get 
    { 
       return this._answers; 
    }  
}    

单项(答案)

public class PrawoJazdyDataAnswer : NPCHelper// PrawoJazdy.Common.BindableBase
{
    public PrawoJazdyDataAnswer(String ans, bool ansb)
    {
        this._ans = ans;
        this._isSelected = ansb;
    }

    public override string ToString() 
    { 
        return _isSelected.ToString();  //Only For debug purposes 
                                        //normally return _ans 
    }
    private string _ans;
    public string Ans
    {
        get { return this._ans; }
        //set { this.SetProperty(ref this._ans, value); }
    }

    private bool _isSelected;
    public bool IsSelected
    {
        get { return this._isSelected; }
        set
        {
            _isSelected = value;
            FirePropertyChanged("IsSelected");
            //this.SetProperty(ref this._isSelected, value); 
        }
    }
}

FirePropertyChanged

public class NPCHelper : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void FirePropertyChanged(string prop)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
    }
}

转换器(有时似乎需要,有时不需要……我尝试了来自不同教程/示例的约10种方法)

public class LogicToText : IValueConverter
{
    /// <summary>
    /// 
    /// </summary>
    public object Convert(object value, Type targetType, 
                          object parameter, string language)
    {
        //if (value == null || (bool)value == false)
          //  return "False";

        return value.ToString();
    }

    /// <summary>
    /// 
    /// </summary>
    public object ConvertBack(object value, Type targetType, 
                              object parameter, string language)
    {
        return value.ToString().Contains("True") ? true : false;
    }

谢谢您的提前帮助,我的英语还在学习中,请见谅。

@编辑 感谢您的快速回复。

为了测试目的,我创建了一个按钮和文本块:

<Button Click="spr" >Sprawdź</Button>
<TextBlock Text="{Binding Answers[0].IsSelected, Mode=TwoWay}" > </TextBlock> 

这个在其他控件部分(列表框上方,但在FlipView中) 点击方法

private void spr(object sender, RoutedEventArgs e)
    {
        var ans = ((PrawoJazdyDataQuestion)this.flipView.SelectedItem).Answers;
        foreach (var item in ans)
            item.IsSelected = item.IsSelected ? false : true;
    }

当我从代码端改变数据时,它会改变元素的内容,但不会改变ListBoxItem的外观。如果我只是在ListBox上选择它,它既不会改变TextBlock中的数据,也不会改变ListBox本身中的数据。
@edit2 修正了拼写错误...

转换器不应该需要,因为绑定源和目标属性都是 bool 类型。但是我认为一切看起来都很好。你能否发布一些更新属性的示例代码? - Dylan Meador
2个回答

11

要更改 ListBoxItemIsSelected 属性,您需要更改 ListBox.ItemContainerStyle。请参见此处:

<ListBox Grid.Row="1" Grid.ColumnSpan="3"
                SelectionMode="Multiple" VerticalAlignment="Center" 
                ItemsSource="{Binding Answers}">
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
        </Style>
    </ListBox.ItemContainerStyle>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding IsSelected}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

由于绑定模式为 TwoWay,选择和取消选择 ListBoxItem 动态更改了项目内容以显示 TrueFalse

还要注意我将 ListBox.ItemTemplate 更改为 TextBlock 而不是 ListBoxItemItemTemplate 定义了 ListBoxItem 的内容,因此通常使用某种类型的内容控件。下面是不同布局的 UI 结构(可以使用 WPF 树形可视化器查看)。

ListBoxItem 作为 ItemTemplate

enter image description here

TextBlock 作为 ItemTemplate

enter image description here

编辑

还请注意,我删除了 IValueConverter。由于您的源属性和目标属性都是 bool,在这种情况下不需要转换器。尝试删除转换器引用,看看是否解决了问题。


谢谢回复,但是在代码更改后,它仍然以它习惯的方式工作,文本正在改变,但选择并没有出现。 - Kinmarui
@Kinmarui 好的。我的意思是在 PrawoJazdyDataAnswer 类的 IsSelected 属性设置器中设置断点。如果绑定设置正确,当您选择/取消选择列表项时,该设置器应该被触发。 - Dylan Meador
如果你的意思是public bool IsSelected { set {_isSelected = value;} },那么它在我点击ListBox中的项目时不会被触发,只有当我点击按钮时才会触发。 - Kinmarui
@Kinmarui 那个 setter 应该已经触发了。由于某些原因,绑定没有起作用。您可以在输出窗口中查找绑定错误(如果您没有看到任何内容,则可能需要将此选项 工具->选项->调试->输出窗口->WPF 跟踪设置->数据绑定 设置为 Warning)。此外,这里 是我创建的测试项目的所有代码,它可以正常工作。 - Dylan Meador
@MeadorDylan
没有错误或警告。 非常感谢您的帮助, 现在我能想到的唯一一件事是,为什么它不起作用是因为listBoxDataTemplate中,在您的示例中不是这样。现在我尝试通过将SelectedItems属性与代码后台中的另一个集合绑定来解决这个问题。
- Kinmarui
@Kinmarui,是的,很抱歉我找不到解决方案。我不确定发生了什么。有趣的是,在输出窗口中没有绑定消息,而且该属性的Setter也未被触发。 - Dylan Meador

1

不要将IsSelected绑定到ListBoxItem上。ListBox有SelectedItem或SelectedItems属性,您应该通过绑定将要选择的项传递给它们。 在模型中设置IsSelected属性不是一个好主意。最好在ViewModel中创建SelectedItem通知属性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接