【问题标题】:Static combobox within a datagrid in WPF, but have the Selected Value set by SQLWPF中数据网格内的静态组合框,但具有由SQL设置的选定值
【发布时间】:2020-03-23 14:37:39
【问题描述】:

我正在尝试在组合框中使用资产状态代码的静态列表,但使用 SQL 查询从 SQL 服务器中提取适当的状态并将其用作选定值。

例如,组合框将设置“Active”、“Returned”或“Repair Depot”,但它会通过数据库表 Assets 获取选定的值,其中包含一个名为 Status 的字段。

我在填充组合框时遇到问题。没有错误,但也没有数据。

XAML:

<Window x:Class="Test_Personnel.Dialogs.WinAssets"
    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:Test_Personnel.Dialogs"
    mc:Ignorable="d"
    Title="Assets" Height="450" Width="800" Loaded="AssetsLoad">
<Grid Margin="0,10,0,0">
    <DataGrid Name="AssetGrid" HorizontalAlignment="Left" Margin="31,57,0,0" VerticalAlignment="Top" ItemsSource="{Binding Path=Assets}" AutoGenerateColumns="False" AlternatingRowBackground="LightBlue" RenderTransformOrigin="0.534,2.99">
        <DataGrid.Columns>
            <DataGridComboBoxColumn Header="Status" ItemsSource="{Binding Status}"/>
            <DataGridTemplateColumn>
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Button x:Name="Save" Content="Save" Click="Button_Assets_Save_Click" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTextColumn Binding="{Binding Path=AssetType, UpdateSourceTrigger=LostFocus}" Header="Type" Width="auto"/>
            <DataGridTextColumn Binding="{Binding Path=AssetNo, UpdateSourceTrigger=LostFocus}" Header="Asset Number" Width="auto"/>
            <DataGridTextColumn Binding="{Binding Path=AssetSerialNo, UpdateSourceTrigger=LostFocus}" Header="Serial No" Width="auto"/>
            <DataGridTextColumn Binding="{Binding Path=AssetPhoneNo, UpdateSourceTrigger=LostFocus}" Header="Phone No" Width="auto"/>
        </DataGrid.Columns>
    </DataGrid>
    <ComboBox Name="cmbEmployee" SelectedValuePath="Tag" SelectionChanged="CmbEmployee_Changed" HorizontalAlignment="Left" Margin="31,30,0,0" VerticalAlignment="Top" Width="193"/>
</Grid>

背后的代码:

/// <summary>
/// Interaction logic for WinAssets.xaml
/// </summary>
public partial class WinAssets : Window
{

    // Create a new string to store the employee ID so we can use it later
    public String strEmpID
    { get; set; }

    // Class for the status portion of the combobox
    public class Option
    {
        public int OptionId { get; set; }
        public string StatusText { get; set; }
    }

    public class BoundObject
    {
        public List<Option> cmbStatus { get; set; }
    }

    readonly SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder
    {
        DataSource = "",
        UserID = "",
        Password = "",
        InitialCatalog = "Personnel",
        PersistSecurityInfo = false,
        MultipleActiveResultSets = false,
        Encrypt = true,
        TrustServerCertificate = false,
        ConnectTimeout = 30
    };

    public WinAssets()
    {
        InitializeComponent();

    }

    // assign the employee ID to the object
    public WinAssets(String strempID):this()
    { this.strEmpID = strempID;
    }


private void AssetsLoad(object sender, RoutedEventArgs e)
    {
        int j = 0;

        SqlConnection connection = new SqlConnection(builder.ConnectionString);
        connection.Open();

        // Create daPersonnel adapter to get employee information so we can use it to select data in ComboBox
        SqlDataAdapter daPersonnel = new SqlDataAdapter("SELECT * FROM Employee", connection);
        DataTable dtPersonnel = new DataTable();
        daPersonnel.Fill(dtPersonnel);

        ComboBoxItem item = new ComboBoxItem();
        item.Content = "All";
        item.Tag = "0";
        cmbEmployee.Items.Add(item);
        for (int i = 0; i < dtPersonnel.Rows.Count; i++)
        {
            ComboBoxItem item1 = new ComboBoxItem();
            item1.Content = dtPersonnel.Rows[i]["LastName"].ToString() + ", " + dtPersonnel.Rows[i]["FirstName"].ToString();
            item1.Tag = dtPersonnel.Rows[i]["EmployeeID"].ToString();
            cmbEmployee.Items.Add(item1);

            //if the string strEmpId is set, then someone requested it via the MainWindow, so get the row (j) corresponding to the appropriate Employee
            if (dtPersonnel.Rows[i]["EmployeeId"].ToString() == strEmpID)
            {
                j = i;
            }
        }

        if (strEmpID != null)
        {
            cmbEmployee.SelectedValue = dtPersonnel.Rows[j]["EmployeeId"].ToString();
        }

        StringBuilder sb = new StringBuilder();
        sb.Append("SELECT EmployeeID, Status, AssetType, AssetNo, AssetPhoneNo, AssetSerialNo FROM Assets WHERE EmployeeID = @strEmpID1;");
        String sql = sb.ToString();

        SqlCommand command = new SqlCommand(sql, connection);
        var strEmpIDparam = new SqlParameter("strEmpID1", SqlDbType.VarChar);
        strEmpIDparam.Value = strEmpID;
        command.Parameters.Add(strEmpIDparam);
        DataTable dt = new DataTable();
        SqlDataAdapter adapter = new SqlDataAdapter(command);
        adapter.Fill(dt);

        // Set status combobox to be selected to what is in the database
        var sOpts = new List<Option> { new Option { StatusText = "Active" }, new Option { StatusText = "Returned" }, new Option { StatusText = "Repair Depot" } };
        var list = new List<BoundObject> { new BoundObject { cmbStatus = sOpts } };

        //AssetGrid.ItemsSource = list;

        AssetGrid.ItemsSource = dt.DefaultView;
        AssetGrid.CanUserAddRows = false;

        daPersonnel.Dispose();
        adapter.Dispose();
        command.Dispose();
        connection.Close();
    }

    private void Filldatagrid()
    {

        int j = 0;

        SqlConnection connection = new SqlConnection(builder.ConnectionString);
        connection.Open();

        // Create daPersonnel adapter to get employee information so we can use it to select data in ComboBox
        SqlDataAdapter daPersonnel = new SqlDataAdapter("SELECT * FROM Employee", connection);
        DataTable dtPersonnel = new DataTable();
        daPersonnel.Fill(dtPersonnel);

        ComboBoxItem item = new ComboBoxItem();
        item.Content = "All";
        item.Tag = "0";
        cmbEmployee.Items.Add(item);
        for (int i = 0; i < dtPersonnel.Rows.Count; i++)
        {
            ComboBoxItem item1 = new ComboBoxItem();
            item1.Content = dtPersonnel.Rows[i]["LastName"].ToString() + ", " + dtPersonnel.Rows[i]["FirstName"].ToString();
            item1.Tag = dtPersonnel.Rows[i]["EmployeeID"].ToString();
            cmbEmployee.Items.Add(item1);

            //if the string strEmpId is set, then someone requested it via the MainWindow, so get the row (j) corresponding to the appropriate Employee
            if (dtPersonnel.Rows[i]["EmployeeId"].ToString() == strEmpID)
            {
                j = i;
            }
        }

        if (strEmpID != null)
        {
            cmbEmployee.SelectedValue = dtPersonnel.Rows[j]["EmployeeId"].ToString();
        }

        StringBuilder sb = new StringBuilder();
        sb.Append("SELECT EmployeeID, Status, AssetType, AssetNo, AssetPhoneNo, AssetSerialNo FROM Assets WHERE EmployeeID = @strEmpID1;");
        String sql = sb.ToString();

        SqlCommand command = new SqlCommand(sql, connection);
        var strEmpID1param = new SqlParameter("strEmpID1", SqlDbType.VarChar);
        strEmpID1param.Value = strEmpID;
        command.Parameters.Add(strEmpID1param);
        DataTable dt = new DataTable();
        SqlDataAdapter adapter = new SqlDataAdapter(command);
        adapter.Fill(dt);

        AssetGrid.ItemsSource = dt.DefaultView;
        AssetGrid.CanUserAddRows = false;

        daPersonnel.Dispose();
        adapter.Dispose();
        command.Dispose();
        connection.Close();

    }

    private void Button_Assets_Save_Click(object sender, RoutedEventArgs e)
    {

    }

    private void CmbEmployee_Changed(object sender, SelectionChangedEventArgs e)
    {

        strEmpID = (string)((ComboBoxItem) cmbEmployee.SelectedItem).Tag; //get value of combobox (the ID)
        int j = 0;

        SqlConnection connection = new SqlConnection(builder.ConnectionString);
        connection.Open();

        // Create daPersonnel adapter to get employee information so we can use it to select data in ComboBox
        SqlDataAdapter daPersonnel = new SqlDataAdapter("SELECT * FROM Employee", connection);
        DataTable dtPersonnel = new DataTable();
        daPersonnel.Fill(dtPersonnel);

        for (int i = 0; i < dtPersonnel.Rows.Count; i++)
        {

            //if the string strEmpId is set, then someone requested it via the MainWindow, so get the row (j) corresponding to the appropriate Employee
            if (dtPersonnel.Rows[i]["EmployeeId"].ToString() == strEmpID)
            {
                j = i;
            }
        }

        if (strEmpID != null)
        {
            cmbEmployee.SelectedValue = strEmpID;
        }

        StringBuilder sb = new StringBuilder();
        if (strEmpID == "0")
        {
            sb.Append("SELECT Employee.FirstName, Employee.LastName, Assets.EmployeeID, Assets.AssetType, Assets.AssetNo, Assets.AssetPhoneNo, Assets.AssetSerialNo, Assets.Status FROM Assets JOIN Employee ON Assets.EmployeeID = Employee.EmployeeId;");
            DataGridTextColumn textColumnFN = new DataGridTextColumn();
            AssetGrid.AutoGenerateColumns = false;
            textColumnFN.Header = "First Name";
            textColumnFN.Binding = new Binding("FirstName");
            AssetGrid.Columns.Add(textColumnFN);
            DataGridTextColumn textColumnLN = new DataGridTextColumn();
            textColumnLN.Header = "Last Name";
            textColumnLN.Binding = new Binding("LastName");
            AssetGrid.Columns.Add(textColumnLN);
        }
        else
        {
            // If AssetGrid has more than 4 columns than someone selected all, which needs FirstName, LastName, but now we don't need those
            if (AssetGrid.Columns.Count > 6)
            { 
                AssetGrid.Columns.RemoveAt(6);  // Remove First Name column
                AssetGrid.Columns.RemoveAt(6);  // Since we removed First Name column, Last Name Column is now column 6, remote it too.
            }
            sb.Append("SELECT EmployeeID, Status, AssetType, AssetNo, AssetPhoneNo, AssetSerialNo FROM Assets WHERE EmployeeID = @strEmpID1;");
        }

        String sql = sb.ToString();

        SqlCommand command = new SqlCommand(sql, connection);
        var strEmpID1param = new SqlParameter("strEmpID1", SqlDbType.VarChar);
        strEmpID1param.Value = strEmpID;
        command.Parameters.Add(strEmpID1param);
        DataTable dt = new DataTable();
        SqlDataAdapter adapter = new SqlDataAdapter(command);
        adapter.Fill(dt);

        AssetGrid.ItemsSource = dt.DefaultView;
        AssetGrid.CanUserAddRows = false;

        daPersonnel.Dispose();
        adapter.Dispose();
        command.Dispose();
        connection.Close();
    }

}

}

我现在主要处理的是 AssetsLoad。如果我可以让它在加载时工作,我想我可以处理剩下的。

我无法让组合框加载任何静态数据或来自 SQL 服务器的数据。

提前谢谢你!

Image of broken combobox

【问题讨论】:

  • 你应该看看 mvvm 和一个 orm。根据我的经验,Dapper 是最接近麻烦的。数据网格行的数据上下文是它呈现的数据项 - 这就是数据网格中的行获取数据的方式。这意味着您需要一些位于资源中的集合或父数据上下文中的静态或属性。然后你可以告诉它去那里查找数据。通常这将是一个窗口视图模型。 social.technet.microsoft.com/wiki/contents/articles/…

标签: c# wpf combobox datagrid


【解决方案1】:

我猜你不熟悉 WPF 编程。我想你想绑定“状态” 到 ComboBoxColumn ItemsSsource。

<Window x:Class="Test_Personnel.Dialogs.WinAssets"
    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:Test_Personnel.Dialogs"
    mc:Ignorable="d" x:Name="mainWnd"
    Title="Assets" Height="450" Width="800" Loaded="AssetsLoad">
<Grid Margin="0,10,0,0">
    <DataGrid Name="AssetGrid" HorizontalAlignment="Left" Margin="31,57,0,0" VerticalAlignment="Top" ItemsSource="{Binding Path=Assets}" AutoGenerateColumns="False" AlternatingRowBackground="LightBlue" RenderTransformOrigin="0.534,2.99">
        <DataGrid.Columns>
            <DataGridComboBoxColumn Header="Status" ItemsSource="{Binding Status,ElementName=MainWnd}" DisplayMemberPath="StatusText" />
            <DataGridTemplateColumn>
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Button x:Name="Save" Content="Save" Click="Button_Assets_Save_Click" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTextColumn Binding="{Binding Path=AssetType, UpdateSourceTrigger=LostFocus}" Header="Type" Width="auto"/>
            <DataGridTextColumn Binding="{Binding Path=AssetNo, UpdateSourceTrigger=LostFocus}" Header="Asset Number" Width="auto"/>
            <DataGridTextColumn Binding="{Binding Path=AssetSerialNo, UpdateSourceTrigger=LostFocus}" Header="Serial No" Width="auto"/>
            <DataGridTextColumn Binding="{Binding Path=AssetPhoneNo, UpdateSourceTrigger=LostFocus}" Header="Phone No" Width="auto"/>
        </DataGrid.Columns>
    </DataGrid>
    <ComboBox Name="cmbEmployee" SelectedValuePath="Tag" SelectionChanged="CmbEmployee_Changed" HorizontalAlignment="Left" Margin="31,30,0,0" VerticalAlignment="Top" Width="193"/>
</Grid>

但您的代码没有 Status 属性。写吧。

public List<Option> Status { get; set; }

重写初始化状态。

Status = new List<Option> { new Option { StatusText = "Active" }, new Option { StatusText = "Returned" }, new Option { StatusText = "Repair Depot" } };

试试看。祝你好运!

【讨论】:

  • 是的,我对 WPF 很陌生。我添加了 Status 属性并放置了新的 init Status,但组合框仍然是空白的。没有错误,但也没有数据。我在原始帖子中添加了损坏组合框的图片。谢谢!
  • 我想知道组合框的 ItemSource 是否与从数据表中提取的 AssetGrid.ItemSource 冲突。
猜你喜欢
  • 1970-01-01
  • 2011-06-05
  • 2019-11-16
  • 1970-01-01
  • 1970-01-01
  • 2017-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多