我有以下针对StackPanel的RegionAdapter实现,但我需要对与区域关联的项进行严格排序。有谁可以帮助我吗?
我希望注册到区域的视图能够控制那里的位置,也许是某种索引号
protected override void Adapt(IRegion region, StackPanel regionTarget)
{
region.Views.CollectionChanged += (sender, e) =>
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (FrameworkElement element in e.NewItems)
{
regionTarget.Children.Add(element);
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (UIElement elementLoopVariable in e.OldItems)
{
var element = elementLoopVariable;
if (regionTarget.Children.Contains(element))
{
regionTarget.Children.Remove(element);
}
}
break;
}
};
}发布于 2013-07-14 17:57:18
如何处理这个问题在很大程度上取决于排序是指(a)视图的类型还是(b)视图的实例。例如,如果您只想指定类型为ViewA的视图应该位于类型为ViewB的视图之上,则可以使用前者。如果您想指定如何对同一视图类型的多个具体实例进行排序,则可以使用后一种方法。
A.按类型排序
On选项是实现一个自定义属性,类似于OrderIndexAttribute,它公开一个整数属性:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public OrderIndexAttribute : Attribute
{
public int Index { get; }
public OrderIndexAttribute(int index)
{
Index = index;
}
}使用该属性标记视图类:
[OrderIndex(2)]
public ViewA : UserControl
{...}在将视图添加到地域时获取类型的属性:
case NotifyCollectionChangedAction.Add:
foreach (FrameworkElement element in e.NewItems)
{
// Get index for view
var viewType = element.GetType();
var viewIndex= viewType.GetCustomAttribute<OrderIndexAttribute>().Index;
// This method needs to iterate through the views in the region and determine
// where a view with the specified index needs to be inserted
var insertionIndex = GetInsertionIndex(viewIndex);
regionTarget.Children.Insert(insertionIndex, element);
}
break;B.对实例进行排序
让你的视图实现一个接口:
public interface ISortedView
{
int Index { get; }
}在将视图添加到区域时,尝试将插入的视图转换到界面,读取索引,然后执行上述操作:
case NotifyCollectionChangedAction.Add:
foreach (FrameworkElement element in e.NewItems)
{
// Get index for view
var sortedView = element as ISortedView;
if (sortedView != null)
{
var viewIndex = sortedView.Index;
// This method needs to iterate through the views in the region and determine
// where a view with the specified index needs to be inserted
var insertionIndex = GetInsertionIndex(viewIndex);
regionTarget.Children.Insert(insertionIndex, sortedView);
}
else
{ // Add at the end of the StackPanel or reject adding the view to the region }
}发布于 2020-11-14 07:12:10
我发现Marc的"A。Sort type wise“案例对我的情况非常有帮助。我需要使用OrderIndexAttribute将视图排序到区域中,并且如果视图实际上没有OrderIndexAttribute,仍然可以添加视图。
正如您将在下面看到的,我通过跟踪列表中的视图索引实现了这一点。没有该属性的视图的插入索引默认为零,以便它排序到StackPanel的前面(或顶部)。
这篇原创文章相当古老,但也许有人会像我一样偶然发现它,并会发现我的贡献是有帮助的。重构建议是受欢迎的。:-)
public class StackPanelRegionAdapter : RegionAdapterBase<StackPanel>
{
private readonly List<int> _indexList;
public StackPanelRegionAdapter(IRegionBehaviorFactory behaviorFactory)
: base(behaviorFactory)
{
_indexList = new List<int>();
}
protected override void Adapt(IRegion region, StackPanel regionTarget)
{
region.Views.CollectionChanged += (sender, e) =>
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (FrameworkElement element in e.NewItems)
{
var viewType = element.GetType();
// Get the custom attributes for this view, if any
var customAttributes = viewType.GetCustomAttributes(false);
var viewIndex = 0; // Default the viewIndex to zero
// Determine if the view has the OrderIndexAttribute.
// If it does have the OrderIndexAttribute, get its sort index.
if (HasThisAttribute(customAttributes))
{
viewIndex= viewType.GetCustomAttribute<OrderIndexAttribute>().Index;
}
// Get the insertion index
var insertionIndex = GetInsertionIndex(viewIndex);
regionTarget.Children.Insert(insertionIndex, element);
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (UIElement elementLoopVariable in e.OldItems)
{
var element = elementLoopVariable;
if (regionTarget.Children.Contains(element))
{
regionTarget.Children.Remove(element);
}
}
break;
}
};
}
private static bool HasThisAttribute(IReadOnlyList<object> customAttributes)
{
// Determine if the view has the OrderIndexAttribute
if (customAttributes.Count == 0) return false;
for (var i = 0; i < customAttributes.Count; i++)
{
var name = customAttributes[i].GetType().Name;
if (name == "OrderIndexAttribute") return true;
}
return false;
}
private int GetInsertionIndex(in int viewIndex)
{
// Add the viewIndex to the index list if not already there
if (_indexList.Contains(viewIndex) == false)
{
_indexList.Add(viewIndex);
_indexList.Sort();
}
// Return the list index of the viewIndex
for (var i = 0; i < _indexList.Count; i++)
{
if (_indexList[i].Equals(viewIndex))
{
return i;
}
}
return 0;
}
protected override IRegion CreateRegion()
{
return new AllActiveRegion();
}
}发布于 2021-08-24 00:17:59
Marc和R.Evans的回答帮助我创建了自己的更通用的RegionAdapter,并进行了以下改进:
自适应方法:
protected override void Adapt(IRegion region, StackPanel regionTarget)
{
region.Views.CollectionChanged += (s, e) =>
{
if (e.Action == NotifyCollectionChangedAction.Add)
foreach (FrameworkElement item in e.NewItems)
{
regionTarget.Children.Insert(regionTarget.Children.GetInsertionIndex(item), item);
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
foreach (UIElement item in e.OldItems)
{
if (regionTarget.Children.Contains(item))
{
regionTarget.Children.Remove(item);
}
}
};
}帮助器/扩展:
internal static int GetInsertionIndex(this IList items, in object newItem)
{
// Return the list index of the viewIndex
foreach (object item in items)
{
var currentIndex = item.GetType().GetCustomAttribute<ViewSortHintAttribute>()?.Hint ?? "0";
var intendedIndex = newItem.GetType().GetCustomAttribute<ViewSortHintAttribute>()?.Hint ?? "0";
if (currentIndex.CompareTo(intendedIndex) >= 0)
return items.IndexOf(item);
}
// if no greater index is found, insert the item at the end
return items.Count;
}https://stackoverflow.com/questions/17638053
复制相似问题