列表内容属性
如上图,是一个列表标题排序控件,我们需要定义一个标题列表,从而让调用方可以*的设置标题信息。
在自定义控件时,会遇到列表依赖属性,那么该如何定义呢?
下面是错误的定义方式:
/// <summary>
/// 标识 <see cref="Headers"/> 的依赖项属性。
/// </summary>
public static readonly DependencyProperty HeadersProperty = DependencyProperty.Register(
"Headers", typeof(List<HeaderContent>), typeof(ListViewHeader),
new PropertyMetadata(new List<HeaderContent>(), (d, e) => ((ListViewHeader)d).InitHeaderList())); /// <summary>
/// 获取或设置表头的信息集合。
/// 由于这是依赖项属性,所以很难限制其不为 null,需要总是判空。
/// </summary>
public List<HeaderContent> Headers
{
get => (List<HeaderContent>)GetValue(HeadersProperty);
set => SetValue(HeadersProperty, value);
}
按照如上依赖属性的定义,
- 必须提供一个默认属性new List<HeaderContent>() 或者 在自定义控件初始化时设置默认列表值,不然界面调用此列表属性去添加项,界面初始化时肯定会报错~
- 在Xaml中显示时,不会报出一些错误提示信息~(虽然不影响正常启动,但是错误列表中一直显示,对有强迫症的我来说。。不可忍受)
正确的实现方案
- 定义列表依赖属性:
/// <summary>
/// 标识 <see cref="Headers"/> 的依赖项属性。
/// </summary>
public static readonly DependencyProperty HeadersProperty = DependencyProperty.Register(
"Headers", typeof(ListViewHeaderContentCollection), typeof(ListViewHeader),
new PropertyMetadata(default(ListViewHeaderContentCollection), (d, e) => ((ListViewHeader)d).InitHeaderList())); /// <summary>
/// 获取或设置表头的信息集合。
/// 由于这是依赖项属性,所以很难限制其不为 null,需要总是判空。
/// </summary>
public ListViewHeaderContentCollection Headers
{
get => (ListViewHeaderContentCollection)GetValue(HeadersProperty);
set => SetValue(HeadersProperty, value);
}
- 定义列表内容集合类:
通过实现IList<T>和IList接口,可以让列表在界面调用时,可以以列表的形式添加内容。
注:将实现的接口方法修改下内容即可
public sealed class ListViewHeaderContentCollection : IList<HeaderContent>, IList
{
private readonly List<HeaderContent> _headContents = new List<HeaderContent>();
public IEnumerator<HeaderContent> GetEnumerator()
{
return _headContents.GetEnumerator();
} IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
} public void Add(HeaderContent item)
{
_headContents.Add(item);
} public int Add(object value)
{
_headContents.Add((HeaderContent)value);
return _headContents.Count;
} public bool Contains(object value)
{
return _headContents.Contains((HeaderContent)value);
} public void Clear()
{
_headContents.Clear();
} public int IndexOf(object value)
{
return _headContents.IndexOf((HeaderContent)value);
} public void Insert(int index, object value)
{
_headContents.Insert(index, (HeaderContent)value);
} public void Remove(object value)
{
_headContents.Remove((HeaderContent)value);
} void IList.RemoveAt(int index)
{
_headContents.RemoveAt(index);
} object IList.this[int index]
{
get => _headContents[index];
set => _headContents[index] = (HeaderContent)value;
} public bool Contains(HeaderContent item)
{
return _headContents.Contains(item);
} public void CopyTo(HeaderContent[] array, int arrayIndex)
{
_headContents.CopyTo(array, arrayIndex);
} public bool Remove(HeaderContent item)
{
return _headContents.Remove(item);
} public void CopyTo(Array array, int index)
{
_headContents.CopyTo((HeaderContent[])array, index);
} public int Count => _headContents.Count; public object SyncRoot { get; } public bool IsSynchronized { get; } public bool IsReadOnly { get; } public bool IsFixedSize { get; } public int IndexOf(HeaderContent item)
{
return _headContents.IndexOf(item);
} public void Insert(int index, HeaderContent item)
{
_headContents.Insert(index, item);
} void IList<HeaderContent>.RemoveAt(int index)
{
_headContents.RemoveAt(index);
} public HeaderContent this[int index]
{
get => _headContents[index];
set => _headContents[index] = value;
}
}
调用: