2016-10-26 7 views
0

웹 사이트에서 기사 링크를 다운로드하여 눈금으로 표시하는 WPF 응용 프로그램을 작성 중입니다. 문제의WPF에서 데이터 격자를 동적으로 업데이트

요약 :

내가 타격하고있어 문제는 내가 내 뷰 모델에 정의 된 데이터 그리드에 바인딩 된 ObservableCollection에 기사에 대한 액세스 (하지 않는 모델의 논리를 다운로드 한 것입니다).

새로운 기사를 다운로드 할 때이 컬렉션을 업데이트하려면 어떻게해야합니까? (데이터 그리드가 새로운 기사를 하나씩 계속 추가 할 수 있도록)

세부 사항 :

여기에 (내가 쉽게 읽을 유지하기 위해하지 않는 것이 중요 부품의 일부를 잘라) MVVM 패턴을 구현하는 내 응용 프로그램의 개요입니다 :

DisplayWindow.xaml 가 바인딩 소스가 PresenterViewModel.cs와 ItemSource가 ObservableCollection에 어떤 기사로 설정 그것은 또한 문서의 다운로드를 트리거 버튼이

<Grid DataContext="{Binding Source={StaticResource presenterViewModel}}"> 
     <DataGrid ItemsSource="{Binding Articles}"> 
      <DataGrid.Columns> 
       <DataGridTextColumn Header="Url" Binding="{Binding Url}"/> 
... 
      </DataGrid.Columns> 
     </DataGrid> 
</Grid> 

(아래 참조)

 <Button Content="Download" Command="{Binding DownloadArticles, Mode=OneWay}"/> 

DownloadArticles 방법을 통해 링크 PresenterViewModel의 일부이며 ICommand의 인터페이스를 구현 DownloadCommand의 인스턴스를 리턴한다.

PresenterViewModel.cs

contains ObservableCollection<Article> Articles 

private ObservableCollection<Article> articles; 

     public ObservableCollection<Article> Articles 
     { 
      get { return articles; } 

      set 
      { 
       articles = value; 
       RaisePropertyChangedEvent("Articles"); 
      } 
     } 
     public ICommand DownloadArticles 
     { 
      get 
      { 
       return downloadCommand; 
      } 
     } 

DownloadCommand는 PresenterViewModel과는 제 모델 자체 DownloadArticles를 호출하는 방법 DownloadArticles을의 방법은 호출 실행에 대한 참조를 포함합니다. DownloadCommand.cs에서

:

 public void Execute(object parameter) 
     { 
      presenterViewModel.DownloadArticles(); 
     } 

솔루션 나는 생각했다 :

자, 문제는 내가 Article.cs 모델 DownloadArticles 방법에있어 및 ObservableCollection에 기사를 업데이트해야되는 PresenterViewModel의 일부입니다 ... 어떻게해야합니까? DownloadArticles 메서드는 별도의 스레드에서 다운로드 논리를 실행합니다.

PresenterViewModel에 대한 참조를 모델의 DownloadArticles 메서드에 전달해야합니까?

이것은 쉽게 할 수있는 것처럼 보이지만 모델이 ViewModel에 연결되어야한다고 생각하지 않습니다.이 경우 메소드 중 하나에서 PresenterViewModel 객체를 사용할 수 있습니다.

또 다른 옵션은 PresenterViewModel에서 직접 로직을 다운로드하는 것이지만 내 ViewModel을 경량으로하고 로직을 포함하지 않기를 바라는 한 느낌이 들지 않습니다.

이 경우 가장 좋은 해결책은 무엇입니까? 내 아키텍처가 근본적으로 잘못되었다고 생각한다면,이 경우 구조화의 가장 좋은 방법이 무엇인지 알려 주시기 바랍니다.

정말 고맙게 생각합니다.

+0

프로세스를 처리하기 위해 중간에 DLL이 필요하다고 생각됩니다. 다운로더는 뷰 모델에 대해 알지 못하며 반대의 경우도 마찬가지입니다. –

+0

모델에서 이벤트를 격렬하게해야 할 수도 있습니다. 그리고 뷰 모델에서 구독하십시오. –

+0

당신의'Command'는'VM'에 있어야하고 당신의 다운로더는'Model'에 있어야합니다. 귀하의'VM' 모델에 대한 참조가 있어야합니다. 이 방법은 Model과 ViewModel 간의 통신에 문제가 없으며 MvvM이 작동하는 방식입니다. – XAMlMAX

답변

1

자, 문제는 내가 그렇게 어떻게 ... PresenterViewModel의 일부이다 ObservableCollection에 내가 Article.cs 모델 에서 DownloadArticles 방법에있어 및 기사를 업데이트해야입니까?

당신이해야 할 일은 데이터 액세스 로직을 다른 레이어로 분리하여 ViewModel에 의존성으로 주입하는 것입니다. 이렇게하면 데이터 접근 로직을 ViewModel에 연결하지 않을 것입니다. 그 작업은 Model을 View에 노출시키고 사용자 입력에 응답해야하기 때문입니다.

public class Article : INotifyPropertyChanged 
{ 
    private string _url; 
    public string Url 
    { 
     get 
     { 
      return _url; 
     } 
     set 
     { 
      _url = value; 
      PropertyChanged("Url"); 
     } 
    } 
} 

모든 데이터 액세스 로직 내가 DataService의를 호출 별도의 레이어로 이동 :

이 모델은 다음과 같이 보입니다한다고 가정하자. 사용자 요청이 DownloadCommand이 작업을 위임을 유발하여 기사를 다운로드 할 때 데이터 액세스 계층은 다음의 ViewModel 마지막으로

public class PresenterViewModel : BaseViewModel 
{ 
    private readonly IDataService _dataService; 

    public PresenterViewModel(IDataService dataService) 
    { 
     _dataService = dataService; 
    } 
} 

을에 주입

public interface IDataService 
{ 
    IList<Article> DownloadArticles(); 
} 

public class DataService : IDataService 
{ 
    public IList<Article> DownloadArticles() 
    { 
     var articles = new List<Article>(); 
     // you actually download articles here 
     return articles; 
    } 
} 

: 그 작업은 외부 자원과 다운로드 기사에 액세스하는 것입니다 귀하의 서비스에 대한 응답을 기다리고 결과가 귀하의 ViewModel의 ObservableCollection<Article> Articles 속성에 의해 노출 될 것입니다 :

// your DownlodArticles command's execute method 
public void Execute(object parameter) 
{ 
    var articles = _dataService.DownloadArticles(); 
    Articles = new ObservableCollection(articles); 
} 
어떤 이유로 당신이 의존성 주입을 사용하지 않으려면 14,, 당신이 싱글로 DataService의를 구현하고 뷰 모델에서 호출 할 수 있습니다

public class DataService 
{ 
    private static DataService _instance; 
    public static DataService Instance 
    { 
     get 
     { 
      if (_instance == null) 
      { 
       _instance = new DataService(); 
      } 

      return _instance; 
     } 
    } 

    public IList<Articles> DownloadArticles() 
    { 
     // ... 
    } 
} 

public void Execute(object parameter) 
{ 
    var articles = _DataService.Instance.DownloadArticles(); 
    Articles = new ObservableCollection(articles); 
} 

UPDATE :

귀하의 데이터 서비스 GetArticles 방법 :

public Task DownloadArticles(ICollection<Article> articles) 
{ 
    // clear the collection if neccessary 
    articles.Clear(); 

    return Task.Run(() => 
    { 
     // load articles one by one and add them to the collection 
    } 
} 

귀하의 ViewModel의 명령을 실행 방법 :

private async void Execute(object parameter) 
{ 
    await _dataService.LoadArticles(Articles); 
} 
+0

알렉스 감사합니다! 두 가지 질문 : 1) IDataService dataService를 PresenterViewModel 생성자로 어떻게 보냅니 까? 현재이 객체는 DisplayWindow.xaml의 섹션에 정의되어 있습니다. 2) 귀하의 구현에서 DataService의 DownloadArticles()는 단순히 기사를 다운로드하여 반환합니다 ... 하나씩 다운로드해야하고 ObservableCollection을 다운로드 할 때 (다운로드 될 때까지 기다리는 대신) 어떻게 처리해야합니까? ? 다운로드 할 기사 컬렉션을 업데이트 할 수 있도록 PresenterViewModel에 대한 참조를 DownloadArticles()에 전달해야합니까? – Bart

+0

첫 번째 질문은 의존성 주입과 제어 반전에 관한 것입니다. 이 기사에서 IoC 컨테이너를 사용하는 이유와 방법 및시기에 대해 설명합니다. https://msdn.microsoft.com/en-us/magazine/jj991965.aspx. 그러나 싱글 톤을 만드는 것과 같은 다른 접근법 (내 대답에서 언급 한 것과 같은)이 있거나 뷰 모델에서 서비스의 인스턴스를 직접 생성하는 것과 같이 반드시 사용해야 할 필요는 없습니다. – Alex

+0

기사를 하나씩 다운로드 할 때 단순히 컬렉션에 대한 참조를 받아들이고 새로운 컬렉션을 반환하는 대신 업데이트하는 방법을 구현할 수 있습니다. 분명히 비동기 적이어야 UI 스레드를 차단하지 않으므로 스레드 선호도 및 기타 비동기 관련 항목을 기억하십시오. 예를 들어 업데이트 된 답변을 살펴보십시오. – Alex

관련 문제