Implementing combobox with command search - c#

well i m having a problem when i use the method search i get only the textbox and not the combobox i m using mmvm here is my code:
in my constructor i have :
CountryList = new FastObservableCollection<Country>(DummyWebservice.GetCountries());
SearchCitizenCommand = new RelayCommand(SearchCitizen);
and for display countries and cities:
private FastObservableCollection<City> citylist;
public FastObservableCollection<City> CityList
{
get
{
return citylist;
}
set
{
Set(() => CityList, ref citylist, value);
}
}
private FastObservableCollection<Country> countryList;
public FastObservableCollection<Country> CountryList
{
get
{
return countryList;
}
set
{
Set(() => CountryList, ref countryList, value);
}
}
private Country selectedcountry;
public Country SelectedCountry
{
get
{
return selectedcountry;
}
set
{
Set(() => SelectedCountry, ref selectedcountry, value);
OnPropertyChanged(() => SelectedCity);
CityList = DummyWebservice.GetCitiesByCountryId(SelectedCountry.Id);
}
}
private City selectedcity;
public City SelectedCity
{
get
{
return selectedcity;
}
set
{
Set(() => SelectedCity, ref selectedcity, value);
}
}
and finnally in the method search i tried
SelectedCountry = new Country();
SelectedCountry.Name = citizen.Citizenship.Name;
in the view i got :
<ComboBox x:Name="txtBirthCountryPicker"
Grid.Row="1"
Grid.Column="1"
HorizontalContentAlignment="Left"
DisplayMemberPath="Name"
ItemsSource="{Binding CountryList}"
SelectedItem="{Binding SelectedCountry}" />
but im still getting it umpty

If you want to select an item in a combo, you need to choose the exact same object that is part of the ItemsSource.
SelectedCountry = CountryList.FirstOrDefault(
x => x.Name == citizen.Citizenship.Name
)

The Combobox uses object equality to determine which of item in the ItemsSource is the selected item. As you're assigning a new instance of Country to the SelectedItem, it is unable to locate the country in the ItemsSource.
Try this instead:
SelectedCountry = CountryList.FirstOrDefault(c => c.Name.Equals(citizen.Citizenship.Name, StringComparison.CurrentCultureIgnoreCase);

Related

Dynamic Dropdown Combobox [duplicate]

I have searched Google for a simple solution to this but no luck. I have a standard WPF combo box which I would simply like to be able to filter the list displayed according to the first 2 or 3 letters a users types when the combo box has focus. I tried some coding including some lamba expressions but the error "System.NotSupportedException" keeps getting thrown on the line where "combobox.Items.Filter" is specified. I'm not using MVVM and would just like this simple functionality available for the user. Please help! P.S. IsEditable, IsTextSearchEnabled and StaysOpenOnEdit properties are set to true but the desired functionality is not yet achieved.
I have developed a sample application. I have used string as record item, you can do it using your own entity. Backspace also works properly.
public class FilterViewModel
{
public IEnumerable<string> DataSource { get; set; }
public FilterViewModel()
{
DataSource = new[] { "india", "usa", "uk", "indonesia" };
}
}
public partial class WinFilter : Window
{
public WinFilter()
{
InitializeComponent();
FilterViewModel vm = new FilterViewModel();
this.DataContext = vm;
}
private void Cmb_KeyUp(object sender, KeyEventArgs e)
{
CollectionView itemsViewOriginal = (CollectionView)CollectionViewSource.GetDefaultView(Cmb.ItemsSource);
itemsViewOriginal.Filter = ((o) =>
{
if (String.IsNullOrEmpty(Cmb.Text)) return true;
else
{
if (((string)o).Contains(Cmb.Text)) return true;
else return false;
}
});
itemsViewOriginal.Refresh();
// if datasource is a DataView, then apply RowFilter as below and replace above logic with below one
/*
DataView view = (DataView) Cmb.ItemsSource;
view.RowFilter = ("Name like '*" + Cmb.Text + "*'");
*/
}
}
XAML
<ComboBox x:Name="Cmb"
IsTextSearchEnabled="False"
IsEditable="True"
ItemsSource="{Binding DataSource}"
Width="120"
IsDropDownOpen="True"
StaysOpenOnEdit="True"
KeyUp="Cmb_KeyUp" />
I think the CollectionView is what you are looking for.
public ObservableCollection<NdfClassViewModel> Classes
{
get { return _classes; }
}
public ICollectionView ClassesCollectionView
{
get
{
if (_classesCollectionView == null)
{
BuildClassesCollectionView();
}
return _classesCollectionView;
}
}
private void BuildClassesCollectionView()
{
_classesCollectionView = CollectionViewSource.GetDefaultView(Classes);
_classesCollectionView.Filter = FilterClasses;
OnPropertyChanged(() => ClassesCollectionView);
}
public bool FilterClasses(object o)
{
var clas = o as NdfClassViewModel;
// return true if object should be in list with applied filter, return flase if not
}
You wanna use the "ClassesCollectionView" as your ItemsSource for your Combobox

Xamarin forms set Picker SelectedItem

I am working with a xamarin Forms.
I am using Picker for DropDownList.
How can I set selectedItem to Picker?
My code
<Picker x:Name="VendorName" Title="Select" ItemDisplayBinding="{Binding VendorName}" SelectedItem="{Binding VendorName}" Style="{StaticResource PickerStyle}"></Picker>
and server side code is
Device.BeginInvokeOnMainThread(() =>
{
VendorName.ItemsSource = VendorList;
});
var currentVendor = new List<Vendor>();
currentVendor.Add(new Vendor { VendorID = "111", VendorName = "aaaa" });
VendorName.SelectedItem = currentVendor;
This may not be the most efficient but you could loop to find the index and set that way.
for (int x = 0; x < VendorList.Count; x++)
{
if (VendorList[x].VendorName == currentVendor .VendorName )
{
VendorName.SelectedIndex = x;
}
}
After adding all values as list in Picker
just treat with it as an array
so if you want to set selected item just set selected item index
currentVendor.SelectedIndex = 0;
zero means you make selected item is the first one you added to Picker
If you are using MVVM, and want to set SelectedItem from the view model, things get tricky. There seems to be a bug in Xamarin that prevents us from using SelectedItem with a two way binding. More info: Xamarin Forms ListView SelectedItem Binding Issue and https://xamarin.github.io/bugzilla-archives/58/58451/bug.html.
Luckily, we can easily write our own Picker.
public class TwoWayPicker : Picker
{
public TwoWayPicker()
{
SelectedIndexChanged += (sender, e) => SelectedItem = ItemsSource[SelectedIndex];
}
public static new readonly BindableProperty SelectedItemProperty = BindableProperty.Create(
nameof(SelectedItem), typeof(object), typeof(TwoWayPicker), null, BindingMode.TwoWay, propertyChanged: OnSelectedItemChanged);
public new object SelectedItem
{
get => GetValue(SelectedItemProperty);
set => SetValue(SelectedItemProperty, value);
}
private static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue)
{
var control = (TwoWayPicker)bindable;
control.SetNewValue(newValue);
}
private void SetNewValue(object newValue)
{
if (newValue == null)
{
return;
}
for(int i = 0; i < ItemsSource.Count; i++)
{
if (ItemsSource[i].Equals(newValue))
{
SelectedIndex = i;
return;
}
}
}
}
Because is uses the same SelectedItem property, it is a drop-in replacement for Picker.
Note that if you want value equality rather than reference equality for the item class, you'll also need to override Equals like this:
public override bool Equals(object obj)
{
var other = obj as YourClass;
if (other == null)
{
return false;
}
else
{
return other.SomeValue == SomeValue; // implement your own
}
}
If you define the item class as a record instead of a class then it can select the item programmatically using the SelectedItem property.
In your case change
public class Vendor { // your class properties }
to
public record Vendor { // your class properties }
This will now work
VendorName.SelectedItem = currentVendor;

dxe:listbox not checking items

Im creating a listbox (devexpress control) like this
<dxe:ListBoxEdit x:Name="lstBoxFeatures" DisplayMember="Description" ValueMember="FeatureId" SelectionMode="Multiple"
ItemsSource="{Binding Path=DataContext.Features, RelativeSource={RelativeSource AncestorType=Window}}" Height="320"
EditValue="{Binding Path=DataContext.SelectedFeatures, RelativeSource={RelativeSource AncestorType=Window}}"
>
<dxe:ListBoxEdit.StyleSettings>
<dxe:CheckedListBoxEditStyleSettings />
</dxe:ListBoxEdit.StyleSettings>
</dxe:ListBoxEdit>
I have the view, i fill it like this
I filling the values like this (are using a list of features)
_CustomerLicense.Features = GetFeatureList(SelectedLicense.Product.ProductId);
_CustomerLicense.SelectedFeatures =_CustomerLicense.Features.Where(x => FeaturesIds.Contains(x.FeatureId)).ToList();
The process where i get ths list of features
private List<Feature> GetFeatureList(Project.Common.Domain.ProductEnum ProductID )
{
var Res = new List<Feature>();
var Features = new LicenseService().GetFeatures(ProductID);
Features.ForEach((x)=> {
Res.Add(new Feature(x));
});
return Res;
}
The view i have this way
public List<Feature> Features
{
get { return _Features;}
set
{
_Features = value;
this.NotifyPropertyChanged("Features");
}
}
public List<Feature> SelectedFeatures
{
get { return _SelectedFeatures; }
set
{
_SelectedFeatures = value;
NotifyPropertyChanged("SelectedFeatures");
}
}
When i run the app it sets the values, the listbox is populated with all the reatures in the list but the selected features are not checked.
Regards
Try declaring SelectedFeatures as a List of Objects (you'll need to change _SelectedFeatures too):
public List<object> SelectedFeatures
{
get { return _SelectedFeatures; }
set
{
_SelectedFeatures = value;
NotifyPropertyChanged("SelectedFeatures");
}
}
and change this line:
_CustomerLicense.SelectedFeatures =_CustomerLicense.Features.Where(x => FeaturesIds.Contains(x.FeatureId)).Cast<object>().ToList();
The SelectedFeatures collection should contain a subset of the Feature instances that are in the Features collection. Try this:
var features = GetFeatureList(SelectedLicense.Product.ProductId);
_CustomerLicense.Features = features;
var selectedFeatureIds = _CustomerLicense.Features.Where(x => FeaturesIds.Contains(x.FeatureId)).Select(x => x.FeatureId).ToList();
_CustomerLicense.SelectedFeatures = features.Where(x => selectedFeatureIds.Contains(x.FeatureId)).ToList();

ComboBox(Previous DataContext) SelectedItem property set as null value in UWP?

Initially, ComboBox DataContext is set with Profession1 and SelectedValue as Politician. At Runtime, i changed the Datacontext to Profession2. Doing this is changing the Profession1 to null.
Please refer the below code:
<Page.Resources>
<local:MainPageViewModel x:Key="datacontent"></local:MainPageViewModel>
</Page.Resources>
<ComboBox x:Name="comboBox"
ItemsSource="{Binding Professions,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding Profession, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
Width="100"
Height="100"
VerticalAlignment="Center"
HorizontalAlignment="Stretch" />
Code Behind:
var datacontent = (this.Resources["datacontent"] as MainPageViewModel);
this.comboBox.DataContext = datacontent.Profession1;
Model:
public class MainPageViewModel
{
public MainPageViewModel()
{
Profession1 = new Person();
Profession2 = new Person();
}
private Person profession1;
public Person Profession1
{
get { return profession1; }
set { this.profession1 = value; }
}
private Person profession2;
public Person Profession2
{
get { return profession2; }
set { this.profession2 = value; }
}
}
public class Person : INotifyPropertyChanged
{
public Person()
{
_professions = new List<string>();
_professions.Add("Lawyer");
_professions.Add("Politician");
_professions.Add("Other");
}
private string _profession;
public string Profession
{
get
{
if (string.IsNullOrWhiteSpace(_profession))
{
// _profession = _professions.LastOrDefault();
}
return _profession;
}
set
{
if (_profession != value)
{
_profession = value;
NotifyPropertyChanged("Profession");
}
}
}
private List<string> _professions;
public List<string> Professions
{
get
{
return _professions;
}
}
}
I have used the below code, to check the previous datacontext (Profession1->Professon) value .
Code
((this.Resources["datacontent"] as MainPageViewModel).Profession1 as Person).Profession
Output is : null.
Expected value : Politician
Please someone suggest on this.
((this.Resources["datacontent"] as MainPageViewModel).Profession1 as Person).Profession
Output is : null. Expected value : Politician
Please someone suggest on this.
The problem is that when you modify the DataContext of combobox, the DataContext is set null first and then turns to Profession2. So the Profession property of Profession1 will be set null. For your requirement, you could set the judgment condition to solve this issue.
public string Profession
{
get
{
return _profession;
}
set
{
if (_profession != value && value != null)
{
_profession = value;
OnPropertyChange();
}
}
}

Silverlight Combobox in DataTemplate

I have defined a data template for a c# class in xaml as follows
<DataTemplate x:Key="ApplicationTemplate">
<StackPanel Orientation="Vertical">
<telerik:RadComboBox DisplayMemberPath="Name"
ItemsSource="{Binding CurrentItem.Apps, RelativeSource={RelativeSource FindAncestor, AncestorType=telerik:RadDataForm}}"
IsEnabled="{Binding IsReadOnly, RelativeSource={RelativeSource AncestorType=ContentControl}, Converter={StaticResource BooleanInverterConverter}}" />
</StackPanel>
</DataTemplate>
My "Apps" Enumerable is composed of this object:
public class InteractiveApplicationModel : ValidatingModel
{
public string Name
{
get { return GetProperty(() => Name); }
set { SetProperty(() => Name, value); }
}
public string Type
{
get { return GetProperty(() => Type); }
set { SetProperty(() => Type, value); }
}
public string URL
{
get { return GetProperty(() => URL); }
set { SetProperty(() => URL, value); }
}
public string Image
{
get { return GetProperty(() => Image); }
set { SetProperty(() => Image, value); }
}
public InteractiveApplicationModel()
{
this.Type = string.Empty;
this.Name = string.Empty;
this.URL = string.Empty;
this.Image = string.Empty;
}
public InteractiveApplicationModel(string name, string type, string url, string image)
{
this.Name = name;
this.Type = type;
this.URL = url;
this.Image = image;
}
}
}
In the View model i have:
public IList<InteractiveApplicationModel> Apps
{
get
{
return new List<InteractiveApplicationModel>()
{
new InteractiveApplicationModel(null,null,null,null),
new InteractiveApplicationModel("name","type","url","image"),
new InteractiveApplicationModel("name2","type2","url2","image2")
};
}
}
I then have a form page which loads "complex" objects which contain "InteractiveApplicationModel" objects and use the data template to display those objects.
Everything is working except one thing. I need the selected value of the combobox to be the same as the value of the "InteractiveApplicationModel" objects in my "complex" objects.
My "complex" objects can have up to 5 "InteractiveApplicationModel" objects inside them.
You have to Bind the SelectedItem property on the RadComboBox
SelectedItem="{Binding SelectedInteractiveApplicationModel, [.... ancestor ....] Mode=TwoWay}"
with a Selected property on the ViewModel
public InteractiveApplicationModel SelectedInteractiveApplicationModel
{
get { return GetProperty(() => SelectedInteractiveApplicationModel); }
set { SetProperty(() => SelectedInteractiveApplicationModel, value); }
}

Categories

Resources