绑定UserControl依赖属性和MVVM

joe*_*erg 11 wpf dependency-properties mvvm

我有一个包含UserControl的MainWindow,它们都是用MVVM模式实现的.MainWindowVM具有我想要绑定到UserControl1VM中的属性的属性.但这不起作用.

这里是一些代码(viewmodels使用某种mvvm框架,在ViewModelBase类中实现INotifyPropertyChanged,但希望没问题):

MainWindow.xaml:

<Window x:Class="DPandMVVM.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:DPandMVVM"
    Title="MainWindow" Height="300" Width="300">
    <Grid>
        <local:UserControl1 TextInControl="{Binding Text}" />
    </Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)

CodeBehind MainWindow.xaml.cs:

using System.Windows;
namespace DPandMVVM
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainWindowVM();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

MainWindow-ViewModel MainWindowVM.cs:

namespace DPandMVVM
{
    public class MainWindowVM : ViewModelBase
    {
        private string _text;
        public string Text { get { return _text; } }

        public MainWindowVM()
        {
            _text = "Text from MainWindowVM";
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这里是UserControl1.xaml:

<UserControl x:Class="DPandMVVM.UserControl1"
             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>
        <TextBlock Text="{Binding TextInTextBlock}" />  
    </Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)

Codebehind UserControl1.xaml.cs:

using System.Windows.Controls;    
namespace DPandMVVM
{
    /// <summary>
    /// Interaction logic for UserControl1.xaml
    /// </summary>
    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
            DataContext = new UserControl1VM();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

和Viewmodel UserControl1VM.cs:

using System.Windows;    
namespace DPandMVVM
{
    public class UserControl1VM : DependencyObject
    {
        public UserControl1VM()
        {
            TextInControl = "TextfromUserControl1VM";
        }

        public string TextInControl
        {
            get { return (string)GetValue(TextInControlProperty); }
            set { SetValue(TextInControlProperty, value); }
        }

        public static readonly DependencyProperty TextInControlProperty =
            DependencyProperty.Register("TextInControl", typeof(string), typeof(UserControl1VM));
    }
}
Run Code Online (Sandbox Code Playgroud)

使用此星座,无法在MainWindow.xaml中找到DP.

我究竟做错了什么?

Roh*_*ats 10

首先,如果要从外部绑定它,则需要在TextInControl内部声明DependencyProperty UserControl1.

移动DP内部的声明UserControl1.

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

    public string TextInControl
    {
        get { return (string)GetValue(TextInControlProperty); }
        set { SetValue(TextInControlProperty, value); }
    }

    public static readonly DependencyProperty TextInControlProperty =
        DependencyProperty.Register("TextInControl", typeof(string), 
                                       typeof(UserControl1));
}
Run Code Online (Sandbox Code Playgroud)

其次,您已将UserControl的DataContext外部设置为UserControl1VM,

    public UserControl1()
    {
        InitializeComponent();
        DataContext = new UserControl1VM(); <-- HERE (Remove this)
    }
Run Code Online (Sandbox Code Playgroud)

因此,WPF绑定引擎寻找财产TextUserControl1VM替代MainWindowVM.删除设置DataContext并将UserControl1的XAML更新为:

<UserControl x:Class="DPandMVVM.UserControl1"
             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="userControl1">
    <Grid>
        <TextBlock Text="{Binding TextInTextBlock, ElementName=userControl1}" />  
    </Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)

使用UserControl ElementName设置绑定DP x:Name.


UPDATE

如果您想要ViewModel完整的for UserControl,您必须更新MainWindow中的绑定.明确告诉WPF绑定引擎在MainWindow的DataContext中使用如下ElementName绑定查找属性:

<local:UserControl1 TextInControl="{Binding DataContext.Text,
                    ElementName=mainWindow}" />
Run Code Online (Sandbox Code Playgroud)

为此,您需要设置x:Name="mainWindow"窗口根级别.

  • 将 UserControl 想象成其他人的“黑匣子”。它只是其他用户也会使用的控件。所以我们有一个控件开发人员(在 mvvm 中工作)和一个 MainWindow 开发人员(在 mvvm 中工作)。MainWindow 的开发人员只想“轻松”使用 UserControl 而无需了解内部细节。他只是想将他的 VM-Properties 绑定到 UserControl 的 DP。 (3认同)
  • 如何从VM访问UserControl中的这些DP? (2认同)
  • 您不能从 VM 访问 UserControl 内的 DP。你和那些 DP 绑定。就像`Text` 是在`TextBox` 中声明的DP,您可以从XAML 绑定到VM 中的某些属性。这也是您对自定义 DP 的处理方式。 (2认同)

小智 1

您的控件的 XAML 现在TextInTextBlock通过 DataContext 引用该属性,而 DataContext 又“指向”您的主窗口的视图模型。引用控件的数据就完成了(顺便说一句,因此不要设置 DataContext - 绑定将不再起作用):

<UserControl x:Class="DPandMVVM.UserControl1"
             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="self">
    <Grid>
        <TextBlock Text="{Binding TextInTextBlock, ElementName=self}" />  
   </Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)