我正在使用 anXceed PropertyGrid来显示各种对象的属性。在大多数情况下,这很简单。我只是将SelectedObject属性设置为适当的对象。
但是,我有一种情况,其中一个对象属性是对来自不同类的集合的另一个对象的引用。我在这里创建了一个简化示例,用于演示和测试目的。在这个例子中,Person对象有一个City属性,它是CityModel类的一个实例。因此,对于任何给定Person的,用户应该能够从cities集合中选择他们的居住城市。人和城市的集合是——或者至少是真实的——动态的和用户可以改变的。
ComboBox我可以使用 an填充 a ,但在引用该集合EditorTemplate时遇到问题。cities
如果试图将 定义Source为StaticResource,我没有得到预期的行为。Microsoft 的此操作指南显示ObservableCollection( People) 被定义为 aResource并随后在数据绑定中被引用为 a StaticResource。当我尝试做同样的事情时,Visual Studio 显然期望Resource定义是一个类而不是类实例。它为我提供了CityModelor选项PersonModel,但不是cities我认为应该根据操作方法在此处指定的集合。
如果Source不指向集合,我不确定在绑定中如何以及在何处指定它,因为(再次基于 Intellisense)它不能进入Path .
在不使用 aStaticResource的情况下,我可以执行以下任一操作,这两者都会导致空白列表:
ItemsSource="{Binding Source=DataContext.cities, Path=Name}"
ItemsSource="{Binding Source=cities, Path=Name}"
或者这样,导致文本字符串“城市”被用作源:
ItemsSource="{Binding Source=cities}"
cities在下面的代码中,我可以通过在类中复制集合来获得所需的结果Person,这将其暴露给 ,ComboBox而不必指定 a Source,但这在很大程度上是一种解决方法。
<Grid>
<StackPanel Orientation="Vertical">
<TextBlock Padding="0,10,0,5">People:</TextBlock>
<ListBox Name="listPeople" ItemsSource="{Binding people}" DisplayMemberPath="FirstName" SelectionChanged="listBox_SelectionChanged" />
<TextBlock Padding="0,10,0,5">Cities:</TextBlock>
<ListBox Name="listCities" ItemsSource="{Binding cities}" DisplayMemberPath="Name" SelectionChanged="listBox_SelectionChanged" />
<TextBlock Padding="0,10,0,5">Properties:</TextBlock>
<xctk:PropertyGrid x:Name="MyPropertyGrid">
<xctk:PropertyGrid.EditorDefinitions>
<xctk:EditorTemplateDefinition TargetProperties="City">
<xctk:EditorTemplateDefinition.EditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Instance.citiesList}" SelectedValue="{Binding Instance.City}" />
</DataTemplate>
</xctk:EditorTemplateDefinition.EditingTemplate>
</xctk:EditorTemplateDefinition>
</xctk:PropertyGrid.EditorDefinitions>
</xctk:PropertyGrid>
</StackPanel>
</Grid>
public partial class MainWindow : Window
{
public ObservableCollection<CityModel> cities { get; set; } = new ObservableCollection<CityModel>();
public ObservableCollection<PersonModel> people { get; set; } = new ObservableCollection<PersonModel>();
public MainWindow()
{
InitializeComponent();
DataContext = this;
// Create some cities...
CityModel tokyo = new CityModel() { Id = 0, Name = "Tokyo" };
CityModel london = new CityModel() { Id = 1, Name = "London" };
CityModel buenosAires = new CityModel() { Id = 2, Name = "Buenos Aries" };
cities = new ObservableCollection<CityModel>() { tokyo, london, buenosAires };
// Create some people...
PersonModel juan = new PersonModel() { FirstName = "Juan", LastName = "Garcia", City = buenosAires };
PersonModel bridget = new PersonModel() { FirstName = "Bridget", LastName = "Jones", City = london };
PersonModel aoife = new PersonModel() { FirstName = "Aoife", LastName = "O'Connor", City = tokyo };
people = new ObservableCollection<PersonModel>() { juan, bridget, aoife };
// Workaround in order to expose list of cities along with Person properties...
foreach (PersonModel person in people) { person.citiesList = cities; }
}
private void listBox_SelectionChanged(object sender, RoutedEventArgs e)
{
ListBox listBox = sender as ListBox;
MyPropertyGrid.SelectedObject = listBox.SelectedItem;
}
}
public class PersonModel
{
public string FirstName { get; set; } = "";
public string LastName { get; set; } = "";
public CityModel City { get; set; } = new CityModel();
// Workaround in order to expose list of cities along with Person properties...
public ObservableCollection<CityModel> citiesList { get; set; } = new ObservableCollection<CityModel>();
}
public class CityModel
{
public int Id { get; set; } = 0;
public string Name { get; set; } = "";
public override string ToString() { return Name; }
}
