使用XAML为多个控件设置DataContext

时间:2019-04-05 15:13:07

标签: c# wpf mvvm data-binding viewmodel

我有绑定到不同类别ViewModel类的不同控件组。

ViewModel是

  • MainViewModel
  • VideoViewModel
  • AudioViewModel

问题

如何使用XAML而不是C#设置DataContext

1。。我尝试将DataContext="{Binding VideoViewModel}"添加到ComboBox XAML中,但是它不起作用,并且项目显示为空。

2。。我还尝试将ComboBoxes中某个类别的所有UserControlDataContext进行分组:

<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"/>

视频ViewModel类

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");
        }
    }
}

3 个答案:

答案 0 :(得分:0)

您可以在xaml中实例化一个对象:

  <Window.DataContext>
      <local:MainWindowViewmodel/>
  </Window.DataContext>

您也可以对用户控件的视图模型进行操作。

在窗口视图模型中实例化任何子视图模型更为常见。作为公共属性公开,然后将子视图模型的数据上下文绑定到该属性。

我建议您首先使用google viewmodel,然后看一些示例。

答案 1 :(得分:0)

我不确定这是否正确,但是我能够将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,其中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";

答案 2 :(得分:0)

其他人显然提供了很好的答案,但是,绑定的根本问题是您对主视图模型的第一套DataContext = = = = =。

一旦您将主窗体的数据上下文连接到MAIN视图模型,则其下的每个控件都将ITS STARTING点作为MAIN视图模型。由于MAIN视图模型在视频和音频视图模型的基础上没有公共财产,因此它找不到绑定的对象。

如果删除“ this.DataContext =”,则将没有默认的数据上下文,并且每个控件都应该能够按预期的方式进行绑定。

所以改变

this.DataContext =
tbxInput.DataContext =
tbxOutput.DataContext =
cboPreset.DataContext =
MainViewModel.vm;

tbxInput.DataContext =
tbxOutput.DataContext =
cboPreset.DataContext =
MainViewModel.vm;