首页 > 解决方案 > ViewModel 数据不会以独占方式绑定到 UserControl

问题描述

我的 MainWindow 有一个简单的测试 ViewModel:

namespace MyApp.ViewModels
{
    class MainWindowViewModel : ViewModelBase
    {
        public string Test { get; set; } = "TEST";
    }
}

没有比这更简单的了。现在我提供有关它的 MainWindow 知识并将 Test 属性绑定到 TextBox 和自己的 UserControl:

<Window x:Class="MyApp.MainWindow"
                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:MyApp"
                xmlns:uc="clr-namespace:MyApp.UserControls"
                xmlns:vm="clr-namespace:MyApp.ViewModels"
                mc:Ignorable="d"
                Width="800"
                Height="600">
    <Window.DataContext>
        <vm:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <TextBox HorizontalAlignment="Left"
                             Grid.Row="0"
                             TextWrapping="Wrap"
                             VerticalAlignment="Top"
                             Width="120"
                             Text="{Binding Test, PresentationTraceSources.TraceLevel=High}" />

        <uc:TestUserControl Grid.Row="1" Test="{Binding Test, PresentationTraceSources.TraceLevel=High}" />

    </Grid>
</Window>

再次,非常简单。

我的 TestUserControl 看起来像这样:

<UserControl x:Class="MyApp.UserControls.TestUserControl"
             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" 
             xmlns:local="clr-namespace:MyApp.UserControls"
                         mc:Ignorable="d"
                         DataContext="{Binding RelativeSource={RelativeSource Self}}"
                         d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <TextBox HorizontalAlignment="Left"
                         TextWrapping="Wrap"
                         VerticalAlignment="Top"
                         Width="120"
                         Text="{Binding Test, PresentationTraceSources.TraceLevel=High}" />
    </Grid>
</UserControl>
namespace MyApp.UserControls
{
    public partial class TestUserControl : UserControl
    {
        public static readonly DependencyProperty TestProperty =
                DependencyProperty.Register("Test", typeof(string), typeof(TestUserControl),
                        new FrameworkPropertyMetadata((string)String.Empty));

        public string Test
        {
            get { return (string)GetValue(TestProperty); }
            set { SetValue(TestProperty, value); }
        }


        public TestUserControl()
        {
            InitializeComponent();
        }
    }
}

我基本上最终得到的是两个文本框,一个包含在我的 UserControl 中,另一个没有。

两个文本框都应包含文本“TEST”,但只有嵌入 UserControl的文本框包含文本。

当我像这样跳过 ViewModel 的绑定时:

<uc:TestUserControl Grid.Row="1" Test="TEST" />

文本显示在 TextBox 中,这表明用户控件正常。

这是调试输出:

System.Windows.Data Warning: 56 : Created BindingExpression (hash=52579650) for Binding (hash=50581426) BindingExpression:Path=Test; DataItem=null; 
System.Windows.Data Warning: 58 :  Path: 'Test'
System.Windows.Data Warning: 60 : BindingExpression (hash=52579650): Default mode resolved to TwoWay
System.Windows.Data Warning: 61 : BindingExpression (hash=52579650): Default update trigger resolved to LostFocus
System.Windows.Data Warning: 62 : BindingExpression (hash=52579650): Attach to System.Windows.Controls.TextBox.Text (hash=15537542)
System.Windows.Data Warning: 67 : BindingExpression (hash=52579650): Resolving source 
System.Windows.Data Warning: 70 : BindingExpression (hash=52579650): Found data context element: TextBox (hash=15537542) (OK)
System.Windows.Data Warning: 78 : BindingExpression (hash=52579650): Activate with root item MainWindowViewModel (hash=13189358)
System.Windows.Data Warning: 108 : BindingExpression (hash=52579650):   At level 0 - for MainWindowViewModel.Test found accessor RuntimePropertyInfo(Test)
System.Windows.Data Warning: 104 : BindingExpression (hash=52579650): Replace item at level 0 with MainWindowViewModel (hash=13189358), using accessor RuntimePropertyInfo(Test)
System.Windows.Data Warning: 101 : BindingExpression (hash=52579650): GetValue at level 0 from MainWindowViewModel (hash=13189358) using RuntimePropertyInfo(Test): 'TEST'
System.Windows.Data Warning: 80 : BindingExpression (hash=52579650): TransferValue - got raw value 'TEST'
System.Windows.Data Warning: 89 : BindingExpression (hash=52579650): TransferValue - using final value 'TEST'
System.Windows.Data Warning: 56 : Created BindingExpression (hash=26543418) for Binding (hash=62601592) BindingExpression:Path=Test; DataItem=null; 
System.Windows.Data Warning: 58 :  Path: 'Test'
System.Windows.Data Warning: 60 : BindingExpression (hash=26543418): Default mode resolved to TwoWay
System.Windows.Data Warning: 61 : BindingExpression (hash=26543418): Default update trigger resolved to LostFocus
System.Windows.Data Warning: 62 : BindingExpression (hash=26543418): Attach to System.Windows.Controls.TextBox.Text (hash=21868813)
System.Windows.Data Warning: 67 : BindingExpression (hash=26543418): Resolving source 
System.Windows.Data Warning: 70 : BindingExpression (hash=26543418): Found data context element: TextBox (hash=21868813) (OK)
System.Windows.Data Warning: 78 : BindingExpression (hash=26543418): Activate with root item TestUserControl (hash=21522166)
System.Windows.Data Warning: 108 : BindingExpression (hash=26543418):   At level 0 - for TestUserControl.Test found accessor DependencyProperty(Test)
System.Windows.Data Warning: 104 : BindingExpression (hash=26543418): Replace item at level 0 with TestUserControl (hash=21522166), using accessor DependencyProperty(Test)
System.Windows.Data Warning: 101 : BindingExpression (hash=26543418): GetValue at level 0 from TestUserControl (hash=21522166) using DependencyProperty(Test): ''
System.Windows.Data Warning: 80 : BindingExpression (hash=26543418): TransferValue - got raw value ''
System.Windows.Data Warning: 89 : BindingExpression (hash=26543418): TransferValue - using final value ''
System.Windows.Data Warning: 56 : Created BindingExpression (hash=3865173) for Binding (hash=22799085) BindingExpression:Path=Test; DataItem=null; 
System.Windows.Data Warning: 58 :  Path: 'Test'
System.Windows.Data Warning: 60 : BindingExpression (hash=3865173): Default mode resolved to OneWay
System.Windows.Data Warning: 61 : BindingExpression (hash=3865173): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 62 : BindingExpression (hash=3865173): Attach to MyApp.UserControls.TestUserControl.Test (hash=21522166)
System.Windows.Data Warning: 67 : BindingExpression (hash=3865173): Resolving source 
System.Windows.Data Warning: 70 : BindingExpression (hash=3865173): Found data context element: TestUserControl (hash=21522166) (OK)
System.Windows.Data Warning: 78 : BindingExpression (hash=3865173): Activate with root item TestUserControl (hash=21522166)
System.Windows.Data Warning: 107 : BindingExpression (hash=3865173):   At level 0 using cached accessor for TestUserControl.Test: DependencyProperty(Test)
System.Windows.Data Warning: 104 : BindingExpression (hash=3865173): Replace item at level 0 with TestUserControl (hash=21522166), using accessor DependencyProperty(Test)
System.Windows.Data Warning: 101 : BindingExpression (hash=3865173): GetValue at level 0 from TestUserControl (hash=21522166) using DependencyProperty(Test): ''
System.Windows.Data Warning: 80 : BindingExpression (hash=3865173): TransferValue - got raw value ''
System.Windows.Data Warning: 89 : BindingExpression (hash=3865173): TransferValue - using final value ''

请问这个问题是什么原因造成的,如何解决?

标签: wpfwindowsdata-binding.net-5

解决方案


不要更改 UserControl DataContext - 您正在中断与 Window DataContext 的连接。而是将文本投标更改为通过 ElementName 引用测试属性。

<UserControl x:Class="MyApp.UserControls.TestUserControl"
             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" 
             xmlns:local="clr-namespace:MyApp.UserControls"
             mc:Ignorable="d"
             Name="userControl"
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <TextBox HorizontalAlignment="Left"
                         TextWrapping="Wrap"
                         VerticalAlignment="Top"
                         Width="120"
                         Text="{Binding Test, ElementName=userControl, PresentationTraceSources.TraceLevel=High}" />
    </Grid>
</UserControl>

请注意,即使没有ElementName=userControl绑定工作,但它会直接连接到 dataContext - MainWindowViewModel.Test 而不是 TestUserControl.Test 属性。在这种情况下,没有绑定的设置属性 - <uc:TestUserControl Grid.Row="1" Test="TEST" />- 将不起作用。

还将 TestProperty 更改为双向属性:

public static readonly DependencyProperty TestProperty = DependencyProperty.Register
(
    "Test", 
    typeof(string), 
    typeof(TestUserControl),
    new FrameworkPropertyMetadata(String.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)
);

推荐阅读