【问题标题】:WPF MVVM Master Detail View with TreeView Control带有 TreeView 控件的 WPF MVVM 主详细信息视图
【发布时间】:2016-08-18 09:06:02
【问题描述】:

我想使用 WPF TreeView 控件和 MVVM 设计模式实现主/详细视图(非常类似于 Windows 资源管理器)。我对处理 TreeView 控件很安全,但我不知道如何将主视图(TreeView)中当前选定的项目作为 DataContext 传递给 Detail 视图(实际上是一个持有 ListView 的 UserControl)。最好我想做那个 XAML。有人知道怎么做吗?

为了澄清,我将在这里发布一个小地址簿演示。

这是主窗口视图,它基本上使用网格将客户区分成三列。左边是树,中间是拆分器,右边是细节视图。

<Window.Resources>
    <HierarchicalDataTemplate DataType="{x:Type vm:Address}" ItemsSource="{Binding Residents}">
        <TextBlock>
            <TextBlock.Text>
                <MultiBinding StringFormat="{}{0}, {1}, {2}">
                    <Binding Path="Street"/>
                    <Binding Path="City"/>
                    <Binding Path="ZipCode"/>
                </MultiBinding>
            </TextBlock.Text>
        </TextBlock>
    </HierarchicalDataTemplate>

    <DataTemplate DataType="{x:Type vm:Resident}">
        <TextBlock>
            <TextBlock.Text>
                <MultiBinding StringFormat="{}{0} {1}">
                    <Binding Path="FirstName"/>
                    <Binding Path="LastName"/>
                </MultiBinding>
            </TextBlock.Text>
        </TextBlock>
    </DataTemplate>
</Window.Resources>

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="150"/>
        <ColumnDefinition Width="5"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <TreeView BorderThickness="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding Addresses}"/>
    <GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch" />
    <v:ResidentDetailView Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" DataContext="???"/>
</Grid>

正如您在最后一行中看到的,我想将树中的选定项目作为 DataContext 传递给详细信息视图。

这是一个用户控件的详细信息视图:

<ListView ItemsSource="{Binding Residents}">
    <ListView.View>
        <GridView>
            <GridViewColumn DisplayMemberBinding="{Binding FirstName}" Header="FirstName" Width="100"/>
            <GridViewColumn DisplayMemberBinding="{Binding LastName}" Header="LastName" Width="100"/>
        </GridView>
    </ListView.View>
</ListView>

最后是我想在主视图和详细视图之间共享的主窗口视图模型:

public class Resident
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
    public int ZipCode { get; set; }
    public List<Resident> Residents { get; } = new List<Resident>();
}

public class MainWindowViewModel
{
    public ObservableCollection<Address> Addresses { get; } = new ObservableCollection<Address>();

    public MainWindowViewModel()
    {
        var a = new Address {Street = "Broadway 1", City = "New York", ZipCode = 12345};
        a.Residents.Add(new Resident { FirstName = "John", LastName = "Miller" });
        a.Residents.Add(new Resident { FirstName = "Lisa", LastName = "Miller" });
        Addresses.Add(a);
        a = new Address { Street = "Wall Street 1", City = "New York", ZipCode = 12345 };
        a.Residents.Add(new Resident { FirstName = "Paul", LastName = "Walker" });
        a.Residents.Add(new Resident { FirstName = "Frank", LastName = "Brown" });
        a.Residents.Add(new Resident { FirstName = "Mark", LastName = "Smith" });
        Addresses.Add(a);
        a = new Address { Street = "Market Street 1", City = "San Francisco", ZipCode = 23456 };
        a.Residents.Add(new Resident { FirstName = "Jack", LastName = "Ness" });
        a.Residents.Add(new Resident { FirstName = "Joe", LastName = "Jackson" });
        a.Residents.Add(new Resident { FirstName = "Jill", LastName = "Baude" });
        Addresses.Add(a);
        a = new Address { Street = "Rodeo Drive 1", City = "Los Angeles", ZipCode = 34567 };
        a.Residents.Add(new Resident { FirstName = "Roger", LastName = "Water" });
        a.Residents.Add(new Resident { FirstName = "Andy", LastName = "Murray" });
        a.Residents.Add(new Resident { FirstName = "Peter", LastName = "Hammer" });
        a.Residents.Add(new Resident { FirstName = "Lola", LastName = "White" });
        Addresses.Add(a);
    }
}

感谢您的帮助。 约翰内斯

【问题讨论】:

  • 长问题,而您只是问“我不知道如何在主视图中传递当前选定的项目”。见this
  • 嗯,我希望得到像 这样的答案,我在这里找到了stackoverflow.com/questions/15206671/…。不幸的是,它不起作用
  • 我知道我可以使用混合交互来处理 VM 中的选择更改事件,例如然后更新 DetailsVM 并使 Details 视图自行更新。但我仍然希望这应该做得更简单

标签: c# wpf xaml mvvm treeview


【解决方案1】:

这当然可以通过您在其他线程中找到的那种绑定来实现。

但是,我只需将当前选定项目的属性添加到 ViewModel。无论如何,跟踪它可能会很好(例如,如果您想在他们单击其他内容时更改详细信息视图):

public class MainWindowViewModel
{
    public ObservableCollection<Address> Addresses { get; } = new ObservableCollection<Address>();

    public Address SelectedAddress { //get and set with INotifyPropertyChanged }

    public MainWindowViewModel()
    {
        ...
    }
}

在视图中:

<TreeView BorderThickness="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding Addresses}" SelectedItem="{Binding SelectedAddress}"/>
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch" />
<v:ResidentDetailView Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" DataContext="{Binding SelectedAddress}"/>

【讨论】:

  • 是的,这就是我要找的。谢谢。
猜你喜欢
  • 2016-08-16
  • 2011-10-05
  • 1970-01-01
  • 2011-01-30
  • 1970-01-01
  • 2018-05-22
  • 2010-09-28
  • 1970-01-01
  • 2010-12-06
相关资源
最近更新 更多