0

У меня есть страница (ProfilePage) и её ViewModel (Page1ViewModel).

С первого экземпляра страницы ProfilePage есть возможность перехода на второй экземпляр страницы ProfilePage

_pageService.ChangePage(new ProfilePage());
await _messageBus.SendTo<Page1ViewModel>(new TextMessage(ID.ToString()));

Если оставить как сейчас, то есть создавать экземпляр Page и передать в Page1ViewModel id выбранного пользователя, то создается новая страница с новым пользователем, но при нажатии кнопки back в навигации frame, старая страница так же с новым id.

Я подумал, что логично было бы, бы если каждая страница имела свой экземпляр Page1ViewModel, и при выборе на первой странице пользователя, создавалась страница со своим VM, и передать ID в новый VM

Как это реализовывается?

ProfilePage XAML

<Page
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:views="clr-namespace:SystemBackdropTypes.Enums"
      xmlns:local="clr-namespace:SystemBackdropTypes"
      DataContext="{Binding Page1ViewModel, Source={StaticResource ViewModelLocator}}" x:Class="SystemBackdropTypes.ProfilePage"
      mc:Ignorable="d"
      d:DesignHeight="450" d:DesignWidth="800"
      Title="{Binding CurrentID}" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
&lt;Page.Resources&gt;
    &lt;Style TargetType=&quot;TextBlock&quot; x:Key=&quot;TextBlockDescription&quot;&gt;
        &lt;Style.Triggers&gt;
            &lt;Trigger Property=&quot;Text&quot; Value=&quot;&quot;&gt;
                &lt;Setter Property=&quot;Visibility&quot; Value=&quot;Collapsed&quot; /&gt;
            &lt;/Trigger&gt;
            &lt;Trigger Property=&quot;Text&quot; Value=&quot;{x:Null}&quot;&gt;
                &lt;Setter Property=&quot;Visibility&quot; Value=&quot;Collapsed&quot; /&gt;
            &lt;/Trigger&gt;
        &lt;/Style.Triggers&gt;
    &lt;/Style&gt;
&lt;/Page.Resources&gt;

&lt;i:Interaction.Triggers&gt;
    &lt;i:EventTrigger EventName=&quot;Loaded&quot;&gt;
        &lt;i:InvokeCommandAction Command=&quot;{Binding LoadedCommand}&quot; /&gt;
    &lt;/i:EventTrigger&gt;
&lt;/i:Interaction.Triggers&gt;

&lt;Grid&gt;
    &lt;Grid ShowGridLines=&quot;True&quot;&gt;
        &lt;Grid.RowDefinitions&gt;
            &lt;RowDefinition  MinHeight=&quot;150&quot; /&gt;
            &lt;RowDefinition  MinHeight=&quot;200&quot; Height=&quot;*&quot;/&gt;
            &lt;RowDefinition  MinHeight=&quot;170&quot;/&gt;
        &lt;/Grid.RowDefinitions&gt;
        &lt;Grid.ColumnDefinitions&gt;
            &lt;ColumnDefinition Width=&quot;72&quot; MinWidth=&quot;72&quot;/&gt;
            &lt;ColumnDefinition Width=&quot;240*&quot; MinWidth=&quot;258&quot; MaxWidth=&quot;480&quot;/&gt;
            &lt;ColumnDefinition Width=&quot;121&quot;/&gt;
            &lt;ColumnDefinition Width=&quot;337&quot;/&gt;
        &lt;/Grid.ColumnDefinitions&gt;
        &lt;Border CornerRadius=&quot;5&quot; Opacity=&quot;40&quot; Grid.Column=&quot;1&quot; Grid.Row=&quot;0&quot; Margin=&quot;10&quot; Background=&quot;#FF383838&quot; VerticalAlignment=&quot;Center&quot;&gt;
            &lt;Grid&gt;
                &lt;Image x:Name=&quot;image&quot; Grid.Column=&quot;0&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;106&quot; Margin=&quot;10&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;106&quot; Source=&quot;{Binding avatar}&quot; Stretch=&quot;UniformToFill&quot;/&gt;
                &lt;DockPanel Margin=&quot;130,0,0,0&quot; d:Background=&quot;Red&quot; VerticalAlignment=&quot;Top&quot; &gt;
                    &lt;TextBlock TextWrapping=&quot;WrapWithOverflow&quot; DockPanel.Dock=&quot;Top&quot; Foreground=&quot;White&quot; FontSize=&quot;20&quot;&gt;&lt;Run d:Text=&quot;Имя}&quot; Text=&quot;{Binding first_name}&quot;/&gt;&lt;Run Text=&quot; &quot;/&gt;&lt;Run d:Text=&quot;Фамилия&quot; Text=&quot;{Binding last_name}&quot;/&gt;&lt;/TextBlock&gt;
                    &lt;TextBlock x:Name=&quot;status&quot; DockPanel.Dock=&quot;Top&quot; TextWrapping=&quot;Wrap&quot; d:Text=&quot;Статус&quot; Foreground=&quot;White&quot; RenderTransformOrigin=&quot;0.5,0&quot; Text=&quot;{Binding status}&quot;/&gt;
                &lt;/DockPanel&gt;
            &lt;/Grid&gt;
        &lt;/Border&gt;

        &lt;Border CornerRadius=&quot;5&quot; Opacity=&quot;40&quot; Grid.Column=&quot;1&quot; Grid.Row=&quot;1&quot; Margin=&quot;10&quot; Background=&quot;#FF383838&quot; VerticalAlignment=&quot;Top&quot;&gt;
            &lt;Grid&gt;
                &lt;DockPanel d:Background=&quot;Red&quot;&gt;
                    &lt;TextBlock Style=&quot;{StaticResource TextBlockDescription}&quot; Margin=&quot;10,5,10,5&quot; DockPanel.Dock=&quot;Top&quot; TextWrapping=&quot;Wrap&quot; d:Text=&quot;29 подписчиков&quot; Foreground=&quot;White&quot; FontSize=&quot;15&quot; VerticalAlignment=&quot;Top&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;Auto&quot; Text=&quot;{Binding followers_count}&quot;/&gt;
                    &lt;TextBlock Style=&quot;{StaticResource TextBlockDescription}&quot; Margin=&quot;10,5,10,5&quot; DockPanel.Dock=&quot;Top&quot; TextWrapping=&quot;Wrap&quot; d:Text=&quot;Город: &quot; Foreground=&quot;White&quot; FontSize=&quot;15&quot; VerticalAlignment=&quot;Top&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;Auto&quot; Text=&quot;{Binding home_town}&quot;/&gt;
                    &lt;TextBlock Style=&quot;{StaticResource TextBlockDescription}&quot; Margin=&quot;10,5,10,5&quot; DockPanel.Dock=&quot;Top&quot; TextWrapping=&quot;Wrap&quot; d:Text=&quot;Работает в: &quot; Foreground=&quot;White&quot; FontSize=&quot;15&quot; VerticalAlignment=&quot;Top&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;Auto&quot; Text=&quot;{Binding Occupations}&quot;/&gt;
                    &lt;TextBlock Style=&quot;{StaticResource TextBlockDescription}&quot; Margin=&quot;10,5,10,5&quot; DockPanel.Dock=&quot;Top&quot; TextWrapping=&quot;Wrap&quot; d:Text=&quot;Сайт&quot; Foreground=&quot;White&quot; FontSize=&quot;15&quot; VerticalAlignment=&quot;Top&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;Auto&quot; Text=&quot;{Binding site}&quot;/&gt;
                    &lt;Button DockPanel.Dock=&quot;Top&quot; HorizontalAlignment=&quot;Stretch&quot; Content=&quot;Подробная информация&quot; Command=&quot;{Binding AddPanel}&quot;/&gt;
                &lt;/DockPanel&gt;
            &lt;/Grid&gt;
        &lt;/Border&gt;

        &lt;Grid Grid.Column=&quot;1&quot; Margin=&quot;10&quot; Grid.Row=&quot;2&quot; Background=&quot;#FF383838&quot; VerticalAlignment=&quot;Top&quot;&gt;
            &lt;StackPanel&gt;
                &lt;Label Content=&quot;Друзья&quot; Margin=&quot;10&quot; Foreground=&quot;White&quot; FontSize=&quot;20&quot;/&gt;
                &lt;ListBox Margin=&quot;10&quot; ItemsSource=&quot;{Binding Friends}&quot; SelectedValue=&quot;{Binding SelectedFriendId}&quot; SelectedValuePath=&quot;IdFriend&quot;&gt;
                    &lt;ListBox.ItemsPanel&gt;
                        &lt;ItemsPanelTemplate&gt;
                            &lt;StackPanel Orientation=&quot;Horizontal&quot;/&gt;
                        &lt;/ItemsPanelTemplate&gt;
                    &lt;/ListBox.ItemsPanel&gt;

                    &lt;ListBox.ItemTemplate&gt;
                        &lt;DataTemplate&gt;
                            &lt;Grid VerticalAlignment=&quot;Stretch&quot;&gt;
                                &lt;Grid.RowDefinitions&gt;
                                    &lt;RowDefinition Height=&quot;50&quot;&gt;&lt;/RowDefinition&gt;
                                    &lt;RowDefinition&gt;&lt;/RowDefinition&gt;
                                &lt;/Grid.RowDefinitions&gt;
                                &lt;Image Grid.Row=&quot;0&quot; Source=&quot;{Binding AvatarFriend}&quot;/&gt;
                                &lt;TextBlock Grid.Row=&quot;1&quot; Text=&quot;{Binding NameFriend}&quot; HorizontalAlignment=&quot;Center&quot; VerticalAlignment=&quot;Center&quot;/&gt;
                            &lt;/Grid&gt;
                        &lt;/DataTemplate&gt;
                    &lt;/ListBox.ItemTemplate&gt;
                &lt;/ListBox&gt;
            &lt;/StackPanel&gt;
        &lt;/Grid&gt;
    &lt;/Grid&gt;

&lt;/Grid&gt;

</Page>

ProfilePage

namespace SystemBackdropTypes.ViewModels
{
    public class Page1ViewModel : BindableBase
    {
        private readonly PageService _pageService;
        private readonly ControlService _controlService;
        private readonly EventBus _eventBus;
        private readonly MessageBus _messageBus;
    public string CurrentID { get; set; } // ID текущего пользователя
    public string? LogText { get; set; }

    #region Первая панель | Текущий пользователь
    public string? first_name { get; set; }
    public string? last_name { get; set; }
    public string? status { get; set; }
    public string avatar { get; set; } = &quot;https://vk.com/images/camera_200.png&quot;;
    #endregion

    #region Вторая панель | Описание пользователя
    public string? home_town { get; set; } // Родной город
    public string? followers_count { get; set; } // Подписчики
    public string? Occupations { get; private set; }// Род деятельности
    public string? site { get; private set; } // Сайт
    #endregion

    #region Третья панель | Друзья
    private int _selectedFriendId;
    public IEnumerable&lt;Friend&gt;? Friends { get; private set; }
    #endregion

    public Page1ViewModel(PageService pageService, ControlService controlService, EventBus eventBus, MessageBus messageBus, int id = 0)
    {

        PanelVMs = new ObservableCollection&lt;PanelViewModel&gt;();


        Debug.WriteLine(Properties.Settings.Default.token);

        _pageService = pageService;
        _controlService = controlService;
        _eventBus = eventBus;
        _messageBus = messageBus;

        _controlService.OnUserControlChanged += (usercontrol) =&gt; Change(usercontrol);

        _messageBus.Receive&lt;TextMessage&gt;(this, async message =&gt;
        {
            //MessageBox.Show(&quot;Открыл профиль &quot; + message.Text);
            CurrentID = message.Text;
        });
    }

    private void Change(System.Windows.Controls.UserControl usercontrol)
    {
        CurrentPage = usercontrol;
    }

    public async void OpenProfile(int ID)
    {


        await _eventBus.Publish(new LeaveFromFirstPageEvent());
        //Loaded();
        _pageService.ChangePage(new ProfilePage());
        await _messageBus.SendTo&lt;Page1ViewModel&gt;(new TextMessage(ID.ToString()));

        //MessageBox.Show(CurrentID.ToString());

    }

    public ICommand SendLog =&gt; new AsyncCommand(async () =&gt;
    {
        await _messageBus.SendTo&lt;LogPageViewModel&gt;(new TextMessage(LogText.ToString()));
        //await _messageBus.SendTo&lt;object&gt;(new TextMessage(LogText));

    });



    public void Loaded()
    {
        avatar = &quot;https://imgur.com/pKopwXp&quot;; // загрузка
        if (CurrentID == null)
        {
            //MessageBox.Show(&quot;Моя старница&quot;);
            GetProfileInfo();
            CurrentID = &quot;0&quot;;
        }
        else
        {

            UsersGet();
        }

        GetFindFriends();
    }

    private async void GetFindFriends()
    {

        var data = await Utility.FetchFriendsInfo(CurrentID, &quot;5&quot;);
        Friends = new ObservableCollection&lt;Friend&gt;();
        foreach (var friend in data.response.items)
        {
            Friends = Friends.Concat
                  (new[] {
                      new Friend {IdFriend = friend.id, NameFriend = friend.first_name, AvatarFriend = friend.photo_100},
                  });
        }

    }

    public async void GetProfileInfo()
    {
        var data = await Utility.GetProfileInfo();
        await _messageBus.SendTo&lt;MainViewModel&gt;(new TextMessage(data.ToString()));
        first_name = data.response.first_name;
        last_name = data.response.last_name;
        avatar = data.response.photo_200;
        home_town = &quot;Город: &quot; + data.response.home_town;
        status = data.response.status == null ? &quot;&quot; : data.response.status;
    }

    private dynamic ProfileInfo {get; set;}
    public async void UsersGet()
    {
        var data = await Utility.UsersGet(CurrentID);
        await _messageBus.SendTo&lt;MainViewModel&gt;(new TextMessage(data.ToString()));
        ProfileInfo = data;
        first_name = data.response[0].first_name;
        last_name = data.response[0].last_name;
        avatar = data.response[0].photo_100;
        home_town = &quot;Город: &quot; + data.response[0].home_town;
        status = data.response[0].status == null ? &quot;&quot; : data.response[0].status;
        followers_count = data.response[0].followers_count + &quot; подписчиков&quot;;
        Occupations = data[&quot;response&quot;][0][&quot;occupation&quot;][&quot;name&quot;];
        site = data[&quot;response&quot;][0][&quot;site&quot;];
    }

    private ObservableCollection&lt;PanelViewModel&gt; _panelVMs;
    public ObservableCollection&lt;PanelViewModel&gt; PanelVMs
    {
        get { return _panelVMs; }
        set { SetProperty(ref _panelVMs, value, () =&gt; PanelVMs); }
    }
    private DelegateCommand _AddPanel;
    public DelegateCommand AddPanel
    {
        get { return _AddPanel ?? (_AddPanel = new DelegateCommand(AddPanelExecute)); }
    }
    private async void AddPanelExecute()
    {
        //PanelVMs.Add(new PanelViewModel());
        //Panel b = new Panel();
        //CurrentPage = b;

        _controlService.ChangeUserControl(new Panel());
        await _messageBus.SendTo&lt;PanelViewModel&gt;(new TextMessage(ProfileInfo.ToString()));
    }

    #region Выбор id друга
    public int SelectedFriendId
    {
        get { return _selectedFriendId; }
        set
        {
            if (value != _selectedFriendId)
            {
                Debug.WriteLine(string.Format(&quot;setting friend to: {0}&quot;, value));
                OpenProfile(value);
                _selectedFriendId = value;
            }
        }
    }
    #endregion

    /*public int SelectedOccupationId
    {
        get { return _selectedOccupationId; }
        set
        {
            if (value != _selectedOccupationId)
            {
                Debug.WriteLine(string.Format(&quot;Selected Occupation: {0}&quot;, value));
                _selectedOccupationId = value;
            }
        }
    }*/

    private DelegateCommand loadedCommand;
    public ICommand LoadedCommand =&gt; loadedCommand ??= new DelegateCommand(Loaded);

    private object currentPage;

    public object CurrentPage { get =&gt; currentPage; set =&gt; SetValue(ref currentPage, value); }
}

public class Friend
{
    public int IdFriend { get; set; }
    public string AvatarFriend { get; set; }
    public string NameFriend { get; set; }
}

/*public class Occupation
{
    public int IdOccupation { get; set; }
    public string type { get; set; }
    public string NameOccupation { get; set; }
}*/

}

PageService

public class PageService
    {
        public event Action<Page, string> OnPageChanged;
    public void ChangePage(Page page, string message = &quot;&quot;)
    {
        OnPageChanged?.Invoke(page, message);
    }
}

MainViewModel

public Page PageSource { get; set; }
public MainViewModel(PageService pageService, MessageBus messageBus)
{
        _pageService = pageService;
        _messageBus = messageBus;
    _pageService.OnPageChanged += (page, message) =&gt; Change(page, message);
    _pageService.ChangePage(new LoginPage());


    _messageBus.Receive&lt;TextMessage&gt;(this, async message =&gt;
    {
        logtext = message.Text;

    });

} public void Change(Page page, string message) { PageSource = page; }

Mr. Dandomi
  • 117
  • 1
  • 10
  • Ничего непонятно, но очень интересно. Вам уже писали здесь, что Frame+Page в WPF - неудачное решение. Зря игнорируете. А чтобы разобраться с вашей ситуацией, нужен минимальный воспроизводимый пример, потому что инструменты для реализации задачи, вы выбрали мягко говоря непопулярные. – aepot Jan 11 '22 at 09:29
  • Если уж хочется приложение с модной навигацией, пишите сразу под Windows App SDK, а не WPF. Там конечно своих приколов достаточно, но навигация в порядке, и события есть, по которым видно, когда сраница пришла на экран, и когда ушла. И NavigationView толковый. – aepot Jan 11 '22 at 09:33
  • Честно, отвечать вообще не хочется, ибо я вам уже много раз писал, что вы делаете ерунду: 1. Page и Frame - это ИМХО, нарушение MVVM, они не предназначены для него от слова совсем! 2. View слой не должен отвечать за VM, а значит не должно быть всяких DataContext="{Binding Page1ViewModel, Source={StaticResource ViewModelLocator}}" в XAML. 3. Статика ЗЛО, а у вас весь ViewModelLocator на нем... Не захотели, ну вот, страдайте теперь, вас предупреждали, раз не хотите слушать более опытных людей. А у меня нет желания разбирать этот костыль и повторять все в сотый раз, извините. – EvgeniyZ Jan 11 '22 at 11:14
  • @EvgeniyZ а можно пример проекта, например с GitHub? Я просто не совсем понимаю, я на WPF даже и месяц на работал. Я делал по этому примеру – Mr. Dandomi Jan 11 '22 at 19:14
  • @Mr.Dandomi Я вам очень сильно советую научиться выбирать правильных учителей, правильный материал, а не первого попавшегося парня с ютуба, который сам толком не знает, что делает, но учит людей. Научитесь сами анализировать, сами воспринимать материал, искать его на англоязычных ресурсах и т.д. Я вам уже говорил: "забудьте про фреймворки, познайте базу WPF, а затем облегчайте себе жизнь всем сторонним", вы же меня не послушали. Ну а пример, вам уже кидали пример, смотрите предыдущие ваши вопросы. – EvgeniyZ Jan 11 '22 at 19:49
  • @EvgeniyZ я решил последовать Вашему совету. Я воспользовался примером который мне кидали. Но View1 и View2 ошибка, которую мне не удалось исправить. Скрин – Mr. Dandomi Jan 11 '22 at 20:10
  • @Mr.Dandomi Проект пересоберите, WPF обновляет все данные для XAML только после успешной сборки! Ключевое слово "успешной", если есть еще ошибки, которые мешают сборке, устраните их. – EvgeniyZ Jan 11 '22 at 20:13
  • @EvgeniyZ вот и в этом проблема. Я был удивлён, но именно эти ошибки мешают сборки. Больше ошибок нет – Mr. Dandomi Jan 11 '22 at 20:16
  • 1
    @Mr.Dandomi ну тут уж извините, без самодостаточного примера, я вам не скажу, где у вас проблема. У вас, по сути, несколько вариантов: 1. Есть еще ошибка, помимо XAML привязок. 2. Проект не пересобрали. 3. namespace указанного класса отличается от того, что вы пишете в XAML. Вот собственно и проверяйте все это. – EvgeniyZ Jan 11 '22 at 20:21
  • @EvgeniyZ так и не смог найти причину. Не поможете? – Mr. Dandomi Jan 16 '22 at 20:19
  • @Mr.Dandomi Скачал, чуть подправил namespace в xaml (clr-namespace:WpfMVVMCore.ViewModels;assembly=WpfMVVMCore, тут ;assembly=WpfMVVMCore лишнее), очистил, пересобрал. Вроде проблем нет... – EvgeniyZ Jan 16 '22 at 20:33
  • Да, спасибо, получилось (хотя ранее я удалял ;assembly=WpfMVVMCore, и у меня всё равно не работало, ну да ладно). Это несколько сложная реализация MVVM для меня. Как тут можно создавать окна профиля с разным id и реализовать кнопку back page? – Mr. Dandomi Jan 20 '22 at 19:37

0 Answers0