gpt4 book ai didi

WPF 互斥列表框

转载 作者:行者123 更新时间:2023-12-04 16:22:52 26 4
gpt4 key购买 nike

我有一个具有 ListBox 列表框的应用程序。我想让 InnerList 框互斥。我的 ViewModel 有一个集合 Foos ,它有一个描述、一个 IsSelected 属性和一个集合 Bars ,它有一个 name 和 IsSelected 属性。

public class MyViewModel : INotifyPropertyChanged
{
public ObservableCollection<Foo> Foos { /* code removed for brevity */ }
}

public class Foo : INotifyPropertyChanged
{
public string Description { /* code removed for brevity */ }
public ObservableCollection<Bar> Bars { /* code removed for brevity */ }
public bool IsSelected { /* code removed for brevity */ }
}

public class Bar : INotifyPropertyChanged
{
public string Name { /* code removed for brevity */ }
public bool IsSelected { /* code removed for brevity */ }
}

下面是我的 MainWindow 的一部分,其 DataContext 设置为 MyViewModel。此 ListBox 的 ItemsSource 属性使用 ItemsSource={Binding Path=Foos} 绑定(bind)。在这个 ListBox 的模板中是一个内部 ListBox,它使用 ItemsSource="{Binding Path=Bars}" 绑定(bind)。 . A、B 和 C 是 Foos 的描述。其中包含的项目是酒吧的名称。
|--------------------------|
| A |--------------------| |
| | Item 1 | |
| | Item 2 | |
| | Item 3 | |
| |--------------------| |
| |
| B |--------------------| |
| | Item X | |
| | Item Y | |
| | Item Z | |
| |--------------------| |
| |
| C |--------------------| |
| | Item l | |
| | Item m | |
| |--------------------| |
|--------------------------|

我需要这样做,以便用户只能从任何条中选择一个项目。因此,如果用户从 Foo A 中选择了 Item 1,然后从 Foo B 中选择了 Item X,则应取消选择 Item 1。

我还需要将所选项目绑定(bind)到窗口上其他地方的 TextBox 控件,但我想每次只有一件事。

在代码和选择更改事件中执行此操作不是一种选择。我宁愿只使用 XAML 来保留它。

提前致谢。

更新
按照 Moonshield 的建议,我想出了这个,但它仍然没有完全起作用。
public class MyViewModel
{
private Bar _selectedBar;

public ObservableCollection<Foo> Foos { /* code removed for brevity */ }
public Bar SelectedBar
{
get { return _selectedBar; }
set
{
_selectedBar = null;
NotifyPropertyChanged("SelectedBar");

_selectedBar = value;
NotifyPropertyChanged("SelectedBar");
}
}
}
<ListBox x:Name="lbFoos" ItemsSource="{Binding Path=Foos}" SelectedItem="{Binding Path=SelectedBar}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<StackPanel>
<TextBlock Text="Foo: " />
<TextBlock Text="{Binding Path=Description}" />
<ListBox ItemsSource="{Binding Path=Bars}" SelectedItem="{Binding Path=SelectedItem RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ListBox}}}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<TextBlock Text="{Binding Path=Name}" />
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=OneWayToSource}" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>

最佳答案

最简单的方法可能是将 SelectedBar 属性添加到 MyViewModel 类并将列表框的 SelectedItem 属性绑定(bind)到该属性。这只允许一次选择一个项目,并为您提供稍后将文本框绑定(bind)到的内容。

然后,您可以在每个 ListBoxItem 的 IsSelected 属性上设置绑定(bind) (OneWayToSource)(可能通过 ItemContainerStyle)以更新每个栏的 IsSelected 属性。要更新 Foo 对象的 IsSelected 属性,请使用 valueconverter 设置与列表框的 SelectedItem 的绑定(bind)以检查它是否为空。

编辑:

SelectedItem 属性(实现 Dan 的修复):

protected Bar selectedItem;
public Bar SelectedItem{
get
{
return selectedItem;
}
set
{
selectedItem = null;
NotifyPropertyChanged("SelectedItem");

selectedItem = value;
NotifyPropertyChanged("SelectedItem");
}

带绑定(bind)的 ListBoxItem(假设 ListBoxItem DataContext 是 Bar viewmodel):
<ListBoxItem IsSelected="{Binding Path=IsSelected, Mode=OneWayToSource}" />

编辑 - 修复您的代码:

我设法让你的代码工作。我发现了两个问题:
  • 项目没有出现选择的原因是您重新模板化了填充有 Bar 对象的 ListBoxItems,因此选择项目时没有突出显示样式 - 通过设置 ItemTemplate 来解决此问题,它模板化了项目而不是覆盖整个模板。
  • 我没有将嵌套列表框之一的 SelectedItem 绑定(bind)到父项的 SelectedItem 索引,然后将其绑定(bind)到 View 模型,而是将绑定(bind)更改为直接绑定(bind)到 View 模型,从而解决了多选问题。
    <ListBox x:Name="lbFoos" ItemsSource="{Binding Path=Foos}"> <!--Removed SelectedItem binding.-->
    <ListBox.ItemContainerStyle>
    <Style TargetType="{x:Type ListBoxItem}">
    <Setter Property="Template">
    <Setter.Value>
    <ControlTemplate TargetType="{x:Type ListBoxItem}">
    <StackPanel>
    <TextBlock Text="Foo: " />
    <TextBlock Text="{Binding Path=Description}" />
    <ListBox ItemsSource="{Binding Path=Bars}" SelectionChanged="ListBox_SelectionChanged" SelectedItem="{Binding Path=DataContext.SelectedBar, RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ListBox}}}"><!--Changed binding to bind directly to ViewModel-->
    <ListBox.ItemTemplate><!--Set ItemTemplated rather than ControlTemplate-->
    <DataTemplate>
    <TextBlock Text="{Binding Path=Name}" />
    </DataTemplate>
    </ListBox.ItemTemplate>
    <ListBox.ItemContainerStyle>
    <Style TargetType="ListBoxItem">
    <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=OneWayToSource}" />
    </Style>
    </ListBox.ItemContainerStyle>
    </ListBox>
    </StackPanel>
    </ControlTemplate>
    </Setter.Value>
    </Setter>
    </Style>
    </ListBox.ItemContainerStyle>
    </ListBox>
  • 关于WPF 互斥列表框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4293253/

    26 4 0