ListPicker TwoWay Binding and itemsource - c#

I try to build settings page to my Windows Phone 8 app, the settings page has couple of ListPickers. The basic idea has been taken from here: http://msdn.microsoft.com/en-us/library/windowsphone/develop/ff769510(v=vs.105).aspx
In my settings page xaml I have just declared:
<toolkit:ListPicker x:Name="listPicker1" ExpansionMode="FullScreenOnly" SelectionMode="Single" FullModeItemTemplate="{StaticResource generalListPickerFullTemplate}" ItemTemplate="{StaticResource generalListPickerTemplate}" SelectedItem="{Binding Source={StaticResource appSettings}, Path=listPicker1, Mode=TwoWay}" />
In "code behind", I create list and set it item source to listPicker1
listPicker1List.Add(new ListPickerItem() { name = "First value", value = "value_1" });
listPicker1List.Add(new ListPickerItem() { name = "Second value", value = "value_2" });
this.listPicker1.ItemsSource = listPicker1List;
StaticResource appSettings points to class which is basically similar than in the MS example,
public ListPickerItem listPicker1
{
get
{
return GetValueOrDefault<ListPickerItem>(KeyName, Default);
}
set
{
if (AddOrUpdateValue(KeyName, value))
{
Save();
}
}
}
So is it not possible to set itemsource and use two way bindig? If I set these both, I get System.ArgumentOutOfRangeException.
Basically my only goal is to have listPicker with items, which have text to display for user and value. And to easily set and get these to Isolates storage.

You have this error when you set itemsource or select an item?

Related

Set Combobox value to a default value depending on computers printer settings

I have a ComboBox on a WPF application that contains all the printers attached to a computer. The printers are getting to the ComboBox correctly and I am also capturing the default printer. Now what I want to do is set the default or selected value on the ComboBox to the default printer.
I am getting the list of printers and the default with this
private void GetPrinterList()
{
var server = new PrintServer();
var queues = server.GetPrintQueues(new[] {EnumeratedPrintQueueTypes.Shared,
EnumeratedPrintQueueTypes.Connections});
string defaultPrinter = GetDefaultPrinter();
Printers = new ObservableCollection<Printer>();
foreach (var item in queues)
{
Printers.Add(new Printer { Name = item.FullName });
}
queues = server.GetPrintQueues(new[] { EnumeratedPrintQueueTypes.Local });
foreach (var item in queues)
{
Printers.Add(new Printer { Name = item.FullName });
}
var defPrinter = Printers.FirstOrDefault(i => i.Name == defaultPrinter);
if (defPrinter != null)
{
//NOTE Modified example after posting because #ASh
//made aware (in comments) I had an error in code.
CurrentDefaultPrinter = defPrinter.Name.ToString();
}
}
On the XAML side I have tried binding both the SelectedValue and SelectedValuePath to the CurrentDefaultPrinter but neither show the selected value in the ComboBox. What am missing to make this work?
<ComboBox
Width="150"
Height="35"
Margin="0,0,0,2"
DisplayMemberPath="Name"
FontSize="18"
SelectedItem="{Binding CurrentDefaultPrinter, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
ItemsSource="{Binding Printers}" />
I did find this solution that is similar to what I am trying to do but isn't close enough for me to solve my issue.
Setting a default selected item in ComboBox in WPF MVVM application
Note Both my code and XAML have been modified after posting because it was pointed out there was an error in my code. However, after the modification I am still not getting the ComboBox to show the default printer with updated code.
don't bind SelectedValue or SelectedValuePath, only SelectedItem:
SelectedItem="{Binding CurrentDefaultPrinter}"
note that SelectedItem should be present in ItemsSource collection. so it should have the same type as items in that collection, not string. additionally it should raise PropertyChanged event (from INPC interface)
public Printer CurrentDefaultPrinter { get; set; }
CurrentDefaultPrinter = Printers.FirstOrDefault(i => i.Name == defaultPrinter);

WPF - Hiding a ComboBox Selection

I have a combobox which allows users to select from a collection of images. Because of the size of the images I would like to not display the image in the combobox once an image has been selected. I simply want nothing displayed in the combobox when an item is selected.
So far I have tried setting the selectedImageIndex to -1 once the selectedImageSource has been set when the user makes a selection however this did not work as the first image at [0] is still displayed in the combobox by default. I am using MVVM.
XAML
<ComboBox Grid.Row="1" SelectedIndex="{Binding SelectedImageIndex}" ItemsSource="{Binding SymbolImageCollection}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Img}" Width="50" Height="50"/>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Width="300" HorizontalAlignment="Left"/>
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
View Model
public ObservableCollection<SymbolImage> SymbolImageCollection { get { return AppearanceLayerProperties.Instance.SymbolImageCollection; } }
private string _selectedImageSource;
public string SelectedImageSource
{
get { return _selectedImageSource; }
set
{
SetProperty(ref _selectedImageSource, value);
//SelectedImageIndex = -1;
}
}
private int _selectedImageIndex;
public int SelectedImageIndex
{
get { return _selectedImageIndex; }
set
{
var selectedImage = AppearanceLayerProperties.Instance.SymbolImageCollection[value].ImgSource;
SelectedImageSource = selectedImage;
SetProperty(ref _selectedImageIndex, -1);
}
}
Changing the selection back to null after selecting an item of the ComboBox is not good practice, because if you need to use the selected value, it is not available anymore.
A solution could be to have a different template for the selected item of the ComboBox. That way, you could remove the image, but in its place put something else, like text, so the user as an idea of what item is selected. Here is a previous StackOverflow post explaining how to do this :
Can I use a different Template for the selected item in a WPF ComboBox than for the items in the dropdown part?
I hope this helps!

ComboBox selected item binding not showing the initial value - then working OK

I have a weird problem with something simple I suppose.
I have a combobox with two bindings set up - one for ItemsSource and another for SelectedItem.
The selected item is not working on initial startup, but then it works OK. Output does not indicate any binding problems, I have also set up a TextBlock with the same binding to see if it works - and it does.
Here's the code
<ComboBox IsSynchronizedWithCurrentItem="True" IsEditable="False"
Name="ProgramsCollectionComboBox"
SelectedItem="{Binding ElementName=ThisUc,
Path=SelectedProgram}"
ItemsSource="{Binding ElementName=ThisUc,
Path=ProgramsCollection}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Text="{Binding ElementName=ThisUc,
Path=SelectedProgram.Name, Mode=TwoWay}" />
The property:
private Program _selectedProgram;
public Program SelectedProgram
{
get
{
if (_selectedProgram == null)
{
_selectedProgram = new Program(Settings.Default.SelectedProgramPath);
}
return _selectedProgram;
}
set
{
_selectedProgram = value;
Settings.Default.SelectedProgramPath = SelectedProgram.PathProgramFolder;
RaisePropertyChanged("SelectedProgram");
}
}
It saves and reads the settings OK, the initial values is shown in the textblock below the combobox, when I change the selected item, the textblock is updated, the settings are changed and everything works fine - except for the fact that on app startup, selected item is not selected.
Thanks for help!
There are two reasons your initial binding is not working. First, as Jehof has mentioned himself, is the fact that you're setting your SelectedProgram to an item that is not part of the ProgramsCollection.
Furthermore, when you are setting the initial value of your SelectedProgram you are doing so in the getter, where PropertyChanged is not invoked and thus the binding will never be aware of that change. You can either invoke PropertyChanged when initializing it in the getter:
...
get
{
if (_selectedProgram == null)
{
_selectedProgram = _programsCollection?.FirstOrDefault();
RaisePropertyChanged("SelectedProgram");
}
return _selectedProgram;
}
...
Or even better, set the default value on the private field:
private Program _selectedProgram = _programsCollection?.FirstOrDefault();
...
The getter of your property SelectedProgram should return a value of your ProgrammsCollection and not a new instance if it is null.
If the value is not part of the collection that is bound to the combobox it is not displayed.

Combo box default value

I want to use combo box and the following code is working but now I want to
add to the combo box header default value ,i.e. there is value and like
Item and when you open it you have the option to change it,how I can do that?
<ComboBox ItemsSource="{Binding Items}" SelectedValue="{Binding SelectedItem}"
Name="comboBox1" Text="Item" Grid.Column="3" Grid.Row="2" />
the code
private List<String> _items;
private String _selectedItem;
private String _selectedBusinessItem;
public List<String> Items
{
get { return _items; }
set
{
_items = value;
OnPropertyChanged("Items");
}
}
public String SelectedItem1
{
get { return _selectedItem; }
set
{
_selectedItem = value;
OnPropertyChanged("Items");
}
}
private void InitCombo()
{
Items = new List<string> { "item", "Item2", "Item3" };
SelectedItem1 = Items[0];
}
It's hard to understand you are asking, but I think you are just looking for the ComboBox to show the first value in the collection of Items.
I believe you can do this a few ways.
First you need to fix SelectedValue binding to match your property name, and drop the Text="Item":
<ComboBox ItemsSource="{Binding Items}" SelectedValue="{Binding SelectedItem1}"
Name="comboBox1" Grid.Column="3" Grid.Row="2" />
From your code you can set the SelectedValue1 property that you have to any of the string items. Examples of this:
SelectedValue1 = "item";
-or-
SelectedValue1 = Items.FirstOrDefault();
I used FirstOrDefault as a safety incase these items didn't exist.
-or-
SelectedValue1 = Items[0];
And there are several more options here. But I'm going to try and limit the scope of the answer.
Also, you should be able to set the ComboBox.SelectedIndex to 0.
<ComboBox ItemsSource="{Binding Items}" SelectedValue="{Binding SelectedItem1}"
Name="comboBox1" Grid.Column="3" Grid.Row="2"
SelectedIndex="0"/>
I think that you're talking about the ComboBox.Text Property... from the linked page:
Gets or sets the text of the currently selected item
This is not a free field that you can display a message in. It displays the value of the currently selected item from the ComboBox.Items collection. If the text is not in one of the items, then this TextBox 'should' not display that value.
However, there are always workarounds. The correct way to do it would be to define a new ControlTemplate for the ComboBox that contains a TextBlock that is overlayed on top of the selected item TextBox and hidden when required.
Some people think that that is too much work though and so you can find a number of alternative solutions in the How to display default text “--Select Team --” in combo box on pageload in WPF? post here on StackOverflow.
List Items = new List { "item", "Item 2", "Item 3" };
Set the Selected Index = 0, It will select the first element in the combo box Item-source
XAML:
<ComboBox ItemsSource="{Binding Items}"
Name="comboBox1" Grid.Column="3" Grid.Row="2"
SelectedIndex="0"/>

How to set SelectedId of Combobox and set text of Textbox in a specific format from ViewModel in WPF

I am working on a textbox and combobox in my wpf app. I am sorry for weird title. Well here is the scenario:
Xaml:
<ComboBox ItemsSource="{Binding PortModeList}" SelectedItem="{Binding SelectedPortModeList, Mode=OneWayToSource}" SelectedIndex="0" Name="PortModeCombo" />
<TextBox Grid.Column="1" Text="{Binding OversampleRateBox}" Name="HBFilterOversampleBox" />
ViewModel Class:
public ObservableCollection<string> PortModeList
{
get { return _PortModeList; }
set
{
_PortModeList = value;
OnPropertyChanged("PortModeList");
}
}
private string _selectedPortModeList;
public string SelectedPortModeList
{
get { return _selectedPortModeList; }
set
{
_selectedPortModeList = value;
OnPropertyChanged("SelectedPortModeList");
}
}
private string _OversampleRateBox;
public string OversampleRateBox
{
get
{
return _OversampleRateBox;
}
set
{
_OversampleRateBox = value;
OnPropertyChanged("OversampleRateBox");
}
}
Here I have three requirements:
By using SelectedIdin xaml I am able to select the id but I want to set the selectedid of my combobox from viewmodel class. I.e.
int portorder = 2
PortModeList->SetSelectedId(portOrder). How can I do something like this? or is their any other approach?
I need to restrict number of entries inside a textbox to 4. I.e. 1234 is entered in textbox, it should not let user exceed 4 digits.
I want to set the format of text in OversampleRateBox as: 0x__. I.e. if user wants to enter 23 present in a variable, then I shud set text as 0x23. Basically 0x should be present at the beginning.
Please help :)
I would use the SelectedItem property of the ComboBox (as you are doing), but make the binding two-way. Then, you can set your SelectedPortModeList (which should be called SelectedPortMode) in your view model.
<ComboBox ItemsSource="{Binding PortModeList}"
SelectedItem="{Binding SelectedPortMode}" ...
In the view model:
// Select first port mode
this.SelectedPortMode = this.PortModeList[0];
If you want to limit the number of characters in a TextBox, then use the MaxLength property:
<TextBox MaxLength="4" ... />
If you wish to add a prefix to the OversampleRateBox, one option would be to test for the presence of this in the setter for OversampleRateBox, and if it's not there, then add it before assigning to your private field.
Update
Bind your TextBox to a string property:
<TextBox Grid.Column="1" Text="{Binding OversampleRateBox}" ... />
In the setter for your property, check that the input is valid before setting your private field:
public string OversampleRateBox
{
get
{
return _OversampleRateBox;
}
set
{
// You could use more sophisticated validation here, for example a regular expression
if (value.StartsWith("0x"))
{
_OversampleRateBox = value;
}
// Now if the value entered is not valid, then the text box will be refreshed with the old (valid) value
OnPropertyChanged("OversampleRateBox");
}
}
Because the binding is two-way, you can also set the value from your view model code (for example in the view model constructor):
this.OversampleRateBox = "0x1F";

Categories