2017-05-14 81 views
0

有很多MVVM的例子,但我不能申請一個我的情況,因爲我有幾個相同的類的實例。另外,我需要直接操作模型,以便我可以訂閱Observer的一些觀察者。WPF MVVM與多個模型實例

我簡化了我的問題。 我有三個來自我的模型的類:燈,開關和網格。 他們可以通過Observer/Observable機制進行交互。 基本上,激活一個開關會打開/關閉連接到同一個網格的所有燈。

我想創建一個窗口,顯示這些類的具體用法。應該有Button的綁定到Switch和綁定到Lamp的TextBlock。

如何將每個實例綁定到我爲它準備的UI組件?

下面是一個簡單的例子,我想建立一個用戶界面爲:

Grid entranceGrid = new Grid("Entrance Grid"); 
Lamp hallLamp = new Lamp("Hall Lamp"); 
Lamp stairsLamp = new Lamp("Stairs Lamp"); 
Switch downSwitch = new Switch("Downstair Switch"); 
Switch upSwitch = new Switch("Upstair Switch"); 

downSwitch.Subscribe(entranceGrid); 
upSwitch.Subscribe(entranceGrid); 
entranceGrid.Subscribe(hallLamp); 
entranceGrid.Subscribe(stairsLamp); 

// Below are four instances I'd like to bind to some UI component. 
LampViewModel hallLampVM = new LampViewModel(hallLamp); 
LampViewModel stairsLampVM = new LampViewModel(stairsLamp); 
SwitchViewModel downSwitchVM = new downSwitchVM(downSwitch); 
SwitchViewModel upSwitchVM = new downSwitchVM(upSwitch); 

Here is my full code if you want to play with it (VS 2017)

+0

如果你有任意數量的燈和開關,你不需要使用一些顯示元素集合的UI元素,例如s的ListViews或其他ItemControls ...? – elgonzo

+0

我只是想說我可以有很多,所以解決方案必須能夠輕鬆處理多個或更少的實例。 –

回答

0

這個答案是醜陋的,但它的工作,也許這將幫助別人來的東西更好。

我會暫時實施這個解決方案。也許,我只會更好地處理NotifyPropertyChanged。

窗口XAML:

<Window.DataContext> 
    <vm:MainViewModel /> 
</Window.DataContext> 
<Grid Margin="0,0,0,0"> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="2*" /> 
     <RowDefinition Height="3*" /> 
     <RowDefinition Height="2*" /> 
    </Grid.RowDefinitions> 
    <GroupBox Grid.Row="0" Header="Entrée"> 
     <Grid> 
      <Grid.RowDefinitions> 
       <RowDefinition/> 
       <RowDefinition/> 
      </Grid.RowDefinitions> 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition /> 
       <ColumnDefinition /> 
       <ColumnDefinition /> 
      </Grid.ColumnDefinitions> 
      <TextBlock Grid.Row="0" Grid.Column="0" Text="Hall d'entrée"/> 
      <TextBlock Grid.Row="1" Grid.Column="0" Text="Escalier"/> 

      <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding TxtHallLamp}"/> 
      <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding TxtStairsLamp}"/> 

      <Button Grid.Row="0" Grid.Column="2" Content="rez" Command="{Binding DownSwitchCommand}"/> 
      <Button Grid.Row="1" Grid.Column="2" Content="1er" Command="{Binding UpSwitchCommand}"/> 
     </Grid> 
    </GroupBox> 
    [Few lines you don't need] 
</Grid> 

沿MainViewModel的ViewModelBase:

public class ViewModelBase : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    public void NotifyPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    public bool NotifyPropertyChanged<T>(ref T variable, T value, [CallerMemberName] string propertyName = null) 
    { 
     if (object.Equals(variable, value)) return false; 

     variable = value; 
     NotifyPropertyChanged(propertyName); 
     return true; 
    } 
} 


class MainViewModel : ViewModelBase 
{ 
    private Lamp _HallLamp, _StairsLamp; 
    private Switch _DownSwitch, _UpSwitch; 

    private IRelayCommand _DownSwitchCommand, _UpSwitchCommand; 

    public MainViewModel() 
    { 
     #region entrance 

     Grid entranceGrid = new Grid("Entrance Grid"); 
     _HallLamp = new Lamp("Hall Lamp"); 
     _StairsLamp = new Lamp("Stairs Lamp"); 
     _DownSwitch = new Switch("Downstair Switch"); 
     _UpSwitch = new Switch("Upstair Switch"); 

     _DownSwitch.Subscribe(entranceGrid); 
     _UpSwitch.Subscribe(entranceGrid); 
     entranceGrid.Subscribe(_HallLamp); 
     entranceGrid.Subscribe(_StairsLamp); 

     #endregion // entrance 
    } 

    private string LampToTxt(Lamp lamp) 
    { 
     return lamp.Light ? "ON" : "OFF"; 
    } 

    public string TxtHallLamp 
    { 
     get 
     { 
      return LampToTxt(_HallLamp); 
     } 
    } 

    public string TxtStairsLamp 
    { 
     get 
     { 
      return LampToTxt(_StairsLamp); 
     } 
    } 

    private void NotifyEntranceGridPropertyChanged() 
    { 
     NotifyPropertyChanged(nameof(TxtHallLamp)); 
     NotifyPropertyChanged(nameof(TxtStairsLamp)); 
    } 

    public IRelayCommand DownSwitchCommand 
    { 
     get 
     { 
      return _DownSwitchCommand ?? (_DownSwitchCommand = new RelayCommand(
       () => { 
        _DownSwitch.Press(); 
        NotifyEntranceGridPropertyChanged(); 
       }, 
       () => true)); 
     } 
    } 

    public IRelayCommand UpSwitchCommand 
    { 
     get 
     { 
      return _UpSwitchCommand ?? (_UpSwitchCommand = new RelayCommand(
       () => { 
        _UpSwitch.Press(); 
        NotifyEntranceGridPropertyChanged(); 
       }, 
       () => true)); 
     } 
    } 
} 

和接口IRelayCommand沿着類RelayCommand:

public interface IRelayCommand : ICommand 
{ 
    void RaiseCanExecuteChanged(); 
} 

class RelayCommand : IRelayCommand 
{ 

    private Action _Execute; 
    private Func<bool> _CanExecute; 
    public event EventHandler CanExecuteChanged; 

    public RelayCommand(Action Execute) : this(Execute, null) 
    { 

    } 

    public RelayCommand(Action Execute, Func<bool> CanExecute) 
    { 
     if (Execute == null) 
      throw new ArgumentNullException(); 

     _Execute = Execute; 
     _CanExecute = CanExecute; 
    } 

    public bool CanExecute(object parameter) 
    { 
     return (_CanExecute == null) ? true : _CanExecute(); 
    } 

    public void Execute(object parameter) 
    { 
     _Execute(); 
    } 

    public void RaiseCanExecuteChanged() 
    { 
     if (CanExecuteChanged != null) 
     { 
      CanExecuteChanged(this, EventArgs.Empty); 
     } 
    } 
}