0

EDITED:

I've put two different programs into my code:

  1. Two ListBoxes (LeftListBox and RightListBox), to transfer the items between the two
  2. One ListBox (called listBox_Selector) and one TextBox, to show a number which corresponds to the SelectedItem in listBox_Selector

Now I'd like to merge those two and replace listBox_Selector with RightListBox.

My Goal: When an item of RightListBox (NOT of listBox_Selector) is selected, the corresponding number should show up (e.g., if Key="Test_2", then Value=20, etc.) in TextBox. Then, I want to remove listBox_Selector. But, I can't. It's tough because RightListBox uses TestModel, whereas listBox_Selector uses Dictionary<string, Graph>.

enter image description here

Here is my code:

MainWindow.xaml.cs

using ListBoxMoveAll.Model;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;

namespace ListBoxMoveAll
{
    public partial class MainWindow : Window
    {
        public ObservableCollection<TestModel> LeftListBoxItems { get; } = new ObservableCollection<TestModel>();
        public ObservableCollection<TestModel> RightListBoxItems { get; } = new ObservableCollection<TestModel>();

        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
            LeftListBoxItems.Add(new TestModel("Test_1"));
            LeftListBoxItems.Add(new TestModel("Test_2"));
            LeftListBoxItems.Add(new TestModel("Test_3"));

            listBox_Selector.ItemsSource = new Dictionary<string, Graph>()
            // RightListBox.ItemsSource = new Dictionary<string, Graph>()
            {
                { "Test_1", new Graph(10) },
                { "Test_2", new Graph(20) },
                { "Test_3", new Graph(30) }
            };
        }

        private void Add_Button_Click(object sender, RoutedEventArgs e)
        {
            foreach (TestModel item in LeftListBox.SelectedItems.OfType<TestModel>().ToList())
            {
                LeftListBoxItems.Remove(item);
                RightListBoxItems.Add(item);
            }
        }

        private void Remove_Button_Click(object sender, RoutedEventArgs e)
        {
            foreach (TestModel item in RightListBox.SelectedItems.OfType<TestModel>().ToList())
            {
                RightListBoxItems.Remove(item);
                LeftListBoxItems.Add(item);
            }
        }
    }
}

MainWindow.xaml

<Window x:Class="ListBoxMoveAll.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:ListBoxMoveAll"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="647.096">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="2*" />
            <ColumnDefinition Width="80" />
            <ColumnDefinition Width="2*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="2*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <ListBox x:Name="LeftListBox" Grid.Row="0" Grid.RowSpan="3" Grid.Column="0"
            DisplayMemberPath="TestItem" ItemsSource="{Binding LeftListBoxItems}"
            SelectionMode="Extended" Margin="0,10"/>
        <StackPanel Grid.Column="1" Grid.Row="0" VerticalAlignment="Center">
            <Button Content="Add" x:Name="Add_Button" Click="Add_Button_Click"/>
        </StackPanel>
        <StackPanel Grid.Column="1" Grid.Row="2" VerticalAlignment="Center">
            <Button Content="Remove" x:Name="Remove_Button" Click="Remove_Button_Click"/>
        </StackPanel>
        <ListBox x:Name="RightListBox" Grid.Row="0" Grid.RowSpan="3" Grid.Column="2"
            DisplayMemberPath="TestItem" ItemsSource="{Binding RightListBoxItems}"
            SelectionMode="Extended" Margin="0,10"/>

        <StackPanel Grid.Column="4" Grid.Row="0" Grid.RowSpan="1" Margin="0,10">
            <ListBox x:Name="listBox_Selector" DisplayMemberPath="Key" SelectedValuePath="Value"/>
        </StackPanel>
        <StackPanel Grid.Column="4" Grid.Row="1" Grid.RowSpan="1" Margin="0,10">
            <TextBox Text="{Binding SelectedValue.Step, ElementName=listBox_Selector}"/>
        </StackPanel>
    </Grid>
</Window>

Model/TestItem.cs

namespace ListBoxMoveAll.Model
{
    public class TestModel
    {
        public TestModel(string _testItem)
        { TestItem = _testItem; }

        public string TestItem { get; set; }
    }
}

Model/Graph.cs

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

        public int Step { get; set; }
    }
}

I tried to change to RightListBox.ItemsSource = new Dictionary<string, Graph>(), but I got stuck. Please help me. Thank you in advance.

IanHacker
  • 541
  • 9
  • 27
  • It isn't clear what you are trying to achieve, your list box selector has an item source of Graph objects while your right list box has a collection of TestModel as Item source which doesn't have the property that's bound to the textBox !! – SamTh3D3v Nov 16 '19 at 22:04
  • @SamTheDev Sorry for my poor explanation. I'd like to replace `listBox_Selector` with `RightListBox`. When an item of `RightListBox` is selected, the corresponding number should show up (if Key="Test_2", then Value=20, etc.). You should compare `TestModel` with **`string`** as in `Dictionary`. They both are inputs, while `Graph` is an output. Please run my code and click `Test_2` in `listBox_Selector`. `20` should be shown. I want the same behavior on `RightListBox` (and then remove `listBox_Selector`). – IanHacker Nov 16 '19 at 23:40
  • Hello guys, I've just made it with some flaws, so I created another question [here](https://stackoverflow.com/questions/58898268/how-to-show-multiple-dictionary-items-in-listbox). Please see what I wanted to achieve and answer my question, if you could. I don't have any issue with closing this question, so I will probably delete this. Thank you guys. – IanHacker Nov 17 '19 at 07:07

1 Answers1

0

That is where we use value converters.

public class GraphValueConverter:IValueConverter  
    {  
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)  
        {  
            var graph = value as Graph;
            // check for null
            return graph.Step;  
        }  
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)  
        {  
            throw new NotImplementedException();  
        }  
    }  

Then in your XAML import value converter :

<Window.Resources>  
        <local:GraphValueConverter x:Key="valueconverter"></local:GraphValueConverter>   
    </Window.Resources> 

Use the imported value converter:

<TextBox Text="{Binding SelectedValue.Step, ElementName=listBox_Selector,Converter={StaticResource valueconverter}}"/>

Check the namespace that your value converter is defined. If it is in different namespace like "ListBoxMoveAll.Model" in your example. You should import that namespace in your xaml too :

<Window x:Class="ListBoxMoveAll.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:ListBoxMoveAll"
        xmlns:model="clr-namespace:ListBoxMoveAll.Model" <--  add this
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="647.096">

Then change your import to this :

<Window.Resources>
 <model:GraphValueConverter x:Key="valueconverter"></model:GraphValueConverter>   
</Window.Resources> 
Eldar
  • 9,781
  • 2
  • 10
  • 35
  • Thank you, but I got an error `MC3074: The tag 'GraphValueConverter' does not exist in XML namespace 'clr-namespace:ListBoxMoveAll'.` No matter what, it doesn't go away (I removed all files under Debug, and then Clean Solution, Rebuild Solution, etc.). Have you also tried to compile your code on your machine? Perhaps not, because I'm afraid, but your `TextBox` has an extra `}"`. Anyway, do you know how to fix this? – IanHacker Nov 16 '19 at 22:43
  • I didn't test my code. I tried to guide you how to add and use a value converter. It seems like a namespace problem i will edit my answer for it. – Eldar Nov 17 '19 at 08:13
  • Thank you, but still doesn't work, even though I replaced and with `model:` ones.The same behavior as it referred to `local:`. Now `local:` is grayed out and `model:` is in normal color, so the path must be correct. Does it work on your side? – IanHacker Nov 17 '19 at 09:19