WPF ComboBox selection change on TabItem selection change - c#

I have a combobox in a tab item in MVVM. This tab can be created multiple times in my application (same view, same view model but different instance), so I can switch from one tab to another (but they are tab of the same type).
It works perfectly with every WPF control, but with combobox I have a strange behaviour:
the focus tab, when it loses focus, gets the selected item of the combox box of the tab that the application is focusing on.
If I switch from 2 tabs that are not of the same type everything works correctly, any idea about that? Thanks.
XAML:
<CollectionViewSource x:Key="StatusView" Source="{Binding Path=StatusList}"/>
<ComboBox Name="_spl2Status" Grid.Column="3" Grid.Row="0"
ItemsSource="{Binding Source={StaticResource StatusView}}"
SelectedValue="{Binding Path=CurrentSPL2.ID_SPL2_STATUS, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedValuePath="FL_TYPE"
DisplayMemberPath="ID_TYPE">
</ComboBox>
VM:
public List<NullableByteEnumType> StatusList
{
get
{
return (SPC_SPL2.SPL2StatusCollection.Skip(1)).ToList();
}
}
private SPC_SPL2 _currentSPL2 = null;
public SPC_SPL2 CurrentSPL2
{
get
{
if (_currentSPL2== null)
Controller.Execute(delegate(IResult result)
{
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("FL_ACTIVE", true);
parameters.Add("ID_SPL2", _itemcode);
Model.Invalidate(typeof(SPC_SPL2), Filter.GENERIC<SPC_SPL2>(parameters, "ID_SPL2"));
Model.Include<SPC_SPL2>();
if (Model.Appendload(result) == false)
return false;
Debug.Assert(Context.SPC_SPL2.Count == 1);
_currentSPL2= Context.SPC_SPL2.FirstOrDefault();
return result.Successful;
});
return _currentSPL2;
}
set
{
_currentSPL2= value;
OnPropertyChanged(() => CurrentSPL2);
}
}
my tabs are handled in this way:
<Grid>
<Border Grid.Row="0">
<ContentControl
Content="{Binding Path=Workspaces}"
ContentTemplate="{StaticResource MasterWorkspacesTemplate}"
/>
</Border>
</Grid>
where
<DataTemplate x:Key="MasterWorkspacesTemplate">
<TabControl IsSynchronizedWithCurrentItem="True"
BorderThickness="0"
ItemsSource="{Binding}"
SelectedItem="{Binding}"
ItemContainerStyleSelector="{StaticResource TabItemTemplate}"
/>
</DataTemplate>
and workspaces (my viewmodels list) (T is a class who inherit from viewModelBase)
public T CurrentWorkspace
{
get { return WorkspacesView.CurrentItem as T; }
}
private ObservableCollection<T> _workspaces;
public ObservableCollection<T> Workspaces
{
get
{
if (_workspaces == null)
{
_workspaces = new ObservableCollection<T>();
_workspaces.CollectionChanged += _OnWorkspacesChanged;
}
return _workspaces;
}
}
protected ICollectionView WorkspacesView
{
get
{
ICollectionView collectionView = CollectionViewSource.GetDefaultView(Workspaces);
Debug.Assert(collectionView != null);
return collectionView;
}
}

I have recreated your problem. But I couldn't find any issue. Please look at the code below and you might get the solustion. Here is my solution.
MyTab view model
public class MyTab : ViewModelBase
{
#region Declarations
private ObservableCollection<string> statusList;
private string selectedStatus;
#endregion
#region Properties
/// <summary>
/// Gets or sets the header.
/// </summary>
/// <value>The header.</value>
public string Header { get; set; }
/// <summary>
/// Gets or sets the content.
/// </summary>
/// <value>The content.</value>
public string Content { get; set; }
/// <summary>
/// Gets or sets the status list.
/// </summary>
/// <value>The status list.</value>
public ObservableCollection<string> StatusList
{
get
{
return statusList;
}
set
{
statusList = value;
NotifyPropertyChanged("StatusList");
}
}
/// <summary>
/// Gets or sets the selected status.
/// </summary>
/// <value>The selected status.</value>
public string SelectedStatus
{
get
{
return selectedStatus;
}
set
{
selectedStatus = value;
NotifyPropertyChanged("SelectedStatus");
}
}
#endregion
}
MainViewModel view model
public class MainViewModel : ViewModelBase
{
#region Declarations
private ObservableCollection<MyTab> tabs;
private MyTab selectedTab;
#endregion
#region Properties
/// <summary>
/// Gets or sets the tabs.
/// </summary>
/// <value>The tabs.</value>
public ObservableCollection<MyTab> Tabs
{
get
{
return tabs;
}
set
{
tabs = value;
NotifyPropertyChanged("Tabs");
}
}
/// <summary>
/// Gets or sets the selected tab.
/// </summary>
/// <value>The selected tab.</value>
public MyTab SelectedTab
{
get
{
return selectedTab;
}
set
{
selectedTab = value;
NotifyPropertyChanged("SelectedTab");
}
}
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="MainViewModel"/> class.
/// </summary>
public MainViewModel()
{
this.Tabs = new ObservableCollection<MyTab>();
MyTab tab1 = new MyTab();
tab1.Header = "tab1";
tab1.Content = "Tab 1 content";
ObservableCollection<string> tab1StatusList = new ObservableCollection<string>();
tab1StatusList.Add("tab1 item1");
tab1StatusList.Add("tab1 item2");
tab1StatusList.Add("tab1 item3");
tab1.StatusList = tab1StatusList;
tab1.SelectedStatus = tab1StatusList.First();
this.Tabs.Add(tab1);
MyTab tab2 = new MyTab();
tab2.Header = "tab2";
tab2.Content = "Tab 2 content";
ObservableCollection<string> tab2StatusList = new ObservableCollection<string>();
tab2StatusList.Add("tab2 item1");
tab2StatusList.Add("tab2 item2");
tab2StatusList.Add("tab2 item3");
tab2.StatusList = tab2StatusList;
tab2.SelectedStatus = tab2StatusList.First();
this.Tabs.Add(tab2);
this.SelectedTab = tab1;
}
#endregion
}
And finally this is my XAML
<Window x:Class="ComboboxSelectedItem.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModel="clr-namespace:ComboboxSelectedItem.ViewModels"
Title="MainWindow" Height="350" Width="525">
<Grid Name="mainGrid">
<Grid.DataContext>
<viewModel:MainViewModel />
</Grid.DataContext>
<TabControl
ItemsSource="{Binding Tabs, Mode=TwoWay}"
SelectedItem="{Binding SelectedTab}">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Header}" Margin="0 0 20 0"/>
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
<!--Content section-->
<TabControl.ContentTemplate>
<DataTemplate>
<Grid>
<StackPanel Orientation="Vertical">
<TextBlock
Text="{Binding Content}" />
<ComboBox
ItemsSource="{Binding StatusList}"
SelectedItem="{Binding SelectedStatus}" />
</StackPanel>
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
</Window>

Are you absolutely sure that you are creating a new instance of the viewmodel. If not, then the comboboxes are sharing the same collectionviewsource which means that a change in one combobox will be reflected in all comboboxes. I had this same problem myself.
Try declaring the collection view source in code:
CollectionViewSource StatusListViewSource = new CollectionViewSource();
StatusListViewSource.Source = SPL2StatusCollection;
then in xaml change binding to the collectionviewsource:
ItemsSource="{Binding StatusListViewSource.View}"
I converted from vb so it might need some edits.
Does that help?

Related

How predicate works with ListCollectionView

How predicate filters works with ListCollectionView?
In my case i have ListCollectionView<Users> FilteredUserList.
To filter single value i am using
private void AddFilterAndRefresh(string name, Predicate<User> predicate)
{
//Adds filter to filter list
Filters.Add(name, predicate);
//Filters doesn't fire event automatically
OnPropertyChanged("Filters");
//Refresh list to by correctly displayed
FilteredUserList.Refresh();
}
Usage example AddFilterAndRefresh(key, user => user.Name.Contains(u.Name))
Now things from here is not understandable for me. When i use function above, in datagridview is shown only one row. So it means that before filter all values are "true" to show, but when i pass filter all values becomes false and one value true?
For stacking filters i use
private bool FilterEntries(object obj)
{
User c = (User)obj;
return Filters.Values.Aggregate(true, (prevValue, predicate) => prevValue && predicate(c));
}
But I want to make excel like filter, when user checks values what to show. It means that i have to filter multiple values. When i do foreach(User u in SelectedOptions) {AddFilterAndRefresh()} Datagrid is empty - but it is obvious because after one filter datagrid shows one row. So how to filter multiple values?
Well. I did some modifications. It works but not correctly. Imagine I have user list:
Tabelis Name Departament
5 Marius Some
20 Darius unknown
20 Koste unknown
20 Gediminas unknown
20 Nerijus tech
Now if i exclude by Departament "unknown" (uncheck chekbox) it filters ok :
Tabelis Name Departament
5 Marius Some
20 Nerijus tech
Now when i uncheck by Tabelis "20" it filter ok:
Tabelis Name Departament
5 Marius Some
But when i out check on Tabelis "20" again it filters wrong:
Tabelis Name Departament
5 Marius Some
20 Darius unknown
20 Koste unknown
20 Gediminas unknown
20 Nerijus tech
Turns Departament values on.
Where i am doing a mistake?
view:
<DataGrid x:Name="myGrd"
DataContext="{Binding ElementName=userPage, Path=DataContext}"
SelectionMode="Single"
SelectionUnit="Cell"
CurrentItem="{Binding SelectedUser, Mode=TwoWay}"
CurrentColumn="{Binding CurrentColumn, Mode=TwoWay}"
IsReadOnly="True"
CanUserResizeColumns="False"
Grid.Row="1"
ItemsSource="{Binding FilteredUserList}"
AutoGenerateColumns="True"
CanUserAddRows="False">
<DataGrid.Resources>
<!--Popup-->
<ContextMenu x:Key="ContextMenu">
<ContextMenu.Items>
<MenuItem Header="Filter by Selection" Command="{Binding IncludeCommand, Source={x:Reference vm}}"/>
<MenuItem Header="Filter exclude Selection" Command="{Binding ExcludeCommand, Source={x:Reference vm}}"/>
<MenuItem Header="Remove all Filters" Command="{Binding RemoveAllFiltersCommand, Source={x:Reference vm}}" Visibility="{Binding Filters.Count, Source={x:Reference vm}, Converter={Wpf:VisibilityConverter}}"/>
</ContextMenu.Items>
</ContextMenu>
<!--Custom Datagrid header View-->
<Style TargetType="DataGridColumnHeader" x:Name="FilterHeader">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<TextBox Margin="0,0,0,10" Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridColumnHeader}}, Path=Width}" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" HorizontalAlignment="Center"/>
<ToggleButton Name="FilterButton"
Content="[-F-]"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}, Path=DataContext.GenerateExcelFilterViewItemsCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=DataGridColumnHeader}, Path=Content}"
>
</ToggleButton>
<Popup Name="MyPopup"
StaysOpen="False"
Placement="Right"
IsOpen="{Binding ElementName=FilterButton, Path=IsChecked}"
PlacementTarget="{Binding ElementName=FilterButton}"
>
<Border CornerRadius="0" BorderThickness="2" BorderBrush="{StaticResource AQBlueBrush}">
<StackPanel Width="Auto" Background="{StaticResource AQBackgroundLightBrush}" MinWidth="100">
<TextBlock Margin="2" Text="Filter" Foreground="{StaticResource AQVeryDarkBlueBrush}"/>
<Separator/>
<ListView Padding="5"
MaxHeight="150"
MinHeight="80"
Background="Transparent"
BorderThickness="0"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}, Path=DataContext.FilterList}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay}"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}, Path=DataContext.IsSelectedItemsCommand}"
CommandParameter="{Binding}"/>
<ContentPresenter Content="{Binding Value}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Margin="2,0,2,2"
Content="Submit"
Foreground="{StaticResource AQVeryDarkBlueBrush}"
Background="AliceBlue"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}, Path=DataContext.AddMultipleFiltersAndRefreshCommand}"/>
</StackPanel>
</Border>
</Popup>
</StackPanel>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="ContextMenu" Value="{StaticResource ContextMenu}"/>
</Style>
</DataGrid.CellStyle>
</DataGrid>
ViewModel:
public class UsersViewModel: BaseViewModel
{
#region Private Properties
/// <summary>
/// User's information holding list that could be used
/// </summary>
private ObservableCollection<User> UserList = new ObservableCollection<User>();
/// <summary>
/// Selected Header in datagrid
/// </summary>
private string SelectedColumnHeader { get; set; }
/// <summary>
/// List of isSelected Values
/// </summary>
private ObservableCollection<FilterPredicate> SelectedFilters { get; set; } = new ObservableCollection<FilterPredicate>();
#endregion
#region public Properties
/// <summary>
/// Filter list used to excel like filter functionality
/// </summary>
public ObservableCollection<FilterPredicate> FilterList { get; set; }
/// <summary>
/// Filters every filter used is saved in this dictionary
/// </summary>
public List<Predicate<User>> Filters { get; set; } = new List<Predicate<User>>();
/// <summary>
/// Filtered user list
/// </summary>
public ListCollectionView FilteredUserList { get; set; }
/// <summary>
/// Current Selected Object
/// </summary>
public User SelectedUser { get; set; }
/// <summary>
/// Current Selected Column
/// </summary>
public DataGridColumn CurrentColumn { get; set; }
public bool PopupVisible { get; set; }
public UIElement FilterButton { get; set; }
#endregion
#region Commands
public ICommand ExcludeCommand { get; set; }
public ICommand IncludeCommand { get; set; }
public ICommand RemoveAllFiltersCommand { get; set; }
public ICommand RemoveFilterCommand { get; set; }
public ICommand GenerateExcelFilterViewItemsCommand { get; set; }
public ICommand IsSelectedItemsCommand { get; set; }
public ICommand AddMultipleFiltersAndRefreshCommand { get; set; }
#endregion
#region Constructor
/// <summary>
/// Default constructor
/// </summary>
public UsersViewModel()
{
//Populate UserList
GetUsers();
//Set filtered user list with values
FilterList = new ObservableCollection<FilterPredicate>();
FilteredUserList = new ListCollectionView(UserList);
ExcludeCommand = new RelayParamCommand((e) => ExcludeFilter(SelectedUser));
IncludeCommand = new RelayParamCommand((e) => IncludeFilter(SelectedUser));
RemoveAllFiltersCommand = new RelayCommand(() => RemoveAllFiltersAndRefresh());
GenerateExcelFilterViewItemsCommand = new RelayParamCommand((e) => GenerateExcelFilterItems(e));
IsSelectedItemsCommand = new RelayParamCommand((e) => IsSelectedItems(e));
//AddMultipleFiltersAndRefreshCommand = new RelayCommand(AddMultipleFilterss);
FilteredUserList.Filter = (e) => { return FilterEntries(e); };
}
#endregion
#region Filter Methods
/// <summary>
/// Filter Collection view values
/// </summary>
private bool FilterEntries(object obj)
{
User c = (User)obj;
bool isIn = true;
if (Filters.Count == 0)
{
//return Filters.TrueForAll(x => x(c));
return isIn;
}
else
{
return Filters.TrueForAll(x => x(c));
// return Filters.Aggregate(true, (prevValue, predicate) => prevValue && predicate(c));
}
}
/// <summary>
/// Exclude selected value
/// </summary>
/// <param name="obj"></param>
public void ExcludeFilter(object obj)
{
User u = (User)obj;
switch (CurrentColumn.DisplayIndex)
{
case 0:
AddFilterAndRefresh(user => !user.Tabelis.ToString().Contains(u.Tabelis.ToString()));
return;
case 1:
AddFilterAndRefresh(user => !user.Name.Contains(u.Name));
return;
case 2:
AddFilterAndRefresh(user => !user.Departament.Contains(u.Departament));
return;
}
}
/// <summary>
/// Include selected filter value
/// </summary>
/// <param name="obj">Object</param>
private void IncludeFilter(object obj)
{
User u = (User)obj;
switch (CurrentColumn.DisplayIndex)
{
case 0:
AddFilterAndRefresh(user => user.Tabelis.ToString().Contains(u.Tabelis.ToString()));
return;
case 1:
AddFilterAndRefresh(user => user.Name.Contains(u.Name));
return;
case 2:
AddFilterAndRefresh(user => user.Departament.Contains(u.Departament));
return;
}
}
/// <summary>
/// Add filter to Filter list
/// </summary>
/// <param name="name">Key</param>
/// <param name="predicate">Filter (predicate) object</param>
private void AddFilterAndRefresh(Predicate<User> predicate)
{
//Adds filter to filter list
Filters.Add(predicate);
//Filters doesn't fire event automatically
OnPropertyChanged("Filters");
//Refresh list to by correctly displayed
FilteredUserList.Refresh();
}
/// <summary>
/// Remove all filters from filter list
/// </summary>
private void RemoveAllFiltersAndRefresh()
{
Filters.Clear();
FilterList.Clear();
SelectedFilters.Clear();
FilteredUserList.Refresh();
OnPropertyChanged("Filters");
}
/// <summary>
/// Gets property to get filter items by this property value
/// </summary>
/// <param name="obj">Object property</param>
private void GenerateExcelFilterItems(object obj)
{
//set header name as string
SelectedColumnHeader = (string)obj;
//Clear Filter list
FilterList.Clear();
foreach(FilterPredicate i in SelectedFilters)
{
//insert right not selected value
//because after filter excecution that value dissapears
if (!FilterList.Contains(i) && i.ColumnName == SelectedColumnHeader) { FilterList.Add(i); }
}
//Fill filter list with new values depend on selectedColumnHeader property
FillFilterValues(SelectedColumnHeader);
}
/// <summary>
/// Remove or add "IsSelected" values to SelectedFilters List
/// </summary>
/// <param name="obj"></param>
private void IsSelectedItems(object obj)
{
var SelectedItem = (FilterPredicate)obj;
if (SelectedItem.IsSelected)
{
Filters.Add(AddMultipleFilters);
//Refresh list to by correctly displayed
FilteredUserList.Refresh();
}
else
{
FilterList[FilterList.IndexOf(SelectedItem)].IsSelected = false;
Filters.Add(AddMultipleFilters);
//RemoveMultipleFilters(SelectedItem);
if(!SelectedFilters.Contains(SelectedItem))
SelectedFilters.Add(SelectedItem);
//Refresh list to by correctly displayed
FilteredUserList.Refresh();
}
}
private bool AddMultipleFilters(object obj)
{
User u = (User)obj;
return FilterList.Any(x => x.IsSelected && x.Value.Contains(u.GetType().GetProperty(SelectedColumnHeader).GetValue(u).ToString()));
}
#endregion
#region helpers
/// <summary>
/// Fill filter items list with values from FilteredUsersList
/// </summary>
/// <param name="Property"></param>
private void FillFilterValues(string Property)
{
foreach (User u in FilteredUserList)
{
User i = u;
var item = new FilterPredicate(Property, u.GetType().GetProperty(Property).GetValue(i).ToString(), true);
if (!FilterList.Any(x => x.ColumnName == item.ColumnName && x.Value == item.Value))
FilterList.Add(item);
}
}
/// <summary>
/// Fill userList with data from database
/// </summary>
private void GetUsers()
{
UserList.Add(new User
{
Name = "Marius",
Departament = "some",
Tabelis = 5
});
UserList.Add(
new User
{
Name = "Darius",
Departament = "unknown",
Tabelis = 20
});
UserList.Add(
new User
{
Name = "Koste",
Departament = "unknown",
Tabelis = 20
});
UserList.Add(
new User
{
Name = "Gediminas",
Departament = "unknown",
Tabelis = 20
});
UserList.Add(
new User
{
Name = "Nerijus",
Departament = "Tech",
Tabelis = 20
});
}
#endregion
}
}
Filter predicate should return true for items which needs to be displayed, and false for hidden items.
CollectionView needs only one predicate. To filter by selected names, keep them in a list and compare CollectionView item for possible match with any name, not with each name.
private bool FilterEntries(object obj)
{
User u = (User)obj;
// converting original condition to ANY instead of EACH
return Filters.Values.Aggregate(false, (prevValue, predicate) => prevValue || predicate(u));
// looks like Filters is a Dictionary, maybe simplify condition?
return Filters.ContainsKey(u.Name);
// or maybe search in a List without multiple predicates
return Filters.Keys.Any(name => name.Contains(u.Name));
}

How to add images from Resources.resx in a combobox

I have searched a lot but cannot get what I want. I need to fill a combo box with images (114 images embedded in Resources.resx).
I am just getting list, not images. Here is my code.
ResourceSet rsrcSet =MyProject.Properties.Resources.ResourceManager.GetResourceSet(CultureInfo.CurrentCulture, true, true);
List<object> images = new List<object>();
foreach (DictionaryEntry entry in rsrcSet)
{
//String name = entry.Key.ToString();
//Object resource = entry.Value;
images.Add( Don't know what will be here? );
}
var comboBox = sender as ComboBox;
comboBox.ItemsSource = images;
and my XAML
<ComboBox HorizontalAlignment="Left" Grid.Column="0" Grid.Row="0" VerticalAlignment="Top" Width="320" Loaded="ComboBox_Loaded" SelectionChanged="ComboBox_SelectionChanged"/>
It's the easiest to use an item template. To do so we define a DataTemplate with DataType String and set it to the ComboBox.ItemTemplate. In order to use String in XAML we need to reference the xmlns:system="clr-namespace:System;assembly=mscorlib" assembly and namespace. For the binding we use a ObservableCollection<string> that holds the relative paths to your images:
View model:
public class ViewModel : INotifyPropertyChanged
{
public TestViewModel()
{
this.ImageSources = new ObservableCollection<string>() { #"Resources\Icons\image.png" };
}
/// <summary>
/// Event fired whenever a child property changes its value.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Method called to fire a <see cref="PropertyChanged"/> event.
/// </summary>
/// <param name="propertyName"> The property name. </param>
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private ObservableCollection<string> imageSources;
public ObservableCollection<string> ImageSources
{
get => this.imageSources;
set
{
this.imageSources = value;
OnPropertyChanged();
}
}
}
Xaml:
<Window x:Class="MainWindow"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<Window.DataContext>
<viewModels:ViewModel />
</Window.DataContext>
<Window.Resources>
<DataTemplate x:Key="ComboBoxItemTemplate" DataType="system:String">
<Image Source="{Binding}" Height="100" Width="100"/>
</DataTemplate>
</Window.Resources>
<Grid>
<StackPanel>
<ComboBox ItemTemplate="{StaticResource ComboBoxItemTemplate}"
ItemsSource="{Binding ImageSources}" />
</StackPanel>
</Grid>
</Window>
To make it work, your dictionary should contain the relative image paths. If not you have to convert. So instead of initializing the ObservableCollection in the constructor, like in the example, you can move the initialization to anywhere else.

How to filter ListBox using TextBox from XAML and code in ViewModel, MVVM Light

What are the codes to use to filter out my ListBox as the user is typing in the TextBox?
The data in my ListBox is from database. I have used a RelayCommand to get all the details of an Event then place the details in an ObservableCollection. Then bind my ListBox to the ObservableCollection and a TextBlock to show the Event Names.
XAML code:
<TextBox x:Name="txtSearch" Text="{Binding HomePage.TxtEntered , Mode=TwoWay}" Background="White" FontSize="30" Height="57" Margin="19,10,19,0" Grid.Row="1" />
<Grid Grid.Row="1" x:Name="ContentRoot" Margin="19,72,19,0">
<ListBox Background="Black" x:Name="listBox" FontSize="26" Margin="0,10,0,0" LayoutUpdated="listbox_layoutUpdate" ItemsSource="{Binding HomePage.SearchEventCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="txtEventName" TextWrapping="Wrap" Text="{Binding EventName , UpdateSourceTrigger=PropertyChanged}" Tapped="txtEventName_Tapped" IsTapEnabled="True" Foreground="White" Width="300" Margin="10,15,0,0" Height="55"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
RelayCommand in ViewModel:
private RelayCommand _eventSearch;
/// <summary>
/// Gets the EventSearch.
/// </summary>
public RelayCommand EventSearch
{
get
{
return _eventSearch
?? (_eventSearch = new RelayCommand(
async() =>
{
SearchEventCollection.Clear();
var eventList = await App.MobileService.GetTable<Event>().ToListAsync();
foreach (Event ename in eventList)
{
SearchEventCollection.Add(new Event
{
Id = ename.Id,
EventName = ename.EventName,
Date = ename.Date,
Location = ename.Location,
Desc = ename.Desc
});
}
}));
}
}
ObservableCollection:
private static ObservableCollection<Event> _searchEventCollection = new ObservableCollection<Event>();
public static ObservableCollection<Event> SearchEventCollection
{
get { return _searchEventCollection; }
set { _searchEventCollection = value; }
}
PropertyChange in ViewModel:
public const string TxtEnteredPropertyName = "TxtEntered";
private string _txtEntered;
/// <summary>
/// Sets and gets the TxtEntered property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public string TxtEntered
{
get
{
return _txtEntered;
}
set
{
if (_txtEntered == value)
{
return;
}
_txtEntered = value;
RaisePropertyChanged(TxtEnteredPropertyName);
}
}
try this with wild card search:
System.Text.RegularExpressions.Regex regEx = new System.Text.RegularExpressions.Regex(EventName);
var display = SearchEventCollection
.Where<string>(item => regEx.IsMatch(item.EventName))
.ToList<string>();
or
var display = SearchEventCollection.Where(q=>q.EventName.ToLower().Contains(EventName));

Bind content control depends on user click button

I am writing a wpf application and implements mvvm light tool. The GUI looks like:
Every time when a user click on button, it should change the content on the right side, marked with red border. The XAML code:
<igWpf:XamRibbonWindow x:Class="BackupCustomizing.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ignore="http://www.ignore.com"
xmlns:ig="http://schemas.infragistics.com/xaml"
xmlns:views="clr-namespace:BackupCustomizing.Views"
xmlns:igWpf="http://schemas.infragistics.com/xaml/wpf"
mc:Ignorable="d ignore"
Height="400"
Width="700"
Title="Backup customizing V0.1"
DataContext="{Binding Main, Source={StaticResource Locator}}" ResizeMode="NoResize">
<igWpf:XamRibbonWindow.Resources>
<DataTemplate DataType="{x:Type views:ServerView}"></DataTemplate>
</igWpf:XamRibbonWindow.Resources>
<ig:ThemeManager.Theme>
<ig:Office2013Theme />
</ig:ThemeManager.Theme>
<igWpf:RibbonWindowContentHost x:Name="_content"
Theme="Office2013"
igWpf:RibbonWindowContentHost.ApplicationAccentColor="#0072C6">
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<views:NavigationView Grid.Column="0"/>
<ContentPresenter Content="{Binding}" Grid.Column="1"/>
</Grid>
</igWpf:RibbonWindowContentHost>
</igWpf:XamRibbonWindow>
and the code behind:
using System.Windows;
using BackupCustomizing.ViewModel;
using Infragistics.Themes;
using Infragistics.Windows.Ribbon;
namespace BackupCustomizing
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : XamRibbonWindow
{
/// <summary>
/// Initializes a new instance of the MainWindow class.
/// </summary>
public MainWindow()
{
InitializeComponent();
Closing += (s, e) => ViewModelLocator.Cleanup();
}
}
}
As you can see the code above, I tried with:
<igWpf:XamRibbonWindow.Resources>
<DataTemplate DataType="{x:Type views:ServerView}"></DataTemplate>
</igWpf:XamRibbonWindow.Resources>
and the content presenter:
<ContentPresenter Content="{Binding}" Grid.Column="1"/>
and here I stocked, how to continue?
The ViewModel code:
using BackupCustomizing.Model;
using GalaSoft.MvvmLight;
namespace BackupCustomizing.ViewModel
{
/// <summary>
/// This class contains properties that the main View can data bind to.
/// <para>
/// See http://www.galasoft.ch/mvvm
/// </para>
/// </summary>
public class MainViewModel : ViewModelBase
{
private readonly IDataService _dataService;
private string _welcomeTitle = string.Empty;
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel(IDataService dataService)
{
_dataService = dataService;
_dataService.GetData(
(item, error) =>
{
});
}
}
}
To get you code working in minimum changes
public class MainViewModel : ViewModelBase
{
private readonly IDataService _dataService;
private string _welcomeTitle = string.Empty;
private ViewModelBase detailsViewModel = null;
public ViewModelBase DetailsViewModel{
get { return detailsViewModel;}
set { detailsViewModel = value; RaisePropertyChanged("DetailsViewModel"); }
}
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel(IDataService dataService)
{
_dataService = dataService;
_dataService.GetData(
(item, error) =>
{
detailsViewModel = new ServerViewModel(item); //ViewModel for the ServerView
});
}
}
<igWpf:XamRibbonWindow.Resources>
<DataTemplate DataType="{x:Type viewModel:ServerViewModel}">
<views:ServerView />
</DataTemplate>
</igWpf:XamRibbonWindow.Resources>
<ContentPresenter Content="{Binding DetailsViewModel}" Grid.Column="1"/>
There are other techniques to do MVVM, I am just showing the way to do it with the approach you have started with. Problem with this approach is that it will not scale well to large number of views in the ContentPresenter.

Header text shifted in TreeView control

I am playing with WPF TreeView control and facing strange problem.
When I add TreeView items programmatically all working correct, but in case I have added items through binding - I have Items with gap in header:
furthermore, this gap is only one "sensitive" part of the TreeItem's line. I cant select item by clicking on the text, it can be selected only if I click on the gap area.
Here is my code:
namespace WPFTreeViewExperience
{
/// <summary>
/// Data item interface
/// </summary>
public interface IMyTree
{
string Title { get; set; }
List<IMyTree> Items { get; set; }
}
/// <summary>
/// Hierarchical data model
/// </summary>
public class MyTreeLevel : IMyTree
{
public string Title { get; set; }
public List<IMyTree> Items { get; set; }
public MyTreeLevel(string Title, params MyTreeLevel[] Items)
{
this.Title = Title;
this.Items = new List<IMyTree>();
foreach (MyTreeLevel item in Items)
{
this.Items.Add(item);
}
}
}
/// <summary>
/// Viewmodel
/// </summary>
public class MyTreeViewModel : INotifyPropertyChanged
{
private void NotifyChanges(string PropName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(PropName));
}
}
private List<MyTreeLevel> _Tree;
public List<MyTreeLevel> MyTree
{
get
{
return _Tree;
}
set
{
_Tree = value;
NotifyChanges("MyTree");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public MyTreeViewModel()
{
List<MyTreeLevel> simpleTree = new List<MyTreeLevel>();
simpleTree.Add(new MyTreeLevel("1-0", new MyTreeLevel("1-1"),
new MyTreeLevel("1-2",
new MyTreeLevel("1-2-1"),
new MyTreeLevel("1-2-2")
),
new MyTreeLevel("1-3")));
simpleTree.Add(new MyTreeLevel("2-0", new MyTreeLevel("2-1"),
new MyTreeLevel("2-2",
new MyTreeLevel("2-2-1"),
new MyTreeLevel("2-2-2"),
new MyTreeLevel("2-3"))));
MyTree = simpleTree;
}
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
TreeExample.DataContext = new MyTreeViewModel();
}
}
}
and my XAML code:
<Window x:Class="WPFTreeViewExperience.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPFTreeViewExperience"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TreeView Name="TreeExample" ItemsSource="{Binding MyTree}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Items}" DataType="{x:Type local:MyTreeLevel}">
<TreeViewItem Header="{Binding Title}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</Window>
What is wrong with my binding?
I think that ItemTemplate should be something like this:
<HierarchicalDataTemplate ItemsSource="{Binding Items}" DataType="{x:Type local:MyTreeLevel}">
<Grid>
<TextBlock Margin="0" Text="{Binding Path=Title}" />
</Grid>
</HierarchicalDataTemplate>

Categories

Resources