【问题标题】:Data binding doesn't work with my dependency property数据绑定不适用于我的依赖属性
【发布时间】:2013-11-20 07:53:19
【问题描述】:

我正在使用 .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 是未更新。我认为我没有连接好东西,但我没有找到。

有什么想法吗?

【问题讨论】:

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


    【解决方案1】:

    您必须对您的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}}"
    

    除了SelectedItems 属性之外,您的控件还应该具有可绑定的ItemsItemsSource,而不是这样做。然后,您可以像这样简单地编写绑定:

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

    【讨论】:

    • 我两个都加了,但效果不大。我还仔细检查了输出窗口中的绑定错误,看起来没问题。所以一切似乎都很好。
    • 谢谢,这现在就像一个魅力,代码看起来更好。你的答案现在被接受了:)
    【解决方案2】:

    将列表更改为 observablecollection,因为 observablecollection 实现了 INotifyCollectionChanged 和 INotifyPropertyChanged,而列表没有这样做

    【讨论】:

    • 我试过了,但没有用,因为我没有使用 AddRemove 等方法更新 List ,我创建了一个新的 List 所以引用是不同的。
    猜你喜欢
    • 2017-03-04
    • 1970-01-01
    • 1970-01-01
    • 2014-02-03
    • 2015-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多