wpf mvvm嵌套用户控件datacontext

dst*_*ssi 0 c# wpf mvvm wpf-controls

datacontext对nested 有问题user-controls。问题在于ViewModel中的模型绑定在第一个DependencyProperty的上user-control。第一user-control是第二user-control。第二个user-control也有一个DependencyProperty。第一个user-controlDependencyProperty第二个绑定user-control

主视图:

<UserControl x:Class="XXX.XXX.Hmi.Views.L1SetupViewerView"
             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:prism="http://prismlibrary.com/"
             xmlns:uc="clr-namespace:XXX.XXX.Hmi.UserControls"
             d:DesignHeight="450"
             d:DesignWidth="800"
             prism:ViewModelLocator.AutoWireViewModel="True"
             Background="{DynamicResource BaseBrush}"
             Foreground="{DynamicResource TextBrush}"
             mc:Ignorable="d">
.
.
.
    <GroupBox Grid.Row="1" Header="Entry Section">
        <uc:L1SetupViewerEntrySectionView Margin="8" Setup="{Binding L1Setup}" />
    </GroupBox>
.
.
.
</UserControl>
Run Code Online (Sandbox Code Playgroud)

MainViewModel:

public class L1SetupViewerViewModel : ViewModelBase
{
    private L1Setup _l1Setup;
    private Pdi _pdi;

    public L1SetupViewerViewModel()
    {
        Title = LanguageProvider.Instance.GetValue("L1SetupViewer_Window_Title");
        LanguageProvider.Instance.UiCultureChanged += Instance_UiCultureChanged;
    }

    #region Properties

    public L1Setup L1Setup
    {
        get { return _l1Setup; }
        set { SetProperty(ref _l1Setup, value); }
    }
    public Pdi Pdi
    {
        get { return _pdi; }
        set { SetProperty(ref _pdi, value); }
    }

    #endregion

    #region Navigation

    public override void OnNavigatedTo(NavigationContext navigationContext)
    {
        if (navigationContext.Parameters.ContainsKey("L1Setup"))
        {
            L1Setup = navigationContext.Parameters.GetValue<L1Setup>("L1Setup");
        }

        if (navigationContext.Parameters.ContainsKey("Pdi"))
        {
            Pdi = navigationContext.Parameters.GetValue<Pdi>("Pdi");
        }
    }

    #endregion

    private void Instance_UiCultureChanged(object sender, EventArgs e)
    {
        Title = LanguageProvider.Instance.GetValue("L1SetupViewer_Window_Title");
    }
}
Run Code Online (Sandbox Code Playgroud)

第一个用户控件:

<UserControl x:Class="XXX.XXX.Hmi.UserControls.L1SetupViewerEntrySectionView"
             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:uc="clr-namespace:XXX.XXX.Hmi.UserControls"
             d:DesignHeight="450"
             d:DesignWidth="800"
             mc:Ignorable="d">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" SharedSizeGroup="c" />
            <ColumnDefinition Width="*" SharedSizeGroup="c" />
            <ColumnDefinition Width="*" SharedSizeGroup="c" />
            <ColumnDefinition Width="*" SharedSizeGroup="c" />
            <ColumnDefinition Width="*" SharedSizeGroup="c" />
            <ColumnDefinition Width="*" SharedSizeGroup="c" />
            <ColumnDefinition Width="*" SharedSizeGroup="c" />
        </Grid.ColumnDefinitions>
        <uc:L1SetupViewerCellControl Title="Over Speed"
                                     Grid.Row="0"
                                     Grid.Column="0"
                                     Margin="0,0,5,0"
                                     Value="{Binding Setup.EnOveSpd}" />
         .
         .
         .
    </Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)

第一个UserControl代码背后:

public partial class L1SetupViewerEntrySectionView : UserControl
{
    public L1Setup Setup
    {
        get { return (L1Setup)GetValue(SetupProperty); }
        set { SetValue(SetupProperty, value); }
    }
    public static readonly DependencyProperty SetupProperty =
        DependencyProperty.Register("Setup", typeof(L1Setup), typeof(L1SetupViewerEntrySectionView), new PropertyMetadata(null));

    public L1SetupViewerEntrySectionView()
    {
        InitializeComponent();
        this.DataContext = this;
    }
}
Run Code Online (Sandbox Code Playgroud)

第二个UserControl:

<UserControl x:Class="XXX.XXX.Hmi.UserControls.L1SetupViewerCellControl"
             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"
             d:DesignHeight="450"
             d:DesignWidth="800"
             mc:Ignorable="d">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0"
                   Margin="0,0,3,0"
                   Text="{Binding Title}" />
        <TextBox Grid.Column="1" Text="{Binding Value}" />
    </Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)

第二个UserControl代码背后:

public partial class L1SetupViewerCellControl : UserControl
{
    public string Title
    {
        get { return (string)GetValue(TitleProperty); }
        set { SetValue(TitleProperty, value); }
    }
    public static readonly DependencyProperty TitleProperty =
        DependencyProperty.Register("Title", typeof(string), typeof(L1SetupViewerCellControl), new PropertyMetadata(string.Empty));

    public string Value
    {
        get { return (string)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }
    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(string), typeof(L1SetupViewerCellControl), new PropertyMetadata(string.Empty));

    public L1SetupViewerCellControl()
    {
        InitializeComponent();
        this.DataContext = this;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我运行该应用程序,则会收到以下绑定错误:

System.Windows.Data Error: 40 : BindingExpression path error: 'L1Setup' property not found on 'object' ''L1SetupViewerCellControl' (Name='')'. BindingExpression:Path=L1Setup.EnPor1OutDia; DataItem='L1SetupViewerCellControl' (Name=''); target element is 'L1SetupViewerCellControl' (Name=''); target property is 'Value' (type 'String')

Run Code Online (Sandbox Code Playgroud)

我在stackOverflow上尝试了几个答案,但对我没有任何帮助,我也没弄错。

mm8*_*mm8 5

设置this.DataContext = thisL1SetupViewerEntrySectionView从中断的数据上下文的继承L1SetupViewerView,这就是为什么绑定L1Setup失败。

而不是DataContext在后面的代码中显式设置,您应该像这样设置DataContext根元素的UserControl

<Grid DataContext="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}>
Run Code Online (Sandbox Code Playgroud)

...或每个绑定的来源:

<uc:L1SetupViewerCellControl ... 
    Value="{Binding Setup.EnOveSpd, RelativeSource={RelativeSource AncestorType=UserControl}}" />
Run Code Online (Sandbox Code Playgroud)

同样的事情适用于L1SetupViewerCellControl,即this.DataContext = this从构造函数中删除并使用绑定到Value属性RelativeSource

<TextBox Grid.Column="1" Text="{Binding Value, RelativeSource={RelativeSource AncestorType=UserControl}}" />
Run Code Online (Sandbox Code Playgroud)