【问题标题】:Wpf - Binding one gridcontrol selected row data and populate it in another gridcontrolWpf - 绑定一个网格控件选定的行数据并将其填充到另一个网格控件中
【发布时间】:2017-04-06 11:18:56
【问题描述】:

我有一个网格控件,其中包含我在代码中没有提到的各种字段

<dxg:GridControl   HorizontalAlignment="Stretch" Height="300"  VerticalAlignment="Top" x:Name="grid1"  AutoPopulateColumns="False" ItemsSource="{Binding Collection1}"    >
                    <dxg:GridControl.View >
                        <dxg:TableView x:Name="TableView1" />
                    </dxg:GridControl.View>
                .   
                .   
                .   
                .

我在同一页面上有另一个网格控件,其中包含各种字段

<dxg:GridControl HorizontalAlignment="Stretch" Height="250"  VerticalAlignment="Top" x:Name="grid2"  AutoPopulateColumns="False"
                                 ItemsSource="{Binding ElementName="TableView1" ,path=Collection2.FocusedRow}"    >
                    <dxg:GridControl.View >
                        <dxg:TableView x:Name="TableView2"  />
                    </dxg:GridControl.View>
                .   
                .   
                .   
                .

现在collection1 Id 是主键,collection2 colID 是外键,两者都有关系

这里的场景是如果我在 grid1 中选择一行,所有相应的记录都必须显示在 grid 2 中

 public class myCollection: BindingList<orders>
{
     public DataContext dc;

    public myCollection(IList<orders> list)
        : base(list)
    {
    }

    protected override void RemoveItem(int index)
    {
        orders deleteItem = this.Items[index];

        if (Dc.Order != null)
        {
            Dc.Order.DeleteOnSubmit(deleteItem);
        }
        base.RemoveItem(index);
    }

}

我的订单通用类和大师通用类是一样的

【问题讨论】:

  • Collection2 是 Collection1 中对象类型的属性吗?
  • Collection2 是 collection1 中的 EntityRef 对象
  • 它必须是 IEnumerable 才能将 DataGrid 的 ItemsSource 属性绑定到它。在 WPF 应用程序中使用自动生成的实体框架类在实际场景中很少有用。您应该创建自己的类。

标签: c# wpf


【解决方案1】:

如果我说的是 XAML 属性,这里您想在第一个 Datagrid 的 SelectedItem 属性的基础上更新第二个 Datagrid 的 ItemsSource 属性。

为此,在 ViewModel 中添加一个新属性“SelectedItemDg1”,它将保存第一个 DataGrid 的选择。在此“SelectedItemDg1”属性的 Setter 中,根据需要设置 Collection2。

确保实现 INotifyPropertyChanged 接口并为两个集合使用 ObservableCollection 类型。

以下是相同的代码示例:

模型类:

public class Country
{
    public string CountryName { get; set; }

    public int CountryId { get; set; }

    public List<State> States { get; set; }
}

public class State
{
    public string StateName { get; set; }
    public int StateId { get; set; }
}

视图模型:

public class MainWindowViewModel : INotifyPropertyChanged
{

    public MainWindowViewModel()
    {
        CountriesCollection = new ObservableCollection<Country>();
        StateCollection = new ObservableCollection<State>();
        LoadData();
    }

    private ObservableCollection<Country> _CountriesCollection;

    public ObservableCollection<Country> CountriesCollection
    {
        get { return _CountriesCollection; }
        set
        {
            _CountriesCollection = value;
            NotifyPropertyChanged("CountriesCollection");
        }
    }

    private ObservableCollection<State> _StatesCollection;

    public ObservableCollection<State> StateCollection
    {
        get { return _StatesCollection; }
        set
        {
            _StatesCollection = value;
            NotifyPropertyChanged("StateCollection");
        }
    }

    private Country _SelectedCountry;

    public Country SelectedCountry
    {
        get { return _SelectedCountry; }
        set
        {
            _SelectedCountry = value;
            if (_SelectedCountry != null && _SelectedCountry.States != null)
            {
                StateCollection = new ObservableCollection<State>(_SelectedCountry.States);
            }
            NotifyPropertyChanged("SelectedCountry");
        }
    }

    private void LoadData()
    {
        if (CountriesCollection != null)
        {
            CountriesCollection.Add(new Country
            {
                CountryId = 1,
                CountryName = "India",
                States = new List<State>
                            {
                                    new State { StateId = 1, StateName = "Gujarat"},
                                    new State { StateId = 2, StateName = "Punjab"},
                                    new State { StateId = 3, StateName = "Maharastra"}
                            }
            });
            CountriesCollection.Add(new Country
            {
                CountryId = 2,
                CountryName = "Chine",
                States = new List<State>
                            {
                                    new State { StateId = 4, StateName = "Chine_State1"},
                                    new State { StateId = 5, StateName = "Chine_State2"},
                                    new State { StateId = 6, StateName = "Chine_State3"}
                            }
            });
            CountriesCollection.Add(new Country
            {
                CountryId = 3,
                CountryName = "japan",
                States = new List<State>
                            {
                                    new State { StateId = 7, StateName = "Japan_State1"},
                                    new State { StateId = 8, StateName = "Japan_State2"},
                                    new State { StateId = 9, StateName = "Japan_State3"}
                            }
            });
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String info)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info));
    }

}

XALM:

 <StackPanel Orientation="Horizontal" >
    <DataGrid AutoGenerateColumns="True" 
              Height="300" Width="300" 
              HorizontalAlignment="Left" Margin="30" 
              ItemsSource="{Binding CountriesCollection}" 
              SelectedItem="{Binding SelectedCountry}">

    </DataGrid>
    <DataGrid AutoGenerateColumns="True" 
              Height="300" Width="300" 
              HorizontalAlignment="Left" Margin="30"  
              ItemsSource="{Binding SelectedCountry.States}">

    </DataGrid>
</StackPanel>

这里我有 DataGrid 的 AutoGenerateColumns 属性,但您必须根据您的要求进行更改。

我希望这个示例代码能让你更容易理解。

【讨论】:

  • 我有带有 INotifyPropertyChanged 和 IBindingList 的 L2S。是的,这正是我需要的
  • 我想了解更多,因为我是新手。
  • 我看到您的问题与 Country 和 State 组合框的经典示例非常相似。这是一个此类示例的链接。我想你可以从中更好地理解:stackoverflow.com/questions/43050501/…
  • 您提供的链接对于 selectedItem 可以正常工作,但对于 TableView 中的focusedrow,我无法实现同样的效果
  • 你所说的“focusedrow”是什么意思?您是否在使用某些第三方控件?
【解决方案2】:

我发现对集合进行这种主从绑定的最简单和最干净的方法是将ObservableCollection 包装在一个类中,公开它的ListCollectionView 并将你的ItemsSource 绑定到它,如下所示(它有一些用于简化 xml 序列化的额外代码):

public class ViewableCollection<T> : ObservableCollection<T>
{
    private ListCollectionView _View;

    public ViewableCollection(IEnumerable<T> items)
        : base(items) { }

    public ViewableCollection()
        : base() { }

    [XmlIgnore]
    public ListCollectionView View
    {
        get
        {
            if (_View == null)
            {
                _View = new ListCollectionView(this);
                _View.CurrentChanged += new EventHandler(InnerView_CurrentChanged);
            }
            return _View;
        }
    }

    [XmlIgnore]
    public T CurrentItem
    {
        get
        {
            return (T)this.View.CurrentItem;
        }
        set
        {
            this.View.MoveCurrentTo(value);
        }
    }

    private void InnerView_CurrentChanged(object sender, EventArgs e)
    {
        this.OnPropertyChanged(new PropertyChangedEventArgs("CurrentItem"));
    }

    public void AddRange(IEnumerable<T> range)
    {
        if (range == null)
            throw new ArgumentNullException("range");

        foreach (T item in range)
        {
            this.Items.Add(item);
        }

        this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
        this.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
        this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, (IList)range.ToList()));
    }

    public void ReplaceItems(IEnumerable<T> range)
    {
        if (range == null)
            throw new ArgumentNullException("range");

        this.Items.Clear();
        foreach (T item in range)
        {
            this.Items.Add(item);
        }

        this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
        this.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
        this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    public void RemoveItems(IEnumerable<T> range)
    {

        if (range == null)
            throw new ArgumentNullException("range");

        foreach (T item in range)
        {
            this.Items.Remove(item);
        }

        this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
        this.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
        this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, (IList)range.ToList()));
    }

    public void ClearAll()
    {
        IList old = this.Items.ToList();
        base.Items.Clear();
        this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
        this.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
        this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, old));
    }

    public void CallCollectionChaged()
    {
        this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    // necessary for xml easy serialization using [XmlArray] attribute
    public static implicit operator List<T>(ViewableCollection<T> o)
    {
        return o == null ? default(List<T>) : o.ToList();
    }

    // necessary for xml easy serialization using [XmlArray] attribute
    public static implicit operator ViewableCollection<T>(List<T> o)
    {
        return o == default(List<T>) || o == null ? new ViewableCollection<T>() : new ViewableCollection<T>(o);
    }
}

然后在您的ViewModel 中(记得实现INotifyPropertyChanged,我使用nuget 包Fody.PropertyChanged 自动在属性上实现它):

[ImplementPropertyChanged]
public class MyViewModel
{
    public ViewableCollection<MySecondViewModel> Collection1 { get; set; }

    public MyViewModel()
    {
        this.Collection1 = new ViewableCollection<MySecondViewModel>();
    }
}

[ImplementPropertyChanged]
public class MySecondViewModel
{ 
    public string MyColumn1 { get; set; }
    public string MyColumn2 { get; set; }
    public ViewableCollection<MyThirdViewModel> Collection2 { get; set; }

    public MySecondViewModel()
    {
        this.Collection1 = new ViewableCollection<MyThirdViewModel>();
    }
}

[ImplementPropertyChanged]
public class MyThirdViewModel
{ 
    public string MyColumn1 { get; set; }
    public string MyColumn2 { get; set; }
}

//...
this.DataContext = new MyViewModel();

那么,保持网格同步就这么简单:

<DataGrid ItemsSource="{Binding Collection1.View, Mode=OneWay}" 
          IsSynchronizedWithCurrentItem="True" />
<DataGrid ItemsSource="{Binding Collection1.CurrentItem.Collection2.View, Mode=OneWay}"
          IsSynchronizedWithCurrentItem="True" />

例如,在当前选定的Collection2 中绑定到当前选定项目中的Column1 属性将是:

<TextBlock Text="{Binding Collection1.CurrentItem.Collection2.CurrentItem.Column1}" />

此外,您还可以在后面的代码中管理选择,例如:

Collection1.CurrentItem=null;

将清除集合上的选择。

您还可以从后面的代码中对ViewableCollection 进行排序(过滤和分组),如下所示:

Collection1.View.SortDescriptions.Add(new SortDescription("Column1",ListSortDirection.Ascending));

请记住,您不应在实例化后替换整个 ViewableCollection,只需从中添加/删除项目(为此,有方法 AddRangeReplaceItems 用于批量添加/替换项目无需增加CollectionChanged 事件)

【讨论】:

  • 检查我的问题,我已经更新了它,我在我的收藏中实现了 Ibindnglist。
猜你喜欢
  • 2017-03-16
  • 1970-01-01
  • 1970-01-01
  • 2013-03-28
  • 1970-01-01
  • 2016-04-16
  • 2022-01-03
  • 1970-01-01
  • 2019-03-29
相关资源
最近更新 更多