【问题标题】:How to get a property of a type when BindingBinding时如何获取类型的属性
【发布时间】:2014-12-04 11:46:15
【问题描述】:

我有一个名为“MyType”的类型,并且我的 Pivot 的 ItemsSource 绑定到“myFirstVM”ViewModel 内名为“DataSource”的 ObservableCollection 属性。在“MyType”中,我有属性 Title。从我的 XAML 中可以看出,TextBlock 绑定到 MyProperty。如何让它返回当前的item Title?

例如,如果我在第二个 PivotItem 上,我需要 DataSource 集合中第二个项目的标题

XAML:

<Grid x:Name="LayoutRoot">
    <Pivot Name="myPivot"
           SelectedItem="{Binding myFirstVM.SelItem, Mode=TwoWay}"
           ItemsSource="{Binding myFirstVM.DataSource}"
           ItemTemplate="{Binding myFirstVM.OtherTemplate}">
        <Pivot.HeaderTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding DataContext.myFirstVM.MyProperty, ElementName=myPivot}"/>
            </DataTemplate>
        </Pivot.HeaderTemplate>
    </Pivot>
</Grid>

myFirstVM 代码:

private ObservableCollection<MyType> _dataSource;
public ObservableCollection<MyType> DataSource
{
    get
    {
        if (this._dataSource == null)
        {
            this._dataSource = new ObservableCollection<MyType>();
        }
        return this._dataSource;
    }
    set { }
}

public string MyProperty 
{ 
    get
    {
        if (null != this.SelItem)
        {
            return this.SelItem.Title;
        }

        return "no title";
    } 
    set { }
}

private MyType _selItem;
public MyType SelItem
{
    get
    {
        return _selItem;
    }
    set
    {
        _selItem = value;

        RaisePropertyChanged("SelItem");
        RaisePropertyChanged("MyProperty");
    }
}

public ObservableCollection<MyOtherType> OtherDataSource
{
    get
    {
        if (null != this.SelItem)
        {
            return this.SelItem.OtherCollection;
        }
        else
        {
            return new ObservableCollection<MyOtherType>();
        }
    }
    set { }
}

private MyOtherType _selOtherItem;
public MyOtherType SelOtherItem
{
    get
    {
        return _selSegment;
    }
    set
    {
        _selSegment = value;

        RaisePropertyChanged("SelOtherItem");
        RaisePropertyChanged("PartsDataSource");
    }
}

public ObservableCollection<MyThirdType> ThirdDataSource
{
    get
    {
        if (null != this.SelOtherItem)
        {
            return this.SelOtherItem.ThirdCollection;
        }
        else
        {
            return new ObservableCollection<MyThirdType>();
        }
    }
    set { }
}

这些是我的内部集合“OtherDataSource”和“ThirdDataSource”的数据模板,它们是列表框:

<DataTemplate x:Key="OtherTemplate">
    <ListBox DataContext="{Binding Source={StaticResource Locator}}"
             ItemsSource="{Binding myFirstVM.OtherDataSource}"
             ItemTemplate="{StaticResource ThirdTemplate}"
             SelectedItem="{Binding myFirstVM.SelOtherItem, Mode=TwoWay}">
    </ListBox>
</DataTemplate>

<DataTemplate x:Key="ThirdTemplate">
    <ListBox DataContext="{Binding Source={StaticResource Locator}}"
             ItemsSource="{Binding myFirstVM.ThirdDataSource}"
             ItemTemplate="{StaticResource FourthTemplate}">
    </ListBox>
</DataTemplate>

编辑:我按照@olitee 的建议使用完整的 ViewModel 和 DataTemplates 更新了问题。如您所见,这种方法的问题在于,在第二个和第三个 dataTemplate 中,我有 ListBoxes。我对所有事情都使用一个 ViewModel。有什么想法吗?

【问题讨论】:

    标签: c# xaml mvvm binding parent


    【解决方案1】:

    您需要做一些额外的工作。您的 ViewModel 当前不知道选择了哪个项目。您可以创建一个名为“SelectedItem”的新属性,并绑定 Pivots 的 SelectedItem 值。

    然后您可以在代码中访问所选项目。

    <Grid x:Name="LayoutRoot">
       <Pivot Name="myPivot"
           Tag="{Binding}"
           SelectedItem="{Binding myFirstVM.SelectedItem}"
           ItemsSource="{Binding myFirstVM.DataSource}"
           ItemTemplate="{Binding myFirstVM.ViewDataTemplate}">
       <Pivot.HeaderTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding DataContext.myFirstVM.MyProperty, ElementName=myPivot}"/>
            </DataTemplate>
       </Pivot.HeaderTemplate>
    </Pivot>
    </Grid>
    

    那么您的虚拟机将如下所示:

    private ObservableCollection<MyType> _dataSource;
    public ObservableCollection<MyType> DataSource
    {
        get
        {
            if (this._dataSource == null)
            {
                this._dataSource = new ObservableCollection<MyType>();
            }
            return this._dataSource;
        }
        set { }
    }
    
    public string MyProperty 
    { 
        get
        {
            if (this.SelectedItem != null)
            {
                return this.SelectedItem.Title;
            }
            else
            {
                return null;
            }
        } 
    }
    
    private MyType _selectedItem;
    
    public MyType SelectedItem
    { 
        get
        {
            return _selectedItem;
        } 
        set
        {
            _selectedItem = value;
            OnNotifyPropertyChanged("SelectedItem");
            OnNotifyPropertyChanged("MyProperty");
        }
    }
    

    或者,如果您只是想修复文本以进行演示,并且在您的 VM 中并不真正需要 SelectedItem,您可以采用 @Jehof 的方法 - 但实现一个执行修复的 IValueConvertor。

    【讨论】:

    • 我可以看到,但 _selectedItem 为 null,然后在 MyProperty getter 上崩溃,说对象引用未设置为对象的实例。
    • 是的,_selectedItem 可以(并且可能会)为空 - 特别是在您的视图正在加载时。您需要在 MyProperty getter 中包含一个空检查。我已经更新了示例代码...
    • 我也做了空检查,但它不起作用。它不会崩溃,但它也不起作用。标题中没有显示任何内容。
    • 您使用的是哪个 Pivot 控件?基础设施? DevExpress?
    • 啊,您使用的是 Windows Phone? @Jehof 的绑定是否有效,即使它不是您想要的解决方案?还是更新失败?您可能需要订阅 SelectionChanged 事件。
    【解决方案2】:

    这应该可以解决问题

    <TextBlock Text="{Binding SelectedItem.Title, ElementName=myPivot}"/>
    

    将 Text-Property 绑定到 Pivot 元素的 SelectedItem 属性。当 Pivot 的选定项目发生变化时,TextBlock 应显示项目的标题。

    【讨论】:

    • 酷,但它直接绑定到模型,我需要将它绑定到 ViewModel 属性包装器,我必须先做一些修复值。
    【解决方案3】:

    这是正确的 XAML 实现:

    SelectedItem="{Binding myFirstVM.SelectedItem, Mode=TwoWay}"
    

    在后面的代码中,ViewModel 需要继承 ViewModelBase,而不是 OnNotifyPropertyChanged,这是 MVVM Light 的一部分,然后在 SelectedItem 属性的设置器中:

    RaisePropertyChanged("SelectedItem");
    

    【讨论】:

    • 这个解决方案的问题是,当使用ListBox控件而不是Pivot时,只需要显示项目,而不改变选择,它就不起作用了。使用枢轴,您可以向左/向右滑动并更改 SelectedItem,但不会在 listBox 中更改。有没有人知道如何使用另一个控件来执行此操作,您只需要在其中显示项目。如何遍历所有这些以强制绑定?
    猜你喜欢
    • 2018-03-19
    • 2018-02-16
    • 1970-01-01
    • 2019-09-28
    • 2018-08-12
    • 2021-07-16
    • 2017-01-15
    • 1970-01-01
    • 2012-04-04
    相关资源
    最近更新 更多