Я отвечаю на свой вопрос.Но прежде чем ответить на мой вопрос, просто хочу кое-что прояснить.Я пытался создать полностью инкапсулированный UserControl с его собственной ViewModel.И где бы ни использовался пользовательский контроль, потребитель не должен ничего знать о внутренней модели представления пользовательского контроля.Единственная опция связи, которую я хочу, чтобы потребитель имел, - это установка некоторых свойств и использование механизма привязки.Таким образом, я решил свою проблему так: я создал свойство зависимостей внутри UserControl и устанавливал его всякий раз, когда что-то меняется в viewmodel usercontrol.
UserNameControl.xaml (usercontrol)
<UserControl x:Class="TestCustomUserControl.MyControls.UserNameControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestCustomUserControl.ViewModels"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.Resources>
<local:UserNameViewModel x:Key="TheViewModel"/>
</UserControl.Resources>
<Grid x:Name="NameCtrlRoot" Background="White" DataContext="{StaticResource TheViewModel}">
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="First Name:" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="Last Name: "/>
<TextBox Grid.Row="0" Grid.Column="1" x:Name="txtFirstName" Text="{Binding FirstName, Mode=TwoWay}">
<i:Interaction.Behaviors>
<!-- This behavior updates the binding after a specified delay
instead of the user having to lose focus on the TextBox. -->
<local:TextChangedDelayedBindingBehavior RefreshTimeMilliseconds="750" />
</i:Interaction.Behaviors>
</TextBox>
<TextBox Grid.Row="1" Grid.Column="1" x:Name="txtLastName" Text="{Binding LastName, Mode=TwoWay}">
<i:Interaction.Behaviors>
<!-- This behavior updates the binding after a specified delay
instead of the user having to lose focus on the TextBox. -->
<local:TextChangedDelayedBindingBehavior RefreshTimeMilliseconds="750" />
</i:Interaction.Behaviors>
</TextBox>
<TextBlock Grid.Row="3" Grid.Column="0" Text="fullname inside control:" />
<TextBlock Grid.Row="3" Grid.Column="1" Text="{Binding FullName}" />
<Border Height="1" Background="Black" Grid.Column="2" Grid.Row="4" />
</Grid>
</StackPanel>
</Grid>
BaseViewModel.cs
public class BaseViewModel : INotifyPropertyChanged
{
#region Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
#endregion
protected void NotifyPropertyChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
UserNameViewModel.cs
public class UserNameViewModel : BaseViewModel
{
private String _firstName;
public String FirstName
{
get { return _firstName; }
set
{
_firstName = value;
NotifyPropertyChanged("FirstName");
OnNameChange();
}
}
private String _lastName;
public String LastName
{
get { return _lastName; }
set
{
_lastName = value;
NotifyPropertyChanged("LastName");
OnNameChange();
}
}
public Action NameChanged { get; set; }
private void OnNameChange()
{
FullName = String.Format("{0} {1}", FirstName, LastName);
if(NameChanged != null) NameChanged.Invoke();
}
private String _fullName;
public String FullName
{
get { return _fullName; }
set {
_fullName = value;
NotifyPropertyChanged("FullName");
}
}
}
UserNameControl.xaml.cs (код контроля пользователя с декларацией DependencyProperty)
public partial class UserNameControl : UserControl
{
private UserNameViewModel _TheViewModel;
public UserNameControl()
{
InitializeComponent();
_TheViewModel = Resources["TheViewModel"] as UserNameViewModel;
_TheViewModel.NameChanged = OnNameChanged;
}
public String SelectedFullName
{
get { return (String) GetValue(SelectedFullNameProperty); }
set { SetValue(SelectedFullNameProperty, value); }
}
public static readonly DependencyProperty SelectedFullNameProperty =
DependencyProperty.Register("SelectedFullName", typeof (String), typeof (UserNameControl), null);
private void OnNameChanged()
{
SelectedFullName = _TheViewModel.FullName;
}
}
ConsumeName.xaml (потребительская страница навигации, пользователь выше контроля пользователя и перетаскивает SelectedFullName в UserFullName)
<navigation:Page xmlns:my="clr-namespace:TestCustomUserControl.MyControls" x:Class="TestCustomUserControl.Views.ConsumeName"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:local="clr-namespace:TestCustomUserControl.ViewModels"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
d:DesignWidth="640" d:DesignHeight="480"
Title="ConsumeName Page">
<navigation:Page.Resources>
<local:ConsumeNameViewModel x:Key="TheConsumeNameViewModel"/>
</navigation:Page.Resources>
<Grid x:Name="LayoutRoot" DataContext="{StaticResource TheConsumeNameViewModel}">
<StackPanel>
<my:UserNameControl x:Name="MyNameControl" SelectedFullName="{Binding UserFullName, Mode=TwoWay}" />
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="10" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Full Name in Parent: " />
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding UserFullName}"/>
</Grid>
</StackPanel>
</Grid>
ConsumeNameViewModel.cs
public class ConsumeNameViewModel : BaseViewModel
{
private string _UserFullName;
public string UserFullName
{
get { return _UserFullName; }
set
{
if (value != _UserFullName)
{
_UserFullName = value;
NotifyPropertyChanged("UserFullName");
}
}
}
}