Связанные значения динамического ViewModel становятся нулевыми в WPF - PullRequest
0 голосов
/ 25 апреля 2019

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

  1. В моем MainWindow у меня есть ListView на левой панели с ItemsSource списка под ViewModels.(Каждая подчиненная ViewModel реализует Интерфейс)
  2. Каждая ViewModel имеет свой собственный View в качестве DataTemplate.
  3. Я вызываю метод GenerateReport () для выбранного представления из MainWindow.Но значения выбранных представлений становятся нулевыми.

Загрузите мой источник с Github .

Действия по воспроизведению проблемы:

  1. Запустите приложение и введите текст вИдентификатор и имя отчета студентов.(Точки останова в свойствах StudentReportViewModels правильно устанавливаются и значения обновляются.)
  2. Затем нажмите кнопку «Создать отчет».Значения свойств StudentReportViewModels становятся нулевыми.

Как решить проблему?Пожалуйста, помогите.

Источник: MainWindow.xaml

<Window.Resources>
    <DataTemplate DataType="{x:Type vm:StudentsReportViewModel}">
        <view:StudentsReport/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:MarksReportViewModel}">
        <view:MarksReport />
    </DataTemplate>
</Window.Resources>
<Window.DataContext>
    <local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="200"/>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <ListView ItemsSource="{Binding Reports}" SelectedItem="{Binding SelectedReport, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Name}"/>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

    <GridSplitter Grid.Row="1" Grid.Column="1" Width="5" ResizeBehavior="PreviousAndNext" HorizontalAlignment="Stretch"/>
    <Grid Grid.Column="2">
        <Grid.RowDefinitions>
            <RowDefinition Height="2*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
            <ContentControl Content="{Binding SelectedReport.ViewModel, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        </ScrollViewer>
        <Button Content="Generate Report" Grid.Row="2" Margin="5" HorizontalAlignment="Right" Command="{Binding GenerateReportCommand}"/>
    </Grid>
</Grid>

MainWindowViewModel:

public class MainWindowViewModel : INotifyPropertyChanged
{
    private ICommand _generateReportCommand;

    private Report selectedReport;
    public Report SelectedReport
    {
        get
        {
            return this.selectedReport;
        }

        set
        {
            if (value != this.selectedReport)
            {
                this.selectedReport = value;
                NotifyPropertyChanged();
            }
        }
    }

    public List<Report> Reports { get; set; }

    public ICommand GenerateReportCommand
    {
        get
        {
            if (_generateReportCommand == null)
            {
                _generateReportCommand = new RelayCommand(
                    p => GenerateReport()
                    );
            }

            return _generateReportCommand;
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    public MainWindowViewModel()
    {
        Reports = new List<Report>
        {
            new Report{ Name = "Students Report", ViewModel = new StudentsReportViewModel()},
            new Report{ Name = "Marks Report", ViewModel = new MarksReportViewModel()}
        };

        SelectedReport = Reports[0];
    }

    public void GenerateReport()
    {
        SelectedReport.ViewModel.GenerateReport();
    }
}

StudentsReport.xaml

<TextBox Height="25" Width="100" Margin="5" Text="{Binding Id, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
        <TextBox Height="25" Width="100" Margin="5" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

StudentsReportViewModel:

public class StudentsReportViewModel : INotifyPropertyChanged, IReportViewModel
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private string id;
    public string Id
    {
        get
        {
            return this.id;
        }

        set
        {
            if (value != this.id)
            {
                this.id = value;
                NotifyPropertyChanged();
            }
        }
    }

    private string name;
    public string Name
    {
        get
        {
            return this.name;
        }

        set
        {
            if (value != this.name)
            {
                this.name = value;
                NotifyPropertyChanged();
            }
        }
    }

    public StudentsReportViewModel()
    {

    }

    public void GenerateReport()
    {
        System.Windows.MessageBox.Show($"Id = {Id}, Name = {Name}");
    }
}

Интерфейс:

public interface IReportViewModel
{
    void GenerateReport();
}

Модель:

public class Report
{
    public string Name { get; set; }

    public IReportViewModel ViewModel { get; set; }
}

1 Ответ

2 голосов
/ 25 апреля 2019

Ваш StudentReport.xaml UserControl привязывается к экземпляру StudentsReportViewModel, созданному в XAML:

<UserControl.DataContext>
    <vm:StudentsReportViewModel/>
</UserControl.DataContext>

Однако кнопка Создать отчет вызывает другой экземпляр StudentsReportViewModel, который создается в конструкторе MainWindowVieModel и хранится в классе отчета.

Reports = new List<Report>
{
    new Report{ Name = "Students Report", ViewModel = new StudentsReportViewModel()},
    new Report{ Name = "Marks Report", ViewModel = new MarksReportViewModel()}
};

Вам необходимо удалить один из этих экземпляров, чтобы DataContext UserControl был привязан к тому же экземпляру модели представления, из которого вы генерируете сообщение отчета. Я предлагаю удалить этот код из StudentsReport.xaml:

<UserControl.DataContext>
    <vm:StudentsReportViewModel/>
</UserControl.DataContext>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...