如何使用纯 MVVM 概念和依赖注入,将不同面板上可用的 XamDataGrids 与 WPF 页面上的不同集合绑定。

How to bind XamDataGrids available on different panels with different collections on a WPF page, using pure MVVM concepts & dependency injection.

我有一个 WPF XAML 页面,有 3 个部分,由 DockPanel 分隔。一个面板包含一个要与集合绑定的 INFRAGITICS XamDataGrid 控件。

  1. 我想以纯 MVVM 方式使用 DataContext/DataSource 属性 绑定 XamDataGrid 控件。
  2. 此外,很高兴了解绑定是否通过依赖项注入完成。

我尝试了不同的方法,但没有成功。我在下面粘贴了我的代码以供参考。请帮忙。

XAML 页数:

<Window x:Class="UserInterface.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:UserInterface"
        xmlns:igDP="clr-namespace:Infragistics.Windows.DataPresenter;assembly=InfragisticsWPF.DataPresenter"
             xmlns:igEditors="clr-namespace:Infragistics.Windows.Editors;assembly=InfragisticsWPF.Editors"   
             xmlns:sys="clr-namespace:System;assembly=mscorlib" 
        xmlns:dc ="clr-namespace:UserInterface.ViewModel"
         xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
        mc:Ignorable="d"
        Title="MainWindow">
    <Window.Resources>
        <dc:GraphicViewModel x:Key="dataContext"/>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height=".5*"/>
            <RowDefinition Height=".5*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width=".5*"/>
            <ColumnDefinition Width=".5*"/>
        </Grid.ColumnDefinitions>

        <DockPanel  Grid.Column="0" Grid.Row="0">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
            </Grid>
            <!--<StackPanel Orientation="Vertical" DockPanel.Dock="Top">
                <StackPanel Orientation="Horizontal" Margin="5" Grid.Row="0">
                    <DockPanel>
                        <TextBlock Text="*.cfg File" Grid.Column="0" DockPanel.Dock="Left"/>
                        <Button Content="Browse..." Grid.Column="2" DockPanel.Dock="Right"/>
                        <TextBox FontStyle="Italic" FontWeight="Light"  Text="Browse *.cfg file..." Grid.Column="1" DockPanel.Dock="Right"/>
                    </DockPanel>
                </StackPanel>
                <StackPanel Orientation="Horizontal" Margin="5" Grid.Row="1">
                    <TextBlock Text="*.ps File  " Grid.Column="0"/>
                    <TextBox FontStyle="Italic" FontWeight="Light"  Text="Browse *.ps file..." Grid.Column="1"/>
                    <Button Content="Browse..." Grid.Column="2"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal" Margin="5" Grid.Row="2">
                    <TextBlock Text="*.pic File " Grid.Column="0"/>
                    <TextBox FontStyle="Italic" FontWeight="Light" Text="Browse *.pic file..." Grid.Column="1"/>
                    <Button Content="Browse..." Grid.Column="2"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal" Margin="5" Grid.Row="3">
                    <TextBlock Text="*.xlsx File" Grid.Column="0"/>
                    <TextBox FontStyle="Italic" FontWeight="Light"  Text="Browse *.xlsx file..." Grid.Column="1"/>
                    <Button Content="Browse..." Grid.Column="2"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal" Margin="5" Grid.Row="4">
                    <TextBlock Text="*.xlsx File"/>
                    <TextBox FontStyle="Italic" FontWeight="Light"  Text="Browse *.xlsx file..." Grid.Column="1"/>
                    <Button Content="Browse..." Grid.Column="2"/>
                </StackPanel>
            </StackPanel>-->
            <StackPanel Orientation="Horizontal">
                <StackPanel Orientation="Vertical" Margin="5" Grid.Row="0">
                    <TextBlock MinHeight="20.5" Text="*.cfg File" Grid.Column="0"/>
                    <TextBlock MinHeight="20.5" Text="*.ps File  " Grid.Column="0"/>
                    <TextBlock MinHeight="20.5" Text="*.pic File " Grid.Column="0"/>
                    <TextBlock MinHeight="20.5" Text="*.xlsx File" Grid.Column="0"/>
                    <TextBlock MinHeight="20.5" Text="*.xlsx File"  Grid.Column="0"/>                   
                </StackPanel>
                <StackPanel Orientation="Vertical" Margin="5" Grid.Row="1">
                    <TextBox FontStyle="Italic" FontWeight="Light"  Text="Browse *.cfg file..." Grid.Column="1" MinHeight="20.5"/>
                    <TextBox FontStyle="Italic" FontWeight="Light"  Text="Browse *.ps file..." Grid.Column="1"  MinHeight="20.5"/>
                    <TextBox FontStyle="Italic" FontWeight="Light" Text="Browse *.pic file..." Grid.Column="1"  MinHeight="20.5"/>
                    <TextBox FontStyle="Italic" FontWeight="Light"  Text="Browse Model mapping file..." Grid.Column="1"  MinHeight="20.5"/>
                    <TextBox FontStyle="Italic" FontWeight="Light"  Text="Browse Parameter mapping file..." Grid.Column="1"  MinHeight="20.5"/>                   
                </StackPanel>
                <StackPanel Orientation="Vertical" Margin="5" Grid.Row="2">
                    <Button Content="Browse..." Grid.Column="2"/>
                    <Button Content="Browse..." Grid.Column="2"/>
                    <Button Content="Browse..." Grid.Column="2"/>
                    <Button Content="Browse..." Grid.Column="2"/>
                    <Button Content="Browse..." Grid.Column="2"/>
                </StackPanel>               
            </StackPanel>
        </DockPanel>
        <DockPanel  Grid.Column="1" Grid.Row="0">
            <igDP:XamDataGrid x:Name="ItemsSource"  DataContext="{Binding Source={StaticResource dataContext}, Path=ItemsSource, Mode=TwoWay}" Grid.Row="0" Margin="10" AutoFit="true">
                <igDP:XamDataGrid.ViewSettings>
                    <igDP:GridViewSettings/>
                </igDP:XamDataGrid.ViewSettings>

                <igDP:XamDataGrid.FieldSettings>
                    <igDP:FieldSettings  LabelTextAlignment="Left" AllowRecordFiltering="true" FilterOperandUIType="ExcelStyle" FilterStringComparisonType="CaseInsensitive" FilterOperatorDefaultValue="Contains"
                                       LabelClickAction="SortByOneFieldOnlyTriState" SortComparisonType="Default"/>
                </igDP:XamDataGrid.FieldSettings>
                <igDP:XamDataGrid.FieldLayoutSettings>
                    <igDP:FieldLayoutSettings  DataErrorDisplayMode="ErrorIconAndHighlight" SupportDataErrorInfo="RecordsAndCells" SelectionTypeRecord ="Single"                                
                              AutoGenerateFields="False" FilterUIType="FilterRecord"/>
                </igDP:XamDataGrid.FieldLayoutSettings>
                <igDP:XamDataGrid.FieldLayouts>
                    <igDP:FieldLayout>
                        <igDP:FieldLayout.Fields>
                            <igDP:Field  Name="IsSelected" Label="Select" HorizontalContentAlignment="Left"  Width="Auto" VerticalContentAlignment="Center">
                                <igDP:Field.Settings>
                                    <igDP:FieldSettings DataItemUpdateTrigger="OnCellValueChange">
                                        <igDP:FieldSettings.LabelPresenterStyle>
                                            <Style TargetType="{x:Type igDP:LabelPresenter}">
                                                <Setter Property="ContentTemplate">
                                                    <Setter.Value>
                                                        <DataTemplate>
                                                            <CheckBox Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked" Content="" />
                                                        </DataTemplate>
                                                    </Setter.Value>
                                                </Setter>
                                            </Style>
                                        </igDP:FieldSettings.LabelPresenterStyle>
                                    </igDP:FieldSettings>
                                </igDP:Field.Settings>
                            </igDP:Field>
                            <igDP:Field Label="Name" Name="Name" AllowEdit="False" HorizontalContentAlignment="Left" Width="Auto">                               
                            </igDP:Field>
                            <igDP:Field Label="Type" Name="Type" AllowEdit="False" HorizontalContentAlignment="Left" Width="*"/>
                            <igDP:Field Label="Background" Name="Background" AllowEdit="False" HorizontalContentAlignment="Left" Width="Auto"/>
                            <igDP:Field Label="Width" Name="Width" AllowEdit="False" HorizontalContentAlignment="Right" Width="Auto"/>
                            <igDP:Field Label="Height" Name="Height" AllowEdit="False" HorizontalContentAlignment="Right" Width="Auto"/>                            
                        </igDP:FieldLayout.Fields>
                    </igDP:FieldLayout>
                </igDP:XamDataGrid.FieldLayouts>
            </igDP:XamDataGrid>
        </DockPanel>
        <DockPanel Grid.Column="0" Grid.Row="1" Grid.RowSpan="2">
            <StackPanel Orientation="Vertical" DockPanel.Dock="Bottom">    
                <TextBox Text="Sample Text1"/>
                <TextBox Text="Sample Text2"/>    
                <TextBox Text="Sample Text3"/>
                <TextBox Text="Sample Text4"/>    
            </StackPanel>
        </DockPanel>
        <!--</StackPanel>-->
    </Grid>
</Window>

Xaml后面的页面代码:

namespace UserInterface
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();                
            //GraphicViewModel obj = new GraphicViewModel();                
            //ItemsSource.DataSource = obj.ItemsSource;
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(string info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        #endregion INotifyPropertyChanged Members
        public GraphicViewModel GraphicViewModel
        {
            get { return this.DataContext as GraphicViewModel; }
            set
            {
                this.DataContext = value;
                if (this.DataContext != null)
                    NotifyPropertyChanged("GraphicViewModel");
            }
        }

        private void CheckBox_Checked(object sender, RoutedEventArgs e)
        {

        }

        private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
        {

        }
    }
}

型号Class:

namespace UserInterface.Model
{
    public class GraphicsModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void NotifyOfPropertyChange(string property)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(property));
        }

        private bool _isSelected;
        public bool IsSelected
        {
            get { return _isSelected; }
            set
            {
                if (_isSelected == value) return;

                _isSelected = value;
                NotifyOfPropertyChange("IsSelected");
            }
        }

        private string _name = string.Empty;
        public string Name
        {
            get { return _name; }
            set
            {
                if (_name != value)
                    _name = value;
                NotifyOfPropertyChange("Name");
            }
        }

        private string _type = string.Empty;
        public string Type
        {
            get { return _type; }
            set
            {
                if (_type != value)
                    _type = value;
                NotifyOfPropertyChange("Type");
            }
        }

        private string _width = string.Empty;
        public string Width
        {
            get { return _width; }
            set
            {
                if (_width != value)
                    _width = value;
                NotifyOfPropertyChange("Width");
            }
        }

        private string _height = string.Empty;
        public string Height
        {
            get { return _height; }
            set
            {
                if (_height != value)
                    _height = value;
                NotifyOfPropertyChange("Height");
            }
        }
    }
}

ViewModel class:

namespace UserInterface.ViewModel
{
    public class GraphicViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void NotifyOfPropertyChange(string property)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(property));
        }

        private ObservableCollection<GraphicsModel> _itemsSource = new ObservableCollection<GraphicsModel>();


       // MainWindow _view = null;
        public ObservableCollection<GraphicsModel> ItemsSource
        {
            get { return _itemsSource; }
            set
            {
                if (_itemsSource == value) return;

                _itemsSource = value;
                NotifyOfPropertyChange("ItemsSource");
            }
        }

        public GraphicViewModel()
        {
            //_view = view;           
            _itemsSource = new ObservableCollection<GraphicsModel>() { new GraphicsModel() { Name = "sdasdad", Type = "Model", IsSelected = false, Height = "1000", Width = "1370" } ,
            new GraphicsModel() { Name = "sdsa", Type = "Model", IsSelected = false, Height = "1000", Width = "1370" } ,new GraphicsModel() { Name = "sdasdad", Type = "Model", IsSelected = false, Height = "1000", Width = "1370" } ,new GraphicsModel() { Name = "asas", Type = "Model", IsSelected = false, Height = "1000", Width = "1370" } ,new GraphicsModel() { Name = "rewwe", Type = "Model", IsSelected = false, Height = "1000", Width = "1370" } ,};            
            //view.GraphicViewModel = this;
        }
    }
}

写的时候

<Window.Resources>
    <dc:GraphicViewModel x:Key="dataContext"/>
</Window.Resources>

你说的是"create a property of type GraphicViewModel and name it dataContext"。这几乎与在代码隐藏中做这样的事情完全一样:

private GraphicViewModel dataContext = new GraphicViewModel();

当你写

<igDP:XamDataGrid DataContext="{Binding Source={StaticResource dataContext}, Path=ItemsSource, Mode=TwoWay}" .. />

你说的是"bind the igDP:XamDataGrid.DataContext property to dataContext.ItemsSource"。

现在,为什么网格无法加载,.DataContext 属性 实际上没有做任何事情。它只是位于控件后面的数据的持有者。所以如果你要写

<igDP:XamDataGrid ItemsSource="{Binding MyProperty}" />

就是告诉WPF"set XamDataGrid.ItemsSource property equal to XamDataGrid.DataContext.MyProperty"。

由于在上面的代码中您将 DataContext 设置为 dataContext.ItemsSource,它会尝试将值设置为 dataContext.ItemsSource.MyProperty(当然不存在)。

你真正需要的是

<igDP:XamDataGrid ItemsSource="{Binding Source={StaticResource dataContext}, Path=ItemsSource}" .. />

这会将网格的 .ItemsSource 属性(这是它构建数据行的 属性)绑定到在 <Window.Resources> 中创建的名为 "dataContext",以及那个名为 ItemsSource.

的对象上的 属性

这里的第二个问题是您的代码中似乎有多个 ViewModel 副本。我个人建议永远不要像为 GraphicViewModel 那样在 XAML 中创建对象。相反,我会推荐这样的东西:

public MainWindow()
{
    InitializeComponent();                
    this.DataContext = new GraphicViewModel();
}

现在应该注意,这会创建一个新的 GraphicViewModel 实例,但不会将其存储在任何地方。如果您想在其他代码隐藏中访问此对象而不将 this.DataContext 强制转换为 GraphicViewModel,那么您应该将值存储在某处。

设置 Window.DataContext 后,无需为绑定指定自定义 Source 属性 即可编写绑定。

<igDP:XamDataGrid ItemsSource="{Binding ItemsSource}" .. />

这将起作用,因为 WPF 控件默认情况下会从其父级查找 DataContext(如果未专门设置的话)。因此,在这种情况下,XamDataGrid 的 .DataContext 属性 为空,因此它将在可视化树中向上移动,寻找带有 DataContext 的内容,直到遇到您在GraphicViewModel 的新实例的构造函数。

对于希望了解 DataContext 属性 的人,我通常将他们发送到 this SO answer 以避免必须一直重新键入相同的内容。如果您仍在努力了解 DataContext 是什么或如何使用它,我建议您阅读它。

此外,依赖注入是不同的东西,根本不会在这里使用。

非常感谢@Rachel、@Daniel Filipov 和@quetzalcoatl,我的代码现在可以运行了。在以下文件中完成的更改:

MainWindow.xaml.cs

public MainWindow()
        {
            InitializeComponent();           
            ItemsSource.DataContext= new GraphicViewModel();
        }

MainWindow.xaml:

 <igDP:XamDataGrid x:Name="ItemsSource" DataSource="{Binding ItemsSource, Mode=TwoWay}" .../>