C# 在特性网格中选择特性
我正在使用PropertyGrid向用户显示对象的内容 假设单元格值与属性值匹配,则此PropertyGrid与Excel工作表同步 当用户在PropertyGrid中选择一个属性时,应用程序会高亮显示旁边打开的Excel工作表中相应的单元格。我可以使用SelectedGridItemChanged事件执行此操作 现在,当用户在Excel工作表中选择单元格时,我希望在我的PropertyGrid中选择一个属性C# 在特性网格中选择特性,c#,propertygrid,C#,Propertygrid,我正在使用PropertyGrid向用户显示对象的内容 假设单元格值与属性值匹配,则此PropertyGrid与Excel工作表同步 当用户在PropertyGrid中选择一个属性时,应用程序会高亮显示旁边打开的Excel工作表中相应的单元格。我可以使用SelectedGridItemChanged事件执行此操作 现在,当用户在Excel工作表中选择单元格时,我希望在我的PropertyGrid中选择一个属性 void myWorkbook_SheetSelectionChangeEvent(N
void myWorkbook_SheetSelectionChangeEvent(NetOffice.COMObject Sh, Excel.Range Target)
{
if (eventMask > 0)
return;
try
{
eventMask++;
this.Invoke(new Action(() =>
{
propertyGrid1.SelectedGridItem = ... // ?
}
}
finally
{
eventMask--;
}
}
我注意到SelectedGridItem可以写入
不幸的是,我没有找到访问PropertyGrid的GridItems集合的方法,因此我可以查找正确的GridItem并选择它
如何执行此操作?您可以从根目录获取所有GridItems。我使用下面的代码检索属性网格中的所有griditems
private GridItem Root
{
get
{
GridItem aRoot = myPropertyGrid.SelectedGridItem;
do
{
aRoot = aRoot.Parent ?? aRoot;
} while (aRoot.Parent != null);
return aRoot;
}
}
并将根传递给下面的方法
private IList<GridItem> GetAllChildGridItems(GridItem theParent)
{
List<GridItem> aGridItems = new List<GridItem>();
foreach (GridItem aItem in theParent.GridItems)
{
aGridItems.Add(aItem);
if (aItem.GridItems.Count > 0)
{
aGridItems.AddRange(GetAllChildGridItems(aItem));
}
}
return aGridItems;
}
您可以从根目录获取所有GridItems。我使用下面的代码检索属性网格中的所有griditems
private GridItem Root
{
get
{
GridItem aRoot = myPropertyGrid.SelectedGridItem;
do
{
aRoot = aRoot.Parent ?? aRoot;
} while (aRoot.Parent != null);
return aRoot;
}
}
并将根传递给下面的方法
private IList<GridItem> GetAllChildGridItems(GridItem theParent)
{
List<GridItem> aGridItems = new List<GridItem>();
foreach (GridItem aItem in theParent.GridItems)
{
aGridItems.Add(aItem);
if (aItem.GridItems.Count > 0)
{
aGridItems.AddRange(GetAllChildGridItems(aItem));
}
}
return aGridItems;
}
我在一个项目中遇到了这个问题,所以我为它编写了一个扩展方法:
if (!SetupManagerSettings.BootStrapperLocation.IsFile()) // Just another extension method to check if its a file
{
settingsToolStripMenuItem.Checked = true; // Event handler OnChecked ensures the settings panel is unhidden
settingsPropertyGrid.ActivateControl();
settingsPropertyGrid.SelectPropertyGridItemByName("BootStrapperLocation"); // Here is the extension method
return false;
}
下面是一个扩展方法,其中包含一个私有的支持方法,用于遍历对象层次结构(如果适用于对象模型):
public static bool SelectPropertyGridItemByName(this PropertyGrid propertyGrid, string propertyName)
{
MethodInfo getPropEntriesMethod = propertyGrid.GetType().GetMethod("GetPropEntries", BindingFlags.NonPublic | BindingFlags.Instance);
Debug.Assert(getPropEntriesMethod != null, @"GetPropEntries by reflection is still valid in .NET 4.6.1 ");
GridItemCollection gridItemCollection = (GridItemCollection)getPropEntriesMethod.Invoke(propertyGrid, null);
GridItem gridItem = TraverseGridItems(gridItemCollection, propertyName);
if (gridItem == null)
{
return false;
}
propertyGrid.SelectedGridItem = gridItem;
return true;
}
private static GridItem TraverseGridItems(IEnumerable parentGridItemCollection, string propertyName)
{
foreach (GridItem gridItem in parentGridItemCollection)
{
if (gridItem.Label != null && gridItem.Label.Equals(propertyName, StringComparison.OrdinalIgnoreCase))
{
return gridItem;
}
if (gridItem.GridItems == null)
{
continue;
}
GridItem childGridItem = TraverseGridItems(gridItem.GridItems, propertyName);
if (childGridItem != null)
{
return childGridItem;
}
}
return null;
}
我在一个项目中遇到了这个问题,所以我为它编写了一个扩展方法:
if (!SetupManagerSettings.BootStrapperLocation.IsFile()) // Just another extension method to check if its a file
{
settingsToolStripMenuItem.Checked = true; // Event handler OnChecked ensures the settings panel is unhidden
settingsPropertyGrid.ActivateControl();
settingsPropertyGrid.SelectPropertyGridItemByName("BootStrapperLocation"); // Here is the extension method
return false;
}
下面是一个扩展方法,其中包含一个私有的支持方法,用于遍历对象层次结构(如果适用于对象模型):
public static bool SelectPropertyGridItemByName(this PropertyGrid propertyGrid, string propertyName)
{
MethodInfo getPropEntriesMethod = propertyGrid.GetType().GetMethod("GetPropEntries", BindingFlags.NonPublic | BindingFlags.Instance);
Debug.Assert(getPropEntriesMethod != null, @"GetPropEntries by reflection is still valid in .NET 4.6.1 ");
GridItemCollection gridItemCollection = (GridItemCollection)getPropEntriesMethod.Invoke(propertyGrid, null);
GridItem gridItem = TraverseGridItems(gridItemCollection, propertyName);
if (gridItem == null)
{
return false;
}
propertyGrid.SelectedGridItem = gridItem;
return true;
}
private static GridItem TraverseGridItems(IEnumerable parentGridItemCollection, string propertyName)
{
foreach (GridItem gridItem in parentGridItemCollection)
{
if (gridItem.Label != null && gridItem.Label.Equals(propertyName, StringComparison.OrdinalIgnoreCase))
{
return gridItem;
}
if (gridItem.GridItems == null)
{
continue;
}
GridItem childGridItem = TraverseGridItems(gridItem.GridItems, propertyName);
if (childGridItem != null)
{
return childGridItem;
}
}
return null;
}
我看了上面的选项,不太喜欢它们,我稍微修改了一下,发现这对我来说很好
bool TryFindGridItem(PropertyGrid grid, string propertyName, out GridItem discover)
{
if (grid is null)
{
throw new ArgumentNullException(nameof(grid));
}
if (string.IsNullOrEmpty(propertyName))
{
throw new ArgumentException("You need to provide a property name", nameof(propertyName));
}
discover = null;
var root = pgTrainResult.SelectedGridItem;
while (root.Parent != null)
root = root.Parent;
foreach (GridItem item in root.GridItems)
{
//let's not find the category labels
if (item.GridItemType!=GridItemType.Category)
{
if (match(item, propertyName))
{
discover= item;
return true;
}
}
//loop over sub items in case the property is a group
foreach (GridItem child in item.GridItems)
{
if (match(child, propertyName))
{
discover= child;
return true;
}
}
//match based on the property name or the DisplayName if set by the user
static bool match(GridItem item, string name)
=> item.PropertyDescriptor.Name.Equals(name, StringComparison.Ordinal) || item.Label.Equals(name, StringComparison.Ordinal);
}
return false;
}
它使用一个名为match的本地方法,如果您的C版本不允许它,那么只需将它放在该方法的外部,也许可以给它一个更好的名称
Match会查看DisplayName和属性名,并返回true。如果其中一个是匹配项,则返回true。这可能不是您想要的,因此请更新该项
在我的用例中,我需要根据用户可以选择的值来选择属性,以便像这样调用上述方法:
if (TryFindGridItem(pgMain, propertyName, out GridItem gridItem))
{
gridItem.Select();
}
理论上,除非用户选择一个不合适的字符串,否则它永远不会找到它。通过这种方式,可以使用else更新if。。我宁愿保证它的安全,如果找不到指定的名称,就会出现空指针异常
此外,我不会讨论子类和类列表,因为我的用例不需要这些,如果您的用例需要的话,那么可能会在GridItem中进行递归调用
请注意,将GridItem替换为var,代码在编译时停止。IDE不知道GridItemCollection返回什么…我查看了上述选项,但不太喜欢它们,我对其进行了一些修改,发现这对我来说很好
bool TryFindGridItem(PropertyGrid grid, string propertyName, out GridItem discover)
{
if (grid is null)
{
throw new ArgumentNullException(nameof(grid));
}
if (string.IsNullOrEmpty(propertyName))
{
throw new ArgumentException("You need to provide a property name", nameof(propertyName));
}
discover = null;
var root = pgTrainResult.SelectedGridItem;
while (root.Parent != null)
root = root.Parent;
foreach (GridItem item in root.GridItems)
{
//let's not find the category labels
if (item.GridItemType!=GridItemType.Category)
{
if (match(item, propertyName))
{
discover= item;
return true;
}
}
//loop over sub items in case the property is a group
foreach (GridItem child in item.GridItems)
{
if (match(child, propertyName))
{
discover= child;
return true;
}
}
//match based on the property name or the DisplayName if set by the user
static bool match(GridItem item, string name)
=> item.PropertyDescriptor.Name.Equals(name, StringComparison.Ordinal) || item.Label.Equals(name, StringComparison.Ordinal);
}
return false;
}
它使用一个名为match的本地方法,如果您的C版本不允许它,那么只需将它放在该方法的外部,也许可以给它一个更好的名称
Match会查看DisplayName和属性名,并返回true。如果其中一个是匹配项,则返回true。这可能不是您想要的,因此请更新该项
在我的用例中,我需要根据用户可以选择的值来选择属性,以便像这样调用上述方法:
if (TryFindGridItem(pgMain, propertyName, out GridItem gridItem))
{
gridItem.Select();
}
理论上,除非用户选择一个不合适的字符串,否则它永远不会找到它。通过这种方式,可以使用else更新if。。我宁愿保证它的安全,如果找不到指定的名称,就会出现空指针异常
此外,我不会讨论子类和类列表,因为我的用例不需要这些,如果您的用例需要的话,那么可能会在GridItem中进行递归调用
请注意,用var替换GridItem,代码在编译时停止,IDE不知道GridItemCollection返回什么…。。。然后我可以使用PropertyDescriptor属性来获取我想要的GridItem,然后我可以进行选择。要是我能投两次票就好了。。。我唯一的怪癖是我的PropertyGrid有时是空的,所以在应用它之前,我必须检查是否选择了GridItem。明亮的非常感谢你。的确顺便说一句,欢迎来到SO社区。。。。然后我可以使用PropertyDescriptor属性来获取我想要的GridItem,然后我可以进行选择。要是我能投两次票就好了。。。我唯一的怪癖是我的PropertyGrid有时是空的,所以在应用它之前,我必须检查是否选择了GridItem。明亮的非常感谢你。的确顺便说一句,欢迎来到SO社区。