更改组合框时填充ListView - 正确的MVVM实现

时间:2018-04-29 16:06:38

标签: c# wpf mvvm jira-rest-api

我的目标是:带有Jira帐户名和ListView列表的ComboxBox,它将显示发送给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 :(得分:1)

有各种框架,如PrismCaliburn MicroMVVMLight等等,它们提供了编写MVVM设计模式应用程序的功能。提到的框架提供的功能很少

  1. DelegateCommand或RelayCommand
  2. ViewModelLocator
  3. 集装箱/模块
  4. Event Aggregator
  5. 这些功能很容易在MVVM设计模式中编写代码。但是,如果您不需要所有这些功能并且不想集成这些功能,那么请不要担心它。

    现在,这个答案中的所有对话都是基于你想要为没有这些框架的实现而编写的。

    您可以参考此博客撰写RelayCommand。如果要将View与ViewModel隔离,则需要ICommand实现。 ViewModel的这些命令可以使用Blends的Interactivity触发器与View集成(请参阅此sample)。

    以上都是解决问题的前期工作。按照步骤

    1. 创建ViewModel
    2. 以下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并在Control的InitializeComponent方法中指定(.Xaml.cs)

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

      然而,这打破了纯粹的MVVM设计模式

      2)您可以在View自身中创建实例

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