【问题标题】:Set DataContext for multiple controls with XAML使用 XAML 为多个控件设置 DataContext
【发布时间】:2019-08-27 13:02:37
【问题描述】:

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

ViewModel 是

  • MainViewModel
  • VideoViewModel
  • AudioViewModel

问题

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

1.我尝试将DataContext="{Binding VideoViewModel}" 添加到ComboBox XAML,但没有奏效,并且项目显示为空。

2. 我还尝试使用DataContext 将某个类别的所有ComboBoxes 分组到UserControl 中:

<UserControl DataContext="{Binding VideoViewModel}">
    <!-- ComboBoxes in here -->
</UserControl>

3. 还尝试将&lt;Window&gt; 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 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");
        }
    }
}

【问题讨论】:

    标签: c# wpf mvvm data-binding viewmodel


    【解决方案1】:

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

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

    您也可以为您的用户控件视图模型这样做。

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

    我建议你先google viewmodel,看看一些示例。

    【讨论】:

    • 还有几个步骤要做。我在 XAML 中使用了您的建议来绑定它们。如果您想看一下,我将其发布为答案。
    【解决方案2】:

    我不确定这是否正确,但我能够将 ComboBoxes 组绑定到不同的 ViewModel。


    我创建了一个 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 ();
    }
    

    我在MainWindow.xaml中使用了Andy的建议&lt;local:VM&gt;

    <Window x:Class="MyProgram.MainWindow"
            ...
            xmlns:local="clr-namespace:MyProgram"
            >
        <Window.DataContext>
            <local:VM/>
        </Window.DataContext>
    

    并使用UserControlDataContext 设置为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 = = = = = 到主视图模型。

      一旦您将主窗体的数据上下文连接到主视图模型,则其中的每个控件都将其起始点作为主视图模型。由于 MAIN 视图模型没有视频和音频视图模型的公共属性 UNDER IT,因此无法找到它们进行绑定。

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

      所以改变

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

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

      【讨论】:

      • 它实际上在有和没有this.DataContext 的情况下都有效,我使用它的原因是绑定程序的标题栏。但我不想在MainWindow() 中使用 C# 设置它。我用我正在使用的新方法发布了一个答案,我在 xaml 中设置了 DataContext,在我命名为 VM 的一个 ViewModel 中设置了 get; set 所有不同的 ViewModel。
      猜你喜欢
      • 1970-01-01
      • 2013-09-29
      • 2013-02-19
      • 2011-02-09
      • 1970-01-01
      • 2014-07-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多