数据绑定不适用于我的依赖项属性

时间:2013-11-20 07:53:19

标签: c# wpf xaml data-binding dependency-properties

我正在使用.NET Framework 4和MVVM Light Toolkit开发WPF应用程序 我创建了一个自定义用户控件,它只包含 DataGrid

<UserControl
    x:Class="PadacEtl.Matcher.Views.LaraDataGrid"
    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" 
    mc:Ignorable="d" 
    d:DesignHeight="300" d:DesignWidth="300"
    DataContext="{Binding}">

    <DataGrid ItemsSource="{Binding}" SelectionChanged="SelectionChanged">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Value" Binding="{Binding Model.Value}" />
        </DataGrid.Columns>
    </DataGrid>
</UserControl>

此控件定义依赖项属性 SelectedItems

public partial class CustomDataGrid : UserControl
{
    public IEnumerable<ItemViewModel> SelectedItems
    {
        get { return (IEnumerable<ItemViewModel>)GetValue(SelectedItemsProperty); }
        set { SetValue(SelectedItemsProperty, value); }
    }

    public static readonly DependencyProperty SelectedItemsProperty =
        DependencyProperty.Register("SelectedItems", typeof(IEnumerable<ItemViewModel>),
            typeof(CustomDataGrid), new PropertyMetadata(new List<ItemViewModel>()));

    public CustomDataGrid()
    {
        InitializeComponent();
    }

    private void SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var dataGrid = sender as DataGrid;
        SelectedItems = dataGrid.SelectedItems.Cast<ItemViewModel>();
    }
}

最后,此自定义用户控件在视图中使用,定义如下:

<Window x:Class="Project.Views.MainView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:uc="clr-namespace:Project.Views"
    Title="Project"
    Height="700" Width="1050"
    DataContext="{Binding Source={StaticResource Locator}, Path=Main}">

    <Window.Resources>
        <ResourceDictionary Source="Styles.xaml" />
    </Window.Resources>

    <Grid>
        <uc:CustomDataGrid DataContext="{Binding Items}"
            SelectedItems="{Binding SelectedItems}" />
    </Grid>
</Window>

使用相应的 ViewModel

public class MainViewModel : ViewModelBase
{
    public ObservableCollection<ItemViewModel> Items { get; private set; }

    private IEnumerable<ItemViewModel> selectedItems = new List<ItemViewModel>();
    public IEnumerable<ItemViewModel> SelectedItems
    {
        get { return selectedItems; }
        set
        {
            if (value != selectedItems)
            {
                selectedItems = value;
                RaisePropertyChanged(() => SelectedItems);
             }
        }
    }

    public MainViewModel()
    {
        //Something useful to feed Items
    }
}

我的问题是:当我从 CustomDataGrid 中选择一行或多行时,来自 MainViewModel SelectedItems 是没有更新。我想我没有做好任何事情,但我找不到。

有什么想法吗?

2 个答案:

答案 0 :(得分:3)

您必须在SelectedItems媒体资源上设置双向绑定。你可以在绑定表达式中明确地这样做:

<uc:CustomDataGrid ... SelectedItems="{Binding SelectedItems, Mode=TwoWay}"/>

或者在依赖项属性声明中设置FrameworkPropertyMetadataOptions.BindsTwoWayByDefault标志:

public static readonly DependencyProperty SelectedItemsProperty =
    DependencyProperty.Register(
        "SelectedItems",
        typeof(IEnumerable<ItemViewModel>),
        typeof(CustomDataGrid),
        new FrameworkPropertyMetadata(
            null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

另请注意,将默认属性值设置为新的集合实例是不好的做法,因为该集合将用作属性的所有“实例”的默认值。换句话说,CustomDataGrid的两个实例上的SelectedItems属性的默认值将是相同的集合对象。如果您向一个项目添加项目,则项目也将包含在另一个项目中。您必须在控件的构造函数中设置默认值。


编辑:在再次查看您的UserControl以及如何绑定其属性之后,我意识到它无法按您设计的方式工作。在绑定声明中设置DataContext

<uc:CustomDataGrid DataContext="{Binding Items}"
    SelectedItems="{Binding SelectedItems}"/>

需要显式设置SelectedItems绑定的绑定源对象,可能就像这个

SelectedItems="{Binding SelectedItems, Source={StaticResource myViewModelInstance}}"

除了Items属性之外,您的控件应该具有可绑定的ItemsSourceSelectedItems。然后你可以简单地编写你的绑定:

<uc:CustomDataGrid DataContext="{StaticResource myViewModelInstance}"
    ItemsSource="{Binding Items}" SelectedItems="{Binding SelectedItems}"/>

答案 1 :(得分:0)

将List更改为observablecollection,因为observablecollection实现了INotifyCollectionChanged和INotifyPropertyChanged,其中列表不这样做