【问题标题】:WPF DataBinding when using usercontrols使用用户控件时的 WPF 数据绑定
【发布时间】:2014-01-21 14:00:08
【问题描述】:

我是 WPF 和 MVVM 模式的新手,我正在尝试制作一个使用多个控件的应用程序,因此我分别创建每个控件,并且在如何在控件之间共享数据方面遇到了一些困难

假设我有一个带有标签的控件和另一个包含文本框的控件, 在我想要的主窗口中,当我添加两个自定义控件时,我需要标签控件来显示我在文本框中输入的内容,如果我直接在窗口中使用标签和文本框,我知道如何实现它,但我需要为了解决类似的问题, 这是标签控件

<UserControl x:Class="TestWPF2.Views.LabelControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Label ></Label>
    </Grid>
</UserControl>

TextBox 自定义控件

<UserControl x:Class="TestWPF2.Views.TextBoxControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <TextBox ></TextBox>
    </Grid>
</UserControl>

这是窗口代码

<Window x:Class="TestWPF2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:V="clr-namespace:TestWPF2.Views"
        xmlns:Controls="clr-namespace:TestWPF2.Views"
        Title="MainWindow" Height="350" Width="525">
    <DockPanel LastChildFill="True">

        <Controls:TextBoxControl   ></Controls:TextBoxControl>
        <Controls:LabelControl   ></Controls:LabelControl>
    </DockPanel>
</Window>

【问题讨论】:

  • 顺便说一句,您不应该创建UserControl 只是为了包装单个控件,例如LabelTextBox;只需直接实例化LabelTextBox。我不知道您的实际代码是否这样做,或者这只是一个简化的示例。
  • 看看Simple Pattern for Creating Re-useable UserControls,以正确的方式进行操作。
  • 您可能应该在问题中包含“代码背后”

标签: c# wpf mvvm


【解决方案1】:

通过绑定,控件将继承其父级的数据上下文。

如果您将窗口数据上下文设置为“模型”(或者如果您需要限制它,则将控件数据上下文设置为“模型”)并且该模型有一个名为“SomeText”的属性,您可以绑定文本框和标签,如图所示下面:

<TextBox BorderBrush="Black" Text="{Binding Path=Model.SomeText,UpdateSourceTrigger=PropertyChanged}" />

如果您需要更多信息,请告诉我。绑定是一开始的野兽。

您不需要任何代码来连接控件。

【讨论】:

  • 感谢您的回答,我知道控件将继承其父级的数据上下文,除非您指定数据上下文但在我的情况下,我需要为每个自定义控件使用不同的视图模型,所以我的问题是什么最好的做法是,我可以使用单例属性,如果我使用单例,文本框和标签将绑定到相同的属性
  • 我不会使用单例。如果我使用 2 个视图模型,我会将它们都绑定到同一个模型(a 的实例),因此更改会在整个过程中激增。已经用 BindableBase 和 CSLA 做了类似的事情。对 PRISM 做的不多,但假设您可以以相同的方式使用所有 MVVM 框架。
【解决方案2】:

刚刚举了一个可能有用的例子。如果需要,记得使用输出窗口来识别绑定错误。

在这个例子中,我的窗口绑定到一个视图模型,它有一个名为“模型”的属性。该模型具有 Forename 和 surname 属性。

我们在主窗口中有一个标签,在控件中有一个文本框。在这个答案和我的第一个答案之间,我会让你完成它以获得你想要的。

主窗口代码(在这种情况下,数据上下文已快速设置在后面的代码中,尽管有很多方法可以做到)。

代码背后

  public partial class BindingTest : Window
  {
    public BindingTest()
    {
      InitializeComponent();

      Models.NamesModel nm = new Models.NamesModel();
      nm.Forename = "Bill";
      nm.Surname = "Gates";
      ViewModels.NamesViewModel vm = new ViewModels.NamesViewModel(nm);


      this.DataContext = vm;
    }
  }

窗口

<Window x:Class="WPFTutSimple.BindingTest"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ctrl="clr-namespace:WPFTutSimple.UserControls"
        Title="BindingTest" Height="300" Width="300"
        >
  <StackPanel>

    <Label Content="Name"></Label>
    <Label Content="{Binding Path=Model.Surname}"></Label>
    <ctrl:TextBoxControl />

  </StackPanel>
</Window>

用户控制代码。

<UserControl x:Class="WPFTutSimple.UserControls.TextBoxControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
  <StackPanel>
    <TextBox Text="{Binding Path=Model.Surname, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
             Width="200" BorderBrush="Black" HorizontalAlignment="Left"></TextBox>

  </StackPanel>
</UserControl>

如果您想/需要查看用户控件中发生的情况(并且您使用的是 WPF,而不是 WinRT),您可以在用户控件中点击 DataContextChanged 事件并在数据上下文更改时检查“e”值:

  public partial class TextBoxControl : UserControl
  {
    public TextBoxControl()
    {
      InitializeComponent();
      this.DataContextChanged += TextBoxControl_DataContextChanged;
    }

    void TextBoxControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
      //Set breakpoint here...
    }
  }

【讨论】:

    【解决方案3】:

    您可以使用依赖属性来适应您的用户控件。

    <UserControl x:Class="TestWPF2.Views.TextBoxControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             x:Name="uc">
    <Grid>
        <TextBox Text="{Binding ElementName=uc, Path=MyText}"></TextBox>
    </Grid>
    </UserControl>
    

    代码隐藏添加依赖属性

       public static readonly DependencyProperty MyTextProperty =
         DependencyProperty.Register("MyText", typeof(string),
         typeof(TextBoxControl), new FrameworkPropertyMetadata(""));
    
        public stringMyText
        {
            get { return (bool)GetValue(MyTextProperty); }
            set { SetValue(MyTextProperty, value); }
        }
    

    现在您可以在任何视图中使用此控件,如下所示:

     <Window x:Class="TestWPF2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:V="clr-namespace:TestWPF2.Views"
        xmlns:Controls="clr-namespace:TestWPF2.Views"
        Title="MainWindow" Height="350" Width="525">
       <DockPanel LastChildFill="True">
    
        <Controls:TextBoxControl MyText="{Binding Path=YourPropertyYouWannaBindTo}"  />
        <Controls:LabelControl   ></Controls:LabelControl>
    </DockPanel>
     </Window>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多