【问题标题】:Correct way to data-bind collections to ComboBox in WPF using MVVM?使用 MVVM 在 WPF 中将集合数据绑定到 ComboBox 的正确方法?
【发布时间】:2016-05-13 19:12:01
【问题描述】:

我正在使用 MVVM 模式,开发我的 WPF 应用程序。我还使用 Entity Framework 作为 ORM。这是我的模型 (EF):

public class User : BaseEntity
{
    public string Name { get; set; }

    public int OfficeId { get; set; }
    public Office Office { get; set; }
}

public class Office : BaseEntity
{
    public string Name { get; set; }

    public int DepartmentId { get; set; }
    public Department Department { get; set; }

    public virtual ICollection<User> Users { get; set; }
}

public class Department : BaseEntity
{
    public string Name { get; set; }

    public virtual ICollection<Office> Offices { get; set; }
}

假设,我从上下文中获得了 User 类的实例:

   var userInstance = context.Get<User>().Single(user => user.ID == 1);

现在我想将此实例传递给我的视图以对具体用户(例如称为UserEditView)进行一些更改,因此我必须创建一个UserModel 类来处理User 数据根据 MVVM。所以,这就是我认为我必须在我的代码中写的内容:

public class UserModel : ObservableObject
{
    private User user;

    public string Office Office
    {
        get
        {
            return this.user.Office.Name;
        }
        set
        {
            //what shoud I write Here??
            if(value != user.Office)
            {
                 user.Office=value;
                 OnPropertyChanged("Office");
            }
        }
    }
}

我真的很沮丧!我应该如何处理?有成千上万的例子,但它们是如此简单。我想知道我应该怎么做才能在我的 EditView 中有一个 ComboBox,其中包含我的数据库中存在的所有办公室的列表。并且办公室列表应该依赖于另一个包含部门列表的组合框。

  • 但是我应该从哪里得到这个列表呢?
  • 我应该从我的 UserModel 传递一个集合吗?还是什么?
  • 谁能给我一个关于如何正确执行此操作的简单示例?

PS:当然,我知道实现这种行为的几种方法,但在这种情况下,我的代码看起来很丑陋且不可维护。请帮忙。非常感谢!

【问题讨论】:

标签: wpf data-binding


【解决方案1】:

这取决于您的数据库架构。这是一些常见的建议(但可能还有很多其他建议)。

  1. 不要惊慌 - 你的问题是正确的。
  2. 创建视图模型,将其设置为窗口的主视图模型。
  3. 在您的视图模型中创建两个集合用户(包含 UserModels)和部门(包含 DepartmentMode),因为您希望每次重新选择部门时都更改办公室,所以您不需要需要主视图模型中的 Offices 集合
  4. 从您的数据库中提取每个集合数据。
  5. 使用 INPC 实现每个模型。
  6. 考虑 WPF MVVM 最佳实践。
  7. 应用正确的绑定。
  8. 祝你幸福——你是一名程序员。

更新 - 1

XAML 代码

    <Grid x:Name="LayoutRoot">
    <Grid.DataContext>
        <someBindingExampleSoHelpAttempt:MainViewModel/>
    </Grid.DataContext>
    <ListView ItemsSource="{Binding Users}">
        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="ContentTemplate">
                    <Setter.Value>
                        <DataTemplate DataType="someBindingExampleSoHelpAttempt:UserModel">
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="100"></ColumnDefinition>
                                    <ColumnDefinition Width="200"></ColumnDefinition>
                                    <ColumnDefinition Width="50"></ColumnDefinition>
                                    <ColumnDefinition Width="50"></ColumnDefinition>
                                </Grid.ColumnDefinitions>
                                <TextBox Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"  Text="{Binding Name, UpdateSourceTrigger=LostFocus, Mode=TwoWay}"/>
                                <TextBox Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"  Text="{Binding LastName, UpdateSourceTrigger=LostFocus, Mode=TwoWay}"/>
                                <ComboBox Grid.Column="2"
                                          IsTextSearchEnabled="True"     
                                          IsTextSearchCaseSensitive="False"     
                                          StaysOpenOnEdit="True"    
                                          TextSearch.TextPath="DepartmentName"
                                          ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, 
                                    AncestorType={x:Type ListView}}, Path=DataContext.Departments}"    
                                          SelectedValue="{Binding Department}"     
                                          DisplayMemberPath="DepartmentName" 
                                          IsEditable="True"
                                          HorizontalAlignment="Stretch"     
                                          VerticalAlignment="Stretch"/>
                                <ComboBox Grid.Column="3"
                                          IsTextSearchEnabled="True"     
                                          IsTextSearchCaseSensitive="False"     
                                          StaysOpenOnEdit="True"
                                          IsEditable="True"
                                          TextSearch.TextPath="OfficeName"
                                          ItemsSource="{Binding OfficesCollection}"    
                                          SelectedValue="{Binding Office}"     
                                          DisplayMemberPath="OfficeName"      
                                          HorizontalAlignment="Stretch"     
                                          VerticalAlignment="Stretch"/>
                            </Grid>

                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListView.ItemContainerStyle>
    </ListView></Grid>

虚拟机和模型

    public class MainViewModel:BaseObservableObject
{
    private DepartmentModel _selectedDepartment;
    private OfficeModel _selectedOffice;

    public MainViewModel()
    {
        Dal = new DataLayer();
        Users = new ObservableCollection<UserModel>();
        Departments = new ObservableCollection<DepartmentModel>(Dal.GetAllDepartments());
        InitUsersCollection();
    }

    private void InitUsersCollection()
    {
        if(Departments == null) return;
        Departments.ToList().ForEach(model =>
        {
            model.Offices.ToList().ForEach(officeModel =>
            {
                if (officeModel.Users == null) return;
                officeModel.Users.ToList().ForEach(userModel => Users.Add(userModel));
            });
        });
    }

    public ObservableCollection<UserModel> Users { get; set; }

    public ObservableCollection<DepartmentModel> Departments { get; set; }

    private DataLayer Dal { get; set; }

}

public class DataLayer
{
    public List<DepartmentModel> GetAllDepartments()
    {
        //pull and map your using your DB service
        //For example:
        return new List<DepartmentModel>
        {
            new DepartmentModel
            {
                DepartmentId = 1,
                DepartmentName = "A",
                Offices = new ObservableCollection<OfficeModel>
                {
                    new OfficeModel
                    {
                        DepartmentId = 1,
                        OfficeName = "AA",
                        Users = new ObservableCollection<UserModel>(new List<UserModel>
                        {
                            new UserModel {Name = "Avicenna", LastName = "Abu Ali Abdulloh Ibn-Sino"},
                            new UserModel {Name = "Omar", LastName = "Khayyam"},
                            new UserModel {Name = "RAMBAM", LastName = "Moshe ben Maimon"}
                        })
                    },
                    new OfficeModel 
                    {

                        DepartmentId = 1, 
                        OfficeName = "AB", 
                        Users = new ObservableCollection<UserModel>(new List<UserModel>
                        {
                            new UserModel {Name = "Leo", LastName = "Tolstoi"},
                            new UserModel {Name = "Anton", LastName = "Chekhov"},
                        })},
                }
            },
            new DepartmentModel
            {
                DepartmentId = 2,
                DepartmentName = "B",
                Offices = new ObservableCollection<OfficeModel>
                {
                    new OfficeModel
                    {
                        DepartmentId = 2, OfficeName = "BA",
                        Users = new ObservableCollection<UserModel>(new List<UserModel>
                        {
                            new UserModel {Name = "B", LastName = "O"},
                            new UserModel {Name = "B", LastName = "N"},
                        }),
                    },
                    new OfficeModel
                    {
                        DepartmentId = 2, OfficeName = "BB",
                        Users = new ObservableCollection<UserModel>(new List<UserModel>
                        {
                            new UserModel {Name = "John", LastName = "Walker"},
                            new UserModel {Name = "Gregory", LastName = "Rasputin"},
                        }),
                    },
                }
            },
            new DepartmentModel
            {
                DepartmentId = 3,
                DepartmentName = "C",
                Offices = new ObservableCollection<OfficeModel>
                {
                    new OfficeModel {DepartmentId = 3, OfficeName = "CA"},
                    new OfficeModel {DepartmentId = 3, OfficeName = "CB"},
                    new OfficeModel {DepartmentId = 3, OfficeName = "CC"}
                }
            }
        };
    }
}

public class OfficeModel:BaseObservableObject
{
    private int _departmentModel;
    private string _officeName;
    private DepartmentModel _department;
    private ObservableCollection<UserModel> _users;

    public int DepartmentId
    {
        get { return _departmentModel; }
        set
        {
            _departmentModel = value;
            OnPropertyChanged();
        }
    }

    public DepartmentModel Department
    {
        get { return _department; }
        set
        {
            _department = value;
            OnPropertyChanged();
        }
    }

    public string OfficeName
    {
        get { return _officeName; }
        set
        {
            _officeName = value;
            OnPropertyChanged();
        }
    }

    public ObservableCollection<UserModel> Users
    {
        get { return _users; }
        set
        {
            _users = value;
            OnPropertyChanged(()=>Users);
        }
    }
}

public class DepartmentModel:BaseObservableObject
{

    private string _departmentName;

    public string DepartmentName
    {
        get { return _departmentName; }
        set
        {
            _departmentName = value;
            OnPropertyChanged();
        }
    }

    public int DepartmentId { get; set; }

    public ObservableCollection<OfficeModel> Offices { get; set; }
}

public class UserModel:BaseObservableObject
{
    private string _name;
    private string _lastName;
    private DepartmentModel _department;
    private OfficeModel _office;

    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            OnPropertyChanged();
        }
    }

    public string LastName
    {
        get { return _lastName; }
        set
        {
            _lastName = value;
            OnPropertyChanged();
        }
    }

    public DepartmentModel Department
    {
        get { return _department; }
        set
        {
            _department = value;
            OnPropertyChanged();
            OnPropertyChanged(()=>OfficesCollection);
        }
    }

    public ObservableCollection<OfficeModel> OfficesCollection
    {
        get { return Department.Offices; }
    }

    public OfficeModel Office
    {
        get { return _office; }
        set
        {
            _office = value;
            OnPropertyChanged();
        }
    }
}

/// <summary>
/// implements the INotifyPropertyChanged (.net 4.5)
/// </summary>
public class BaseObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    protected virtual void OnPropertyChanged<T>(Expression<Func<T>> raiser)
    {
        var propName = ((MemberExpression)raiser.Body).Member.Name;
        OnPropertyChanged(propName);
    }

    protected bool Set<T>(ref T field, T value, [CallerMemberName] string name = null)
    {
        if (!EqualityComparer<T>.Default.Equals(field, value))
        {
            field = value;
            OnPropertyChanged(name);
            return true;
        }
        return false;
    }
}

但请注意,这只是数百种方法中的一种。 如果您需要代码示例,请点击此处。 问候。

【讨论】:

  • 举个小例子就好了
  • @klutch1991 很高兴给我几分钟 :)
猜你喜欢
  • 2019-10-11
  • 1970-01-01
  • 2019-06-23
  • 2011-02-06
  • 2010-12-21
  • 2010-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多