首页 > 解决方案 > 如何将不同的查询结果绑定到组合框并将其作为选定的单元格值传递

问题描述

我已经尝试了很多 Stack Overflow 的答案,但我找不到一个直接简单的例子来说明我希望实现的目标。

我正在尝试用表(dimDate)中的不同结果填充组合框,并在选择网格行(来自安全表)时更改该组合框选择。

不用说我一直在尝试的东西并没有按预期工作。我做错了什么,如何用最简单的工作示例解决它?

主窗口.xaml

<Label Content="Year" Margin="0,0,10,0" Grid.Row="0" Grid.Column="0"/>
<ComboBox x:Name="txtyr" Grid.Row="0" Grid.Column="0"
            Width="115" SelectedIndex="0" DisplayMemberPath="Year"
            ItemsSource="{Binding Years}" 
            SelectedValue="{Binding Path=years_SelectedValue}" 
            SelectedValuePath="value">
</ComboBox>

<Label Content="Quarter" Margin="0,0,10,0" Grid.Row="0" Grid.Column="1"/>
<ComboBox x:Name="txtqt" Grid.Row="0" Grid.Column="1"
            Width="115" SelectedIndex="0" DisplayMemberPath="Year"
            ItemsSource="{Binding Quarters}" 
            SelectedValue="{Binding Path=quarters_SelectedValue}" 
            SelectedValuePath="value"/>

<Label Content="Name" Margin="0,0,10,0" Grid.Row="0" Grid.Column="2"/>
<ComboBox x:Name="txtnm" Grid.Row="0"  Grid.Column="2"
            Width="115" SelectedIndex="0" DisplayMemberPath="Year"
            ItemsSource="{Binding Names}" 
            SelectedValue="{Binding Path=names_SelectedValue}" 
            SelectedValuePath="value"/>

<Label Content="Safery Score:" Margin="0,0,10,0" Grid.Row="1" Grid.Column="0"/>
<Controls:NumericUpDown x:Name="txtssc"  Grid.Row="2" Grid.Column="0"
                        Controls:TextBoxHelper.HasText="True" Width="115" Height="20" 
                        Controls:TextBoxHelper.Watermark="Score"
                        UpDownButtonsWidth="25" Maximum="10" Minimum="-10" HasDecimals="False" 
                        InterceptArrowKeys="True" InterceptMouseWheel="True"                         
                        />

<DataGrid Grid.Row="1" Margin="10,10,0,0" AutoGenerateColumns="False" VirtualizingPanel.IsVirtualizingWhenGrouping="True" EnableColumnVirtualization="True" EnableRowVirtualization="True" VirtualizingPanel.IsVirtualizing="true" ColumnHeaderStyle="{StaticResource lowCase}" x:Name="dtGrid" HorizontalAlignment="Left" CanUserResizeRows="False" ItemsSource="{Binding}" GridLinesVisibility="All" HorizontalContentAlignment="Stretch" CanUserAddRows="false" SelectedCellsChanged="dtGrid_SelectedCellsChanged" VerticalAlignment="Top" Grid.ColumnSpan="2" DataContext="{Binding Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}" IsReadOnly="True">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Year}" Header="Year"/>
        <DataGridTextColumn Binding="{Binding Quarter}" Header="Quarter"/>
        <DataGridTextColumn Binding="{Binding Name}" Header="Name"/>
        <DataGridTextColumn Binding="{Binding SafetyScore}" Header="Safety Score"/>
        <DataGridTextColumn Binding="{Binding ID}" Header="ID" Visibility="Collapsed"/>
    </DataGrid.Columns>
</DataGrid>

主窗口.cs

namespace Safety
{
    public partial class MainWindow : MetroWindow
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new SafetyViewModel();
            string connectionString = "data Source=xxx; initial catalog=xxx; user id=xxx; password=xxx";
            SqlConnection connection = new SqlConnection(connectionString);
            SqlCommand cmd = new SqlCommand("Select ID, Year, Quarter, Name, SaferyScore from MATRIX.dbo.Safety", connection);

            try
            {
                connection.Open();
                DataTable dt = new DataTable();
                dt.Load(cmd.ExecuteReader());
                dtGrid.DataContext = dt;
            }

            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            connection.Close();
        }

        private void dtGrid_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
        {
            DataRowView row_selected = dtGrid.SelectedItem as DataRowView;
            if (row_selected == null) return;
            txtyr.ItemsSource = row_selected["Year"].ToString();
            txtqt.Text = row_selected["Quarter"].ToString();
            txtnm.Text = row_selected["Name"].ToString();
            txtscc.Value = Convert.ToInt16(row_selected["SafetyScore"].ToString());
            txtID.Text = row_selected["ID"].ToString();
        }
    }
}

安全视图模型.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Safety.Model;
using System.Windows;
using Safety;
using System.Collections.ObjectModel;

namespace Safety.ViewModel
{
    public class SafetyViewModel : INotifyPropertyChanged
    {
        public SafetyViewModel()
        {
            this.loadyearlist();
            this.loadnamelist();
            this.loadquarterslist();
        }

        public void loadyearlist()
        {
            using (MATRIXEntities db = new MATRIXEntities())
            {
                var yrs = (from a in db.dimDate
                         select a).Distinct()
                         .ToList();

                Years = new ObservableCollection<dimDate>(yrs);
            }
        }

        public void loadquarterslist()
        {
            using (MATRIXEntities db = new MATRIXEntities())
            {
                var qts = (from a in db.dimDate
                           select a).Distinct()
                         .ToList();

                Quarters = new ObservableCollection<dimDate>(qts);
            }
        }

        public void loadnamelist()
        {
            using (MATRIXEntities db = new MATRIXEntities())
            {
                var nms = (from a in db.Employees
                         select a)
                         .ToList();

                Employees = new ObservableCollection<Employees>(nms);
            }
        }



        private ObservableCollection<dimDate> years;
        public ObservableCollection<dimDate> Years
        {
            get { return years; }
            set
            {
                years = value;
                OnPropertyChanged("Years");
            }
        }

        public string _years_SelectedValue;
        private string years_SelectedValue
        {
            get { return _years_SelectedValue; }
            set
            {
                _years_SelectedValue = value;
                OnPropertyChanged("years_SelectedValue");
            }
        }

        private ObservableCollection<dimDate> quarters;
        public ObservableCollection<dimDate> Quarters
        {
            get { return quarters; }
            set
            {
                quarters = value;
                OnPropertyChanged("Quarters");
            }
        }

        public string _quarters_SelectedValue;
        private string quarters_SelectedValue
        {
            get { return _quarters_SelectedValue; }
            set
            {
                _quarters_SelectedValue = value;
                OnPropertyChanged("quarters_SelectedValue");
            }
        }

        private ObservableCollection<Employees> employees;
        public ObservableCollection<Employees> Employees
        {
            get { return employees; }
            set
            {
                employees = value;
                OnPropertyChanged("Employees");
            }
        }

        public string _names_SelectedValue;
        private string names_SelectedValue
        {
            get { return _names_SelectedValue; }
            set
            {
                _names_SelectedValue = value;
                OnPropertyChanged("names_SelectedValue");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
            => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    }
}

模型

namespace Safety.Model
{
    using System;
    using System.Collections.Generic;

    public partial class dimDate
    {
        public int DateID { get; set; }
        public System.DateTime Date { get; set; }
        public int Year { get; set; }
        public int Month { get; set; }
        public int Day { get; set; }
        public int Quarter { get; set; }
    }
}

namespace Safety.Model
{
    using System;
    using System.Collections.Generic;

    public partial class Safety
    {
        public int ID { get; set; }
        public int Year { get; set; }
        public int Quarter { get; set; }
        public string Name { get; set; }
        public int SafetyScore { get; set; }
    }
}

namespace Safety.Model
{
    using System;
    using System.Collections.Generic;

    public partial class Employees
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Position { get; set; }
    }
}

标签: c#wpfxamldata-binding

解决方案


你的代码有很多问题。下面列出的很少:

  • 绑定属性应该是公共的而不是私有的
  • 在后面的代码中,您试图设置TextComboBox 而不是SelectedValue
  • 您正在将 Code behind 与 ViewModel 设计混合在一起

我编写了下面的代码,演示了使用 MVVM 设计模式的要求。

主窗口.xaml

<Window x:Class="WpfApp1.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:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <StackPanel Margin="5" Grid.Column="0">
                <Label Content="Year" />
                <ComboBox x:Name="txtyr"
                    ItemsSource="{Binding Years}" 
                    SelectedValue="{Binding Path=years_SelectedValue}" />
            </StackPanel>
            <StackPanel Margin="5"  Grid.Column="1">
                <Label Content="Quarter"/>
                <ComboBox x:Name="txtqt"
                ItemsSource="{Binding Quarters}" 
                SelectedValue="{Binding Path=quarters_SelectedValue}" />
            </StackPanel>
            <StackPanel Margin="5"  Grid.Column="2">
                <Label Content="Name" />
                <ComboBox x:Name="txtnm"
                    ItemsSource="{Binding Names}" 
                    SelectedValue="{Binding Path=names_SelectedValue}" />
            </StackPanel>
        </Grid>
        <DataGrid Grid.Row="1" x:Name="dtGrid" ItemsSource="{Binding Safeties}" SelectedItem="{Binding SelectedSafety}">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Year}" Header="Year"/>
                <DataGridTextColumn Binding="{Binding Quarter}" Header="Quarter"/>
                <DataGridTextColumn Binding="{Binding Name}" Header="Name"/>
                <DataGridTextColumn Binding="{Binding SafetyScore}" Header="Safety Score"/>
                <DataGridTextColumn Binding="{Binding ID}" Header="ID" Visibility="Collapsed"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

对于演示,我在 View 中定义了 ViewModel。

主视图模型.Cs

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;

namespace WpfApp1
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        public MainWindowViewModel()
        {
            var data = Model.GetData();
            Safeties.AddRange(data);
            Years.AddRange(data.Select(d => d.Year).Distinct());
            Quarters.AddRange(data.Select(d => d.Quarter).Distinct());
            Names.AddRange(data.Select(d => d.Name).Distinct());
        }

        private ObservableCollection<int> years = new ObservableCollection<int>();
        public ObservableCollection<int> Years
        {
            get { return years; }
        }

        private int _years_SelectedValue;
        public int years_SelectedValue
        {
            get { return _years_SelectedValue; }
            set
            {
                _years_SelectedValue = value;
                OnPropertyChanged("years_SelectedValue");
            }
        }

        private ObservableCollection<int> quarters = new ObservableCollection<int>();
        public ObservableCollection<int> Quarters
        {
            get { return quarters; }
        }

        private int _quarters_SelectedValue;
        public int quarters_SelectedValue
        {
            get { return _quarters_SelectedValue; }
            set
            {
                _quarters_SelectedValue = value;
                OnPropertyChanged("quarters_SelectedValue");
            }
        }

        private ObservableCollection<string> names = new ObservableCollection<string>();
        public ObservableCollection<string> Names
        {
            get { return names; }
        }

        private string _names_SelectedValue;
        public string names_SelectedValue
        {
            get { return _names_SelectedValue; }
            set
            {
                _names_SelectedValue = value;
                OnPropertyChanged("names_SelectedValue");
            }
        }

        private ObservableCollection<Safety> safeties = new ObservableCollection<Safety>();
        public ObservableCollection<Safety> Safeties
        {
            get { return safeties; }
        }

        private Safety selectedSafety;
        public Safety SelectedSafety
        {
            get { return selectedSafety; }
            set
            {
                selectedSafety = value;
                this.OnPropertyChanged(nameof(SelectedSafety));
                if (this.selectedSafety != null)
                {
                    this.years_SelectedValue = selectedSafety.Year;
                    this.quarters_SelectedValue = selectedSafety.Quarter;
                    this.names_SelectedValue = selectedSafety.Name;
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

通过上面的代码合并,下面的 gif 演示了该功能的工作原理:

在此处输入图像描述

附加代码

为了演示,我创建了一个类来获取数据

public static class Model
    {
        public static List<Safety> GetData()
        {
            return new List<Safety>()
            {
                new Safety() { ID = 1, Name = "First", Quarter = 1, SafetyScore = 1, Year = 2001 },
                new Safety() { ID = 2, Name = "Second", Quarter = 2, SafetyScore = 1, Year = 2001 },
                new Safety() { ID = 3, Name = "Third", Quarter = 3, SafetyScore = 1, Year = 2001 },
                new Safety() { ID = 4, Name = "Fourth", Quarter = 4, SafetyScore = 1, Year = 2001 },
                new Safety() { ID = 5, Name = "First", Quarter = 1, SafetyScore = 1, Year = 2002 },
                new Safety() { ID = 6, Name = "Second", Quarter = 2, SafetyScore = 1, Year = 2002 },
                new Safety() { ID = 7, Name = "Third", Quarter = 3, SafetyScore = 1, Year = 2002 },
                new Safety() { ID = 8, Name = "Fourth", Quarter = 4, SafetyScore = 1, Year = 2002 },
            };
        }
    }

以及 AddRange 的扩展名ObservableCollection。但是,您可以使用 C#7.0 中引入的 ObservableRangeCollection

public static class ObservableCollectionExtensions
    { 
        public static void AddRange<T>(this ObservableCollection<T> observableCollection, IEnumerable<T> data)
        {
            foreach (T item in data)
            {
                observableCollection.Add(item);
            }
        }
    }

安全.cs

public class Safety : INotifyPropertyChanged
    {
        private int id;
        public int ID
        {
            get
            {
                return id;
            }
            set
            {
                id = value;
                this.RaisePropertyChange(nameof(ID));
            }
        }

        private int year;
        public int Year
        {
            get
            {
                return year;
            }
            set
            {
                year = value;
                this.RaisePropertyChange(nameof(ID));
            }
        }

        private int quarter;
        public int Quarter
        {
            get
            {
                return quarter;
            }
            set
            {
                quarter = value;
                this.RaisePropertyChange(nameof(ID));
            }
        }

        private string name;
        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
                this.RaisePropertyChange(nameof(ID));
            }
        }

        private int safetyScore;

        public int SafetyScore
        {
            get
            {
                return safetyScore;
            }
            set
            {
                safetyScore = value;
                this.RaisePropertyChange(nameof(ID));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChange(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

推荐阅读