在我的WPF应用程序中,我曾经将动态控件添加到Canvas中。控件的名称格式为“Control_UniqueValue”。
即,如果我将第一个控件添加到画布,则名称将为“Control_1”,下一个将为“Control_2”等...
我的要求是获取添加的控件的最大值
我使用了以下语句
string maxId = (string)canvas1.Children.Cast<FrameworkElement>().ToList().Max(x => (x.Name.Substring(x.Name.LastIndexOf('_') + 1)));
但这里的问题是
需要将值返回为int
如果画布不包含任何控件,则会引发错误(尝试使用Nullable
类型,但失败了)
答案 0 :(得分:4)
要获取整数,可以使用int.Parse
方法。您无需致电ToList()
。
没有错误检查,因此您的控件必须根据您的规则name_id
命名。
如果序列为空,您可以使用DefaultIfEmpty
扩展方法提供默认值:
int maxId = canvas1.Children
.Cast<FrameworkElement>()
.DefaultIfEmpty(new FrameworkElement() { Name = "Control_0" })
.Max(x => (int.Parse(x.Name.Split('_')[1]) + 1)));
答案 1 :(得分:4)
int maxId = canvas1.Children
.Cast<FrameworkElement>()
.Select(e => int.Parse(e.Name.Substring(e.Name.LastIndexOf('_'))))
.DefaultIfEmpty()
.Max();
如果序列中没有元素,则应返回0而不是抛出异常。此外,不需要在代码中调用ToList
。如果任何控件名称不是预期的格式,这仍然会抛出异常。
答案 2 :(得分:3)
由于Max()在其序列中至少需要一个元素,您必须
虽然可以在一个长查询表达式中编写逻辑,但我建议你稍微分解一下以提高可读性。创建一个返回子控件名称的整数部分的方法:
private int NumberFromElementName(string name)
{
// Or search for the last '_' using name.LastIndexOf()
var numString = name.Substring("Control_".Length);
return Int32.Parse(numString);
}
然后分两步执行查询,以便查看返回序列的长度。请注意,我将其转换为数组,以避免必须运行两次查询。我也在使用OfType扩展方法,这样即使画布有一个不属于FrameworkElement类型的子项也能正常工作。
var children = canvas1.Children.OfType<FrameworkElement>().ToArray();
int max = 0;
if (children.Length > 0)
max = children.Max(x => NumberFromElementName(x.Name));
string nextChildName = String.Format ("Control_{0}", max + 1);
编辑:正如@Jan在他的回答中指出的那样,您可以通过在查询中使用Max {{}之前的DefaultIfEmpty来避免将查询拆分为两部分。
答案 3 :(得分:0)
得到了最终答案
int maxId = canvas1.Children .Cast<FrameworkElement>() .Select(e => int.Parse(e.Name.Substring(e.Name.LastIndexOf('_')+ 1))) .DefaultIfEmpty() .Max(x => x + 1);
感谢Jan&amp;利