【问题标题】:WPF Explorer-like MVVM ListBox-in-ListBox (master-detail) binding expressionWPF Explorer-like MVVM ListBox-in-ListBox (master-detail) 绑定表达式
【发布时间】:2012-01-23 00:54:52
【问题描述】:

我的情况的一行总结:当我选择一个detail item时,master仍然没有被选中,所以我得到了错误的detail item。

假设两个ViewModel MasterList 和DetailList 都是ObservableCollection,并尝试制作类似Explorer 的GUI。左侧面板具有主从列表框,右侧面板将显示选定的详细信息项之一。无需在右侧面板中显示主信息。

在我的左侧面板中,ListBox 控件的编码如下。

<ListBox x:Name="listBoxMaster" ItemsSource="{Binding Path=MasterList}" SelectionMode="Extended"
            IsSynchronizedWithCurrentItem="True">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <ListBox x:Name="listBoxDetail" ItemsSource="{Binding Path=DetailList}" IsSynchronizedWithCurrentItem="True" />
        </DataTemplate>
</ListBox.ItemTemplate>

请注意,我将 IsSynchronizedWithCurrentItem="True" 设置为两个 ListBox 控件。

在右侧面板中,选择的详细项目信息将显示如下绑定。让我们简化名为 DetailItemClass 的详细项目类,它具有 Name 和 Number 属性。

试用 1

<WrapPanel Name="wrapPanel1" DataContext="{Binding ElementName=listBoxMaster, Path=SelectedItem}">
    <StackPanel DataContext="{Binding Path="DetailList/">
        <TextBox Text="{Binding Path=Name}" />
        <TextBox Text="{Binding Path=Number}" />
    </StackPanel>
</WrapPanel>

出现了奇怪的 GUI 问题。 如果有的话。

  • Master1 有详细信息 1,2,3。
  • Master2 有细节 4,5,6。

当我选择 M1-D2 时,它可以工作。 之后,当我选择细节 M2-D4 时,它可以工作。 但是,在那之后,当我再次选择 M1-D2 时,它不起作用!预选项目可能不会更新其要选择的主项目。 此外,有时 M2-D5 选择会在右侧面板中给出 M1-D2。 奇怪。

试用 2

<WrapPanel Name="wrapPanel1" DataContext="{Binding Path=MasterList/DetailList/}">
    <StackPanel>
        <TextBox Text="{Binding Path=Name}" />
        <TextBox Text="{Binding Path=Number}" />
    </StackPanel>
</WrapPanel>

只是行不通。虽然我将 IsSynchronizedWithCurrentItem 设置为 true,但是失败了。我不知道为什么。

试用 3

我只是摆脱了 DataContext XAML 绑定并在代码隐藏处使用事件触发器,如下所示。

    private void listBoxMaster_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (e.AddedItems.Count == 1)
        {
            if (e.AddedItems[0] is DetailItemClass)
            {
                var element = (DetailItemClass)e.AddedItems[0];
                wrapPanel1.DataContext = element;
            }
        }
    }

它工作得很好,但它不使用 XAML 绑定。

你能教我正确的绑定表达式吗?

【问题讨论】:

  • 为什么要用ListBox的ListBox?这不酷,也不会工作。有针对这种情况的 TreeView 控件。
  • 最后我用TreeView控件解决了。

标签: wpf xaml binding mvvm master-detail


【解决方案1】:

你试过了吗:

<WrapPanel Name="wrapPanel1" DataContext="{Binding ElementName=listBoxMaster, Path=SelectedItem}">
    <StackPanel>
        <TextBox Text="{Binding Path=DetailList.Name}" />
        <TextBox Text="{Binding Path=DetailList.Number}" />
    </StackPanel>
</WrapPanel>

<WrapPanel Name="wrapPanel1">
    <StackPanel>
        <TextBox Text="{Binding ElementName=listBoxMaster, Path=SelectedItem.DetailList.Name}" />
        <TextBox Text="{Binding ElementName=listBoxMaster, Path=SelectedItem.DetailList.Number}" />
    </StackPanel>
</WrapPanel>

这些是为了确保DataContext是否实际上是级联的。

【讨论】:

  • 不,没有用。点运算符与DetailList(DetailItemClass的ObservableCollection)一起使用是否正确?我也尝试了您的建议和 DetailList/Name,但两个表达式都不起作用。
  • 是的,点可以正常工作,因为 SelectedItem 已经在它所代表的项目的上下文中。所以,数据类型其实和列表项是一样的。
  • 为了更好地解决这个问题,您可以将您的项目发布到某个地方以便我们可以看到整个画面吗?
  • 感谢您的帮助。让我先用TreeView控件试试,如果做不到我会贴出更多细节。
【解决方案2】:

您不应该使用多个列表框,因为会有很多与多选相关的问题。例如,您可以选择第一个列表框,但从第二个列表框中选择项目。

ItemsControl 类替换外部列表框,这样它就不会收到选择并且无法获得焦点。

还将单个属性添加到包含所有列表的单个选定项的根模型。我使用非常简单的模型复制了您的层次结构,在此示例中,此属性称为SelectedDetailItem

public class MasterListViewModel : INotifyPropertyChanged
{
    public ObservableCollection<DetailListViewModel> MasterList { get; set; }

    private ItemViewModel _selectedDetailItem;

    public ItemViewModel SelectedDetailItem
    {
        get { return _selectedDetailItem; }
        set
        {
            _selectedDetailItem = value;
            OnPropertyChanged("SelectedDetailItem");
        }
    }
}

public class DetailListViewModel
{
    public ObservableCollection<ItemViewModel> DetailList { get; set; }
}

public class ItemViewModel
{
    public string Title { get; set; }
}

并将此属性绑定到两个控件:

<ItemsControl x:Name="listBoxMaster" ItemsSource="{Binding Path=MasterList}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ListBox x:Name="listBoxDetail" ItemsSource="{Binding Path=DetailList}" DisplayMemberPath="Title" 
                        SelectedItem="{Binding DataContext.SelectedDetailItem, Mode=TwoWay, ElementName=listBoxMaster}"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

<WrapPanel Name="wrapPanel1" DataContext="{Binding SelectedDetailItem}" Grid.Column="1">
    <TextBox Text="{Binding Path=Title}" />
</WrapPanel>

【讨论】:

  • 感谢您的回答。我发现 ItemsControl 没有用于多选的 SelectionMode 属性。有什么办法可以多选主列表吗?因为我需要让用户可以选择多个主项目以删除或移动到某个地方。 (或者最好的建议是 TreeView 控件?)
  • @Youngjae 没有简单的方法可以通过使用数据绑定来处理多项选择:stackoverflow.com/questions/2511708/…。因此,它需要大量的代码隐藏才能正确实现。
  • @Youngjae 顺便说一下,Windows 资源管理器不允许在左侧面板上选择多个项目。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-09
  • 1970-01-01
  • 2011-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多