【问题标题】:WPF Bind different usercontrols to different viewmodelsWPF 将不同的用户控件绑定到不同的视图模型
【发布时间】:2017-06-21 18:07:30
【问题描述】:

我是 WPF 的新手,我遇到了一个问题,就是将两个不同的 ViewModel 绑定到两个 UserControl 将附加到 Tabcontrol 中的两个 Tabpages。

我的代码sn-ps如下:

MainWindow.xaml

<Window.Resources>
    <local:UserControl1Model x:Key="Control1Model" />
    <local:UserControl2Model x:Key="Control2Model" />
</Window.Resources>

<Grid HorizontalAlignment="Left" Height="330" VerticalAlignment="Top" Width="592">
    <Grid HorizontalAlignment="Left" Height="45" Margin="0,330,-1,-45" VerticalAlignment="Top" Width="593">
        <Button Content="Button" HorizontalAlignment="Left" Margin="490,5,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
    </Grid>
    <TabControl HorizontalAlignment="Left" Height="330" VerticalAlignment="Top" Width="592" >
        <TabItem x:Name="UserControl1TabItem" Header="User Control 1" >
            <Grid x:Name="UserControl1Tabpage" Background="#FFE5E5E5" Margin="0,0,-4,-2" Height="300" VerticalAlignment="Top" IsEnabled="true" >
                <local:UserControl1 VerticalAlignment="Top" DataContext="{Binding Source={StaticResource Control1Model}}" />
            </Grid>
        </TabItem>
        <TabItem x:Name="UserControl2TabItem" Header="User Control 2">
            <Grid x:Name="UserControl2Tabpage" Background="#FFE5E5E5">
                <local:UserControl2 VerticalAlignment="Top" DataContext="{Binding Source={StaticResource Control2Model}}" />
            </Grid>
        </TabItem>
    </TabControl>
</Grid>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    private UserControl1Model _userControl1Model = new UserControl1Model();
    private UserControl2Model _userControl2Model = new UserControl2Model();

    public MainWindow()
    {
        InitializeComponent();

        _userControl1Model.Message = "Hello";
        _userControl2Model.Message = "Test";        
    }
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        // Will do something
    }
}

UserControl1Model.cs

public class UserControl1Model : INotifyPropertyChanged
{
    private string _message;

    public string Message
    {
        get { return _message; }
        set
        {
            _message = value;
            OnPropertyChanged("Message");
        }
    }

    public UserControl1Model()
    {
    }

    // Create the OnPropertyChanged method to raise the event
    protected void OnPropertyChanged(string message)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(message));
        }
    }

    #region INotifyPropertyChanged Members

    // Declare the event
    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

出于试用目的,UserControl2Model.cs 的内容与 UserControl1Model.cs 相同

UserControl1.xaml

<UserControl.Resources>
    <app:UserControl1Model x:Key="Control1Model" />
</UserControl.Resources>

<Grid Margin="0,0,0,42" DataContext="{Binding Source={StaticResource Control1Model}}"> 
    <Label Content="Test:" HorizontalAlignment="Left" Margin="48,57,0,0" VerticalAlignment="Top" Width="47"/>

    <TextBox x:Name="Conrol1ModelTextbox" HorizontalAlignment="Left" Height="23" Margin="90,59,0,0" TextWrapping="Wrap" 
       Text="{Binding Message, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
       VerticalAlignment="Top" Width="466" />
</Grid>

UserControl1.xaml.cs

public partial class UserControl1 : UserControl
{        
    public UserControl1()
    {
        InitializeComponent();
    }
}

UserControl2.xaml

<UserControl.Resources>
    <app:UserControl2Model x:Key="Control2Model" />
</UserControl.Resources>

<Grid Margin="0,0,0,42" DataContext="{Binding Source={StaticResource Control2Model}}"> 
    <Label Content="Test:" HorizontalAlignment="Left" Margin="48,57,0,0" VerticalAlignment="Top" Width="47"/>

    <TextBox x:Name="Conrol2ModelTextbox" HorizontalAlignment="Left" Height="23" Margin="90,59,0,0" TextWrapping="Wrap" 
       Text="{Binding Message, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
       VerticalAlignment="Top" Width="466" />
</Grid>

为了方便起见,UserControl2.xaml.cs 的内容与 UserControl1.xaml.cs 相同

我的问题是在 MainWindow.xaml.cs 中初始化的两个用户控件的初始值“Hello”和“Test”不能 被“绑定”到用户控件文本框中。我做错了什么或错过了什么?

【问题讨论】:

  • 您永远不会绑定到您在 MainWindow 中创建的 VM 实例
  • 如何绑定到虚拟机实例?你会写代码sn-ps来给我建议吗!非常感谢。

标签: c# wpf xaml bind


【解决方案1】:

当你像这样声明资源时

<Window.Resources>
    <local:UserControl1Model x:Key="Control1Model" />
    <local:UserControl2Model x:Key="Control2Model" />
</Window.Resources>

您实际上是在构建 UserControl1Model 和 UserControl2Model 的新实例,而不是使用您在 MainWindow.cs 中声明的实例

您也没有为 MainWindow 创建任何 ViewModel。你应该像这样创建一个 MainWindowViewModel

public class MainWindowViewModel : INotifyPropertyChanged
{
    public ViewModelLocator
    {
        this.FirstModel= new UserControl1Model
        {
            Message = "Hello";
        }

        this.SecondModel = new UserControl2Model
        {
            Message = "Test";
        }
    }

    private UserControl1Model firstModel
    public UserControl1Model FirstModel
    {
        get 
        {
            return this.firstModel;
        }

        set
        {
            this.firstModel= value;
            OnPropertyChanged("FirstModel");
        }
    }

    // Same for the UserControl2Model

    // implementation of the INotifyPropertyChanged
}

您还需要为 MainWindow 设置 DataContext。

public MainWindow()
{
    InitializeComponent();

    this.DataContext = new MainWindowViewModel();     
}

并从 UserControl xamls 中删除资源。您已经在 MainWindow.xaml 中定义了 DataContext,但绑定应该从 MainWindowViewModel 绑定。

<local:UserControl1 VerticalAlignment="Top" DataContext="{Binding FirstModel}" />

【讨论】:

  • 感谢您的回答。我还有另一个与创建 MainWindowViewModel 实例的位置有关的问题。假设我在 xaml 中按如下方式创建此实例: 而不是在 MainWindow.xaml.cs 中创建。然后,我如何在 MainWindow.xaml.cs 中引用这个实例,例如从 MainWindowViewModel.ViewModelLocator.FirstModel.Message 获取价值?
  • 请看我的回答。
【解决方案2】:

创建一个 ViewModelLocator。您可以在 Internet 上找到有关此主题的各种网站。

一个简单的方法是:

public class ViewModelLocator
{
  public UserControl1Model UserControl1Model { get; set; } = new UserControl1Model();
  public UserControl2Model UserControl2Model { get; set; } = new UserControl2Model();
  public ViewModelLocator
  {
    UserControl1Model.Message = "Hello";
    UserControl2Model.Message = "Test";  
  }
}

然后你可以在你的视图中使用它

<UserControl.Resources>
    <app:ViewModelLocator x:Key="ViewModelLocator" />
</UserControl.Resources>

<Grid Margin="0,0,0,42" DataContext="{Binding UserControl2Model Source={StaticResource ViewModelLocator}}"> 
    <Label Content="Test:" HorizontalAlignment="Left" Margin="48,57,0,0" VerticalAlignment="Top" Width="47"/>

    <TextBox x:Name="Conrol2ModelTextbox" HorizontalAlignment="Left" Height="23" Margin="90,59,0,0" TextWrapping="Wrap" 
       Text="{Binding Message, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
       VerticalAlignment="Top" Width="466" />
</Grid>

【讨论】:

    【解决方案3】:

    假设,我在 xaml 中按如下方式创建此实例:&lt;Window.Resources&gt; &lt;local:MainWindowViewModel x:Key="MainWindowViewModel" /&gt; &lt;/Window.Resources&gt; 而不是在 MainWindow.xaml.cs 中创建。那么,我如何在MainWindow.xaml.cs 中引用这个实例,例如从MainWindowViewModel.ViewModelLocator.FirstModel.Message 获取价值?

    像这样:

    MainWindowViewModel viewModel = this.Resources["MainWindowViewModel"] as MainWindowViewModel;
    //access any properties of viewModel here...
    

    【讨论】:

      猜你喜欢
      • 2011-02-22
      • 2021-08-10
      • 1970-01-01
      • 1970-01-01
      • 2018-01-31
      • 2018-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多