Find Items in ObservableCollection and update UI [closed] - c#

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
So, I'm at a lost, and hope for some guidance. I'm using MVVM pattern and EF.
My View contains a datagrid bound to a observable collection within the view model.
The UI has furthermore 3 comboboxes with possible data to minimize the data shown.
So I've been googling around and found nothing I could use (or might not have understood it correctly).
How do I search and select the items from a ObservableCollection, and update the datagrid accordingly?
public ObservableCollection<DimTargets> TargetParameters { get; set; }
private void SelectionChanged(object obj)
{
if (obj is FactTargets)
{
SelectedFactTarget = (FactTargets)obj;
}
else if (obj is DimLocation)
{
SelectedLocation = (DimLocation)obj;
ViewCollection.Select(x => x.Location == SelectedLocation.Location);
TargetParameters.Where(x => x.FactTargets == SelectedLocation.FactTargets);
}
else //DimBladeType
{
SelectedBladeType = (DimBladeType)obj;
int[] a = DimTargetsController.ReturnBladeType(SelectedBladeType);
foreach (int i in a)
{
TargetParameters.Single(k => k.ID == i);
}
var os = TargetParameters.Where(d => d.ID == );
TargetParameters = Convert<DimTargets>(os);
//TargetParameters.Where(ka => ka.ID == a);
//TargetParameters = new ObservableCollection<DimTargets>(TargetParameters.Where(t => t.FactTargets == SelectedBladeType.FactTargets));
//var obs = TargetParameters.Where(t => t.FactTargets == SelectedBladeType.FactTargets);
//TargetParameters = Convert<DimTargets>(obs);
//ViewCollection.Select(x => x.BladeType == SelectedBladeType.BladeType).ToList();
}
}
public ObservableCollection<T> Convert<T>(IEnumerable original)
{
return new ObservableCollection<T>(original.Cast<T>());
}
XAML:
ComboBox ItemsSource="{Binding FactTargetCollection, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding SelectedFactTarget}" DisplayMemberPath="FYQuater" Behaivor:SelectionChangedBehaviour.Command="{Binding SelectionChangedCommand}"/>
<ComboBox ItemsSource="{Binding LocationCollection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding SelectedLocation}" DisplayMemberPath="Location" Behaivor:SelectionChangedBehaviour.Command="{Binding SelectionChangedCommand}"/>
<ComboBox ItemsSource="{Binding BladeTypeCollection, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding SelectedBladeType}" DisplayMemberPath="BladeType" Behaivor:SelectionChangedBehaviour.Command="{Binding SelectionChangedCommand}"/>
<Button Content="Submit" Style="{StaticResource BaseButtonStyle}"></Button>
</StackPanel>
<StackPanel x:Name="WorkPanel" DockPanel.Dock="Right">
<DataGrid ItemsSource="{Binding TargetParameters}">
</DataGrid>
</StackPanel>`
Hope this gives a better idea of what i'm trying to do.
the c# code are filled with examples with what i've tried.

Cant see all of you objects but here is a quick n simple illustration...
public RelayCommand<int> FilterAgeCommand { get; set; }
public Base_ViewModel()
{
FilterAgeCommand = new RelayCommand<int>(OnFilterAgeCommand);
this.TestClassList = new ObservableCollection<TestClass>();
this.TestClassList.Add(new TestClass() { FName = "John", SName = "Doe", Age = 25 });
this.TestClassList.Add(new TestClass() { FName = "Jane", SName = "Doe", Age = 75 });
this.TestClassList.Add(new TestClass() { FName = "Mick", SName = "Doe", Age = 35 });
this.TestClassList.Add(new TestClass() { FName = "Harry", SName = "Doe", Age = 10 });
this.TestClassList.Add(new TestClass() { FName = "Linda", SName = "Doe", Age = 25 });
this.TestClassList.Add(new TestClass() { FName = "Fred", SName = "Doe", Age = 14 });
this.FilteredTestClassList = new ObservableCollection<TestClass>();
this.Age = new List<int>();
for(int i = 1; i <100; i++)
{
this.Age.Add(i);
}
}
private void OnFilterAgeCommand(int obj)
{
this.FilteredTestClassList = Convert<TestClass>((from tc in this.TestClassList where tc.Age < obj select tc).ToList());
}
public List<int> Age { get; set; }
public ObservableCollection<TestClass> TestClassList { get; set; }
private ObservableCollection<TestClass> _FilteredTestClassList;
public ObservableCollection<TestClass> FilteredTestClassList
{
get { return _FilteredTestClassList; }
set { _FilteredTestClassList = value; OnPropertyChanged("FilteredTestClassList"); }
}
public ObservableCollection<T> Convert<T>(IEnumerable original)
{
return new ObservableCollection<T>(original.Cast<T>());
}
A simple class for the demo...
public class TestClass : INotifyPropertyChanged
{
private string _FName;
public string FName
{
get { return _FName; }
set { _FName = value; NotifyPropertyChanged("FName"); }
}
private string _SName;
public string SName
{
get { return _SName; }
set { _SName = value; NotifyPropertyChanged("FName"); }
}
private int _Age;
public int Age
{
get { return _Age; }
set { _Age = value; }
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
And some XAML...
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModels="clr-namespace:_36550006.ViewModels"
xmlns:Views="clr-namespace:_36550006.Views"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
Title="Base_View" Height="300" Width="300">
<Window.DataContext>
<ViewModels:Base_ViewModel/>
</Window.DataContext>
<Grid>
<StackPanel>
<DataGrid ItemsSource="{Binding FilteredTestClassList, NotifyOnSourceUpdated=True}"></DataGrid>
<ComboBox x:Name="cmb" ItemsSource="{Binding Age}" SelectedValuePath="{Binding Age}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding FilterAgeCommand}" CommandParameter="{Binding ElementName=cmb, Path=SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</StackPanel>
</Grid>
I essentially have two ObservableCollection, the first holds ALL of your items and the second is a filtered collection that you bind to....

Related

Search Bar doesnt refresh list on backspace

I have this search bar function in my Xamarin forms app and it works perfectly fine when you start to type all the information but when you start to delete the words. The view doesnt refresh and it just clears all the information.
Here is the code for the search
private void SearchBar_TextChanged(object sender, TextChangedEventArgs e)
{
SearchBar searchBar = (SearchBar)sender;
noMowersFoundLabel.IsVisible = false;
//Check if the user cleared the text bar, if so: reload list of mowers
if (searchBar.Text.Length == 0)
{
_viewModel.IsBusy = true;
return;
}
//Max 6 digits in a serial number
if (searchBar.Text.Length < 6)
{
//compares substrings to add to the list while the user has not entered full serial number
var sorted = new List<Mower>();
foreach (var m in _viewModel.Items)
{
if (m.MachineSerialNumber.Length > searchBar.Text.Length)
{
//var serialNum = m.MachineSerialNumber.Substring(0, Math.Min(searchBar.Text.Length, 6));
if (m.MachineSerialNumber.Contains(searchBar.Text))
{
sorted.Add(m);
}
}
}
foreach(var m in sorted)
{
if (!m.MachineSerialNumber.Contains(searchBar.Text))
{
sorted.Remove(m);
}
}
sorted.Sort((p1, p2) => (p1.MachineSerialNumber.CompareTo(p2.MachineSerialNumber)));
if(sorted.Count != 0)
{
_viewModel.Items.Clear();
foreach(var m in sorted)
{
_viewModel.Items.Add(m);
}
}
else
{
_viewModel.Items.Clear();
noMowersFoundLabel.IsVisible = true;
}
}
else //user has entered full serial number
{
Mower selectedItem = null;
foreach (var m in _viewModel.Items)
{
if(m.MachineSerialNumber == searchBar.Text)
{
selectedItem = m;
}
}
if(selectedItem != null)
{
//We found the item
_viewModel.Items.Clear();
_viewModel.Items.Add(selectedItem);
}
else{
//No item found
_viewModel.Items.Clear();
noMowersFoundLabel.IsVisible = true;
}
}
I want the view to populate the information when you start to delete words
I don't think it is necessary to diffentiate the length of the input string.
I created a demo and achieved this function, you can refer to the following code:
MyViewModel.cs
public class MyViewModel
{
public ObservableCollection<Item> Items { get; set; }
public MyViewModel() {
Items = new ObservableCollection<Item>();
Items.Add(new Item { Name="name1" , MachineSerialNumber="0001"});
Items.Add(new Item { Name = "name2", MachineSerialNumber = "0102" });
Items.Add(new Item { Name = "name3", MachineSerialNumber = "1203" });
Items.Add(new Item { Name = "name4", MachineSerialNumber = "11204" });
}
public List<Item> GetSearchResults(string queryString)
{
var normalizedQuery = queryString?.ToLower() ?? "";
return Items.Where(f => f.MachineSerialNumber.ToLowerInvariant().Contains(normalizedQuery)).ToList();
}
}
Item.cs
public class Item
{
public string Name { get; set; }
public string MachineSerialNumber { get; set; }
}
TestPage1.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SearchBarDemos.TestPage1">
<ContentPage.Content>
<StackLayout>
<SearchBar x:Name="searchBar"
HorizontalOptions="Fill"
VerticalOptions="CenterAndExpand"
Placeholder="Search fruits..."
CancelButtonColor="Orange"
PlaceholderColor="Orange"
TextTransform="Lowercase"
HorizontalTextAlignment="Start"
TextChanged="searchBar_TextChanged"/>
<Label Text="Type in the searchbox to filter results in realtime."
HorizontalOptions="Fill"
VerticalOptions="CenterAndExpand" />
<ListView x:Name="searchResults" ItemsSource="{Binding Items}"
HorizontalOptions="Fill"
VerticalOptions="CenterAndExpand" >
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Name}"
Detail="{Binding MachineSerialNumber}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
TestPage1.xaml.cs
public partial class TestPage1 : ContentPage
{
MyViewModel _viewModel;
public TestPage1()
{
InitializeComponent();
_viewModel = new MyViewModel();
this.BindingContext = _viewModel;
}
private void searchBar_TextChanged(object sender, TextChangedEventArgs e)
{
searchResults.ItemsSource = _viewModel.GetSearchResults(e.NewTextValue);
}
}
Note:
I added a function GetSearchResults into MyViewModel.cs
public List<Item> GetSearchResults(string queryString)
{
var normalizedQuery = queryString?.ToLower() ?? "";
return Items.Where(f => f.MachineSerialNumber.ToLowerInvariant().Contains(normalizedQuery)).ToList();
}
And once entering the input string, we can do as follows:
private void searchBar_TextChanged(object sender, TextChangedEventArgs e)
{
searchResults.ItemsSource = _viewModel.GetSearchResults(e.NewTextValue);
}

Filtering of combobox in c# wpf

XAML:
<ComboBox x:Name="cmb" HorizontalAlignment="Left"
Margin="183,39,0,0"
VerticalAlignment="Top"
Width="120"
ItemsSource="{Binding FilteredNames, Mode=OneWay}"
IsTextSearchEnabled="True"
IsEditable="True"
TextSearch.Text="{Binding Filter, UpdateSourceTrigger=PropertyChanged}"/>
ViewModel:
public List<string> FilteredNames
{
get
{
return (names.FindAll(x => x.Contains(filter))).ToList<string>();
}
}
public string Filter
{
get
{
return this.filter;
}
set
{
this.filter = value;
NotifyPropertyChanged("FilteredNames");
}
}
public ViewModel()
{
this.names = new List<string>() { "Jerry", "Joey", "Roger", "Raymond", "Jessica", "Mario",
"Jonathan" };
this.filter = "";
}
This is what I have implemented. Please help me out how to get filtered dropdown in combobox.
Like when I input "j", I want to get all the items containing "j" in it.
You should bind string input to ComboBox's Text property:
Text="{Binding Filter, UpdateSourceTrigger=PropertyChanged}"
Also I would suggest using CollectionView for filtering like this:
public ICollectionView FilteredNames { get; set; }
IList<string> names = new List<string>() { "Jerry", "Joey", "Roger", "Raymond", "Jessica", "Mario", "Jonathan" };
public VM()
{
FilteredNames = CollectionViewSource.GetDefaultView(names);
FilteredNames.Filter = (obj) =>
{
if (!(obj is string str))
return false;
return str.Contains(filter);
};
}
string filter = "";
public string Filter
{
get
{
return this.filter;
}
set
{
this.filter = value;
FilteredNames?.Refresh();
}
}

How to fix the missing display of rows in a DataGrid, when the columns are dynamically generated?

In my current WPF application, it's required to generate columns of a DataGrid dynamically in my ViewModel. For that I have used the approach with System.Windows.Interactivity and behaviors.
Therefore I created ColumnsBehavior exactly like in this post:
Is it possible to get dynamic columns on wpf datagrid in mvvm pattern?
Everything worked fine, when I initialized the bounded list and generated the columns with the bindings.
When I switched to ListBox to show a DataGrid in every ListBoxItem, everything worked great again.
Now I want to add the information (model) to the bounded list at run time.
When a ListBoxItem is selected, the corresponding DataGrid should be displayed. With a Button above the DataGrid I can pass sample data to the bounded list objects. When I hit the Button, the right amount of columns with the right headers are generated, but the rows only appears the next time, in which the ListBoxItem is visible again. This means the data is appearing as recently as I refresh the grid.
To bind the Botton Command property to the ViewModel I used the ActionCommand implementation:
RelayCommand
I am using the MVVM pattern.
This is my ViewModel:
public class ViewModel
{
public ViewModel()
{
ListItems = new ObservableCollection<ListItemModel>();
ListItems.Add(new ListItemModel()
{
IsSelected = true
});
ListItems.Add(new ListItemModel()
{
IsSelected = false
});
FillCommand = new RelayCommand(FillAction);
}
public ObservableCollection<ListItemModel> ListItems { get; set; }
public ListItemModel SelectedListItem { get; set; }
public ICommand FillCommand { get; set; }
public void FillAction(object sender)
{
SelectedListItem.Entries = new ObservableCollection<Entry>()
{
new Entry()
{
Cells = new ObservableCollection<Cell>()
{
new Cell() { Cond1 = 11, Value = 99 },
new Cell() { Cond1 = 22, Value = 99 },
new Cell() { Cond1 = 33, Value = 99 }
}
},
new Entry()
{
Cells = new ObservableCollection<Cell>()
{
new Cell() { Cond1 = 11, Value = 99 },
new Cell() { Cond1 = 22, Value = 99 },
new Cell() { Cond1 = 33, Value = 99 }
},
},
new Entry()
{
Cells = new ObservableCollection<Cell>()
{
new Cell() { Cond1 = 11, Value = 99 },
new Cell() { Cond1 = 22, Value = 99 },
new Cell() { Cond1 = 33, Value = 99 }
},
}
};
SelectedListItem.GenerateGrid();
}
}
The property for holding the columns is in the ListItemModel.
The object structure behind the ItemsSource of the DataGrid and the columns property you can see in the next code:
public class ListItemModel
{
public ListItemModel()
{
Entries = new ObservableCollection<Entry>();
DataColumns = new ObservableCollection<DataGridColumn>();
}
public ObservableCollection<Entry> Entries { get; set; }
public ObservableCollection<DataGridColumn> DataColumns { get; set; }
public bool IsSelected { get; set; }
public void GenerateGrid()
{
if (Entries.Count != 0)
{
var columns = Entries[0]?.Cells;
for (int i = 0; i < columns.Count; i++)
{
Binding b = new Binding(string.Format("Cells[{0}].Value", i));
DataGridTextColumn text = new DataGridTextColumn();
text.Header = columns[i].Cond1.ToString();
text.Binding = b;
DataColumns.Add(text);
}
}
}
}
public class Entry
{
public ObservableCollection<Cell> Cells { get; set; }
public Entry() { Cells = new ObservableCollection<Cell>(); }
}
public class Cell
{
public Cell() { }
public int Cond1 { get; set; }
public int Value { get; set; }
}
}
For the view you need the namespace:
http://schemas.microsoft.com/expression/2010/interactivity
The following code sample shows the view.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<ListBox ItemsSource="{Binding ListItems}" SelectedItem="{Binding SelectedListItem}">
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
</Style>
</ListBox.Resources>
</ListBox>
<DockPanel Grid.Column="1">
<Button DockPanel.Dock="Top" Command="{Binding FillCommand}">Fill Data</Button>
<DataGrid x:Name="ToleranceGrid" ColumnWidth="*" ItemsSource="{Binding Path=SelectedListItem.Entries}"
CanUserAddRows="False" SelectionMode="Single" SelectionUnit="Cell" AutoGenerateColumns="False" local:ColumnsBindingBehaviour.BindableColumns="{Binding Path=SelectedListItem.DataColumns}">
</DataGrid>
</DockPanel>
</Grid>
The ViewModel is set to the DataContext of the view in code behind.
The result should look like this:
WPF Application
The first ListItemModel is selected and I pressed the Button above the DataGrid. As you can see, the columns were generated, but the rows aren't displayed. I debugged the code, an everything is correctly set in my ViewModel. When I would select the second ListItemModel and would go back to the first one, the content will be shown correctly.
Do you have any ideas?
Your ListItemModel should implement the INotifyPropertyChanged interface and raise the PropertyChanged event when the Entries property is set to a new collection:
public class ListItemModel : INotifyPropertyChanged
{
public ListItemModel()
{
Entries = new ObservableCollection<Entry>();
DataColumns = new ObservableCollection<DataGridColumn>();
}
private ObservableCollection<Entry> _entries;
public ObservableCollection<Entry> Entries
{
get { return _entries; }
set { _entries = value; NotifyPropertyChanged(); }
}
public ObservableCollection<DataGridColumn> DataColumns { get; set; }
public bool IsSelected { get; set; }
public void GenerateGrid()
{
if (Entries.Count != 0)
{
var columns = Entries[0]?.Cells;
for (int i = 0; i < columns.Count; i++)
{
Binding b = new Binding(string.Format("Cells[{0}].Value", i));
DataGridTextColumn text = new DataGridTextColumn();
text.Header = columns[i].Cond1.ToString();
text.Binding = b;
DataColumns.Add(text);
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}

Wpf Depended combobox doesn't dispaly SelectedItem in .Net 4.5

I have main combobox (Categories) and depended combobox (Subcategories). I want it to display SelectedItems when window opens. All works fine in .Net 4.0, but it doesn't work in .Net 4.5. I have two computeres with these .Net versions.
In .net 4.5. only main combobox displays SelectedItem, depended doesn't. How can I fix it?
I made test project to all of you who're interested, just copy and paste. I have no idea how I can make it smaller, sry. But it is simple, clear code example 100% generates the problem.
XAML:
<Window x:Class="GridTest.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Converter="clr-namespace:GridTest"
Title="TestWindow"
Height="300"
Width="300">
<Window.Resources>
<Converter:CategoryConverter x:Key="CategoryConverter"/>
</Window.Resources>
<Grid>
<DataGrid Name="_dataGrid"
CanUserAddRows="False"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ComboBox Grid.Column="0"
Name="_categories"
ItemsSource="{Binding Categories}"
DisplayMemberPath="Name"
SelectedItem="{Binding SelectedCategory, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
</ComboBox>
<ComboBox Grid.Column="1"
SelectedItem="{Binding SelectedSubcategory, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Name">
<ComboBox.ItemsSource>
<MultiBinding Converter="{StaticResource CategoryConverter}">
<Binding Path="Subcategories"/>
<Binding Path="SelectedItem"
ElementName="_categories"/>
</MultiBinding>
</ComboBox.ItemsSource>
</ComboBox>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
Code:
public class CategoryConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[0] == null) return null;
var subcategories = values[0] as List<Subcategory>;
if (subcategories == null) return null;
var category = values[1] as Category;
if (category == null) return subcategories;
return subcategories.Where(g => g.CategoryId == category.Id);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public enum CategoryKinds
{
Car = 0,
Fruit = 1,
}
public class Category
{
public Int32 Id { get; set; }
public String Name { get; set; }
public override Boolean Equals(object obj)
{
var c = obj as Category;
if (c == null) return false;
return Id == c.Id;
}
}
public class Subcategory
{
public Int32 Id { get; set; }
public String Name { get; set; }
public Int32 CategoryId { get; set; }
public override Boolean Equals(object obj)
{
var sc = obj as Subcategory;
if (sc == null) return false;
return Id == sc.Id;
}
}
public class DataGridItem
{
public List<Category> Categories { get; set; }
public Category SelectedCategory { get; set; }
public List<Subcategory> Subcategories { get; set; }
public Subcategory SelectedSubcategory { get; set; }
public DataGridItem()
{
Categories = new List<Category>
{
new Category
{
Id = (Int32)CategoryKinds.Car, Name = "Car"
},
new Category
{
Id = (Int32)CategoryKinds.Fruit, Name = "Fruit"
}
};
Subcategories = new List<Subcategory>
{
new Subcategory
{
Id = 1,
Name = "Volvo",
CategoryId = (Int32) CategoryKinds.Car
},
new Subcategory
{
Id = 2,
Name = "Nissan",
CategoryId = (Int32) CategoryKinds.Car
},
new Subcategory
{
Id = 3,
Name = "Banana",
CategoryId = (Int32)CategoryKinds.Fruit
},
new Subcategory
{
Id = 4,
Name = "Lemon",
CategoryId = (Int32)CategoryKinds.Fruit
},
};
}
}
/// <summary>
/// Interaction logic for TestWindow.xaml
/// </summary>
public partial class TestWindow : Window
{
public List<DataGridItem> GridItems { get; set; }
public TestWindow()
{
InitializeComponent();
DataContext = this;
GridItems = new List<DataGridItem>
{
new DataGridItem
{
SelectedCategory = new Category
{
Id = (Int32)CategoryKinds.Car, Name = "Car"
},
SelectedSubcategory = new Subcategory
{
Id = 2,
Name = "Nissan",
CategoryId = (Int32) CategoryKinds.Car
}
},
new DataGridItem
{
SelectedCategory = new Category
{
Id = (Int32)CategoryKinds.Fruit, Name = "Fruit"
},
SelectedSubcategory = new Subcategory
{
Id = 4,
Name = "Lemon",
CategoryId = (Int32) CategoryKinds.Car
}
}
};
_dataGrid.ItemsSource = GridItems;
}
}
UPDATE
With approach suggested by Ilan and charly_b code will work fine.
GridItems = new List<DataGridItem>
{
new DataGridItem(),
new DataGridItem()
};
GridItems[1].SelectedCategory = GridItems[1].Categories[0];
GridItems[1].SelectedSubcategory = GridItems[1].Subcategories[1];
GridItems[0].SelectedCategory = GridItems[0].Categories[1];
GridItems[0].SelectedSubcategory = GridItems[0].Subcategories[3];
This code will result to:
Fruit - Lemon
Car - Nissan
But I have solution that will work even if you set SelectedItem that don't belong to ItemsSource of Combobox. You can override GetHashCode method like this:
public override int GetHashCode()
{
return Name.GetHashCode();
}
Obviously, in .Net 4.5 some of WPF methods operating with searching SelectedItem in Combobox's ItemsSource have different implementation from .Net 4.0 and now they use GetHashCode method :)
Try the next changes, the best practice is to use the source collection items in order to define the selected item. Firstly it is an architectural error to use a new item to define the selection (in both 4.5 and 4 dot.net versions). And second I advice you to use the mvvm approach (including INotifyPropertyChange implementation) to develop wpf related applications, and then all selection logic have to be moved to ViewModel and separated from the code behind (xaml.cs files).
public MainWindow()
{
InitializeComponent();
DataContext = this;
var f = new DataGridItem();
var firstselectedCategory = f.Categories.FirstOrDefault();
if (firstselectedCategory != null)
{
f.SelectedCategory = firstselectedCategory;
f.SelectedSubcategory =
f.Subcategories.FirstOrDefault(subcategory => subcategory.CategoryId == firstselectedCategory.Id);
}
else
{
f.SelectedCategory = null;
f.SelectedSubcategory = null;
}
var s = new DataGridItem();
var secondSelectedCategory = s.Categories.FirstOrDefault(category => !Equals(category, f.SelectedCategory));
if (secondSelectedCategory != null)
{
s.SelectedCategory = secondSelectedCategory;
s.SelectedSubcategory =
s.Subcategories.FirstOrDefault(subcategory => subcategory.CategoryId == secondSelectedCategory.Id);
}
else
{
s.SelectedCategory = null;
s.SelectedSubcategory = null;
}
GridItems = new List<DataGridItem>
{
f,s,
};
#region
//GridItems = new List<DataGridItem>
//{
// new DataGridItem
// {
// SelectedCategory = new Category
// {
// Id = (Int32) CategoryKinds.Car,
// Name = "Car"
// },
// SelectedSubcategory = new Subcategory
// {
// Id = 2,
// Name = "Nissan",
// CategoryId = (Int32) CategoryKinds.Car
// }
// },
// new DataGridItem
// {
// SelectedCategory = new Category
// {
// Id = (Int32) CategoryKinds.Fruit,
// Name = "Fruit"
// },
// SelectedSubcategory = new Subcategory
// {
// Id = 4,
// Name = "Lemon",
// CategoryId = (Int32) CategoryKinds.Fruit
// }
// }
//};
#endregion
_dataGrid.ItemsSource = GridItems;
}
The xaml code was not changed.
How it looks like:
.
I'll be glad to help if will have problems with the code.
Regards.
The Combobox SelectedItem object must be contained inside the Combobox's ItemsSource List.
In order to make your Programm work you can replace the SelectedSubCategory Property with the following code: (I would not use it like this in the production code, but it demonstrates how it works)
private Subcategory SelectedSubcategoryM;
public Subcategory SelectedSubcategory
{
get
{
return this.SelectedSubcategoryM;
}
set
{
this.SelectedSubcategoryM = (from aTest in this.Subcategories
where aTest.Id == value.Id
select aTest).Single();
}
}

Listbox Sorting based on TextBox value

How can I sort ListBox items using TextBox enterd value.
The match case ListBox Items show top of list box
Here is my code
XAML
<Grid>
<TextBox HorizontalAlignment="Left" Height="23" Margin="67,39,0,0" TextWrapping="Wrap" Text="{Binding CustomerSort,UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
<ListBox Margin="67,79,185,26" Background="LightYellow"
DisplayMemberPath="Name" ItemsSource="{Binding CustomerColloction}"/>
</Grid>
C# code
public class Customers
{
public String Name { get; set; }
public Int32 Age { get; set; }
}
public class ViewModel
{
public ViewModel()
{
CustomerColloction = new ObservableCollection<Customers>();
CustomerColloction.Add(new Customers() { Name = "AAA", Age = 25 });
CustomerColloction.Add(new Customers() { Name = "AA", Age = 25 });
CustomerColloction.Add(new Customers() { Name = "BBB", Age = 26 });
CustomerColloction.Add(new Customers() { Name = "BB", Age = 24 });
CustomerColloction.Add(new Customers() { Name = "AAAA", Age = 13 });
CustomerColloction.Add(new Customers() { Name = "BB", Age = 11 });
CustomerColloction.Add(new Customers() { Name = "XYZ", Age = 44 });
}
public ObservableCollection<Customers> CustomerColloction { get; set; }
private String _CustomerSort = String.Empty;
public String CustomerSort
{
get
{
return _CustomerSort;
}
set
{
_CustomerSort = value;
NotifyPropertyChanged("CustomerSort");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
I want to get the result like if we enter AA in TextBox, To Show sorting item form list box
AA
AAA
AAAA
BB
BB
BBB
XYZ
Set combobox and set drop down mode
Better to sort observable collection and set to ListBox CustomerColloction.OrderBy(q=>q.Name).ToList();
I can see its a pretty vauge requirement but just to give you an idea you can manipulate your bound object collection like this to achieve similar results
Following code has been typed by a mobile device and is not verified..
CustomerColloction.Where(p=>p.name.Contains(CustomerSort)).OrderBy(q=>q.Name).ToList().Add(CustomerColloction.where(r=>r.name.Contains(CustomerSort)=false).OrderBy(s=>s.Name).toList()
And in setter of youe CustomerSort property raise notification for you bound collection

Categories