У меня есть страница (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">
<Page.Resources>
<Style TargetType="TextBlock" x:Key="TextBlockDescription">
<Style.Triggers>
<Trigger Property="Text" Value="">
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
<Trigger Property="Text" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
</Style.Triggers>
</Style>
</Page.Resources>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding LoadedCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid>
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition MinHeight="150" />
<RowDefinition MinHeight="200" Height="*"/>
<RowDefinition MinHeight="170"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="72" MinWidth="72"/>
<ColumnDefinition Width="240*" MinWidth="258" MaxWidth="480"/>
<ColumnDefinition Width="121"/>
<ColumnDefinition Width="337"/>
</Grid.ColumnDefinitions>
<Border CornerRadius="5" Opacity="40" Grid.Column="1" Grid.Row="0" Margin="10" Background="#FF383838" VerticalAlignment="Center">
<Grid>
<Image x:Name="image" Grid.Column="0" HorizontalAlignment="Left" Height="106" Margin="10" VerticalAlignment="Top" Width="106" Source="{Binding avatar}" Stretch="UniformToFill"/>
<DockPanel Margin="130,0,0,0" d:Background="Red" VerticalAlignment="Top" >
<TextBlock TextWrapping="WrapWithOverflow" DockPanel.Dock="Top" Foreground="White" FontSize="20"><Run d:Text="Имя}" Text="{Binding first_name}"/><Run Text=" "/><Run d:Text="Фамилия" Text="{Binding last_name}"/></TextBlock>
<TextBlock x:Name="status" DockPanel.Dock="Top" TextWrapping="Wrap" d:Text="Статус" Foreground="White" RenderTransformOrigin="0.5,0" Text="{Binding status}"/>
</DockPanel>
</Grid>
</Border>
<Border CornerRadius="5" Opacity="40" Grid.Column="1" Grid.Row="1" Margin="10" Background="#FF383838" VerticalAlignment="Top">
<Grid>
<DockPanel d:Background="Red">
<TextBlock Style="{StaticResource TextBlockDescription}" Margin="10,5,10,5" DockPanel.Dock="Top" TextWrapping="Wrap" d:Text="29 подписчиков" Foreground="White" FontSize="15" VerticalAlignment="Top" HorizontalAlignment="Left" Height="Auto" Text="{Binding followers_count}"/>
<TextBlock Style="{StaticResource TextBlockDescription}" Margin="10,5,10,5" DockPanel.Dock="Top" TextWrapping="Wrap" d:Text="Город: " Foreground="White" FontSize="15" VerticalAlignment="Top" HorizontalAlignment="Left" Height="Auto" Text="{Binding home_town}"/>
<TextBlock Style="{StaticResource TextBlockDescription}" Margin="10,5,10,5" DockPanel.Dock="Top" TextWrapping="Wrap" d:Text="Работает в: " Foreground="White" FontSize="15" VerticalAlignment="Top" HorizontalAlignment="Left" Height="Auto" Text="{Binding Occupations}"/>
<TextBlock Style="{StaticResource TextBlockDescription}" Margin="10,5,10,5" DockPanel.Dock="Top" TextWrapping="Wrap" d:Text="Сайт" Foreground="White" FontSize="15" VerticalAlignment="Top" HorizontalAlignment="Left" Height="Auto" Text="{Binding site}"/>
<Button DockPanel.Dock="Top" HorizontalAlignment="Stretch" Content="Подробная информация" Command="{Binding AddPanel}"/>
</DockPanel>
</Grid>
</Border>
<Grid Grid.Column="1" Margin="10" Grid.Row="2" Background="#FF383838" VerticalAlignment="Top">
<StackPanel>
<Label Content="Друзья" Margin="10" Foreground="White" FontSize="20"/>
<ListBox Margin="10" ItemsSource="{Binding Friends}" SelectedValue="{Binding SelectedFriendId}" SelectedValuePath="IdFriend">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Image Grid.Row="0" Source="{Binding AvatarFriend}"/>
<TextBlock Grid.Row="1" Text="{Binding NameFriend}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Grid>
</Grid>
</Grid>
</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; } = "https://vk.com/images/camera_200.png";
#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<Friend>? Friends { get; private set; }
#endregion
public Page1ViewModel(PageService pageService, ControlService controlService, EventBus eventBus, MessageBus messageBus, int id = 0)
{
PanelVMs = new ObservableCollection<PanelViewModel>();
Debug.WriteLine(Properties.Settings.Default.token);
_pageService = pageService;
_controlService = controlService;
_eventBus = eventBus;
_messageBus = messageBus;
_controlService.OnUserControlChanged += (usercontrol) => Change(usercontrol);
_messageBus.Receive<TextMessage>(this, async message =>
{
//MessageBox.Show("Открыл профиль " + 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<Page1ViewModel>(new TextMessage(ID.ToString()));
//MessageBox.Show(CurrentID.ToString());
}
public ICommand SendLog => new AsyncCommand(async () =>
{
await _messageBus.SendTo<LogPageViewModel>(new TextMessage(LogText.ToString()));
//await _messageBus.SendTo<object>(new TextMessage(LogText));
});
public void Loaded()
{
avatar = "https://imgur.com/pKopwXp"; // загрузка
if (CurrentID == null)
{
//MessageBox.Show("Моя старница");
GetProfileInfo();
CurrentID = "0";
}
else
{
UsersGet();
}
GetFindFriends();
}
private async void GetFindFriends()
{
var data = await Utility.FetchFriendsInfo(CurrentID, "5");
Friends = new ObservableCollection<Friend>();
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<MainViewModel>(new TextMessage(data.ToString()));
first_name = data.response.first_name;
last_name = data.response.last_name;
avatar = data.response.photo_200;
home_town = "Город: " + data.response.home_town;
status = data.response.status == null ? "" : data.response.status;
}
private dynamic ProfileInfo {get; set;}
public async void UsersGet()
{
var data = await Utility.UsersGet(CurrentID);
await _messageBus.SendTo<MainViewModel>(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 = "Город: " + data.response[0].home_town;
status = data.response[0].status == null ? "" : data.response[0].status;
followers_count = data.response[0].followers_count + " подписчиков";
Occupations = data["response"][0]["occupation"]["name"];
site = data["response"][0]["site"];
}
private ObservableCollection<PanelViewModel> _panelVMs;
public ObservableCollection<PanelViewModel> PanelVMs
{
get { return _panelVMs; }
set { SetProperty(ref _panelVMs, value, () => 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<PanelViewModel>(new TextMessage(ProfileInfo.ToString()));
}
#region Выбор id друга
public int SelectedFriendId
{
get { return _selectedFriendId; }
set
{
if (value != _selectedFriendId)
{
Debug.WriteLine(string.Format("setting friend to: {0}", value));
OpenProfile(value);
_selectedFriendId = value;
}
}
}
#endregion
/*public int SelectedOccupationId
{
get { return _selectedOccupationId; }
set
{
if (value != _selectedOccupationId)
{
Debug.WriteLine(string.Format("Selected Occupation: {0}", value));
_selectedOccupationId = value;
}
}
}*/
private DelegateCommand loadedCommand;
public ICommand LoadedCommand => loadedCommand ??= new DelegateCommand(Loaded);
private object currentPage;
public object CurrentPage { get => currentPage; set => 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 = "")
{
OnPageChanged?.Invoke(page, message);
}
}
MainViewModel
public Page PageSource { get; set; }
public MainViewModel(PageService pageService, MessageBus messageBus)
{
_pageService = pageService;
_messageBus = messageBus;
_pageService.OnPageChanged += (page, message) => Change(page, message);
_pageService.ChangePage(new LoginPage());
_messageBus.Receive<TextMessage>(this, async message =>
{
logtext = message.Text;
});
}
public void Change(Page page, string message)
{
PageSource = page;
}
PageиFrame- это ИМХО, нарушение MVVM, они не предназначены для него от слова совсем! 2. View слой не должен отвечать за VM, а значит не должно быть всякихDataContext="{Binding Page1ViewModel, Source={StaticResource ViewModelLocator}}"в XAML. 3. Статика ЗЛО, а у вас весьViewModelLocatorна нем... Не захотели, ну вот, страдайте теперь, вас предупреждали, раз не хотите слушать более опытных людей. А у меня нет желания разбирать этот костыль и повторять все в сотый раз, извините. – EvgeniyZ Jan 11 '22 at 11:14namespaceуказанного класса отличается от того, что вы пишете в XAML. Вот собственно и проверяйте все это. – EvgeniyZ Jan 11 '22 at 20:21clr-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