I obviously don't grasp using SelectedValue to change which item a combo box is showing in UWP
The XAML is simple
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ComboBox x:Name="comboBoxColor" />
</Grid>
The code-behind isn't very deep
public MainPage()
{
this.InitializeComponent();
}
public void page_Loaded(object sender, RoutedEventArgs e)
{
populateDdlMultiColor();
comboBoxColor.SelectedValue = Colors.Red;
//comboBoxColor.SelectedIndex = 0 works tho
}
private void populateDdlMultiColor()
{
comboBoxColor.ItemsSource = ColorDict();
comboBoxColor.DisplayMemberPath = "Key";
comboBoxColor.SelectedValuePath = "Value";
}
private Dictionary<string,Color> ColorDict()
{
Dictionary<string, Color> L = new Dictionary<string, Color>();
L.Add("reddish",Colors.Red);
return L;
}
This is obviously tinker-toy but it fails the same way my code fails: After setting the SelectedValue, the combo box is on index -1 and SelectedValue is null. If I set SelectedIndex to a proper value [see comment] the combo box works - it has been loaded.
Thanks for your feedback. This is a known issue that SelectedValue doesn't work with enumeration type.
For now, as a workaround, you can use SelectedIndex or SelectedItem like you've done. However, please note that Dictionary is implemented as a hash table. There's no such concept of an "index" within a Dictionary. The order is undefined and we can't rely on it. So for your scenario, using SelectedItem might be better.
For more info, you can see this answer.
Thanks to Jay Zuo for putting me on the right track! In my scenario, it's then easy enough to convert the colors to integers as a workaround to the known issue. Won't work for every enumeration, but anyone building color dropdowns [in UWP] may find this handy. Note the Dictionary change.
public MainPage()
{
this.InitializeComponent();
}
public void page_Loaded(object sender, RoutedEventArgs e)
{
populateDdlMultiColor();
comboBoxColor.SelectedValue = ColorInt(Colors.Red);
}
private void populateDdlMultiColor()
{
comboBoxColor.ItemsSource = ColorDict();
comboBoxColor.DisplayMemberPath = "Key";
comboBoxColor.SelectedValuePath = "Value";
}
private Dictionary<string,int> ColorDict()
{
Dictionary<string, int> L = new Dictionary<string, int>();
L.Add("reddish",ColorInt(Colors.Red));
return L;
}
private int ColorInt(Color c)
{
return (c.A*16777216) + (c.R*65536) + (c.G*256) + c.B ;
}
Related
I have two ListPickers originating from one TextBox.
private void textBox3_GotFocus(object sender, RoutedEventArgs e)
{
string a = "Domestic";
string b = Convert.ToString(textBox2.Text);
string c = "Foreign";
if (b == a)
{
NavigationService.Navigate(new Uri("/ListPickerExchanges1.xaml", UriKind.Relative));
}
else if (b == c)
{
NavigationService.Navigate(new Uri("/ListPickerExchanges2.xaml", UriKind.Relative));
}
Both ListPickers load and give you the option to choose something from the list. But only one ListPicker will displays the selection back into TextBox3 , and it is always the one under the second Else If (b == c) condition.
The ListPickerExchanges1 under the first condition will not display the selection back into textbox3.
But if i change the code under the second Else If condition to navigate to Exchanges1 instead of Exchanges2, then the Exchanges1 listpicker displays back the selection into textbox 3, and Exchanges2 does not.
Which means, Everything under the second condition works, and does not under the first condition.
Here is the code behind ListpickerExchanges1, which is intended to display the selection back into the textbox.
public partial class ListPickerExchanges1 : PhoneApplicationPage
{
public ListPickerExchanges1()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(ListPickerExchanges1_Loaded);
}
private void ListPickerExchanges1_Loaded(object sender, RoutedEventArgse)
{
ListBoxExchanges.ItemsSource = Page2.ListExchanges;
}
public void Selection(object sender, System.Windows.Input.GestureEventArgs e)
{
ListBox myselecteditem4 = (ListBox)sender;
ItemsModeling4 item4 = (ItemsModeling4)myselecteditem4.SelectedItem;
if (item4 != null)
{
NavigationService.Navigate(new Uri("/Broker.xaml?name4=" + item4.Exchanges, UriKind.RelativeOrAbsolute));
}
}
..............................................................................................................................................................
Update: Additional Code behind Navigation and Selection
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
string name4 = "";
NavigationContext.QueryString.TryGetValue("name4", out name4);
textBox3.Text = string.Format("{0}", name4);
}
..............................................................................................................................................................
public Page2()
{
InitializeComponent();
ListExchanges = new ObservableCollection<ItemsModeling4>();
this.Loaded += new RoutedEventHandler(Page44_Loaded);
}
..............................................................................................................................................................
private void Page44_Loaded(object sender, RoutedEventArgs e)
{
if (ListExchanges.Count == 0)
{
string[] arrangeExchanges = new string[] { "Option1", "Option2", "Option3", "Option4" };
foreach (string item4 in arrangeExchanges)
{
ListExchanges.Add(new ItemsModeling4 { Exchanges = item4 });
}
}
}
public static ObservableCollection<ItemsModeling4> ListExchanges { get; private set; }
..............................................................................................................................................................
public class ItemsModeling4
{
public string Exchanges { get; set; }
}
..............................................................................................................................................................
Xaml
<ListBox x:Name="ListBoxExchanges" Background="Transparent"
Tap="Selection">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Height="Auto" FontFamily="Segoe WP Semibold" FontSize="50" HorizontalAlignment="Left" Margin="12,0,0,0"
Text="{Binding Exchanges}" VerticalAlignment="Top" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
What am i doing wrong here?
It Seems like a Master - Detail binding issue. I just don't see where or how to fix it.
The system doesn't give any errors, and I've checked everything with the debugger and everything seems fine.
The listpickers work independently and i don't see where the code might intervene and stop the one from working. It all seems good to me.
help
But if i change the code under the second Else If condition to navigate to Exchanges1 instead of Exchanges2, then the Exchanges1 listpicker displays back the selection into textbox 3, and Exchanges2 does not.
Are you sure that you are comparing culturaly correct strings? Try this compare instead for both of them.
if (String.Equals(a, b, InvariantCultureIgnoreCase))
See StringComparison Enumeration (System) and Best Practices for Using Strings in the .NET Framework for more info.
Otherwise strings can be tricky with spaces. Try
String.Equals(a.Trim(), b.Trim());
to remove any spaces the user may be adding \r\n maybe?
Frankly since the code knows about the choices it may be better to simply provide a ComboBox with the selectable choices for the user instead of using a TextBox.
I'm working on a windows phone project. I have a listbox with the following selectionchanged event handler:
private void judgeType_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
LoadJudgeCategories(judgeTypeListBox.SelectedItem.ToString());
}
Here is the LoadJudgeCategories method:
void LoadJudgeCategories(string judgeType)
{
string[] categories = judgeCategories[judgeType];
List<LabeledTextBox> itemSource = new List<LabeledTextBox>();
foreach (string cat in categories)
{
itemSource.Add(new LabeledTextBox(cat));
}
CategoryPanel.ItemsSource = itemSource;
}
judgeCategories is of type
Dictionary<string, string[]>
LabeledTextBox is usercontrol with a textblock and a textbox. CategoryPanel is just a listbox.
Whenever the selected item is changed, I want to clear CategoryPanel, and replace it with a new List.
Occasionally, however, when I change the selection, it gives the exception "value does not fall within the expected range".
How do I fix this?
This can happen when you add multiple controls with the same name. Try this code. Broken down with newlines for clarity. I turned it into a linq statement, and also named each of the LabeledTextBox something random.
Note: the only important thing I did was give the LabeledTextBox a name.
Random r = new Random();
void LoadJudgeCategories(string judgeType)
{
CategoryPanel.ItemsSource =
judgeCategories[judgeType]
.Select(cat =>
new LabeledTextBox(cat) { Name = r.Next().ToString() }
).ToList();
}
Just an alternative solution with ObservableCollection - there will be no need to set CategoryPanel.ItemsSource multiple times:
private ObservableCollection<LabeledTextBox> itemSource = new ObservableCollection<LabeledTextBox>();
CategoryPanel.ItemsSource = itemSource; // somewhere in the Constructor
void LoadJudgeCategories(string judgeType)
{
itemSource.Clear();
foreach (string cat in judgeCategories[judgeType])
itemSource.Add(new LabeledTextBox(cat));
}
I have a BindingList< KeyValuePair < string, string > > that is bound to a ComboBox control. Based on some conditions, the BindingList will be added a new KeyValuePair. Now, the Newly added item shows up at index 0 of the Combobox, instead of at the end.
While debugging, I found that the BindingList has got the right order. (i.e, the new KeyValuePair is appended)
Also, I check the SelectedValue of the ComboBox in it's SelectedIndexChanged handler and it seems to be not of the ListItem that got selected. Instead, it is that of the supposed ListItem, if the ComboBox had got the right order as in its DataSource, - the BindingList..
The code is a small part of a large project.. Plz let me know if the question is not clear. I can put the relevant parts of the code as per our context.
How could something like this happen? What can I do differently?
I have this class something like this.
public class DropdownEntity
{
//removed all except one members and properties
private string frontEndName
public string FrontEndName
{
get {return this.frontEndName; }
set {this.frontEndName= value; }
}
//One Constructor
public DropdownEntity(string _frontEndName)
{
this.FrontEndName = _frontEndName;
//Removed code which initializes several members...
}
//All methods removed..
public override string ToString()
{
return frontEndName;
}
}
In my windows form, I have a tab control with several tabs. In one of the tabs pages, I have a DataGridView. The user is supposed to edit the cells and click on a Next - button. Then, some processing will be done, and the TabControl will be navigated to the next tab page.
The next tab page has the combobox that has the problem I mentioned. This page also has a back button, which will take back.. the user can modify the gridview cells again.. and click on the next button. This is when the order gets messed up.
I am posting here the Click event handler of the Next Button.. Along with the class, with the rest of the code removed.
public partial class AddUpdateWizard : Form
{
//Removed all members..
BindingList<KeyValuePair<string, string>> DropdownsCollection;
Dictionary<string, DropdownEntity> DropdownsDict;
//Defined in a partial definition of the class..
DataGridView SPInsertGridView = new DataGridView();
ComboBox DropdownsCmbBox = new ComboBox();
Button NextBtn2 = new Button();
Button BackBtn3 = new Button();
//Of course these controls are added to one of the panels
public AddUpdateWizard(MainForm mainForm)
{
InitializeComponent();
DropdownsDict = new Dictionary<string, DropdownEntity>();
}
private void NextBtn2_Click(object sender, EventArgs e)
{
string sqlArgName;
string frontEndName;
string fieldType;
for (int i = 0; i < SPInsertGridView.Rows.Count; i++)
{
sqlArgName = "";
frontEndName = "";
fieldType = "";
sqlArgName = SPInsertGridView.Rows[i].Cells["InsertArgName"].Value.ToString().Trim();
if (SPInsertGridView.Rows[i].Cells["InsertArgFrontEndName"].Value != null)
{
frontEndName = SPInsertGridView.Rows[i].Cells["InsertArgFrontEndName"].Value.ToString().Trim();
}
if (SPInsertGridView.Rows[i].Cells["InsertArgFieldType"].Value != null)
{
fieldType = SPInsertGridView.Rows[i].Cells["InsertArgFieldType"].Value.ToString().Trim();
}
//I could have used an enum here, but this is better.. for many reasons.
if (fieldType == "DROPDOWN")
{
if (!DropdownsDict.ContainsKey(sqlArgName))
DropdownsDict.Add(sqlArgName, new DropdownEntity(frontEndName));
else
DropdownsDict[sqlArgName].FrontEndName = frontEndName;
}
else
{
if (fieldType == "NONE")
nonFieldCount++;
if (DropdownsDict.ContainsKey(sqlArgName))
{
DropdownsDict.Remove(sqlArgName);
}
}
}
//DropdownsCollection is a BindingList<KeyValuePair<string, string>>.
//key in the BindingList KeyValuePair will be that of the dictionary.
//The value will be from the ToString() function of the object in the Dictionary.
DropdownsCollection = new BindingList<KeyValuePair<string,string>>(DropdownsDict.Select(kvp => new KeyValuePair<string, string>(kvp.Key, kvp.Value.ToString())).ToList());
DropdownsCmbBox.DataSource = DropdownsCollection;
DropdownsCmbBox.DisplayMember = "Value";
DropdownsCmbBox.ValueMember = "Key";
//Go to the next tab
hiddenVirtualTabs1.SelectedIndex++;
}
private void BackBtn3_Click(object sender, EventArgs e)
{
hiddenVirtualTabs1.SelectedIndex--;
}
//On Selected Index Changed of the mentioned Combobox..
private void DropdownsCmbBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (DropdownsCmbBox.SelectedValue != null)
{
if (DropdownsDict.ContainsKey((DropdownsCmbBox.SelectedValue.ToString())))
{
var dropdownEntity = DropdownsDict[DropdownsCmbBox.SelectedValue.ToString()];
DropdownEntityGB.Text = "Populate Dropdowns - " + dropdownEntity.ToString();
//Rest of the code here..
//I see that the Datasource of this ComboBox has got the items in the right order.
// The Combobox's SelectedValue is not that of the selected item. Very Strange behavior!!
}
}
}
}
The very first time the user clicks the Next Button, it's fine. But if he clicks the Back Button again and changes the Data Grid View cells.. The order will be gone.
I know, it can be frustrating to look at. It's a huge thing to ask for help. Any help would be greatly appreciated!
Please let me know if you need elaboration at any part.
Thanks a lot :)
I think you have two problems here.
First, if you want to retain the order of the items you should use an OrderedDictionary instead of a regular one. A normal collection will not retain the order of the items when you use Remove method. You can see more info about this related to List here.
You could use such dictionary like this:
DropDownDict = new OrderedDictionary();
// Add method will work as expected (as you have it now)
// Below you have to cast it before using Select
DropDownCollection = new BindingList<KeyValuePair<string, string>>(DropDownDict.Cast<DictionaryEntry>().Select(kvp => new KeyValuePair<string, string>(kvp.Key.ToString(), kvp.Value.ToString())).ToList());
The second problem could be that you change the display name (FrontEndName) of already existing items, but the key is preserved. When you add a new item, try to remove the old one that you're not using anymore and add a new item.
The Sorted Property of the Combobox is set to True! I didn't check that until now. I messed up. Terribly sorry for wasting your time Adrian. Thanks a lot for putting up with my mess here.. :)
I want to make a ComboBox bound to my data, with a filter. For that I've created a TextBox and a ComboBox. In the code behind I read a file and generate objects of class Channel that are stored as items of the ComboBox. Although the compiler throws no error the filtering doesn't work properly. If I write something the data is gone, if I erase, it's back. After trying and trying I've realized that if I started typing "myNamespace.myChannel" (Unico.Canal) the data remained, but don't filter. Strange behaviour, indeed. I suspect that I've put something in wrong place.
(for better understanding I've translated the code, Canal=Channel)
Here is the scheme of my code:
namespace Unico
{
public partial class ControlesArchivo : UserControl, INotifyPropertyChanged
{
public ControlesArchivo()
{
InitializeComponent();
}
public ObservableCollection<Channel> myListChannels //with INotifyPropertyChanged implemented. But I think I don't need it.
private void loadButton_Click(object sender, RoutedEventArgs e)
{
File loadedFile = new File();
loadedFile.read(); //Generates a bunch of data in lists.
foreach (Channel mychan in loadedFile.channels) //Just duplicating the data (maybe this can be avoided)
{
myListChannels.Add(mychan);
}
var view = CollectionViewSource.GetDefaultView(this.miListaDeCanales);
view.Filter = delegate(object o)
{
if (o.ToString().Contains(myTextBox.Text)) //Delicate place
{
return true;
}
return false;
};
myComboBox.ItemsSource = view;
DataContext = this;
}
private void myTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
((ICollectionView)myComboBox.ItemsSource).Refresh();
myComboBox.SelectedIndex = 0;
}
}
}
The data is bound in XAML with:
ItemsSource="{Binding view}"
EDIT: I think I know where is the problem: I'm not specifing the property to filter. I mean, what you see in the ComboBox is the property channelName of the class Channel listed in myListChannels. When I'm setting the filter, shouldn't I let know what I'm filtering? How could I write this? Thank you very much.
Yes your assumption is correct.
I'm assuming with your translations,
public ObservableCollection<Channel> myListChannels;
is actually
public ObservableCollection<Canal> miListaDeCanales;
with the class Canal in the namespace Unico
Update:
In your filter try using the property that is rendered in the ComboBox than use the ToString() on the object(o) if you've not overridden ToString() from System.Object.
try switching
if (o.ToString().Contains(myTextBox.Text))
to
if (((Canal)o).NameProperty.Contains(myTextBox.Text))
^^ that should fix your issue.
Do you have a DataTemplate for ComboBox.ItemTemplate in xaml. That will explain why you see the valid value rendered in the ComboBox, else all the ComboBoxItem's will also render as Unico.Canal
When I change the datasource of my Listbox all items are cleared, when loading new data into this Listbox it stays clear.
I have another ListBox right new to this one with the same refresh code but that one refreshes perfectly.
private void RefreshContacts()
{
this.ListContacts.DataSource = null;
this.ListContacts.DataSource = this.contacts;
this.BoxCountContacts.Text = this.ListContacts.Items.Count.ToString();
}
Anyone have an idea how to fix the listbox from being cleared and bugged?
Here is the full refresh codes of the two listboxes
private Contact[] contacts, feed; private Boolean isFeed;
internal ArcFeed()
{
this.InitializeComponent();
this.contacts = this.feed = new Contact[0];
}
private void RefreshForm(Boolean isFeed)
{
if (isFeed)
{
this.RefreshFeed();
}
else
{
this.RefreshContacts();
}
}
private void RefreshContacts()
{
this.ListContacts.DataSource = null;
this.ListContacts.DataSource = this.contacts;
this.BoxCountContacts.Text = this.ListContacts.Items.Count.ToString();
}
private void RefreshFeed()
{
this.ListFeed.DataSource = null;
this.ListFeed.DataSource = this.feed;
this.BoxCountFeed.Text = this.ListFeed.Items.Count.ToString();
}
private void OpenFile()
{
if (this.isFeed)
{
this.BoxFileFeed.Text = this.DialogOpen.FileName;
this.feed = ArcBuzz.Load(this.DialogOpen.FileName);
}
else
{
this.BoxFileContacts.Text = this.DialogOpen.FileName;
this.contacts = ArcBuzz.Load(this.DialogOpen.FileName);
}
this.RefreshForm(this.isFeed);
}
All code is debugged and follows it's course properly, I don't see any errors, the correct listbox's datasource are set and changed.
Just to make sure, have you checked that there are actually items in the contacts collection?
Also, if you've got two Listboxes, double check that you are using the right Listbox in each of the refresh code sections.
Sounds stupid, but its silly mistakes like this that get overlooked a lot of the time. With databinding its usually something small like this stopping it working.