Prism for Silverlight: как сохранить представления в определенном порядке внутри региона - PullRequest
3 голосов
/ 11 января 2010

Я создаю своего рода «панель навигации» (которая на самом деле является ItemControl) для SL и использую области, чтобы каждый модуль мог добавить свою ссылку на панель.

Проблема в том, что загрузка модулей не согласована, и поэтому порядок ссылок в панели может меняться в зависимости от порядка загрузки модулей.

Об ограничении порядка модулей не может быть и речи.

Другой возможный вариант - это порядок коллекции представлений региона, которая связана с ItemControl, проблема в том, что ViewCollection очень ограничена, поэтому упорядочивать ее довольно сложно.

Я пропустил вариант, у вас есть идея?

Спасибо Ariel

Ответы [ 6 ]

7 голосов
/ 26 декабря 2010

В Prism4 вы просто применяете атрибут ViewSortHintAttribute к своим представлениям:

[ViewSortHint("100")]
class FirstView : UserControl { }

[ViewSortHint("200")]
class SecondView : UserControl { }

Сравнитель сортировки по умолчанию для регионов подберет этот атрибут и соответствующим образом отсортирует представления. Вы можете поместить любую строку в атрибут, но я склонен использовать числа среднего размера, которые позволяют мне легко разместить новое представление между существующими.

3 голосов
/ 15 декабря 2010

Обращаясь к ответу Сэма, вы сначала должны построить свой компаратор. Следующее также способно к представлениям, у которых нет выделенного желания быть размещенным в. Чтобы прикрепить этот компаратор к области, которую нужно отсортировать, вы можете использовать способ, описанный в руководстве по призме:

public partial class MainView : UserControl
{
    public MainView( ) 
    {
        InitializeComponent( );

        ObservableObject<IRegion> observableRegion = RegionManager.GetObservableRegion( ContentHost );

        observableRegion.PropertyChanged += ( sender, args ) =>
        {
            IRegion region = ( (ObservableObject<IRegion>)sender ).Value;
            region.SortComparison = CompareViews;
        };
    }

    private static int CompareViews( object x, object y )
    {
        IPositionView positionX = x as IPositionView;
        IPositionView positionY = y as IPositionView;
        if ( positionX != null && positionY != null )
        {
            //Position is a freely choosable integer
            return Comparer<int>.Default.Compare( positionX.Position, positionY.Position );
        }
        else if ( positionX != null )
        {
            //x is a PositionView, so we favour it here
            return -1;
        }
        else if ( positionY != null )
        {
            //y is a PositionView, so we favour it here
            return 1;
        }
        else
        {
            //both are no PositionViews, so we use string comparison here
            return String.Compare( x.ToString( ), y.ToString( ) );
        }
    }
}
2 голосов
/ 26 ноября 2010

По крайней мере, в Prism V4 вы можете указать менеджеру региона, как сортировать представления в определенном регионе. Вам просто нужно предоставить функцию сравнения с регионом.

Этот пример сортирует по очень глупому значению, имени функции:

private static int CompareViews(object x, object y)
{
  return String.Compare(x.ToString(), y.ToString());
}

this._regionManager.Regions["MyRegion"].SortComparison = CompareViews;

Конечно, регион должен быть известен менеджеру региона, прежде чем вы сможете установить SortComparison. До сих пор единственным решением, которое я нашел для достижения этой цели, было отложить установку функции сравнения с помощью Dispatcher:

private readonly IRegionManager _regionManager;

[ImportingConstructor]
public ShellViewModel(IRegionManager regionManager)
{
  this._regionManager = regionManager;
  Dispatcher dp = Dispatcher.CurrentDispatcher;
  dp.BeginInvoke(DispatcherPriority.ApplicationIdle, new ThreadStart(delegate
  {
    if (this._regionManager.Regions.ContainsRegionWithName("MyRegion"))
      this._regionManager.Regions["MyRegion"].SortComparison = CompareViews;
  }));
}

Конечно, вы должны использовать более полезную информацию, чем имя класса, для порядка сортировки, но это должно быть легко решить.

1 голос
/ 13 марта 2013

Я обнаружил, что решение Сэма сработало, но обнаружил, что оно выполняет сортировку, когда все виды добавлены в регион, таким образом сортируя виды дважды.

Хотя это все еще верное решение, чтение этого поста в обсуждении Prism заставило меня задуматься о способе реализации этого только после загрузки региона, но до того, как какие-либо представления будут добавлены. 1005 *

1 - Подписаться на коллекцию «Изменившиеся регионы»

Я поместил это в код Shell ViewModel, связанный с представлением, содержащим регион, который я хочу отсортировать. Когда импорт IRegionManager разрешен, я подписываюсь на событие CollectionChanged его коллекции Regions:

this._regionManager.Regions.CollectionChanged +=
        new NotifyCollectionChangedEventHandler(Regions_CollectionChanged);

2 - Изменить SortComparison региона в делегате события

Затем делегат Regions_CollectionChanged будет выполняться всякий раз, когда коллекция Regions будет обновлена, и изменит SortComparison моего желаемого региона:

void Regions_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    if (e.Action == NotifyCollectionChangedAction.Add)
    {
        foreach (var o in e.NewItems)
        {
            IRegion region = o as IRegion;
            if (region != null && region.Name == RegionNames.NavigationRegion)
            {
                region.SortComparison = CompareNavigatorViews;
            }
        }
    }
}

3 - определение делегата CompareNavigatorViews

В моем случае я просто сортирую представления по названию сборки, в которой они содержатся, вы можете реализовать свой собственный метод сравнения здесь. Помните, что объекты, которые вы получите здесь, являются видами, а не моделями представления.

private static int CompareNavigatorViews(object x, object y)
{
    if (x == null)
        if (y == null)
            return 0;
        else
            return -1;
    else
        if (y == null)
            return 1;
        else
        {
            AssemblyInfo xAssemblyInfo = new AssemblyInfo(Assembly.GetAssembly(x.GetType()));
            AssemblyInfo yAssemblyInfo = new AssemblyInfo(Assembly.GetAssembly(y.GetType()));

            return String.Compare(xAssemblyInfo.Title, yAssemblyInfo.Title);
        }
}

На всякий случай, если кто-то спросит, класс AssemblyInfo - это служебный класс, который я создал. Чтобы получить название сборки, вы можете использовать эту функцию:

string GetAssemblyTitle(Assembly assembly)
{
    object[] attributes = assembly.GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
    if (attributes.Length == 1)
    {
        return (attributes[0] as AssemblyTitleAttribute).Title;
    }
    else
    {
        // Return the assembly name if there is no title
        return this.GetType().Assembly.GetName().Name;
    }
}

Надеюсь, это кому-нибудь поможет!

1 голос
/ 13 января 2010

Он не встроен в регионы Prism, однако его легко реализовать.

Дамиан Шенкельман опубликовал созданный им метод расширения для добавления региона в индекс, который, кажется, работает довольно хорошо.http://blogs.southworks.net/dschenkelman/2009/03/14/how-to-add-a-view-to-a-region-in-a-particular-index-with-prism-v2/

Надеюсь, это поможет.

0 голосов
/ 14 января 2010

Ну, как отсчет ответов. Я не нашел решения с Призмой.

Вместо этого я использовал MEF для решения этой проблемы.

Я напишу об этом в блоге и обновлю этот заполнитель.

...