У меня проблемы с получением строкового значения выбранного элемента WPF ComboBox в коде позади.
Я настроил три различных типа массива, которые предоставляют ItemSources для трех ComboBox.Я связал каждый выбранный ComboBox элемент со свойством класса с именем DataBase.Я проверяю, что привязка работает, выводя значение каждого свойства DataBase обратно в TextBox.
В приведенном ниже коде я хочу получить строковое значение каждого выбранного элемента ComboBox.Я могу сделать это для systemComboBox, где SelectedItem и SelectedValue оба возвращают строковое значение выбранного элемента.
Я не могу заставить его работать для oneDComboBox, где SelectedItem и SelectedValue возвращают «ComboBoxes.OneD» или дляtwoDComboBox, который корректно возвращает SelectedValue, но возвращает «ComboBoxes.TwoD» в качестве значения для SelectedItem
Может кто-нибудь сказать мне, как получить строковое значение для элементов oneDComboBox и twoDComboBox?
В Visual Studio я установил «Тип вывода» кода ниже «Сборка» на «Консольное приложение», чтобы я мог писать на консоль.
WPF
<Window x:Class="ComboBoxes.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:local="clr-namespace:ComboBoxes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:sys="clr-namespace:System;assembly=mscorlib" Title="MainWindow" Width="1200" Height="450"
mc:Ignorable="d">
<Window.Resources>
<x:Array x:Key="OneDArray" Type="{x:Type local:OneD}">
<local:OneD OneDName="OneD-0" />
<local:OneD OneDName="OneD-1" />
<local:OneD OneDName="OneD-2" />
<local:OneD OneDName="OneD-3" />
<local:OneD OneDName="OneD-4" />
</x:Array>
<x:Array x:Key="TwoDArray" Type="{x:Type local:TwoD}">
<local:TwoD TwoDName="TwoD-0" TwoDNumber="0" />
<local:TwoD TwoDName="TwoD-1" TwoDNumber="1" />
<local:TwoD TwoDName="TwoD-2" TwoDNumber="2" />
<local:TwoD TwoDName="TwoD-3" TwoDNumber="3" />
<local:TwoD TwoDName="TwoD-4" TwoDNumber="4" />
</x:Array>
<x:Array x:Key="SystemStringArray" Type="sys:String">
<sys:String>SystemString-0</sys:String>
<sys:String>SystemString-1</sys:String>
<sys:String>SystemString-2</sys:String>
<sys:String>SystemString-3</sys:String>
<sys:String>SystemString-4</sys:String>
</x:Array>
</Window.Resources>
<Grid>
<Grid.Resources>
<local:DataBase x:Key="dataBase" />
</Grid.Resources>
<Grid.DataContext>
<Binding Source="{StaticResource dataBase}" />
</Grid.DataContext>
<Grid.RowDefinitions>
<RowDefinition Height="10" />
<RowDefinition Height="auto" />
<RowDefinition Height="20" />
<RowDefinition Height="Auto" />
<RowDefinition Height="10" />
</Grid.RowDefinitions>
<Grid Grid.Row="1" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="40" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="40" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Label Grid.Row="1" Grid.Column="1" Content="OneDComboBox:" HorizontalAlignment="Right"/>
<ComboBox x:Name="oneDComboBox" Grid.Row="1" Grid.Column="2" Width="120" DisplayMemberPath="OneDName"
ItemsSource="{StaticResource OneDArray}"
SelectedItem="{Binding Path=DataBaseOneDName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"
SelectionChanged="ComboBox_SelectionChanged"
/>
<Label Grid.Row="1" Grid.Column="4" Content="SystemComboBox:" HorizontalAlignment="Right"/>
<ComboBox x:Name="systemComboBox" Grid.Row="1" Grid.Column="5" Width="120"
ItemsSource="{StaticResource SystemStringArray}"
SelectedItem="{Binding Path=DataBaseSystemString, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"
SelectionChanged="ComboBox_SelectionChanged"
/>
<Label Grid.Row="1" Grid.Column="7" Content="TwoDComboBox:" HorizontalAlignment="Right"/>
<ComboBox x:Name="twoDComboBox" Grid.Row="1" Grid.Column="8" Width="120" DisplayMemberPath="TwoDName"
ItemsSource="{Binding Source={StaticResource TwoDArray}}"
SelectedValue="{Binding Path=DataBaseTwoDNumber, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"
SelectedValuePath="TwoDNumber" SelectionChanged="ComboBox_SelectionChanged"
/>
</Grid>
<Grid Grid.Row="3" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="40" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="40" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Label Grid.Row="2" Grid.Column="1" Content="BoundOneDName:" HorizontalAlignment="Right"/>
<TextBox x:Name="oneDComboBoxEcho" Grid.Row="3" Grid.Column="2" Width="120"
Text="{Binding Path=DataBaseOneDName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"
TextWrapping="Wrap" />
<Label Grid.Row="2" Grid.Column="4" Content="BoundSystemString:" HorizontalAlignment="Right"/>
<TextBox x:Name="systemComboBoxEcho" Grid.Row="5" Grid.Column="5" Width="120"
Text="{Binding Path=DataBaseSystemString, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"
TextWrapping="Wrap" />
<Label Grid.Row="2" Grid.Column="7" Content="BoundTwoDNumber:" HorizontalAlignment="Right"/>
<TextBox x:Name="twoDComboBoxEcho" Grid.Row="5" Grid.Column="8" Width="120"
Text="{Binding Path=DataBaseTwoDNumber, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"
TextWrapping="Wrap" />
</Grid>
</Grid>
</Window>
C #
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace ComboBoxes
{
/// <summary>
/// Interaction logic for MainWindow.xaml
///
/// The code below reflects the suggestions made by:
/// 1 Ben Broadley (to use e.AddedItems[0]) and Benny (To look in the ItemsSource object) in the responses to /3213577/poluchit-vybrannoe-znachenie-iz-polya-so-spiskom-v-c-wpf.
/// 2 Adam Nathan in the FAQ box on page 266 of his book "WPF 4.5 Unleashed".
///
///
///
/// </summary>
public partial class MainWindow : Window
{
//public MainWindow mainWindow;
DataBase dataBase;
public MainWindow()
{
InitializeComponent();
dataBase = new DataBase();
//DataContext = this;
}
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0) // Test to ensure that an item has been selected.
{
ComboBox sourceComboBox = (ComboBox)sender;
int selectedIndex = -1;
string selectedItem = "???";
string selectedValue = "???";
string displayMemberPath = "???";
if (sourceComboBox.Name == "oneDComboBox")
{
// Because this ComboBox.ItemsSource is bound to an array of types the selected value has to be unbundled from the selected type.
if (oneDComboBox.SelectedValue is OneD) // Verify ComboBox.ItemsSource is bound to what we think its bound to.
{
selectedIndex = sourceComboBox.SelectedIndex;
selectedItem = sourceComboBox.SelectedItem.ToString();
selectedValue = (oneDComboBox.SelectedValue as OneD).OneDName;
displayMemberPath = sourceComboBox.DisplayMemberPath.ToString();
}
}
else
if (sourceComboBox.Name == "systemComboBox")
{
selectedIndex = sourceComboBox.SelectedIndex;
selectedItem = sourceComboBox.SelectedItem.ToString();
selectedValue = sourceComboBox.SelectedValue.ToString();
displayMemberPath = sourceComboBox.DisplayMemberPath.ToString();
}
else
if (sourceComboBox.Name == "twoDComboBox")
{
// Because this ComboBox.ItemsSource is bound to an array of types the selected value has to be unbundled from the selected type.
if (e.AddedItems[0] is TwoD) // Verify ComboBox.ItemsSource is bound to what we think its bound to.
{
selectedIndex = sourceComboBox.SelectedIndex;
selectedItem = sourceComboBox.SelectedItem.ToString();
selectedValue = (e.AddedItems[0] as TwoD).TwoDName;
//selectedValue = (twoDComboBox.SelectedValue as TwoD).TwoDName; // Why doesn't this work? It works for oneDComboBox.
displayMemberPath = sourceComboBox.DisplayMemberPath.ToString();
}
}
Console.WriteLine($"\nComboBox Name = {sourceComboBox.Name}");
Console.WriteLine($"Selected Index = {selectedIndex} Selected Item = {selectedItem} Selected Value = {selectedValue} DisplayMemberPath = {displayMemberPath}");
}
}
}
public partial class DataBase : INotifyPropertyChanged
{
private string _dataBaseOneDName = "OneDArray";
public string DataBaseOneDName
{
get { return _dataBaseOneDName; }
set
{
if (_dataBaseOneDName != value)
{
_dataBaseOneDName = value;
NotifyPropertyChanged("DataBaseOneDName");
}
}
}
private string _dataBaseSystemString = "System_String";
public string DataBaseSystemString // String property used in binding examples.
{
get { return _dataBaseSystemString; }
set
{
if (_dataBaseSystemString != value)
{
_dataBaseSystemString = value;
NotifyPropertyChanged("DataBaseSystemString");
}
}
}
private int _dataBaseTwoDNumber = 99;
public int DataBaseTwoDNumber
{
get { return _dataBaseTwoDNumber; }
set
{
if (_dataBaseTwoDNumber != value)
{
_dataBaseTwoDNumber = value;
NotifyPropertyChanged("DataBaseTwoDNumber");
}
}
} // Int property used in binding examples.
#region INotifyPropertyChanged Members
/// Need to implement this interface in order to get data binding
/// to work properly.
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
public partial class OneD // This class supports the "OneDArray" in the XAML.
{
public string OneDName { get; set; }
}
public partial class TwoD // This class supports the "TwoDArray" in the XAML.
{
public int TwoDNumber { get; set; }
public string TwoDName { get; set; }
}
}