基于来自另一个组合框C#的选择生成组合框列表(由数据库链接)

时间:2016-12-06 13:49:23

标签: c# mysql wpf visual-studio class

我正在使用C#和WPF为Univeristy项目创建预订系统。我已经完成了该项目的绝大部分,现在已经完成了更新,删除并为客户,预订和访客创建了新按钮。我将所有关于Customers,Bookings和Guests的数据存储在各自的类中,然后通过Connection Superclass将它们保存到数据库中。

然而,一切都工作了,我开始在我的数据库中实现外键以将数据链接在一起(并且它可以工作)但是现在我的项目开始看起来有点乱......

创建新预订时,您还必须从ComboBox(cmbCustomerList)中选择CustomerID,这样就可以将CustomerID_FK添加到相同的BookingID实例中。如果您想编辑预订,那么您不仅要选择cmbCustomerList而且还要选择cmbBookingsList,但是,如果您尝试使用新的CustomerID_FK更新BookingID,则会抛出错误,这也会使程序看起来很乱,因为Bookings ComboBox将会无论您选择哪种CustomerID,都会显示每个预订。有没有人知道如何做到这一点,以便当从cmbCustomerList中选择一个CustomerID时,它也只显示在cmbBookingsList中具有相同CustomerID_FK的BookingID?

以下是我的预订窗口的副本,我不会包含我的预订课程,因为它是一个简单的Get / Set方法集合,主要工作是在NewBookings窗口和Connection Class < / p>

NewBookings.xaml.cs

//Refresh the items in cmbBookingsList
    public void BookingsRefresh()
    {
        cmbBookingsList.ItemsSource = con.RefreshBookingsList();
    }

//Refresh the items in cmbCustomerList
    public void CustomerRefresh()
    {
        cmbCustomerList.ItemsSource = con.RefreshCustomerList();
    }

Connections.cs

//show customer information in the list
    public List<CustomerClass> RefreshCustomerList()
    {
        List<CustomerClass> CustomerList = new List<CustomerClass>();

        try
        {
            command.CommandText = "SELECT * FROM Customers";
            command.CommandType = CommandType.Text;
            connection.Open();

            OleDbDataReader reader = command.ExecuteReader();

            while (reader.Read())
            {
                CustomerClass c = new CustomerClass();

                c.Customer_ID = Convert.ToInt16(reader["CustomerID"].ToString());
                c.Customer_FirstName = reader["FirstName"].ToString();
                c.Customer_Surname = reader["Surname"].ToString();
                c.Address_Line1 = reader["AddressLine1"].ToString();
                c.Address_Line2 = reader["AddressLine2"].ToString();
                c.City = reader["City"].ToString();
                c.Country = reader["Country"].ToString();

                CustomerList.Add(c);
            }
            return CustomerList;
        }
        catch (Exception)
        {
            throw;
        }
        finally
        {
            if (connection != null)
            {
                connection.Close();
            }
        }
    }

public List<BookingsClass> RefreshBookingsList()
    {
        List<BookingsClass> BookingsList = new List<BookingsClass>();

        try
        {
            command.CommandText = "SELECT BookingID, CheckIn, CheckOut, Dinner, Breakfast, CarHire, Diet FROM Bookings";
            command.CommandType = CommandType.Text;
            connection.Open();

            OleDbDataReader reader = command.ExecuteReader();

            while (reader.Read())
            {
                BookingsClass b = new BookingsClass();

                b.Booking_ID = Convert.ToInt16(reader["BookingID"].ToString());
                b.Arrival_Date = reader["CheckIn"].ToString();
                b.Departure_Date = reader["CheckOut"].ToString();
                b.Dinner = Convert.ToBoolean(reader["Dinner"]);
                b.Breakfast = Convert.ToBoolean(reader["Breakfast"]);
                b.CarHire = Convert.ToBoolean(reader["CarHire"]);
                b.DietaryReq = reader["Diet"].ToString();

                BookingsList.Add(b);
            }
            return BookingsList;
        }
        catch (Exception)
        {
            throw;
        }
        finally
        {
            if (connection != null)
            {
                connection.Close();
            }
        }
    }

如果这个问题有点宽泛或有点复杂,我很抱歉。我宁愿你留下评论告诉我这不是一个好问题而不是投票,这样我会改进它并使其更容易理解

1 个答案:

答案 0 :(得分:2)

我认为您遇到的主要问题是您尝试在WPF中构建Winforms应用程序

如果你切换到MVVM structure,那就变得容易了

然后你可以将你的Combos绑定到ViewModel上的DataField 然后,视图模型将根据需要自行更新,绑定将自动更新您的视图

这是一个快速而肮脏的例子

XAML

<Window x:Class="WpfApplication1.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:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:BookingVM x:Key="vm"/>
    </Window.Resources>
    <StackPanel DataContext="{Binding Mode=OneWay, Source={StaticResource vm}}">
        <ComboBox ItemsSource="{Binding Types}" SelectedItem="{Binding Type}" DisplayMemberPath="Name"/>
        <ComboBox ItemsSource="{Binding Customers}" SelectedItem="{Binding Customer}" DisplayMemberPath="Name"/>
        <Button Command="{Binding Save, Mode=OneWay}">Save</Button>
    </StackPanel>
</Window>

代码(使用Prism和c#6.0注释)

因为我没有你的数据库可以使用我将创建一些可用于演示目的的示例模型

public class CustomerModel
{
    public int ID { get; set; }
    public string Name { get; set; }
    public int[] BoodkingType { get; set; }
}
public class BoodkingTypeModel
{
    public int ID { get; set; }
    public string Name { get; set; }
}

public static class DummyDatabase
{
    public static IEnumerable<BoodkingTypeModel> BoodkingTypes { get; } = new BoodkingTypeModel[]
    {
        new BoodkingTypeModel { ID=1, Name="Type1"  },
        new BoodkingTypeModel { ID=2, Name="Type2"  },
        new BoodkingTypeModel { ID=3, Name="Type3"  },
        new BoodkingTypeModel { ID=4, Name="Type4"  },
    };
    public static IEnumerable<CustomerModel> Customers { get; } = new CustomerModel[]
    {
        new CustomerModel { ID=1, Name="Customer1" ,BoodkingType= new int[]{ 1,2,3,4 } },
        new CustomerModel { ID=1, Name="Customer2" ,BoodkingType= new int[]{ 1,2 } },
        new CustomerModel { ID=1, Name="Customer3" ,BoodkingType= new int[]{ 3,4 } },
        new CustomerModel { ID=1, Name="Customer4" ,BoodkingType= new int[]{ 1 } },
    };

}

现在这是VM的聪明部分,它实际上完成了所有的工作

public class BookingVM : BindableBase
{
    public BookingVM()
    {
        //Command binding in this situation is better than EventHandling as it allows you to specify requirements as well as actions
        //in this case that you can't save unless Type and Customer have been set
        Save = new DelegateCommand(
            () => Console.WriteLine("Save Clicked"), //ExecuteAction
            () => Type != null && Customer!=null //CanExecute
            );
    }
    private BoodkingTypeModel _Type;

    public BoodkingTypeModel Type
    {
        get { return _Type; }
        //this is triggered both when you change the values in the View via binding, and when you set the values via code meaning that you have a single point of entry so you don't need to check every place you alter the calue to be sure that its updates the control, also this value can be bound to no controls or 500 it doesn't matter its all handled automatically plus everything is now type safe very hard to do with generic controls
        set
        {
            if(SetProperty(ref _Type, value))
            {
                Save.RaiseCanExecuteChanged();
                OnPropertyChanged(nameof(Customers));//instruct all bindings on customers to refresh
            }
        }
    }

    public IEnumerable<BoodkingTypeModel> Types
    {
        get { return DummyDatabase.BoodkingTypes; }
    }


    private CustomerModel _Customer;

    public CustomerModel Customer
    {
        get { return _Customer; }
        set
        {
            if (SetProperty(ref _Customer, value))//SetProperty changes the property if the value has change and raises the event that updates binding
            {
                Save.RaiseCanExecuteChanged();//refresh command state
            }
        }
    }

    public IEnumerable<CustomerModel> Customers
    {
        get
        {
            return from c in DummyDatabase.Customers
                   where Type == null || c.BoodkingType.Contains(Type.ID)
                   //the where clause is the link using the selected type to filter your customers
                   select c;
        }
    }
    public DelegateCommand Save { get;  }
}

Prism中的代码,简化了你必须为每一个类做的一些更烦人的任务,所以我非常推荐它,但你也可以用很少的努力编写自己的版本

可以看到

BindableBase的代码here实际代码只有十几行