Search code examples
c#wpfdictionarytextboxlistbox

Change the value of Dictionary based on the SelectedItem in ListBox


My TextBox shows a property value of a class, which is changed based on the SelectedItem in ListBox. (So far, so good.) However, now I'd like to replace the value defined in Dictionary with a value which a user specified (The key is the SelectedItem in ListBox). This doesn't work, no matter what I do. It just throws an exception. Here is my full code:

MainWindow.xaml.cs

using ChangeTextBoxBasedOnListBox.Model;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;

public partial class MainWindow : Window
    {
        ObservableCollection<string> oc;
        ObservableCollection<Graph> graph;
        Dictionary<string, Graph> dic = new Dictionary<string, Graph>();
        ListBox lB;

        public MainWindow()
        {
            InitializeComponent();

            oc = new ObservableCollection<string>()
            {
                "Test_1",
                "Test_2"
            };

            graph = new ObservableCollection<Graph>()
            {
                new Graph(10),
                new Graph(100)
            };

            listBox.ItemsSource = oc;

            foreach (var test in oc.Select((k, i) => new { kvp = k, index = i }))
            {
                dic.Add(test.kvp, graph[test.index]);
            }
        }

        private void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Graph dicValue = dic[(sender as ListBox).SelectedItem.ToString()];
            textBox.Text = Convert.ToString(dicValue.Step);
        }

        private void textBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            // This works, but this isn't what I want to do
            if (dic.ContainsKey("Test_1"))
                dic["Test_1"].Step = 1000;

            // What I want to do is:
            // (dic[(The current SelectedItem in ListBox)].Step  = (The value user specified)

            // This doesn't work ... throws an exception
            //if (lB.SelectedItem != null)
            //{
            //    if (dic.ContainsKey(lB.SelectedItem.ToString()))
            //    {
            //        dic[lB.SelectedItem.ToString()].Step = (sender as Graph).Step;
            //    }
            //}
        }
    }
}

MainWindow.xaml

<Window x:Class="ChangeTextBoxBasedOnListBox.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:ChangeTextBoxBasedOnListBox"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <ListBox x:Name="listBox" HorizontalAlignment="Left" Height="238" Margin="88,82,0,0" VerticalAlignment="Top" Width="288" SelectionChanged="listBox_SelectionChanged"/>
        <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="523,82,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120" TextChanged="textBox_TextChanged"/>

    </Grid>
</Window>

Model/Graph.cs

namespace ChangeTextBoxBasedOnListBox.Model
{
    public class Graph
    {
        public Graph(int step) { Step = step; }

        public int Step { get; set; }
    }
}

... I think I just need one more step, but I cannot find the way. Please help me. Thank you in advance.


Solution

  • Your approach is far too complicated. Actually, you do not need any event handlers at all.

    Simply pass the Dictionary directly to the ListBox's ItemsSource and set DisplayMemberPath and SelectedValuePath to its Key and Value properties. Thus the ListBox displays the key strings and you can directly access a Graph instance via the SelectedValue property of the ListBox.

    <StackPanel>
        <ListBox x:Name="listBox" DisplayMemberPath="Key" SelectedValuePath="Value"/>
        <TextBox Text="{Binding SelectedValue.Step, ElementName=listBox}"/>
    </StackPanel>
    

    and everything works automatically with this code behind:

    public MainWindow()
    {
        InitializeComponent();
    
        listBox.ItemsSource = new Dictionary<string, Graph>()
        {
            { "Test_1", new Graph(10) },
            { "Test_2", new Graph(100) }
        };
    }