MVVM应用程序的真正插件基于共享DropBox中的csv文件。其中一列(在下面的简化示例“B”中)可能具有需要使用图像进行解释的单元格值。因此,如果需要,我们在DropBox中添加一个文件夹,以包含图像的单元格值(示例中为“B1”)命名。最终这些图像应成为缩略图,如果选择缩略图则为全屏图像。但是现在,如果添加的列可以显示属于相邻单元格中列“B”中的单元格值的文件路径,那将是很好的。然而,经过数天的研究和反复试验,结果是:
Cell in front of A0 and A1 both show D:\Temp\B1\test0.jpg
虽然A0前面的单元格应该是空的,但在A1前面的单元格应该是:
d:\ TEMP \ B1 \ test0.jpg
d:\ TEMP \ B1 \ test1.jpg
我有下一个问题:
观点:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:myViewModel="clr-namespace:WpfApplication3"
Title="MainWindow" Height="120" Width="200">
<Window.Resources>
<myViewModel:testConverter x:Key="myTestConverter"/>
</Window.Resources>
<Window.DataContext>
<myViewModel:ViewModel/>
</Window.DataContext>
<Grid>
<DataGrid x:Name="myXAMLtable" AutoGenerateColumns="True" CanUserAddRows="False"
ItemsSource="{Binding PropDataTable}">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ListBox x:Name="folder" ItemsSource="{Binding MyImageFolderList,
Converter={StaticResource myTestConverter}}">
<ListBox.DataContext>
<myViewModel:ViewModel/>
</ListBox.DataContext>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding MyImageFolderList/MyImageList/MyImagePath}">
<TextBlock.DataContext>
<myViewModel:ViewModel/>
</TextBlock.DataContext>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
(我使用虚拟转换器来测试绑定,这是我在stackoverflow中学到的一个技巧)
ViewModel:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
namespace WpfApplication3
{
class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
//private Model _Model; //for clarity left out
private DataTable propDataTable;
public DataTable PropDataTable
{
get { return propDataTable; }
set
{
propDataTable = value;
NotifyPropertyChanged("PropDataTable");
}
}
private List<MyImageFolder> myImageFolderList;
public List<MyImageFolder> MyImageFolderList
{
get { return myImageFolderList; }
set
{
myImageFolderList = value;
NotifyPropertyChanged("MyImageFolderList");
}
}
public ViewModel()
{
DataTable tempPropDataTable = new DataTable();
tempPropDataTable.Columns.Add("A", typeof(string));
tempPropDataTable.Columns.Add("B", typeof(string));
DataRow row0 = tempPropDataTable.NewRow();
DataRow row1 = tempPropDataTable.NewRow();
row0[0] = "A0";
row0[1] = "B0";
row1[0] = "A1";
row1[1] = "B1";
tempPropDataTable.Rows.Add(row0);
tempPropDataTable.Rows.Add(row1);
PropDataTable = tempPropDataTable;
MyImageFolderList = new List<MyImageFolder>();
//in D:\Temp\B1 there are two filesP test0.jpg and test1.jpg
string B0 = "D:\\Temp\\B1\\test0.jpg";
string B1 = "D:\\Temp\\B1\\test1.jpg";
MyImageFolder mif = new MyImageFolder("B1");
MyImage mi0 = new MyImage(B0);
MyImage mi1 = new MyImage(B1);
mif.MyImageList = new List<MyImage>();//did you forget this???
mif.MyImageList.Add(mi0);
mif.MyImageList.Add(mi1);
MyImageFolderList.Add(mif);
}
}
}
MyImageFolder类:
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace WpfApplication3
{
public class MyImageFolder : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
private string myImageFolderPath = "";
public string MyImageFolderPath
{
get { return myImageFolderPath; }
set
{
myImageFolderPath = value;
NotifyPropertyChanged("MyImageFolderPath");
}
}
private List<MyImage> myImageList = new List<MyImage>();
public List<MyImage> MyImageList
{
get { return myImageList; }
set
{
myImageList = value;
NotifyPropertyChanged("MyImageList");
}
}
public MyImageFolder(string fp)
{
this.MyImageFolderPath = fp;
}
}
}
MyImage类:
using System;
using System.ComponentModel;
namespace WpfApplication3
{
public class MyImage : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
private string myImagePath = "";
public string MyImagePath
{
get { return myImagePath; }
set
{
myImagePath = value;
NotifyPropertyChanged("MyImagePath");
}
}
//constructor
public MyImage(string ip)
{
MyImagePath = ip;
}
}
}
答案 0 :(得分:0)
你到处都写着像
这样的东西<ListBox.DataContext>
<myViewModel:ViewModel/>
</ListBox.DataContext>
您正在创建ViewModel类的新实例,并将其设置为UI对象后面的DataContext。这几乎不是你想要的,因为最终结果是这样的(注意ViewModel对象的许多实例):
<DataGridRow DataContext=ViewModel1.PropDataTable[0]>
<ListBoxItem DataContext=ViewModel2.MyImageFolderList[0]>
<TextBlock DataContext=ViewModel3.MyImageFolderPath />
</ListBoxItem>
<ListBoxItem DataContext=ViewModel2.MyImageFolderList[1]>
<TextBlock DataContext=ViewModel4.MyImageFolderPath />
</ListBoxItem>
<ListBoxItem DataContext=ViewModel2.MyImageFolderList[2]>
<TextBlock DataContext=ViewModel5.MyImageFolderPath />
</ListBoxItem>
</DataGridItem>
<DataGridRow DataContext=ViewModel1.PropDataTable[1]>
<ListBoxItem DataContext=ViewModel6.MyImageFolderList[0]>
<TextBlock DataContext=ViewModel7.MyImageFolderPath />
</ListBoxItem>
<ListBoxItem DataContext=ViewModel6.MyImageFolderList[1]>
<TextBlock DataContext=ViewModel8.MyImageFolderPath />
</ListBoxItem>
<ListBoxItem DataContext=ViewModel6.MyImageFolderList[2]>
<TextBlock DataContext=ViewModel.MyImageFolderPath />
</ListBoxItem>
</DataGridRow>
DataContext继承自父控件,因此您应该使用该假设为您编写绑定。
你想要的是ViewModel对象的一个副本,它是一个名为PropDataTable的属性,它是一个对象集合。 PropDataTable中的每个对象都应该有一个名为MyImageFolderList的对象集合,MyImageFolderList中的每个项都应该有一个名为MyImageFolderPath的属性。
因此,如果您有以下内容(请注意,缺少将.DataContext分配给ViewModel的新实例)
<DataGrid ItemsSource="{Binding PropDataTable"}>
...
<ListBox ItemsSource="{Binding MyImageFolderList"}>
...
<TextBlock Text="{Binding MyImageFolderPath}" />
...
</ListBox>
</DataGrid>
它实际上是按照以下方式呈现的:
<DataGridRow DataContext=ViewModel1.PropDataTable[0]>
<ListBoxItem DataContext=ViewModel1.PropDataTable[0].MyImageFolderList[0]>
<TextBlock DataContext=ViewModel1.PropDataTable[0].MyImageFolderList[0].MyImageFolderPath />
</ListBoxItem>
<ListBoxItem DataContext=ViewModel1.PropDataTable[0].MyImageFolderList[1]>
<TextBlock DataContext=ViewModel1.PropDataTable[0].MyImageFolderList[1].MyImageFolderPath />
</ListBoxItem>
<ListBoxItem DataContext=ViewModel1.PropDataTable[0].MyImageFolderList[2]>
<TextBlock DataContext=ViewModel1.PropDataTable[0].MyImageFolderList[2].MyImageFolderPath />
</ListBoxItem>
</DataGridItem>
<DataGridRow DataContext=ViewModel1.PropDataTable[1]>
<ListBoxItem DataContext=ViewModel1.PropDataTable[1].MyImageFolderList[0]>
<TextBlock DataContext=ViewModel1.PropDataTable[1].MyImageFolderList[0].MyImageFolderPath />
</ListBoxItem>
<ListBoxItem DataContext=ViewModel1.PropDataTable[1].MyImageFolderList[1]>
<TextBlock DataContext=ViewModel1.PropDataTable[1].MyImageFolderList[1].MyImageFolderPath />
</ListBoxItem>
</DataGridRow>
我在我的博客上有一篇文章,如果您也在努力理解它,可以更详细地介绍一下DataContext。 What is this "DataContext" you speak of?