Заполните ListView при изменении combobox - правильная реализация MVVM - PullRequest
0 голосов
/ 29 апреля 2018

Моя цель - : ComboxBox со списком имен учетных записей Jira и ListView, который будет отображать ответ на запрос, отправленный jira, при выборе пользователя в ComboBox (поскольку имя учетной записи является частью запроса).

Что у меня есть: немного знаний о C #, WPF, MVVM и рабочее решение (код ниже), но это не MVVM в любом случае. Итак, я много читал о MVVM (relayCommand, PropertyChanged и т. Д.), Но по какой-то причине я просто не могу найти решение о том, как реорганизовать эту программу в MVVM. Одна из самых больших проблем заключается в том, что я не могу понять, как сделать этот запрос Jira и привести к форме IQueryable, соответствующей шаблону MVVM. Я имею в виду, где я должен это разместить.

Так что, пожалуйста, , если кто-нибудь может намекнуть мне, что я должен делать в целом, чтобы преобразовать эту программу в соответствии с шаблоном MVVM или любым другим типом совета, я был бы очень признателен!

MainWindow.xamls.cs

public ObservableCollection<Issue> Issues { get; set; }

private void OnNameComboChanged(object sender, EventArgs e)
{
    Issues.Clear();

    string name = ((sender as ComboBox).SelectedItem as ComboBoxItem).Content as string;
    Issues fetchedIssues = new Issues();

    var issuesList = fetchedIssues.FetchIssues(name); // returns the list of Issues in a type of --> IQueryable<Issue>
    foreach (var issue in issuesList)
    {
        Issues.Add(issue);
    }    
}

public MainWindow()
{
    Issues = new ObservableCollection<Issue>();
    InitializeComponent();
}

MainWindow.xaml

<Controls:MetroWindow x:Name="Main_Window" x:Class="Dull.MainWindow"
    ........
    DataContext="{Binding RelativeSource={RelativeSource Self}}"> <!-- how I link contexts-->
<Controls:MetroWindow.RightWindowCommands>
    <Controls:WindowCommands>
        <ComboBox x:Name="Name" SelectionChanged="OnNameComboChanged" > <!-- Combox box with nicknames -->
            <ComboBoxItem>name of the user</ComboBoxItem>
            <ComboBoxItem>another name of the user</ComboBoxItem>
        </ComboBox>
    </Controls:WindowCommands>
</Controls:MetroWindow.RightWindowCommands>
<Grid>
    <ListView x:Name="issuesListView" ItemsSource="{Binding Issues}"> <!-- ListView binded to Issues collection -->
        <ListView.ItemTemplate>
            <DataTemplate>
              <TextBlock Text="{Binding Summary}" 
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>

1 Ответ

0 голосов
/ 29 апреля 2018

Существуют различные фреймворки, такие как Prism , Caliburn Micro , MVVMLight и многие другие, которые предоставляют функции для написания приложения шаблона проектирования MVVM. Немного из функций, которые предоставляют упомянутые рамки

  1. DelegateCommand или RelayCommand
  2. ViewModelLocator
  3. Контейнер / Модуль
  4. Агрегатор событий

Эти функции упрощают написание кода в шаблоне проектирования MVVM. Однако, если вам не нужны все эти функции и вы не хотите их интегрировать, не беспокойтесь об этом.

Теперь все разговоры в этом ответе основаны на том, что вы хотите написать для своей реализации без этих каркасов.

Вы можете обратиться к этому блогу, чтобы написать RelayCommand . Вам требуется реализация ICommand, если вы хотите отделить View от ViewModel. Эти команды ViewModel могут быть интегрированы с View с использованием триггера Blends 'Interacctivity (см. sample ).

Все вышеизложенное было подготовкой к решению вашего вопроса. Следуйте инструкциям

  1. Создание ViewModel

В представленной ниже модели ViewModel показано, что вам требуется:

public class MyViewModel : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;

    private ObservableCollection<Issue> issues = new ObservableCollection<Issue>();
    public ObservableCollection<Issue> Issues { get {return issues;} }

    private ObservableCollection<string> users = new ObservableCollection<string>();
    public ObservableCollection<string> Users { get {return users;} }

    private string user;
    public string User 
    {
        get 
        {
            return user;
        }
        set
        {
            user = value;
            NotifyPropertyChanged();
        }
    }

    private ICommand userChangedCommand;

    public ICommand UserChangedCommand
    {
        get
        {
            return userChangedCommand ?? (userChangedCommand = new RelayCommand(
                x =>
                {
                    OnUserChanged();
                }));
        }
    }

    private ICommand loadedCommand;

    public ICommand LoadedCommand
    {
        get
        {
            return loadedCommand?? (loadedCommand= new RelayCommand(
                x =>
                {
                    // Write Code here to populate Users collection.
                }));
        }
    }

    private void OnUserChanged()
    {
        Issues.Clear();

        string name = this.User;
        Issues fetchedIssues = new Issues();

        var issuesList = fetchedIssues.FetchIssues(name); // returns the list of Issues in a type of --> IQueryable<Issue>
        foreach (var issue in issuesList)
        {
            Issues.Add(issue);
        }    
    }

    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

}

2. Просмотреть изменения:

    <Controls:MetroWindow x:Name="Main_Window" x:Class="Dull.MainWindow" ........
    >
    <i:EventTrigger EventName="Loaded" >
        <i:InvokeCommandAction Command="{Binding LoadedCommand}" />
      </i:EventTrigger>
     </i:Interaction.Triggers>
      <Controls:MetroWindow.RightWindowCommands>
       <Controls:WindowCommands>
        <ComboBox x:Name="Name" ItemsSource="{Binding Users}" SelectionChanged="OnNameComboChanged" SelectedItem="{Binding User}" > <!-- Combox box is getting user details from ViewModel -->
            <i:Interaction.Triggers>
         <i:EventTrigger EventName="SelectionChanged" >
           <i:InvokeCommandAction Command="{Binding UserChangedCommand}" />
          </i:EventTrigger>
        </i:Interaction.Triggers>
        </ComboBox>
       </Controls:WindowCommands>
      </Controls:MetroWindow.RightWindowCommands>
    <Grid>
    <ListView x:Name="issuesListView" ItemsSource="{Binding Issues}"> <!-- ListView binded to Issues collection -->
        <ListView.ItemTemplate>
            <DataTemplate>
              <TextBlock Text="{Binding Summary}" 
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>

3. Теперь последняя часть Как Привязать ViewModel к представлению .

Если вы используете упомянутые фреймворки, то это будет тривиально на основе функции ViewModelLocator. Тем не менее, чтобы достичь без рамок, вы можете использовать один из следующих подходов. 1) Создайте экземпляр ViewModel и назначьте его в методе InitializeComponent элемента управления (.Xaml.cs)

var vm = new MyViewModel();
this.DataContext = vm;

Однако это нарушает чистый шаблон проектирования MVVM

2) Вы можете создать экземпляр в самом представлении

   <Controls:MetroWindow x:Name="Main_Window" x:Class="Dull.MainWindow">
       <Controls:MetroWindow.DataContext>
        <VM:MyViewModel />
    </Controls:MetroWindow.DataContext>
    ...............
   </Controls:MetroWindow>
...