Обработчик события Click гиперссылки не видит фрейм

Сделал на странице в WPF разбивку на несколько отдельных фреймов со страницами. Задача сделать по фрейму с оглавлением слева переход на разные страницы с текстом справа- уже в другом фрейме. Решил реализовать через и её параметр click с обработчиком событий в C#, но при попытке прописать в C# навигацию по страницам в другом фрейме компилятор не видит этого фрейма.введите сюда описание изображения

Код, задающий два фрейма:

<Frame Grid.Column="0" Grid.Row="0" x:Name="listframe"></Frame>
    <Frame Grid.Row="0" Grid.Column="1" x:Name="soderzhaniyeframe"></Frame>

Код, задающий гиперссылки и создающий обработчик события:

<Paragraph>
                1.<Hyperlink x:Name="Theme1hyper" Click="Theme1hyper_Click"> Первая тема</Hyperlink>
            </Paragraph>
            <Paragraph>
                <Hyperlink x:Name="Theme1_1pdhyper" Click="Theme1_1pdhyper_Click">1 Подтема</Hyperlink>
            </Paragraph>

Код события click на C#, который я пытаюсь применить, но компилятор не видит soderzhaniyeframe:

  private void Theme1hyper_Click(object sender, RoutedEventArgs e)
    {
        soderzhaniyeframe.navigation(new soderzhanie_page()); 

    }

Ответы (1 шт):

Автор решения: Aarnihauta

Для начала стоит Вам прочитать про Binding в Wpf. Так как Wpf был нацелен непосредственно на MVVM, то и про него стоило бы прочитать и использовать данный подход. Работать с обработчиками событий у контролов неудобно, для этого и существует привязка (она же Binding)

Материала достаточно на YouTube (Павел Шмачилин, у него там часовые видео по WPF), есть Метанит, да и у Майкрософта есть хорошие примеры

Касаемо Вашей задачи, для начала создадим класс BaseViewModel и реализуем в ней INotifyPropertyChanged. Метод SetProperty позволит нам перенести часто используемый код в отдельный метод.

Теперь BaseViewModel.

class BaseViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged([CallerMemberName] string prop = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
    }

    public void SetProperty<T>(ref T store, T value, [CallerMemberName] string prop = "")
    {
        if(store.Equals(value))
           return;

        store = value;
        OnPropertyChanged(prop);
    }
}

Теперь нам нужен класс модели которая будет содержать в себе данные. Назовем её Theme, поскольку нам нужен список тем и подтем. В этом методе переопределю ToString() который будет возвращать Title (Это не самое удачное решение, потому что для вывода ToString() не используется, но мы опустим этот момент)

public class Theme
{
    public string Title { get; set; }
    public string Content { get; set; }
    public override string ToString()
    {
        return Title;
    }
}

Создадим ThemeViewModel которую будем привязывать ко всему окну.

class ThemeViewModel : BaseViewModel
{
    private string _content;
    private string _title;

    //Эти свойства будем привязывать к конкретным элементам окна
    public string Title { get => _title; set => SetProperty(ref _title, value); }
    public string ThemeContent { get => _content; set => SetProperty(ref _content, value); }
    public ObservableCollection<Theme> Themes { get; set; }

    public ThemeViewModel()
    {
        InitThemes();
    }

    private void InitThemes()
    {
        //Это можно получить из БД к примеру, но я заполню вручную. 
        Themes = new ObservableCollection<Theme>();

        Theme theme = new Theme
        {
            Title = "Title 1",
            Content = "Content 1",
        };
        Theme theme2 = new Theme
        {
            Title = "Title 2",
            Content = "Content 2"
        };

        Themes.Add(theme);
        Themes.Add(theme2);
    }
}

Теперь окно xaml. Заметьте, что я добавил SelectionChanged у ListBox.

<Window x:Class="wpftest.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:vm="clr-namespace:wpftest.ViewModels"
        mc:Ignorable="d"
        Title="MainWindow" Height="500" Width="700">

    <!-- Обозначим контекст данных, из этого класса будут браться данные -->
    <Window.DataContext>
        <vm:ThemeViewModel></vm:ThemeViewModel>
    </Window.DataContext>

    <Grid.ColumnDefinitions>
         <ColumnDefinition Width="200"></ColumnDefinition>
         <ColumnDefinition></ColumnDefinition>
     </Grid.ColumnDefinitions>

     <Grid.RowDefinitions>
          <RowDefinition Height="45"></RowDefinition>
          <RowDefinition Height="200"></RowDefinition>
          <RowDefinition></RowDefinition>
     </Grid.RowDefinitions>


    <Grid Grid.Row="1" Grid.Column="0">
        <ListBox x:Name="listBoxThemes" ItemsSource="{Binding Themes}" 
                SelectionChanged="listboxThemes_SelectionChanged">
        </ListBox>
    </Grid>

    <Grid Grid.Row="1" Grid.Column="1">
        <ScrollViewer>
                <TextBlock Text="{Binding ThemeContent}" FontSize="15" TextWrapping="Wrap">
                </TextBlock>
        </ScrollViewer>
    </Grid>
</Window>

Внутри MainWindow.cs:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void listboxThemes_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
    {
        //Приводим текущий контекст данных к нашей ThemeViewModel и задаем свойство ThemeContent из SelectedItem нашего листбокса. Такое возможно, поскольку к листбоксу мы привязали ObservableCollection<Theme>
        (this.DataContext as ThemeViewModel).ThemeContent = (listBoxThemes.SelectedItem as Theme).Content;
    }
}

Теперь запустим и вот что получим:

введите сюда описание изображения

→ Ссылка