xceed wpf propertygrid collection select - c#

i'm new in WPF and may be it's stupid question, but...) a have custom properties class visualased by xceed wpf propertygrid
public class ShopProperties
{
private readonly ObservableCollection<string> _cars = new ObservableCollection<string>();
[Category(#"CarsShop")]
[DisplayName(#"CarsCollection")]
public ObservableCollection<string> CarsCollection { get {return _cars;}}
[Browsable(false)]
private string SelectedCar {get; set;}
}
What simplest and finest PropertyGrid editor(or custom editor) i need to use to assign SelectedCar element from CarsCollection?

after some search and reading http://wpftoolkit.codeplex.com/wikipage?title=PropertyGrid&referringTitle=Documentation
i think its minimum two ways in my case.
1. Customise xctk:CollectionControl and edit XAML.
<xctk:PropertyGrid Name="_generalPropertyGrid" DockPanel.Dock="Top"
ShowSearchBox="False" ShowSortOptions="False" ShowTitle="False" NameColumnWidth="120" BorderThickness="0">
<xctk:PropertyGrid.EditorDefinitions>
<xctk:EditorTemplateDefinition TargetProperties="CarsCollection">
<xctk:EditorTemplateDefinition.EditingTemplate>
<DataTemplate>
<xctk:CollectionControl SelectedItem="{Binding Path=SelectedCar}"/>
</DataTemplate>
</xctk:EditorTemplateDefinition.EditingTemplate>
</xctk:EditorTemplateDefinition>
</xctk:PropertyGrid.EditorDefinitions>
</xctk:PropertyGrid>
2. Create own UserControl that implements the ITypeEditor
see datails in http://wpftoolkit.codeplex.com/wikipage?title=PropertyGrid&referringTitle=Documentation Select by ComboBox. i choose this way.
<UserControl x:Class="proj_namespace.CarSelector"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
x:Name="CarSelector"
d:DesignHeight="25" d:DesignWidth="200">
<Grid>
<ComboBox ItemsSource="{Binding Value, ElementName=CarSelector}" SelectionChanged="Selector_OnSelectionChanged"/>
</Grid>
</UserControl>
And class code behind:
public partial class CarSelector : ITypeEditor
{
public CarSelector()
{
InitializeComponent();
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(ObservableCollection<string>), typeof(CarSelector),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public string Value
{
get { return (string)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public FrameworkElement ResolveEditor(PropertyItem propertyItem)
{
var binding = new Binding("Value");
binding.Source = propertyItem;
binding.Mode = propertyItem.IsReadOnly ? BindingMode.OneWay : BindingMode.TwoWay;
BindingOperations.SetBinding(this, ValueProperty, binding);
return this;
}
private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender != null)
MainWindow.Instance._properties.SelectedCar = (sender as ComboBox).SelectedItem as string;
}
}
and finally add custom editor line above property
[Editor(typeof(CarSelector), typeof(CarSelector))]
public ObservableCollection<string> CarsCollection { get { return _securities; } }

I don't know why you are using propertygrid instead of a datagrid, property grid is used to see and change the properties of an object in memory (like one of the elements of the WPF window), it's like the Property window in visual studio that shows all the properties of the selected object.
if you want to show a collection, even if you want to edit it afterwards, you should try xceed data grid, it will be more up your ally i think.
But anyways, you can bind the selectedProperty property of the propertygrid to the selected car, or you can use the selectedProperty property of propertygrid directly and check if it's a car.

Related

Data Binding for ListBox ItemsSource

I'm having trouble setting up an automatic binding.
I have a simple WPF application with two classes - MovieInfo (contains information about movie files on my filesystem) and a MediaScanner class that just returns a List<MovieInfo>. In my MainWindow.xaml, I have a ListBox:
<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="242" Margin="10,35,0,0" VerticalAlignment="Top" Width="237" d:ItemsSource="{Binding MovieList}"/>
Also in the XAML added to the <Window ...> is
Name="MainWindow1"
DataContext="{Binding ElementName=MainWindow1}"
In the code behind, I made a public property of the MainWindow : Window:
public ObservableCollection<MovieInfo> MovieList { get; set; }
In the constructor:
public MainWindow()
{
DataContext = this;
MovieList = new ObservableCollection<MovieInfo>();
InitializeComponent();
//this doesn't do anything for me
//listBox.ItemsSource = MovieList;
}
I have a button that calls:
private void button_Click(object sender, RoutedEventArgs e)
{
var scanner = new MediaScanner();
MovieList = new ObservableCollection<MovieInfo>(scanner.ScanAll().OrderBy(x => x.Title));
//listBox.ItemsSource = MovieList;
}
It's my understanding that this should take care of everything, yet the ListBox won't populate unless I uncomment the listBox.ItemsSource = MovieList; where it is in the button_Click.
What am I missing?
The ListBox does not bind the MovieList at runtime because you prefixed ItemsSource with d.
After adding the namespaces, you can put d: in front of any attribute or control to show it only in the XAML Designer but not at runtime. [...]
You can use d: with attributes for any UWP or WPF .NET Core control, like colors, font sizes, and spacing. You can even add it to the control itself.
These namespaces are defined on your XAML root element.
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
In order to make the binding work at runtime, remove the d: or add another ItemsSource without the d: prefix so that you have different sources for design and runtime.
<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="242" Margin="10,35,0,0" VerticalAlignment="Top" Width="237" ItemsSource="{Binding MovieList}"/>
<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="242" Margin="10,35,0,0" VerticalAlignment="Top" Width="237" d:ItemsSource="{Binding DesignTimeMovieList}" ItemsSource="{Binding MovieList}"/>
Another issue is that you neither implement a dependency property for your movie list collection nor INotifyPropertyChanged. In practice this means although you assign a new collection to the MovieList property in your button click event handler, the binding does not get notified of the change and will still use the old collection instance. Of course listBox.ItemsSource = MovieList; would work here, but it assigns the collection directly and overwrites the binding, so this is a different solution.
In the long run, you should probably apply the MVVM pattern and separate the data to be bound in a view model that implements INotifyPropertyChanged, which solves your issue and at the same time separates your view and your logic and data that are then connected via bindings.
Example of a dependency property for your window.
public partial class MainWindow : Window
{
public ObservableCollection<MovieInfo> MovieList
{
get => (ObservableCollection<MovieInfo>)GetValue(MovieListProperty);
set => SetValue(MovieListProperty, value);
}
public static readonly DependencyProperty MovieListProperty = DependencyProperty.Register(
nameof(MovieList), typeof(ObservableCollection<MovieInfo>), typeof(MainWindow), new PropertyMetadata(null));
public MainWindow()
{
DataContext = this;
MovieList = new ObservableCollection<MovieInfo>();
InitializeComponent();
// ...other code.
}
private void button_Click(object sender, RoutedEventArgs e)
{
var scanner = new MediaScanner();
MovieList = new ObservableCollection<MovieInfo>(scanner.ScanAll().OrderBy(x => x.Title));
}
// ...other code.
}
Example for a view model in case you want to move to MVVM.
public class MyViewModel : INotifyPropertyChanged
{
private ObservableCollection<MovieInfo> _movieList;
public ObservableCollection<MovieInfo> MovieList
{
get => _movieList;
set
{
if (_movieList == value)
return;
_movieList = value;
OnPropertyChanged();
}
}
// ...other code.
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
As a final remark, you should consider reusing the ObservableCollection<MovieInfo> MovieList instead of creating and assigning a new one each time. This type of collection provides change notifications for adding, removing and replacing items, which will automatically be reflected in the user interface. Exposing an observable collection, but instead of modifying, replacing it, is pointless. If a collection is always replaced, a simple List<T> will do the same.

Add a DependencyProperty to ThreadSeparatedImage class of Meta.Vlc library to follow MVVM model

I'm working on a Video Player application using C# and WPF.
I have to follow a MVVM model for this WPF project.
I want to use the Meta.Vlc library to display severals RTSP stream in a grid.
So, I add a "ThreadSeparatedImage" object in my VideoPlayControl XAML (view part of the model):
VideoPlayerControl.xaml:
<UserControl x:Class="TVSCS_View.VideoDisplay.VideoPlayerControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ctrl="clr-namespace:TVSCS_View.VideoDisplay"
xmlns:vlc="clr-namespace:Vlc.Wpf;assembly=Vlc.Wpf"
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:helpers="clr-namespace:TVSCS_View.Helpers"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="300"
x:Name="controlVideoDisplay"
DataContext="{Binding ElementName=controlVideoDisplay}">
<Border BorderBrush="Black"
BorderThickness="1">
<Grid x:Name="videoPlayerGrid"
Margin="5,5,5,5">
<TextBlock x:Name="videoNameText"
HorizontalAlignment="Left"
Margin="10,10,0,0"
Text="{Binding Path=VideoStreamName, Mode=OneWay}"
VerticalAlignment="Top" Width="100"/>
<vlc:ThreadSeparatedImage x:Name="videoSource"
ThreadImageSource={Binding Path=ImgSource}" />
</Grid>
</Border>
</UserControl>
Then, I have to implement a DependencyProperty to follow a MVVM model. So I modified Meta.Vlc "ThreadSeparatedImage.cs" class, adding the following code:
public static readonly DependencyProperty ThreadImageSourceProperty =
DependencyProperty.RegisterAttached("ThreadImageSource",
typeof(ImageSource),
typeof(ThreadSeparatedImage),
new FrameworkPropertyMetadata(null,
new PropertyChangedCallback(ImageSourcePropertyChanged)));
private static void ImageSourcePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
ThreadSeparatedImage threadSeparatedImage = obj as ThreadSeparatedImage;
if (null != threadSeparatedImage)
{
threadSeparatedImage.Source = (ImageSource)args.NewValue;
}
}
public static void SetImageSource(UIElement element, ImageSource imageSource)
{
element.SetValue(ThreadImageSourceProperty, imageSource);
}
public static ImageSource GetImageSource(UIElement element)
{
return (ImageSource)element.GetValue(ThreadImageSourceProperty);
}
Finally, I have a view model associated to my "VideoPlayerControl" XAML, with the following properties and methods:
VideoPlayerViewModel.cs
private ImageSource _imageSource;
public ImageSource ImgSource
{
get { return _imageSource; }
set
{
if (true == SetProperty(ref _imageSource, value))
{
RaisePropertyChanged("ImgSource");
}
}
}
public void AddVLCPlayer(VlcPlayer mediaPlayer)
{
mediaPlayer.Stop();
mediaPlayer.LoadMedia(#"rtsp://10.2.92.110:554/profile5/media.smp");
mediaPlayer.Play();
ImgSource = mediaPlayer.VideoSource;
mediaPlayer.VideoSourceChanged += MediaPlayer_VideoSourceChanged;
}
private void MediaPlayer_VideoSourceChanged(object sender, VideoSourceChangedEventArgs e)
{
ImgSource = e.NewVideoSource;
}
"AddVLCPlayer" method could be called at initialization.
With this code, the video stream is neither displayed or updated.
Any idea? Thanks.
A Binding like
ThreadImageSource="{Binding Path=ImgSource}"
in the XAML of your UserControl requires that the DataContext of the control is an instance of your view model, i.e. class VideoPlayerViewModel.
This is usually achieved somewhere in your MainWindow code, where you might have something like this:
public MainWindow()
{
InitializeComponent();
DataContext = new VideoPlayerViewModel();
}
Then the DataContext is inherited by your UserControl somewhere in the MainWindow's XAML tree.
However, this will only work if the UserControl does not explicitly set its DataContext, as you do here:
<UserControl ... x:Name="controlVideoDisplay"
DataContext="{Binding ElementName=controlVideoDisplay}">
Remove that DataContext assignment. As a general rule, never set the DataContext of a UserControl explictly, regardless of what they tell you in online tutorials and blog posts.
Besides that, you should probably avoid modifying the code of the Vlc ThreadSeparatedImage class, and instead create a derived class with your dependency property:
public class MyThreadSeparatedImage : ThreadSeparatedImage
{
public static readonly DependencyProperty ThreadImageSourceProperty =
DependencyProperty.Register(
"ThreadImageSource",
typeof(ImageSource),
typeof(MyThreadSeparatedImage),
new FrameworkPropertyMetadata(null, ThreadImageSourcePropertyChanged));
private static void ThreadImageSourcePropertyChanged(
DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
((ThreadSeparatedImage)obj).Source = (ImageSource)args.NewValue;
}
public ImageSource ThreadImageSource
{
get { return (ImageSource)element.GetValue(ThreadImageSourceProperty); }
set { element.SetValue(ThreadImageSourceProperty, imageSource); }
}
}
I use a classic Image control too.
In XAML file (view part):
<Image Source="{Binding Path=VideoImageSource}" />
In my associated view model (VidePlayerViewModel.cs):
private ImageSource _videoImageSource;
public ImageSource VideoImageSource
{
get { return _videoImageSource; }
set
{
if (true == SetProperty(ref _videoImageSource, value))
{
RaisePropertyChanged("VideoImageSource");
}
}
}
public void AddVLCPlayer(string videoStreamPath)
{
//Create MediaPlayer:
VlcMediaPlayer = new VlcPlayer(false);
VlcMediaPlayer.Initialize(Globals.pathLibVlc);
//Start player
VlcMediaPlayer.Stop();
VlcMediaPlayer.LoadMedia(videoStreamPath);
VlcMediaPlayer.Play();
//Link VLC player to image source:
VideoImageSource = VlcMediaPlayer.VideoSource;
VlcMediaPlayer.VideoSourceChanged += MediaPlayer_VideoSourceChanged;
}

Binding dependency property in extended textbox to UserControl

I have extended the functionality of a textbox, below is part of the class with an attached property RegularExpressionEnabled:
public class AlphaNumericTextBox : TextBox
{
#region DependencyProperties
public static readonly DependencyProperty RegularExpressionEnabledProperty =
DependencyProperty.Register("RegularExpressionEnabled", typeof(bool), typeof(AlphaNumericTextBox),
new UIPropertyMetadata(false));
public bool RegularExpressionEnabled
{
get { return (bool)GetValue(RegularExpressionEnabledProperty); }
set { SetValue(RegularExpressionEnabledProperty, value); Console.WriteLine("RegularExpressionEnabled:" + (bool)value); }
}
}
This class is then incorporated into a UserControl.
XAML:
<UserControl x:Class="Libs_ViewLevel.Controls.FilterItemControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Libs_ViewLevel"
xmlns:ctrls="clr-namespace:Libs_ViewLevel.Controls"
x:Name="UserControl">
<Grid x:Name="LayoutRoot" Height="Auto" >
<ctrls:AlphaNumericTextBox x:Name="AlphaNumericTbx"
Grid.ColumnSpan="2"
Text="{Binding AlphaNumericValue}"
RegularExpressionEnabled="{Binding RegExpressionEnabled}" />
</Grid>
</UserControl>
Code-Behind:
public partial class FilterItemControl : UserControl
{
public FilterItemControl()
{
InitializeComponent();
this.DataContext = this;
}
public bool RegExpressionEnabled
{
get { return (bool)GetValue(RegExpressionEnabledProperty); }
set { SetValue(RegExpressionEnabledProperty, value); Console.WriteLine("RegExpressionEnabled:" + (bool)value); }
}
public static readonly DependencyProperty RegExpressionEnabledProperty =
DependencyProperty.Register("RegExpressionEnabled", typeof(bool), typeof(FilterItemControl),
new UIPropertyMetadata(false));
I have placed the UserControl in a Window and in the code-behind of this window, placed this statement: txtbox.RegExpressionEnabled = true;
In both RegularExpressionEnabled and RegExpressionEnabled you can see that I have placed a Console.Write().
The RegExpressionEnabled prints to the Output screen, however it does not get to the second, RegularExpressionEnabled.
Something is wrong in my binding on AlphaNumericTextBox RegularExpressionEnabled="{Binding RegExpressionEnabled}", can someone point me in the right direction?
In the code behind of FilterItemControl, RegExpressionEnabled property should be a standard property as this is what your new textbox is binding to. You don't need the dependency property in the FilterItemControl code behind either as you already have it in the new textbox.
Now instead of setting txtbox.RegExpressionEnabled = true (which actually should be txtbox.RegularExpressionEnabled = true), you set the RegExpressionEnabled property to true and the textbox will bind to this.
You will also need to raise the PropertyChanged event in the setter of the RegExpressionEnabled property to trigger the databinding.

Proper way to use CollectionViewSource in ViewModel

I used Drag and Drop to bind Data Source object (a DB model) to DataGrid (basically following this example in Entity Framework Databinding with WPF.
Everything works fine with this implementation.
XAML
<Window.Resources>
<CollectionViewSource x:Key="categoryViewSource"
d:DesignSource="{d:DesignInstance {x:Type local:Category}, CreateList=True}"/>
</Window.Resources>
<Grid DataContext="{StaticResource categoryViewSource}">
..
Code Behind
private void Window_Loaded(object sender, RoutedEventArgs e)
{
System.Windows.Data.CollectionViewSource categoryViewSource =
((System.Windows.Data.CollectionViewSource)(this.FindResource("categoryViewSource")));
_context.Categories.Load();
categoryViewSource.Source = _context.Categories.Local;
}
ViewModel
public MainWindow()
{
InitializeComponent();
this.DataContext = new MyViewModel();
}
However, when I try to use the same code from within ViewModel, it doesn‘t work (FindResource is not available), besides, I don’t think this is the right approach (i.e. to use x:Key in MVVM).
I would really appreciate any help to point me what is the right way to implement CollectionViewSource and DataBinding with DataGrid.
You have two options to use CollectionViewSource properly with MVVM -
Expose an ObservableCollection of items (Categories in your case) through your ViewModel and create CollectionViewSource in XAML like this -
<CollectionViewSource Source="{Binding Path=Categories}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="CategoryName" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
scm: xmlns:scm="clr-namespace:System.ComponentModel;assembly=Wind‌​owsBase"
see this - Filtering collections from XAML using CollectionViewSource
Create and Expose an ICollectionView directly from your ViewModel
see this - How to Navigate, Group, Sort and Filter Data in WPF
Following example shows how to create a collection view and
bind it to a ListBox
View XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
x:Class="CustomerView">
<ListBox ItemsSource={Binding Customers} />
</Window>
View Codebehind:
public class CustomerView : Window
{
public CustomerView()
{
DataContext = new CustomerViewModel();
}
}
ViewModel:
public class CustomerViewModel
{
private readonly ICollectionView customerView;
public ICollectionView Customers
{
get { return customerView; }
}
public CustomerViewModel()
{
IList<Customer> customers = GetCustomers();
customerView = CollectionViewSource.GetDefaultView( customers );
}
}
Update:
Q. If there is no property to sort on? e.g. if there is an ObservableCollection of string or int?
A. In that case you can Simply use . as the property name:
<scm:SortDescription PropertyName="." />
I found that it is handy to have a CollectionViewSource in my ViewModel and bind the ListBox (in my case) to the CollectionViewSource.View while setting the CollectionViewSource.Source to be the list I want to use.
Like so:
ViewModel:
public DesignTimeVM() //I'm using this as a Design Time VM
{
Items = new List<Foo>();
Items.Add(new Foo() { FooProp= "1", FooPrep= 20.0 });
Items.Add(new Foo() { FooProp= "2", FooPrep= 30.0 });
FooViewSource = new CollectionViewSource();
FooViewSource.Source = Items;
SelectedFoo = Items.First();
//More code as needed
}
XAML:
<ListBox ItemsSource="{Binding FooViewSource.View}" SelectedItem="{Binding SelectedFoo}"/>
This means I can do neat stuff in the VM as needed (from https://blogs.msdn.microsoft.com/matt/2008/08/28/collectionview-deferrefresh-my-new-best-friend/ ):
using (FooViewSource.DeferRefresh())
{
//Remove an old Item
//add New Item
//sort list anew, etc.
}
I suppose this is possible when using the ICollectionView object also, but the demo code in the blog link seems to be some codebehind stuff, refering the listbox directly, which I'm trying to avoid.
BTW before you ask, here's how you use a Design Time VM: WPF Design Time View Model
Just for reference, another way is to use an attached property on the CollectionViewSource which then pipes the functions to the ViewModel (Implementing an Interface).
This is a very basic Demonstration just for filtering, it would need some work for e.g. a second Collection on the VM but i think it's enough to show the general technique.
If this is better or worse than the other methods is up for discussion, i just wanted to point out, that there's another way of doing this
Definition of attached Property:
public static class CollectionViewSourceFilter
{
public static IFilterCollectionViewSource GetFilterObject(CollectionViewSource obj)
{
return (IFilterCollectionViewSource)obj.GetValue(FilterObjectProperty);
}
public static void SetFilterObject(CollectionViewSource obj, IFilterCollectionViewSource value)
{
obj.SetValue(FilterObjectProperty, value);
}
public static void FilterObjectChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.OldValue is IFilterCollectionViewSource oldFilterObject
&& sender is CollectionViewSource oldCvs)
{
oldCvs.Filter -= oldFilterObject.Filter;
oldFilterObject.FilterRefresh -= (s, e2) => oldCvs.View.Refresh();
}
if (e.NewValue is IFilterCollectionViewSource filterObject
&& sender is CollectionViewSource cvs)
{
cvs.Filter += filterObject.Filter;
filterObject.FilterRefresh += (s,e2) => cvs.View.Refresh();
}
}
public static readonly DependencyProperty FilterObjectProperty = DependencyProperty.RegisterAttached(
"FilterObject",
typeof(Interfaces.IFilterCollectionViewSource),
typeof(CollectionViewSourceFilter),
new PropertyMetadata(null,FilterObjectChanged)
);
}
Interface:
public interface IFilterCollectionViewSource
{
void Filter(object sender, FilterEventArgs e);
event EventHandler FilterRefresh;
}
usage in xaml:
<CollectionViewSource
x:Key="yourKey"
Source="{Binding YourCollection}"
classes:CollectionViewSourceFilter.FilterObject="{Binding}" />
and usage in the ViewModel:
class YourViewModel : IFilterCollectionViewSource
{
public event EventHandler FilterRefresh;
private string _SearchTerm = string.Empty;
public string SearchTerm
{
get { return _SearchTerm; }
set {
SetProperty(ref _SearchTerm, value);
FilterRefresh?.Invoke(this, null);
}
}
private ObservableCollection<YourItemType> _YourCollection = new ObservableCollection<YourItemType>();
public ObservableCollection<YourItemType> YourCollection
{
get { return _YourCollection; }
set { SetProperty(ref _YourCollection, value); }
}
public void Filter(object sender, FilterEventArgs e)
{
e.Accepted = (e.Item as YourItemType)?.YourProperty?.ToLower().Contains(SearchTerm.ToLower()) ?? true;
}
}

How do I get a UserControl derived class thats bound to ObservableCollection to respond to adds?

My collection seems fine as I am able to use a ListView and it responds correctly to adds, however when I nest a listview into a UserControl it doesn't. I've provided the pertinent code.
I've created a UserControl derived class in this fashion:
public partial class MyCtrl: UserControl
{
#region Static Properties
public static readonly DependencyProperty ItemsSourceProperty =
ItemsControl.ItemsSourceProperty.AddOwner(
typeof(MyCtrl),
new PropertyMetadata(MyCtrl.ItemsSourcePropertyChangedCallback));
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static void ItemsSourcePropertyChangedCallback(
DependencyObject controlInstance,
DependencyPropertyChangedEventArgs e)
{
MyCtrl myInstance=(MyCtrl)controlInstance;
myInstance.nestedList.ItemsSource=e.NewValue as IEnumerable;
}
}
With the XAML like this:
<UserControl x:Class="MyCtrl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<ListView Name="nestedList" />
</Grid>
</UserControl>
My consuming XAML looks like this:
<MyCtrl x:Name="myInstance" ItemsSource="{Binding Path=MyCollection}" />
Where the collection is defined like this:
public static readonly DependencyProperty MyCollectionProperty =
DependencyProperty.Register("MyCollection",
typeof(ObservableCollection<MyObject>),
typeof(ConsumingObject),
new PropertyMetadata(new ObservableCollection<MyObject>());
public ObservableCollection<MyObject> MyCollection
{
get { return (ObservableCollection<MyObject>)this.GetValue(MyCollectionProperty); }
set { this.SetValue(MyCollectionProperty, value); }
}
maybe you want to register an event handler on CollectionChanged if your ItemSource is an ObservableCollection< T >
This questions maybe can help.
What is the DataContext of myInstance?
Was the code able to go to this line?
myInstance.nestedList.ItemsSource=e.NewValue as IEnumerable;
If yes then is nestedList null or not?

Categories