SelectedItemChanged C# 的问题

Trouble with SelectedItemChanged C#

我在尝试让标签更改为列表框中当前选定的项目时遇到问题。有没有办法在不创建列表的情况下做到这一点?原始选定项目加载得很好,但当值更改或选定项目更改时,我无法更新标签。我需要新鲜的眼睛。

        public frmStudentScores()
    {
        InitializeComponent();
    }
    
    //load list box with initial students and grades
    private void frmStudentScores_Load(object sender, EventArgs e)
    {
        lstStudentInfo.Items.Add("Joel Murach|97|91|83");
        lstStudentInfo.Items.Add("Doug Lowe|99|93|97");
        lstStudentInfo.Items.Add("Anne Boehm|100|100|100");
        //set focus on first item in list
        lstStudentInfo.SelectedIndex = 0;

        //string to seperate items in list box by | to use for labels
        string[] str = lstStudentInfo.SelectedItem.ToString().Split('|');
        int total = 0;

        for (int i = 1; i < str.Length; i++)
        {
            total += int.Parse(str[i]);
        }

        //total of all scores in selected row
        lblTotal.Text = total.ToString();

        //count of the scores in the selected row
        lblCount.Text = (str.Length - 1).ToString();

        //total divided by the count of the scores in selected row
        lblAverage.Text = (total / (str.Length - 1)).ToString();

    }

    

    private void lstStudentInfo_SelectedIndexChanged(object sender, EventArgs e)
    {
        //if the index is changed in the list box
        string current = lstStudentInfo.SelectedItem.ToString();

        if (lstStudentInfo.SelectedIndex >= 0)
        {


            string[] str = lstStudentInfo.SelectedItem.ToString().Split('|');


            int total = 0;

            {
                for (int i = 0; i < str.Length; i++)
                {
                    total += int.Parse(str[i]);
                }

                {

                    lblTotal.Text = lstStudentInfo.SelectedItem.ToString();
                    lblCount.Text = (str.Length - 1).ToString();
                    lblAverage.Text = (total / (str.Length - 1)).ToString();
                }

            }
        }
    }

对你的代码有点困惑。

那里有很多额外的'{''}'。

此外,注释与代码不一致,请参阅下面的注释。

     private void lstStudentInfo_SelectedIndexChanged(object sender, EventArgs e)
        {
            //if the index is changed in the list box
            string current = lstStudentInfo.SelectedItem.ToString();
    
    #region  IF STATEMENT
            //Do you want it to only update if changed?
            //If so, you need to keep track of the index
            if (lstStudentInfo.SelectedIndex >= 0)
            {
                string[] str = lstStudentInfo.SelectedItem.ToString().Split('|');
                int total = 0;
    
                #region UNKNOWN REGION
                {
                    for (int i = 0; i < str.Length; i++)
                    {
                        total += int.Parse(str[i]);
                    }
    
                    #region UNKNOWN REGION
                    {
                        lblTotal.Text = lstStudentInfo.SelectedItem.ToString();
                        lblCount.Text = (str.Length - 1).ToString();
                        lblAverage.Text = (total / (str.Length - 1)).ToString();
                    }
                    #endregion
                }
            }
            #endregion
    #endregion  
        }

我稍微清理了一下,添加了一些错误处理和调试。

private void lstStudentInfo_SelectedIndexChanged(object sender, EventArgs e)
    {
        string current = string.empty;
        string lblCount = string.empty;
        string lblAverage = string.empty;
        string[] str = null;
        int total = 0;
        int valCount = 0;
        int valAvg = 0;

        //added some error handling
        try{
            if (lstStudentInfo.SelectedIndex >= 0)
            {
                //moved inside if statement, avoid errors if nothing is selected;
                current = lstStudentInfo.SelectedItem.ToString();
                str = current.Split('|');
                
                for (int i = 0; i < str.Length; i++)
                    {
                        total += int.Parse(str[i]);
                    }

                valCount = (str.Length - 1);
                lblCount = valCount.ToString();

                valAvg = total/valCount;
                lblAverage = valAvg.ToString();
            }
        }
        catch(Exception e){
            lblCount = "####";
            lblTotal = "####";
            current = "ERROR";
        }

        //moved outside if statment, updates labels when nothing is selected
        lblTotal.Text = current;
        lblCount.Text = lblCount;
        lblAverage.Text = lblAverage;

        //added debugging output
        Debug.WriteLine($"Student Info Selection Changed: Count: {valCount} Avg: {valAvg}");
    }

另一件需要考虑的事情是在多次执行相同代码的地方创建单一方法。

private func<lstStudentInfo,string[]> get_items = x => x.Split('|');

希望这能让您走上正确的道路。

XAML 中也可能存在问题,希望调试文本对您有所帮助。

让我们再添加一点灵感?

听起来你没有正确地将你的视图模型绑定到 window。

见下文。

Window.xaml

创建您要显示内容的基本布局。

将所有内容绑定到数据模型,事件选中的项目。

让视图模型处理所有,window 看起来很漂亮。

Window.xaml.cs

创建视图模型的实例并将其指定为数据上下文。

从这里,您可以对视图模型做任何您喜欢的事情,window 将被更新。

My_View_Model.cs

这是绑定到 Window.xaml 的所有内容所在的地方。

请注意,设置 Label_Text 后,它会调用 OnPropertyChanged 方法。

实现这个的方法有很多种,但基本上它们都是一样的,你所做的就是用 window 中需要刷新的对象的名称调用 PropertyChanged 事件。

PropertyChanged 事件关闭并通知 window 更新。

如有任何问题,请随时提出。

Window.xaml:

<Window x:Class="WPF_Label_Update.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:WPF_Label_Update"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid x:Name="The_WPF_Grid">
        <Grid.DataContext>
            <local:My_View_Model/>
        </Grid.DataContext>
        <Grid.Resources>
            <DataTemplate x:Key="myDataTemplate">
                <StackPanel>
                    <TextBlock Text="{Binding Path=obj_name}" />
                </StackPanel>
            </DataTemplate>   
        </Grid.Resources>
        
        
        <StackPanel Orientation="Horizontal">

            <ListBox x:Name="list_choice" 
                     SelectedItem="{Binding My_Selected_Object}" 
                     SelectionMode="Single" 
                     ItemsSource="{Binding My_Objects}"
                     ItemTemplate="{StaticResource myDataTemplate}">
            </ListBox>

            <StackPanel Orientation="Vertical">
            <Label x:Name="lbl_output_0" Content="{Binding Label_Text_0}"/>
            <Label x:Name="lbl_output_1" Content="{Binding Label_Text_1}"/>
            <Label x:Name="lbl_output_2" Content="{Binding Label_Text_2}"/>
            </StackPanel>

        </StackPanel>

    </Grid>
</Window>

Window.xaml.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WPF_Label_Update
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        My_View_Model myViewModel;


        private void generateData()
        {
            StringBuilder _text = new StringBuilder() ;  

            for (int i = 0; i < 10; i++)
            {
                _text.Clear();
                _text.Append($"Number {i}");

                for (int ii = 0; ii < i; ii++)
                {
                    _text.Append($"|{ii}");   
                }                                                  

                myViewModel.Add_Item(new my_obj(_text.ToString()));
            }
        }

        public MainWindow()
        {
            InitializeComponent();

            myViewModel =
                new My_View_Model();

            this.The_WPF_Grid.DataContext = myViewModel;

            generateData();
        }

        private void ListBoxItem_Selected(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("Something Was Selected");

        }
    }
}

My_View_Model.cs

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

namespace WPF_Label_Update
{
    public class My_View_Model : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public string Label_Text_0 { get { return lbl0; } set { lbl0 = value; OnPropertyChanged(); } }
        private string lbl0 = string.Empty;

        public string Label_Text_1 { get { return lbl1; } set { lbl1 = value; OnPropertyChanged(); } }
        private string lbl1 = string.Empty;

        public string Label_Text_2 { get { return lbl2; } set { lbl2 = value; OnPropertyChanged(); } }
        private string lbl2 = string.Empty;

        public my_obj My_Selected_Object {
            get {
                return mySelectedObj;
            }
            set {
                mySelectedObj = value;
                on_mySelectedObjChange();
            } }
        private my_obj mySelectedObj = null;

        /// <summary>
        /// Update lables when something changes.
        /// </summary>
        private void on_mySelectedObjChange()
        {
            switch (mySelectedObj == null)
            {
                case true:
                    Label_Text_0 = string.Empty;
                    Label_Text_1 = string.Empty;
                    Label_Text_2 = string.Empty;
                    break;
                default:

                    Label_Text_0 = mySelectedObj.obj_text;
                    Label_Text_1 = mySelectedObj.obj_name;
                    Label_Text_2 = mySelectedObj.obj_count.ToString();

                    break;
            }  
        }

        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }


        public ObservableCollection<my_obj> My_Objects { get { return my_objs; } }
        private readonly ObservableCollection<my_obj> my_objs = new ObservableCollection<my_obj>();

        public void Add_Item(my_obj new_obj)
        {
            my_objs.Add(new_obj);
        }

        public My_View_Model()
        {

        }
    }

    public class my_obj
    {
        public string obj_text { get; set; }         
        public string obj_name { get { return obj_text.Split('|')[0]; } }
        public int obj_count { get { return obj_text.Split('|').Length; } }

        public my_obj(string inputText)
        {
            this.obj_text = inputText.Trim();
        }
    }
}

我得到它来处理这个 - 谢谢大家

private void lstStudents_SelectedIndexChanged(object sender, EventArgs e)
{
    if (lstStudents.SelectedIndex != -1)
    {


        string student =
        (string)studentScores[lstStudents.SelectedIndex];
        string[] scores = student.Split('|');
        int total = 0;
        for (int i = 1; i < scores.Length; i++)
            total += Convert.ToInt32(scores[i]);
        int count = scores.Length - 1;
        int average = 0;
        if (total > 0)
            average = total / count;
        lblScoreTotal.Text = total.ToString();
        lblScoreCount.Text = count.ToString();
        lblAverage.Text = average.ToString();
    }
}