В общем есть некоторый список:
private ObservableCollection<SiteConfig> _sites;
public ObservableCollection<SiteConfig> Sites
{
get => _sites;
set => Set(ref _sites, value);
}
Он находится в основной MainWindnowVM и привязан к одному TabItem. Также есть другой TabItem для регистрации нового элемента в списке сайтов, который находится в другой NewSiteVM. Проблема в том, что не знаю как передать данный список из MainWindnowVM в NewSiteVM, чтобы добавить новую запись при срабатывании команды.
DataContext объявил вот так, не знаю данное объявление нарушает принципы MVVM, но мне было так удобнее, нежеле в XAML
public MainWindow()
{
InitializeComponent();
AllSitesTabItem.DataContext = new MainWindnowVM();
CreateNewPasswordTabItem.DataContext = new NewSiteVM();
}
AllSitesTabItem и CreateNewPasswordTabItem - имена TabItem-ов.
Была идея сделать данный список статичным, но думаю это быдет лишь костыль и не знаю можно ли будет потом его связать с DataGrid.
Вся разметка:
<Window x:Class="PWManager.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:col="clr-namespace:System.Collections;assembly=mscorlib"
mc:Ignorable="d"
Title="PasswordsManager" Height="600" Width="800">
<Grid>
<TabControl x:Name="TabControl" SelectedIndex="{Binding SelectedTabItem}">
<TabItem x:Name="AllSitesTabItem" Header="Мои пароли">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.85*"/>
<RowDefinition Height="0.15*"/>
</Grid.RowDefinitions>
<DataGrid Grid.Row="0" AutoGenerateColumns="False"
Margin="10" Padding="5" ItemsSource="{Binding Path=Sites}"
IsReadOnly="True">
<DataGrid.Columns>
<DataGridHyperlinkColumn Header="Название" Binding="{Binding Path=SiteUsl}"
ContentBinding="{Binding Path=SiteName}">
<DataGridHyperlinkColumn.ElementStyle>
<Style TargetType="TextBlock">
<EventSetter Event="Hyperlink.Click" Handler="OnHyperlinkClick"/>
</Style>
</DataGridHyperlinkColumn.ElementStyle>
</DataGridHyperlinkColumn>
<DataGridTextColumn Header="Дата регистрации" Binding="{Binding Path=RegisteDate}"/>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="10">
<TextBlock Text="Пароль: "/>
<TextBlock Text="{Binding Path=SitePassword}" Margin="0, 0, 10, 0"/>
<TextBlock Text="Последнее изменение: "/>
<TextBlock Text="{Binding Path=DateLastChange}"/>
</StackPanel>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
<Button Grid.Row="1" Content="Создать новый пароль"
Height="50" Margin="10" Command="{Binding Path=NewSiteClick}"/>
</Grid>
</TabItem>
<TabItem x:Name="CreateNewPasswordTabItem" Header="Новый пароль">
<StackPanel Orientation="Vertical" Margin="10">
<TextBlock Text="Название Сайта" Margin="10, 20, 0, 15" FontSize="17"/>
<TextBox Margin="10, 0, 10, 0" Text="{Binding Path=SiteName}"/>
<TextBlock Text="Пароль" Margin="10, 15, 0, 15" FontSize="17"/>
<TextBox Margin="10, 0, 10, 0" Text="{Binding Path=Password}"/>
<TextBlock Text="Повторно пароль" Margin="10, 15, 0, 15" FontSize="17"/>
<TextBox Margin="10, 0, 10, 0" Text="{Binding Path=PasswordAgain}"/>
<TextBlock Text="" Margin="10"/>
<TextBlock Text="Ссылка на сайт" Margin="10, 15, 0, 15" FontSize="17"/>
<TextBox Margin="10, 0, 10, 20" Text="{Binding Path=Uri}"/>
<Button Content="Добавить" Margin="10" Height="50"
Command="{Binding Path=NewSiteClick}" />
</StackPanel>
</TabItem>
</TabControl>
</Grid>
class NewSiteVM { private readonly MainWindnowVM _mainVM; public NewSiteVM(MainWindnowVM mainVM) => _mainVM = mainVM; }далее... = NewSiteVM(this);. Поздравляю, вы передали через конструктор ссылку одного класса на другой, теперь вы можете без труда в классеNewSiteVMполучить доступ к объектам главного класса, например,_mainVM.Sites. – EvgeniyZ Jul 16 '23 at 22:50AllSitesTabItem.DataContext = new MainWindnowVM();, где окно (V слой) вдруг знает про VM и отвечает за него. ТакжеOnHyperlinkClick- это должна быть команда, а значит сейчас у вас за логику отвечает View слой, когда должен отвечать VM, а еще лучше M. В общем, уберите всеx:Nameи пишите код так, чтоб UI был в одном месте, а логика в другом и их ничего не связывало, будет вам MVVM. – EvgeniyZ Jul 16 '23 at 23:22PageVM CurrentPage {get; set;}, а в нужных страницах делаемmainVM.CurrentPage = ...;. Да, если идти глубже, проект больше, то там уже пишется все по принципам IoC, используют контейнеры, делают сервисы, но чистый WPF проект, без всего этого, да еще и для обучения, почему и нет? – EvgeniyZ Jul 17 '23 at 09:40Команду должна исполнять М?- Внимательно прочитайте что я написал, я говорил про логику, а не конкретно команду. Вот у нас в команде логика получения данных из базы, где ей место? В VM или всеж M? Я думаю должна быть своя M, которую мы вызываем в команде, которая находится в VM. Об этом я и писал выше. Так что, как по мне, ваш комментарий весьма странный... – EvgeniyZ Jul 17 '23 at 09:41