Предисловие: Трудно объяснить мою проблему в форме вопроса, поэтому позвольте мне объяснить ниже.
Контекст: я разрабатываю пользовательский интерфейс для звукового микшера (см. Рисунок) и как часть из этого у меня есть ряд из 16 «Channel Strips» (UserControl) каждая с фейдером. В модели же микшер имеет 32 канала (+ вспомогательные). Чтобы устранить необходимость в очень большом ItemsControl с полосой прокрутки, я хочу реализовать систему страниц для переключения между каналами в модели, с которыми связан пользовательский интерфейс.
Макет интерфейса пользователя.
После некоторого прочтения примеров архитектуры MVVM я сузил его до слишком многих способов реализовать это, но у меня есть проблемы с каждым из них.
- Привязка канальных полос в пользовательский интерфейс непосредственно к ObservableCollection в ViewModel, а затем с помощью уведомителей о свойствах связать это с данными в модели:
<ItemsControl x:Name="FaderPane1_8" Background="{DynamicResource FaderPanel}" Margin="0" ItemsSource="{Binding Faders}" ScrollViewer.CanContentScroll="False" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:ChannelStrip MaxWidth="50" FaderValue="0"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
MainWindow.xaml
public ObservableCollection<ChannelStrip> Faders
{
get { return _faders; }
set { SetProperty(ref _faders, value); }
}
public void Init()
{
//Create a new mixer
VMixer = new Mixer(32, 8, 8);
VMixer.MixChannels.CollectionChanged += MixChannels_CollectionChanged;
}
//More code to handle "MixChannels_CollectionChanged" as well as changes from ViewModel to Model
ViewModel. cs
Проблема в том, что это создает множество обработчиков событий для изменений свойств во всех направлениях, а также в результате копирует фейдеры в память. Все это кажется мне плохим дизайном, но это то, что я видел, продиктовано соглашением, потому что оно позволяет полностью отделить модель от ViewModel и View, а также не имеет прямой связи между View и Model.
Привязка непосредственно к части модели и использование ViewModel для повторной привязки полосок канала пользовательского интерфейса к другому набору каналов при каждом изменении страницы.
Это кажется более разумным, поскольку я не создавал ненужных копий данных и событий, и может привести к менее сложному коду.
<Grid x:Name="FaderPane9_16" Background="{DynamicResource FaderPanel}" Margin="0" Grid.Column="2">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<local:ChannelStrip/>
<local:ChannelStrip Grid.Column="1"/>
<local:ChannelStrip Grid.Column="2"/>
<local:ChannelStrip Grid.Column="3"/>
<local:ChannelStrip Grid.Column="4"/>
<local:ChannelStrip Grid.Column="5"/>
<local:ChannelStrip Grid.Column="6"/>
<local:ChannelStrip Grid.Column="7"/>
</Grid>
MainWindow.xaml
public void UpdateFaderBindings(ChannelType faderMode, int faderModePage)
{
//[Code omitted for simplicity]
for (int i = 0; i < channels; i++)
{
int newFaderIndex = -1;
//[Code omitted for simplicity]
Binding b = new Binding("VMixer.Channels[newFaderIndex].FaderValue");//I know this is wrong I'm trying to demonstrate the idea
ChannelStrips[i].SetBinding(ChannelStrip.FaderValue, b);
}
}
ViewModel.cs
Обе эти архитектуры у них явно есть свои недостатки, и после нескольких часов чтения я не могу решить, какова правильная архитектура в этой ситуации.