【发布时间】:2016-01-13 22:46:37
【问题描述】:
我有一个小应用程序来帮助自己学习 WPF 和 MVVM 等。我一直在使用 Josh Smith 找到的示例 here 来构建我自己的应用程序。我已经让应用程序添加了TabItems,但是绑定到ObservableCollection<ResourceViewModel> 的嵌入式DataGrid 没有显示任何数据,请参见下图:
DataGrid 是用蓝色包围的部分。 UserControl 似乎也出于某种原因在选项卡本身中显示,但这不是我在这里要问的问题。 UserControl 包含一个DataGrid,其绑定如下
<DataGrid ItemsSource="{Binding Resources}"
dataAccess:DataGridTextSearch.SearchValue="{Binding ElementName=searchBox,
Path=Text, UpdateSourceTrigger=PropertyChanged}"
AlternatingRowBackground="Gainsboro"
AlternationCount="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
...</DataGrid>
Resources 属性在 ViewModels 命名空间中定义为
internal class ResourceDataViewModel : WorkspaceViewModel
{
readonly ResourceDataRepository resourceRepository;
public ObservableCollection<ResourceViewModel> Resources { get; private set; }
...
}
ResourceViewmodel 保存DataGrid 每一行的信息。我可以确认 Resource 属性已填充。当我在 MVVM 之外使用相同的模型并以相同的方式填充 Resource 时。 有人可以告诉我为什么会发生这种情况吗?
我已尝试为绑定设置显式路径
ItemsSource="{Binding Path=(viewModels:Resources)}"
但这也行不通。感谢您的宝贵时间。
编辑。解决 cmets。我通过
在App.xaml.cs文件中设置了DataContext
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow window = new MainWindow();
// Create the ViewModel to which
// the main window binds.
MainWindowViewModel mainWindowViewModel = new MainWindowViewModel();
// When the ViewModel asks to be closed,
// close the window.
EventHandler handler = null;
handler = delegate
{
mainWindowViewModel.RequestClose -= handler;
window.Close();
};
mainWindowViewModel.RequestClose += handler;
// Allow all controls in the window to
// bind to the ViewModel by setting the
// DataContext, which propagates down
// the element tree.
window.DataContext = mainWindowViewModel;
window.Show();
}
MainWindow 的 XAML:
<Window x:Class="ResourceStudio.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModels="clr-namespace:ResourceStudio.ViewModels"
xmlns:views="clr-namespace:ResourceStudio.Views"
Title="MainWindow" Height="629.4" Width="814.4">
<Window.Resources>
<ResourceDictionary Source="MainWindowResources.xaml" />
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="284*"/>
<ColumnDefinition Width="567*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="48"/>
<RowDefinition Height="*"/>
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<DockPanel KeyboardNavigation.TabNavigation="None"
Background="#FFBEC8D8"
Grid.ColumnSpan="2"
Margin="0,0,0.4,0">
<Menu DockPanel.Dock="Top"
Background="#FFF9F9F9"
BorderBrush="Black"
KeyboardNavigation.TabNavigation="Cycle">
<MenuItem Header="_File">
<MenuItem Header="Load _Resource..."
Height="Auto"
Command="{Binding LoadResourceCommand}"/>
<MenuItem Header="_Add Language..."
Height="Auto"/>
<Separator/>
<MenuItem Header="Close _Workspace"
Height="Auto"
Command="{Binding CloseCommand}"/>
<MenuItem Header="E_xit"
Height="Auto" Command="{Binding CloseCommand}" />
</MenuItem>
<MenuItem Header="_Edit">
</MenuItem>
</Menu>
<ToolBarTray DockPanel.Dock="Top" MaxHeight="24" Background="#FFF9F9F9">
<ToolBar Background="#FFF9F9F9">
<Button ToolBar.OverflowMode="Never">One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ToolBar>
</ToolBarTray>
</DockPanel>
<Grid Grid.Row="1" Grid.ColumnSpan="2" Margin="0,0,0.4,23.6" Grid.RowSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TabControl ItemsSource="{Binding Path=Workspaces}"
Grid.Column="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
TabStripPlacement="Top"
Height="Auto"
Width="Auto">
</TabControl>
</Grid>
<StatusBar Grid.Row="2" Grid.ColumnSpan="2" Margin="0,0.4,0.4,-0.4">
<StatusBarItem DockPanel.Dock="Left" Background="#FF007ACC" Margin="0,2,0,0">
<TextBlock Text="Ready" Margin="5,0,0,0"/>
</StatusBarItem>
</StatusBar>
</Grid>
</Window>
MainWindowResources.xaml 在哪里:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModels="clr-namespace:ResourceStudio.ViewModels"
xmlns:views="clr-namespace:ResourceStudio.Views"
>
<!--This template applies a ResourceControl view to an instance of the
ResourceDataViewModel class shown in the main window.-->
<DataTemplate DataType="{x:Type viewModels:ResourceDataViewModel}">
<views:ResourceControl/>
</DataTemplate>
<!--This template explains how to render the 'Workspace'
content area in the main window.-->
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
Margin="4"/>
</DataTemplate>
</ResourceDictionary>
ResourceControl.xaml 的完整代码是:
<UserControl x:Class="ResourceStudio.Views.ResourceControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:viewModels="clr-namespace:ResourceStudio.ViewModels"
xmlns:dataAccess="clr-namespace:ResourceStudio.DataAccess"
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" Name="control">
<DockPanel DataContext="{Binding ElementName=control}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBox Text="M" DockPanel.Dock="Top" Name="searchBox" />
<Grid DockPanel.Dock="Top">
<Border BorderBrush="#FF007ACC" BorderThickness="2" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<DataGrid ItemsSource="{Binding Path=(viewModels:Resources)}"
dataAccess:DataGridTextSearch.SearchValue="{Binding ElementName=searchBox, Path=Text, UpdateSourceTrigger=PropertyChanged}"
AlternatingRowBackground="Gainsboro" AlternationCount="2" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<DataGrid.Resources>
<dataAccess:SearchValueConverter x:Key="searchValueConverter"/>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="dataAccess:DataGridTextSearch.IsTextMatch">
<Setter.Value>
<MultiBinding Converter="{StaticResource searchValueConverter}">
<Binding RelativeSource="{RelativeSource Self}" Path="Content.Text" />
<Binding RelativeSource="{RelativeSource Self}" Path="(dataAccess:DataGridTextSearch.SearchValue)" />
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="dataAccess:DataGridTextSearch.IsTextMatch" Value="True">
<Setter Property="Background" Value="Orange" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="#FF007ACC"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
</DataGrid>
</Border>
</Grid>
</DockPanel>
</UserControl>
TextBox 绑定到DataGrid。当用户输入TextBox 时,DataGrid 过滤并突出显示包含所需文本的单元格。然而,这不是问题,这段代码有效,它只是绑定到我感兴趣的DataGrid。再次感谢您的参观时间。
Edit2:根据@dkozl 的cmets,我已经从DockPanel 声明中删除了DataContext="{Binding ElementName=control}",所以我们现在有了
<DockPanel HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
...
在MainWindowResource.xaml我现在有
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModels="clr-namespace:ResourceStudio.ViewModels"
xmlns:views="clr-namespace:ResourceStudio.Views"
>
<!--This template applies a ResourceControl view to an instance of the
ResourceDataViewModel class shown in the main window.-->
<DataTemplate DataType="{x:Type viewModels:ResourceDataViewModel}">
<views:ResourceControl DataContext="{Binding}"/>
</DataTemplate>
<!--This template explains how to render the 'Workspace'
content area in the main window.-->
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
Margin="4"/>
</DataTemplate>
</ResourceDictionary>
这没有奏效。那就是我在ResourceControl 中的DataGrid 没有被填充。再次感谢您的宝贵时间,非常感谢...
【问题讨论】:
-
您能否提供有关如何在窗口中设置
DataContext-Property 的代码? -
您的用户控件
<DockPanel DataContext="{Binding ElementName=control}"必须控制自己,这没有任何意义。我会尝试删除DataContext="{Binding ElementName=control}"部分并将您的DataTemplate更改为<views:ResourceControl DataContext={Binding}"/>以便每个UserControl将绑定到单独的项目 -
它是否适用于我上面评论中建议的
DataContext更改?基本上问题是您将UserControlDockPanel.DataContext绑定到ResourceControl控件而不是ResourceDataViewModel类。您需要做的是将DataContext的ResourceControl绑定到您的DataTemplate -
不得不推断,因为有些东西丢失了,但通常这是你的代码,它工作正常 - 将项目绑定到
DataGridDownload -
这是因为您将
DataTemplate应用于您的类类型,在这种情况下,选项卡标题内容和选项卡内容是相同的,因此应用相同的模板。删除viewModels:ResourceDataViewModel类型的DataTemplate并将其直接放入主TabControl:<TabControl.ContentTemplate><DataTemplate><views:ResourceControl/></DataTemplate></TabControl.ContentTemplate>。应该可以解决您的问题