简体   繁体   English

如何在WPF / MVVC C#中实现动态绑定

[英]How to achieve dynamic binding in WPF/MVVC C#

I am rather new to MVVC/wpf, having mostly worked with winforms. 我对MVVC / wpf比较陌生,主要是使用winforms。

What I want to accomplish is dynamic databinding without using code behind in WPF. 我要完成的是动态数据绑定,而无需在WPF中使用任何代码。 The user interface consists of a devexpress grid and a couple of buttons. 用户界面由一个devexpress网格和几个按钮组成。 Each button press loads an object list and presents the objects in the grid. 每按一次按钮将加载一个对象列表,并在网格中显示对象。 The lists contain different object types depending on the button pressed. 根据所按下的按钮,列表包含不同的对象类型。 For this example I have two classes to present: FatCat and FatDog. 对于此示例,我提供了两个类:FatCat和FatDog。

In winforms this works: 在winforms中,该方法有效:

    private void button1_Click(object sender, EventArgs e)
    {
        ((GridView)gridCtrl.MainView).Columns.Clear();
        gridCtrl.DataSource = new BindingSource(itsModel.GetAll<FatDog>(), null);
    }


    private void button2_Click(object sender, EventArgs e)
    {
        ((GridView)gridCtrl.MainView).Columns.Clear();
        gridCtrl.DataSource = new BindingSource(itsModel.GetAll<FatCat>(), null);
    }

I have configured the grid to create columns dynamically, so everything just works. 我已将网格配置为动态创建列,因此一切正常。 itsModel is of type CatClientModel. itsModel类型为CatClientModel。

In wpf I have defined the DataContext to be CatClientModel. 在wpf中,我已将DataContext定义为CatClientModel。

What should I use for ItemsSource in the grid to achieve the same behaviour as my winforms solution? 我应该为网格中的ItemsSource使用什么以实现与Winforms解决方案相同的行为?

dxg:GridControl ItemsSource="{Binding SomeDynamicList}" dxg:GridControl ItemsSource =“ {Binding SomeDynamicList}”

In other words, what should SomeDynamicList be in the code above? 换句话说,上面的代码中SomeDynamicList应该是什么? Or am I going about this the wrong way? 还是我走错路了?

I am, as I stated, using the DevExpress wpf grid control, but the question ought to be general and apply to any control presenting object lists. 正如我所说,我使用的是DevExpress wpf网格控件,但问题应该是通用的,并且适用于任何呈现对象列表的控件。

In other words, what should SomeDynamicList be in the code above? 换句话说,上面的代码中SomeDynamicList应该是什么?

SomeDynamicList should be an ObservableCollection<T> property to which you can add any objects of type T that you want to display in the GridControl . SomeDynamicList应该是ObservableCollection<T>属性,可以在其中添加要显示在GridControl中的任何T类型的对象。

Set the DataContext of the GridControl , or any of its parent elements, to an instance of a class where this property is defined: GridControlDataContext或其任何父元素设置为定义了此属性的类的实例:

public class CatClientModel
{
    public ObservableCollection<Animal> SomeDynamicList { get; } = new ObservableCollection<Animal>();
}

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new CatClientModel();
    }
}

Ok. 好。 But the thing is that the ObservableCollection contains different types. 但是,事实是ObservableCollection包含不同的类型。 Unfortunately there is no feasible class to inherit from. 不幸的是,没有可继承的类。 I want to bind to either ObservableCollection or ObservableCollection depending on which button was pressed 我想绑定到ObservableCollection或ObservableCollection,这取决于按下了哪个按钮

Switch the DataContext then, or change the property into an IEnumerable and set it to a new collection each time the button is clicked. 然后切换DataContext ,或将属性更改为IEnumerable并在每次单击按钮时将其设置为新集合。 This requires you to implement the INotifyPropertyChanged interface in your view model 这要求您在视图模型中实现InotifyPropertyChanged接口

private System.Collections.IEnumerable _collection;
public System.Collections.IEnumerable MyProperty
{
    get { return _collection; }
    set { _collection = value; OnPropertyChanged(); }
}

If you want to use XAML to define which data sources your code maps to for each grid that is possible. 如果要使用XAML定义代码,则可以针对每个网格定义哪些数据源。 That does require at least some method of MVVM manager either prism or mvvmlight to connect the view model to the view. 这确实需要MVVM Manager的至少某种方法(棱镜或mvvmlight)将视图模型连接到视图。

so if you do go the MVVM model route, the Model would contain a description for each of your grids like this: 因此,如果您采用MVVM模型路线,则模型将包含对每个网格的描述,如下所示:

 public BulkObservableCollection<icd10facet> FacetList
    {
        get { return this._facets; }
        set { SetProperty(ref this._facets, value); }

    }
    public INotifyTaskCompletion<BulkObservableCollection<PetsConvert>> ConceptList
    {
        get { return this._concept; }
        set
        {
            SetProperty(ref this._concept, value);
        }
    }

In the XAML for your code the grid woud bind to the grid defined by ConceptList in this way: 在代码的XAML中,网格将以这种方式绑定到由ConceptList定义的网格:

ItemsSource="{Binding ConceptList.Result}" 

this answer does NOT address how to wire up Prism 6.0 for example to use a view model but for examples see: 这个答案没有解决如何连接Prism 6.0例如使用视图模型的问题,但是有关示例,请参见:

https://github.com/PrismLibrary/Prism https://github.com/PrismLibrary/Prism

Which contains documentation and starter code. 其中包含文档和入门代码。 Keep in mind that there is not any specific reason that putting code in the code behind for the view is a problem, first solve the problem and then refactor if separation of concerns is an issue for you. 请记住,将代码放在视图中的代码后面没有问题是没有任何特定原因的,如果对您而言,关注点分离是问题,则首先解决该问题,然后进行重构。

Using this technique you can bind each grid to its own data source. 使用此技术,您可以将每个网格绑定到其自己的数据源。 In the MVVM space buttons and other things use a commanding model to communicate with the view model. 在MVVM空间中,按钮和其他功能使用命令模型与视图模型进行通信。

 <Button Content="Load Rule Data" Width="100" Height="40" HorizontalAlignment="Left" Margin="5px" Command="{Binding LoadRuleData }"/>

this requires defining a command delegate in the viewmodel for LoadRuleData 这需要在ViewModel中为LoadRuleData定义命令委托

    public DelegateCommand LoadRuleData { get; private set; }

and then (usually in the constructor) wire the DelegateCommand to the method that is going to do the work. 然后(通常在构造函数中)将DelegateCommand连接到将要完成工作的方法。

 this.LoadRuleData = new DelegateCommand(this.loadRules);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM