Multicolumn autosearch user control in wpf - c#

I need to create an Auto search control which will show the results as rows as this one http://www.devexpress.com/Products/NET/Controls/WPF/Editors/lookup-editor.xml. However, I dont need the graphics and checkboxes here. A simple listview like appearance will work.
Please suggest how to create the user control using WPF.

Here has a nice article on Sorting, Filtering and Grouping ListView.
Basically you set CollectionViewSource to ListCollectionView. You can then use the Filter Property to filter the ListView.

If you're using an MVVM approach you could do the following:
Bind your search Textbox Text member, ListView's ItemsSource and SelectedItem to the ViewModel
Set 'UpdateSourceTrigger=PropertyChanged' on the TextBox's binding
In the setter of the property that the TextBox is bound to add logic that searches the ItemsSource collection and sets the SelectedItem bound property.
Something like this:
XAML:
<TextBox Text="{Binding Path=SearchTerm, UpdateSourceTrigger=PropertyChanged}"/>
<ListView ItemsSource="{Binding Path=SourceCollection}" SelectedItem="{Binding Path=SelectedSearchItem, Mode=TwoWay}" />
Code:
public class ViewModel : INotifyPropertyChanged
{
public string SearchTerm
{
get { return searchTerm; }
set {
searchTerm = value;
SelectedSearchItem = SourceCollection.FirstOrDefault(foo => foo.Name.Contains(searchTerm));
}
}
public Foo SelectedSearchItem
{
get { return selecedSearchItem; }
set {
selectedSearchItem = value;
// Raise PropertyChanged
}
}
public ObservableCollection<Foo> SourceCollection { get; set;}
}

Related

WPF combobox is empty when binding enum

I am trying to bind values of an enum to a combo box but the combo box remain empty with no options to choose.
This is the combo box xaml defintion:
<ComboBox Grid.Row="2" Grid.Column="1" ItemsSource="{Binding Path=SkillItemSource}" SelectedItem="{Binding Path=neededSkill, Mode=TwoWay}" SelectedIndex="0" Margin="5" MinWidth="100"></ComboBox>
And this is the items source and selected item which are defined in the window's cs:
public Skill neededSkill = Skill.FirstSkill;
public string[] SkillItemSource
{
get
{
return Enum.GetNames(typeof(Skill));
}
}
What is missing for the values to appear in the combobox?
What is missing for the values to appear in the combobox?
You need to set the DataContext of the ComboBox, or a parent element, to an instance of the class where the SkillItemSource property is defined. If the property is defined in the code-behind, you could just set the DataContext to the view itself: this.DataContext = this;
Also, you can't mix types. If the ItemsSource is bound to an IEnumerable<string>, the SelectedItem property should be bound to a string property.
Also note that neededSkill must be defined as a public property for you to be able to bind to it.
Try this:
public Skill neededSkill { get; set; } = Skill.FirstSkill;
public IEnumerable<Skill> SkillItemSource { get; } = Enum.GetValues(typeof(Skill)).Cast<Skill>();

Binding to ObservableCollection works, but not ListCollectionView

I'm trying to get my ListCollectionView to bind to a combo box. However, it seems to only work when I bind to my ObservableCollection.
Properties:
private ListCollectionView sitesView;
public ListCollectionView SitesView
{
get { return sitesView; }
set
{
sitesView = value;
RaisePropertyChanged(() => SitesView);
}
}
public ObservableCollection<ISite> SitesCollection { get; set; }
Constructor:
SitesCollection = new ObservableCollection<ISite>();
SitesView = (ListCollectionView)CollectionViewSource.GetDefaultView(SitesCollection);
When binding like so:
<ComboBox Grid.Row="2" ItemsSource="{Binding SitesView, Mode=TwoWay}"/>
any item I add to SitesCollection does not get shown when I click the drop down in my combo box. But if I do the binding like so:
<ComboBox Grid.Row="2" ItemsSource="{Binding SitesCollection, Mode=TwoWay}"/>
it works fine and I see the items when I click the drop down.
Attempts at fixing: After I add the an item to the SitesCollection, I tried to raise property change notifications on both the ListCollectionView and the ObservableCollection and it didn't make a difference. Any ideas?
I didn't have time to test my answer; I apologize and will follow up.
I think your issue is because CollectionViewSource.GetDefaultView(...)
returns an ICollectionView, which I believe is essentially just a wrapper that enables the underlying data to be sorted.
Try setting SitesView to the SourceCollection of the DefaultView.
SitesView = (ListCollectionView)CollectionViewSource.GetDefaultView(SitesCollection).SourceCollection

MVVM Pattern in Master-Detail when editing details

i have a ObservableCollection with some data. They are displayed as Master (ListBox) and Detail (some Labels). I use binding and IsSynchronizedWithCurrentItem to show the correct details to the selected master item. This works all fine. Now i want to edit some details (load different image). I implemeted this a a Button Command in the ViewModel.
But how do i know which item is selected (UI) in the ViewModel-layer ?
Thanks for help
I don't really find the IsSynchronizedWithCurrentItem property that useful in MVVM scenarios.
Just expose another SelectedItem property in the ViewModel.
public ItemType SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
// your logic here
}
}
You need to bind a value or Enumerable of values of your ViewModel to the ListBox's SelectedItems property.
SelectedItems="{Binding VMProperty}"
http://msdn.microsoft.com/en-us/library/system.windows.controls.listbox.selecteditems(v=vs.110).aspx
If you only want one item selected you need to set:
SelectionMode="Single"
SelectedItem="{Binding VMProperty}"
If I understood you right, what you are looking for is the following
<ListBox SelectedItem="{Binding ObjectName, UpdateSourceTrigger=PropertyChanged}"/>
Plus under your ViewModel you have to declare the following
public YourObject ObjectName { get; set; }
Simple as that!
The normal way to detect which item in the collection is currently selected in the UI is to data bind a property of the same type as the items in the collection to the ListBox.SelectedItem property:
<ListBox ItemsSource="{Binding SomeCollection}"
SelectedItem="{Binding SomeProperty}" />
Now, whenever the user selects a new item, the SomeProperty setter will be called:
public YourDataType SomeProperty
{
get { return someProperty; }
set
{
someProperty = value;
// The value has just changed
}
}

WPF binding to a property not in the DataGrid ItemSource

I am wondering how I can bind a DataGrid DataGridTemplateColumn to a property in that isn't in the DataGrid ItemSource, but the property is within the same DataContext of the Itemsource?
XAML
// I am trying to bind the Visibility property to a property called Visible
<DataGridTemplateColumn Header="Apply" Visibility="{Binding source Visible}">
// However the visible property doesnt exist inside the resource cvsCustomers
ItemsSource="{Binding Source={StaticResource CustomerCollection}}"
C#
// But they both live in the same ViewModel i.e. DataContext
private Visibility m_Visible = Visibility.Hidden;
public Visibility Visible
{
get { return m_Visible; }
set { m_Visible = value; }
}
private ObservableCollection<Customer> m_CustomerCollection = null;
public ObservableCollection<Customer> CustomerCollection
{
get { return m_CustomerCollection; }
set { m_CustomerCollection = value; }
}
Can this be achieved?
Thanks
Datagrid columns does not comes under the visual tree of the DataGrid. hence you will need to use the BindingProxy to make ViewModel accessible to your DataGridTemplateColumn. I have explained how to create and use BindingProxy in the answer below:
Bind ViewModel property to DataGridComboBoxColum
Once you have setup the BindingProxy you can bind your DataGridTemplateColumn visiblity as
<DataGridTemplateColumn Header="Apply" Visibility="{Binding Path=Data.Visible, Source={StaticResource ProxyElement}"

WPF MVVM Master detail view with a datagrid and a TabControl

I am trying to implement a Master detail view in WPF MVVM.
In my viewmodel I have a observable collection of "Causes". Each Cause has an observable collection of "Solutions".
I bound an editable Datagrid to the Causes and it is working fine. But when a user selects a row in the DataGrid I want to allow the user to see its associated solutions in the TabControl.
How should I go about doing this? Should I create a property CurrentCause in the Viewmodel and bind it to the SelectedItem. In the TabControl can I bind to CurrentCause.Solutions.
Will this be an optimal approach? Please advise. Thanks!!
You could bind the ItemsSource of the TabControl to be the SelectedItem of the DataGrid using element binding.
<TabControl ItemsSource="{Binding ElementName=myDataGrid, Path=SelectedItem.Solutions}">
You can set IsSynchronizedWithCurrentItem to True and do something like this.
I would bind your DataGrid to a list of Causes, the SelectedItem to CurrentCause in your Model and the TabControl to Solutions. Then you have everything nicely tied up in your MVVM.
private Cause _currentCause;
public Cause CurrentCause
{
get { return _currentCause; }
set
{
if (_currentCause == value) return;
CurrentSolution = _currentCause.Solutions; //However you do this...
_currentCause = value;
RaisePropertyChanged("CurrentCause");
}
}
private ObservableCollection<Cause> _causes;
public ObservableCollection<Cause> Causes
{
get { return _causes; }
set
{
_causes = value;
RaisePropertyChanged("Causes");
}
}
private ObservableCollection<Solution> _solutions;
public ObservableCollection<Solution> Solutions
{
get { return _solutions; }
set
{
_solutions = value;
RaisePropertyChanged("Companies");
}
}
<dg:DataGrid ItemsSource="{Binding Causes}" SelectedItem="{Binding CurrentCause}"...

Categories