繁体   English   中英

WPF自定义控件拾取父窗口的DataContext

[英]WPF Custom Control Picking Up Parent Window's DataContext

我有一个ViewModel

 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”属性。 BindingExpression:Path = TextBody; DataItem ='ViewModel'(HashCode = 2512406); 目标元素是'TextBlock'(Name =''); 目标属性为“文本”(类型为“字符串”)

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

当我观看ProjectorDisplayControl上设置DataContext的私有属性_projectedData的设置器时,我首先看到它被设置为有效值,然后设置为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对象。 有人看到我搞砸了吗?

谢谢大家的帮助!


解决方案是:


投影机DisplayControl

        <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>

子控件从其父级继承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,这就是为什么要在其中搜索它的原因。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM