#c# #wpf #mvvm #data-binding #viewmodel
#c# #wpf #mvvm #привязка данных #viewmodel
Вопрос:
У меня есть разные группы элементов управления, привязанные к разным категориям классов ViewModel.
ViewModels являются
MainViewModel
VideoViewModel
AudioViewModel
Вопрос
Как я могу установить DataContext
с помощью XAML вместо C #?
1. Я попытался добавить DataContext="{Binding VideoViewModel}"
в ComboBox
XAML, но это не сработало, и элементы оказались пустыми.
2. Я также попытался сгруппировать все ComboBoxes
определенной категории внутри UserControl
с DataContext
:
<UserControl DataContext="{Binding VideoViewModel}">
<!-- ComboBoxes in here -->
</UserControl>
3. Также попытался установить <Window>
DataContext
для себя DataContext="{Binding RelativeSource={RelativeSource Self}}"
Контекст данных
В настоящее время я устанавливаю DataContext
этот способ для разных категорий элементов управления:
public MainWindow()
{
InitializeComponent();
// Main
this.DataContext =
tbxInput.DataContext =
tbxOutput.DataContext =
cboPreset.DataContext =
MainViewModel.vm;
// Video
cboVideo_Codec.DataContext =
cboVideo_Quality.DataContext =
tbxVideo_BitRate.DataContext =
cboVideo_Scale.DataContext =
VideoViewModel.vm;
// Audio
cboAudio_Codec.DataContext =
cboAudio_Quality.DataContext =
tbxAudio_BitRate.DataContext =
tbxAudio_Volume.DataContext =
AudioViewModel.vm;
}
XAML ComboBox
<ComboBox x:Name="cboVideo_Quality"
DataContext="{Binding VideoViewModel}"
ItemsSource="{Binding Video_Quality_Items}"
SelectedItem="{Binding Video_Quality_SelectedItem}"
IsEnabled="{Binding Video_Quality_IsEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="105"
Height="22"
Margin="0,0,0,0"/>
Класс модели просмотра видео
public class VideoViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void OnPropertyChanged(string prop)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(prop));
}
}
public VideoViewModel() { }
public static VideoViewModel _vm = new VideoViewModel();
public static VideoViewModel vm
{
get { return _vm; }
set
{
_vm = value;
}
}
// Items Source
private List<string> _Video_Quality_Items = new List<string>()
{
"High",
"Medium",
"Low",
};
public List<string> Video_Quality_Items
{
get { return _Video_Quality_Items; }
set
{
_Video_Quality_Items = value;
OnPropertyChanged("Video_Quality_Items");
}
}
// Selected Item
private string _Video_Quality_SelectedItem { get; set; }
public string Video_Quality_SelectedItem
{
get { return _Video_Quality_SelectedItem; }
set
{
if (_Video_Quality_SelectedItem == value)
{
return;
}
_Video_Quality_SelectedItem = value;
OnPropertyChanged("Video_Quality_SelectedItem");
}
}
// Enabled
private bool _Video_Quality_IsEnabled;
public bool Video_Quality_IsEnabled
{
get { return _Video_Quality_IsEnabled; }
set
{
if (_Video_Quality_IsEnabled == value)
{
return;
}
_Video_Quality_IsEnabled = value;
OnPropertyChanged("Video_Quality_IsEnabled");
}
}
}
Ответ №1:
Вы можете создать экземпляр объекта в xaml:
<Window.DataContext>
<local:MainWindowViewmodel/>
</Window.DataContext>
И вы могли бы сделать это и для своих пользовательских моделей просмотра.
Более привычно создавать экземпляры любых дочерних viewmodels в window viewmodel. Отображается как общедоступные свойства, а datacontext дочерней viewmodel затем привязывается к этому свойству.
Я предлагаю вам сначала погуглить viewmodel и взглянуть на некоторые образцы.
Комментарии:
1. Нужно было выполнить еще несколько шагов. Я использовал ваше предложение в XAML, чтобы связать их. Я опубликовал это как ответ, если вы хотите взглянуть.
Ответ №2:
Я не уверен, что это правильный способ, но я смог привязать группы ComboBoxes
к разным ViewModels.
Я создал одну ViewModel, чтобы ссылаться на них все.
public class VM: INotifyPropertyChanged
{
...
public static MainViewModel MainView { get; set; } = new MainViewModel ();
public static VideoViewModel VideoView { get; set; } = new VideoViewModel ();
public static AudioViewModel AudioView { get; set; } = new AudioViewModel ();
}
Я использовал предложение Энди <local:VM>
в MainWindow.xaml
.
<Window x:Class="MyProgram.MainWindow"
...
xmlns:local="clr-namespace:MyProgram"
>
<Window.DataContext>
<local:VM/>
</Window.DataContext>
И использовал UserControl
with DataContext
, установленный в VideoView
, с ComboBoxes
внутри.
Вместо UserControl
, также можно просто использовать VideoView.Your_Property_Name
для каждой привязки.
<UserControl DataContext="{Binding VideoView}">
<StackPanel>
<ComboBox x:Name="cboVideo_Quality"
ItemsSource="{Binding Video_Quality_Items}"
SelectedItem="{Binding Video_Quality_SelectedItem}"
IsEnabled="{Binding Video_Quality_IsEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="105"
Height="22"
Margin="0,0,0,0"/>
<!-- Other ComboBoxes with DataContext VideoView in here -->
</StackPanel>
</UserControl>
Затем, чтобы получить доступ к одному из свойств:
VM.VideoView.Video_Codec_SelectedItem = "x264";
VM.VideoView.Video_Quality_SelectedItem = "High";
VM.AudioView.Audio_Codec_SelectedItem = "AAC";
VM.AudioView.Audio_Quality_SelectedItem = "320k";
Ответ №3:
Другие, очевидно, предоставили хорошие ответы, однако основной недостаток вашей привязки — это ваш первый набор DataContext = = = = = для модели основного представления.
Как только вы добавите контекст данных основной формы к модели ОСНОВНОГО представления, каждый элемент управления, находящийся там, ожидает СВОЕЙ НАЧАЛЬНОЙ точки в качестве модели ОСНОВНОГО представления. Поскольку ОСНОВНАЯ модель просмотра не имеет общедоступного свойства для моделей просмотра видео и аудио, она не может найти их для привязки do.
Если вы удалите «это.DataContext =», тогда не было бы контекста данных по умолчанию, и каждый элемент управления должен быть привязан так, как вы их предполагали.
Так что измените
this.DataContext =
tbxInput.DataContext =
tbxOutput.DataContext =
cboPreset.DataContext =
MainViewModel.vm;
Для
tbxInput.DataContext =
tbxOutput.DataContext =
cboPreset.DataContext =
MainViewModel.vm;
Комментарии:
1. На самом деле это работало с
this.DataContext
и без него, причина, по которой я использовал это, заключалась в привязке строки заголовка программы. Но я хотел отказаться от его установки с помощью C # вMainWindow()
. Я опубликовал ответ с новым способом, который я использую, я установил DataContext в xaml иget; set
все разные ViewModels в одной ViewModel, которую я назвалVM
.