0

我有一个视图模型

 public class ViewModel:ViewModelObject
{
    public ViewModel()
    {
        ProjectionDataElementList = new ObservableCollection<ProjectionDataElement>();
    }

    public ObservableCollection<ProjectionDataElement> ProjectionDataElementList { get; set; }

    private ProjectionDataElement _currentSelectedProjectionDataElement;

    public ProjectionDataElement CurrentSelectedProjectionDataElement
    {
        get 
        { 
            return _currentSelectedProjectionDataElement; 
        }
        set 
        { 
            _currentSelectedProjectionDataElement = value;
            OnPropertyChanged("CurrentSelectedProjectionDataElement");
        }
    }

}

一个名为 ProjectorDisplayControl 的控件

<UserControl x:Class="Fast_Project.ProjectorDisplayControl"
         ..................>
<Viewbox>
    <StackPanel>
        <TextBlock Text="{Binding Path=TextBody}"/>
    </StackPanel>
</Viewbox>

    public partial class ProjectorDisplayControl : UserControl
{

    public ProjectorDisplayControl()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty ProjectedDataProperty = DependencyProperty.Register("ProjectedData", typeof(ProjectionDataElement), typeof(ProjectorDisplayControl),
            new PropertyMetadata(new PropertyChangedCallback((objectInstance, arguments) =>
            {
                ProjectorDisplayControl projectorDisplayControl = (ProjectorDisplayControl)objectInstance;
                projectorDisplayControl._projectedData = (ProjectionDataElement)arguments.NewValue;
            })));

    public ProjectionDataElement ProjectedData
    {
        get
        {
            return (ProjectionDataElement)GetValue(ProjectedDataProperty);
        }
        set
        {
            SetValue(ProjectedDataProperty, value);
        }
    }


    private ProjectionDataElement _projectedData
    {
        get
        {
            return this.DataContext as ProjectionDataElement;
        }
        set
        {
            this.DataContext = value;
        }
    }
}

该控件用于两个地方。

第一名是在 ListBox 中,它工作得很好:

<ListBox Grid.Column="0" ItemsSource="{Binding Path=ProjectionDataElementList}" Name="projectedDataListBox" 
             SelectedItem="{Binding Path=CurrentSelectedProjectionDataElement, UpdateSourceTrigger=PropertyChanged}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <Border BorderThickness="1" BorderBrush="Black">
                        <controls:ProjectorDisplayControl x:Name="_projectorDisplay" ProjectedData="{Binding}"/>
                    </Border>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

第二个位置是在我使用 ViewModel 对象设置表单的 DataContext 的表单顶部。为了使 ProjectorDisplayControl 使用 ViewModel 中的 CurrentSelectedProjectionDataElement 我希望必须这样做:

<Window x:Class="Fast_Project.DisplayWindow"
    ................>
<Viewbox>
    <StackPanel>
        <controls:ProjectorDisplayControl x:Name="_projectorDisplay" ProjectedData="{Binding CurrentSelectedProjectionDataElement}"/>
    </StackPanel>
</Viewbox>

该代码给了我两个绑定错误:

System.Windows.Data 错误:40:BindingExpression 路径错误:在“对象”“ViewModel”(HashCode=2512406)上找不到“TextBody”属性。绑定表达式:路径=文本体;DataItem='ViewModel' (HashCode=2512406); 目标元素是'TextBlock'(名称='');目标属性是“文本”(类型“字符串”)

System.Windows.Data 错误:40:BindingExpression 路径错误:在“对象”“ProjectionDataElement”(HashCode=37561097)上找不到“CurrentSelectedProjectionDataElement”属性。BindingExpression:Path=CurrentSelectedProjectionDataElement; DataItem='ProjectionDataElement' (HashCode=37561097); 目标元素是“ProjectorDisplayControl”(名称=“_projectorDisplay”);目标属性是“ProjectedData”(类型“ProjectionDataElement”)

当我在 ProjectorDisplayControl 上观察私有属性 _projectedData 的设置器时,它设置了 DataContext,我首先看到它设置了一个有效值,然后设置为 null。

在包含单个 ProjectorDisplayControl 的 DisplayWindow 中,我可以删除与 CurrentSelectedProjectionDataElement 的绑定,然后我只收到第一条绑定错误消息:

<Viewbox>
    <StackPanel>
        <controls:ProjectorDisplayControl x:Name="_projectorDisplay" />
    </StackPanel>
</Viewbox>

第一个绑定错误让我觉得在设置 DisplayWindow 的 DataContext 时使用 ViewModel 对象设置了 ProjectorDisplayControl 的 DataContext。但是从我读过的内容来看,除非您设置,否则控件不会与其父窗口共享相同的数据上下文。

我已经将 DisplayWindow 中 ProjectorDisplayControl.ProjectedData 的绑定路径视为第二条错误消息状态的 ProjectionDataElement 对象。

<Viewbox>
    <StackPanel>
        <controls:ProjectorDisplayControl x:Name="_projectorDisplay" ProjectedData="{Binding }"/>
    </StackPanel>
</Viewbox>

然后是告诉我:

无法创建默认转换器以在“Fast_Project.ViewModel”和“Fast_Project.ProjectionDataElement”类型之间执行“单向”转换

就像它真的是 ViewModel 对象一样,就像我最初认为的那样......

无论如何,我怀疑我的问题的根源在于我如何看待 ProjectorDisplayControl 将 DataContext 设置为 ViewModel 对象。有人看到我哪里搞砸了吗?

谢谢大家的帮助!


解决方案是:


投影仪显示控制

        <StackPanel>
        <TextBlock Text="{Binding Path=ProjectedData.TextBody, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type controls:ProjectorDisplayControl}}}"/>
    </StackPanel>

展示窗

<StackPanel>
        <controls:ProjectorDisplayControl x:Name="_projectorDisplay" ProjectedData="{Binding Path=ViewModel.CurrentSelectedProjectionDataElement, 
            RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type controls:DisplayWindow}}}"/>
    </StackPanel>
4

1 回答 1

0

子控件从其父控件继承 Dependency 属性值(或本例中的 DataContext)。当您在 itemTempalte 中使用 UserControl 时,每个项目的 DataContext 已经是 ProjectionDataElement,因此您的控件的 DataContext 设置为 ProjectionDataElement。

当您在父级内部使用控件时,它将继承其 DataContext。

问题是您在控件上设置 ProjectedData 属性,而不是在其中使用它。如果您希望您的每个控件都应该绑定到 ProjectedData 上设置的值,那么您应该更新绑定,例如:

<UserControl x:Class="Fast_Project.ProjectorDisplayControl"
         ..................>
<Viewbox>
    <StackPanel>
        <TextBlock Text="{Binding Path=ProjectedData.TextBody, RelativeSource={RelativeSource Self}"/>
    </StackPanel>

对于第二个错误,您必须将该窗口的 DataContext 设置为 ProjectionDataElement 某处,这就是为什么在其中搜索它。

于 2013-09-26T02:27:31.990 回答