2017-12-26 45 views
-3

SO 커뮤니티, 초보자이며 아직 배우고 있습니다 (천천히). 나는 그물에있는 모든 잠재적 인 해결책을 성공없이 구현하려했습니다. 나는 DependencyMethods, DependencyProperties, RelayCommands, ICommand, BaseViewModels 등등과 완전히 자신을 혼란스럽게 생각합니다.WPF/MVVM 추상 일반적인 방법

여기 내 시나리오가 있습니다. 프레임이 포함 된 MainWindow (MainWindow)를 가지고 있습니다. UserControl (SampleUC). MainWindow 및 UserControl DataContext는 각각의 ViewModel (MainWindowVM, SampleUCVM)을 가리 킵니다. MainWindowVM 및 SampleUCVM은 ObservableCollection 도우미 클래스를 통해 INotifyPropertyChanged를 사용하는 Base ViewModel (BASEVM)의 자식입니다. SampleUCVM에 생성 된 Facilities ObservableCollection을 메서드 "fillFacility"와 함께 보유하고 Combobox에서 "GetFacilityNum()"메서드로 선택된 경우 SelectedFacilityNum을 저장하는 SampleUC 안에는 Combobox가 있습니다.

SampleUCVM에서 "fillFacility"및 "GetFacilityNum"메소드를 추출하여 BASEVM 또는 다른 ViewModels에서 액세스하여 사용할 수있는 별도의 클래스에 배치하고 싶습니다. 그들은 내 프로젝트에서 반복적으로 사용될 것입니다. 누군가이 일을 어떻게 설명 할 수 있겠습니까? 모든 도움과 인내심에 감사드립니다!

SampleUC.xaml

<Grid> 
    <Label Content="Facility" HorizontalAlignment="Left" Margin="10,32,0,0" VerticalAlignment="Top" Width="87" Height="27"/> 
    <ComboBox Name="cboFacilities" 
       HorizontalAlignment="Left" Margin="119,37,0,0" VerticalAlignment="Top" Width="120" 
       DisplayMemberPath="FacilityName" 
       SelectedValuePath="FacilityName" 
       ItemsSource="{Binding Facilities}" 
       SelectedValue="{Binding SelectedFacility, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
       /> 
</Grid> 

SampleUCVM

public class SampleUCVM : BASEVM 
{ 

    #region MySQL Connection 

    const string dbConnectionString = @"datasource=localhost;port=3306;Initial Catalog='optest1a1';username=root;password="; 

    #endregion 

    private ObservableCollection<Facilities> _facilitiesList; 
    private string _selectedFacility; 
    private int _selectedFacilityNum; 

    public ObservableCollection<Facilities> Facilities 
    { 
     get { return _facilitiesList; } 
     set 
     { 
      SetProperty(ref _facilitiesList, value,() => Facilities); 
     } 
    } 

    public string SelectedFacility 
    { 
     get { return _selectedFacility; } 
     set 
     { 
      SetProperty(ref _selectedFacility, value,() => SelectedFacility); 
      if (_selectedFacility != null) 
      { 
       GetFacilityNum(); 
      } 
     } 
    } 

    public int SelectedFacilityNum 
    { 
     get { return _selectedFacilityNum; } 
     set { SetProperty(ref _selectedFacilityNum, value,() => SelectedFacilityNum); } 
    } 

    public SampleUCVM() 
    { 
     Facilities = new ObservableCollection<Facilities>(); 
     fillFacilities(); 
    } 

    private void fillFacilities() 
    { 
     using (MySqlConnection con = new MySqlConnection(dbConnectionString)) 
     { 
      Facilities = new ObservableCollection<Facilities>(); 
      con.Open(); 
      string Query = "SELECT * FROM facilities"; 
      MySqlCommand createCommand = new MySqlCommand(Query, con); 
      MySqlDataReader dr = createCommand.ExecuteReader(); 
      int count = 1; 
      while (dr.Read()) 
      { 
       string FacilityName = dr.GetString(1); 
       Facilities facilityname = new Facilities(count, FacilityName); 
       Facilities.Add(facilityname); 
       count++; 
      } 
      con.Close(); 
     } 
    } 

    private void GetFacilityNum() 
    { 
     if (SelectedFacility != null) 
     { 
      using (MySqlConnection con = new MySqlConnection(dbConnectionString)) 
      { 
       con.Open(); 
       string Query = "SELECT Facility_ID_Num FROM facilities WHERE Facility_Name='" + SelectedFacility + "' "; 
       MySqlCommand createCommand = new MySqlCommand(Query, con); 
       MySqlDataReader dr = createCommand.ExecuteReader(); 
       int count = 1; 
       while (dr.Read()) 
       { 
        int FacilityNum = dr.GetInt32(0); 
        SelectedFacilityNum = FacilityNum; 
        count++; 
       } 
       con.Close(); 
      } 
     } 
    } 
} 

BASEVM

public class BASEVM : ObservableObject 
{ 
    public BASEVM() 
    { 

    } 
} 
+2

귀하의 질문은 너무 광범위하여 가능한 많은 답변을 가지고 있습니다. 즉 : IMHO VM은 프로그램 자체가 복잡 해짐에 따라 특히 간단해야합니다. "시설"관련 코드를 뷰 모델간에 공유하는 것이 얼마나 유용한 지 분명하지 않지만 여기에 게시 한 내용에 따라 코드가 모두 다른 클래스에 속할 가능성이 더 높습니다. 그런 다음 해당 기능을 필요로하는 뷰 모델 클래스는 해당 기능을 가진 클래스의 인스턴스가 아닌 해당 다른 클래스의 인스턴스를 가질 수 있습니다. –

답변

0

나는 이런 종류의 데이터 액세스 레이어를 구현할 것입니다. 예를 들면 : 당신은 다음의 ViewModel 클래스에 인스턴스를 포함 할 수

public class DataAccess 
{ 
    public ObservableCollection<Facilities> GetFacilities() 
    { 
     ObservableCollection<Facilities> facilities = new ObservableCollection<Facilities>(); 

     using (MySqlConnection con = new MySqlConnection(dbConnectionString)) 
     { 
      con.Open(); 
      string Query = "SELECT * FROM facilities"; 
      MySqlCommand createCommand = new MySqlCommand(Query, con); 
      MySqlDataReader dr = createCommand.ExecuteReader(); 
      int count = 1; 
      while (dr.Read()) 
      { 
       string FacilityName = dr.GetString(1); 
       facilities facilityname = new Facilities(count, FacilityName); 
       facilities.Add(facilityname); 
       count++; 
      } 
      con.Close(); 
     } 

     return facilities; 
    } 
} 

(또는 뷰 모델의 기본 클래스에).당신의 GetFacilityNum() 방법에 관해서

,이 또한 DataAccess 클래스로 갈 수 있지만, 개인적으로는 더 나은 솔루션이 가능하다면, 당신의 Facilities 클래스의 속성으로 Facility_ID_Num을 포함하는 것입니다 생각합니다. 그런 다음이를 적용하기 위해 GetFacilities() 메소드를 수정해야하지만 애플리케이션 내에서 Facilities 모델의 일부로 데이터베이스 호출없이 항상 액세스 할 수 있습니다.

0

당신이하고있는 일의 m uch 복잡한 그들이 진짜보다. ObservableCollection<T>은 변경 사항이 지금까지 발생했음을 WPF 컨트롤에 알리기에 충분합니다. XAML에서 올바르게 바인딩되었는지 확인하십시오.

같은

public ObservableCollection<Facilities> Facilities { get { return _facilitiesList; } set { SetProperty(ref _facilitiesList, value,() => Facilities); } }

로서

는 중복 번만

public ObservableCollection<Facilities> Facilities { get; }

단순화되고 초기화되어야 - 생성자에서.

기본보기 모델에 있기를 원하면 여기에서 코드를 이동하십시오. 그런 다음 기본 모델에서 자녀 모델을 상속하므로 자녀가 자신의 일부로 이러한 속성을 갖게됩니다.

사용자가 DependencyProperty을 등록한 경우가 아니면 고급 시나리오에만 필요하므로 SetValue(...)은 잊어 버리십시오.

시작 지점입니다.

재미있게 보내십시오.

0

나는 Peter Duniho에 동의합니다. 귀하의 질문이 너무 광범위하고 명확한 답변이 없지만 몇 가지 사항을 강조하고 싶습니다. 은 무엇 당신의 BASEVM의 목적이다 그리고 그것은 다른 클래스가 변경 이벤트를 알릴 수 있도록 객체를 래핑 ObservableObject

클래스에서 상속하는 이유. 일반적으로이 클래스는 DependencyObjects에 종속성 속성 로 설정하고, 다른 클래스가 변경 값에서 을 관찰 할 수있다.

기본 알림 변경 기능을 원하면 다음과 같이하십시오. 그 후

source

public class ViewModelBase:INotifyPropertyChanged{ 
    public event PropertyChangedEventHandler PropertyChanged; 
    protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null) 
    { 
     OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); 
    } 
    protected virtual void OnPropertyChanged(PropertyChangedEventArgs args) 
    { 
     PropertyChanged?.Invoke(this, args); 
    } 
    protected void RaisePropertyChanged([CallerMemberName]string propertyName = null) 
    { 
     OnPropertyChanged(propertyName); 
    } 
    protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null) 
    { 
     if (Equals(storage, value)) return false; 

     storage = value; 
     RaisePropertyChanged(propertyName); 

     return true; 
    } 
} 

, 당신은이 ViewModelBase 클래스에서 상속합니다. 어떤 속성이 변경 될 때,이 같은 PropertyChanged 이벤트가 발생 :

public int SelectedFacilityNum 
{ 
    get { return _selectedFacilityNum; } 
    set { SetProperty(ref _selectedFacilityNum,value); } 
} 

나는 BASEVM에 그들도를 SampleUCVM에서 방법 "fillFacility"및 "GetFacilityNum"을 끌어 배치 할 또는 코드와 같이 그들은, 액세스 및 다른 ViewModels

fillFacility 방법으로 사용할 수있는 별도의 클래스는 database에 대해 다루고 있습니다. 지금까지 내가 아는 한, MVVM 패턴, ViewModelsView와 뷰 모델은 뷰와 모델, 사이의 중개자 역할을하며 뷰 로직을 처리하기위한 책임이 Model

사이에 명상을 의미 . 일반적으로 뷰 모델은 모델 클래스의 메소드를 호출하여 모델과 상호 작용합니다. 그런 다음보기 모델은보기에서 쉽게 사용할 수있는 양식 형식으로 모델의 데이터를 제공합니다. 뷰 모델은 모델에서 데이터를 검색 한 다음 뷰에서 데이터를 사용할 수 있도록 만들고 뷰를 처리하는 데 더 간단한 방법으로 데이터를 다시 형식화합니다 ( ).

따라서보기 모델의 로직을 Data Access 레이어로 구분하는 것이 좋습니다. 예를 들어 Repository 패턴을 사용하고 FacilityRepository을 만들 수 있습니다. 그런 다음이 기능을 요구하는 ViewModels에이 저장소를 제공 할 수 있습니다. 그리고 더 엄격하게 만들고 싶다면 IFacilityRepository 인터페이스를 만들고 FacilityRepository을 구현 한 다음이 인터페이스를 ViewModel에 삽입하면이 기능이 필요합니다.