Accessing attached property collection from ViewModel
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
I have a custom control LookupPanelView
which consists of a TextBox
and a ListBox
. It has an attached property ItemsSource
which the ListBox binds to so the bound data can be set from outside the control.
public partial class LookupPanelView : UserControl
{
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(LookupPanelView));
public IEnumerable ItemsSource
{
get => (IEnumerable)GetValue(ItemsSourceProperty);
set => SetValue(ItemsSourceProperty, value);
}
public LookupPanelView()
{
InitializeComponent();
}
}
The control's ItemsSource
is bound to a property in my main ViewModel which decides what data to display.
public class MainViewModel : ViewModelBase
{
public ObservableCollection<DomainObject> LookupPanelItems { get; private set; }
public MainViewModel()
{
LookupPanelItems = // Fetch the data to display in the control.
}
}
<Window x:Class="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"
mc:Ignorable="d"
UseLayoutRounding="True">
<Grid>
<lookupPanelView:LookupPanelView Grid.Column="0" ItemsSource="{Binding LookupPanelItems}"/>
</Grid>
I would like to extend the custom control to have search functionality where you type in the TextBox
and it selects a matching item from the ListBox
. This logic should be contained in the control since it should be aware of how to search it's own items. I think I need to give the control it's own ViewModel to hold the logic but then how do I access the attached property ItemsSource
in the ViewModel to search the items? I would like to avoid using code-behind as much as possible for maintainability and testability.
c# wpf mvvm binding viewmodel
add a comment |
I have a custom control LookupPanelView
which consists of a TextBox
and a ListBox
. It has an attached property ItemsSource
which the ListBox binds to so the bound data can be set from outside the control.
public partial class LookupPanelView : UserControl
{
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(LookupPanelView));
public IEnumerable ItemsSource
{
get => (IEnumerable)GetValue(ItemsSourceProperty);
set => SetValue(ItemsSourceProperty, value);
}
public LookupPanelView()
{
InitializeComponent();
}
}
The control's ItemsSource
is bound to a property in my main ViewModel which decides what data to display.
public class MainViewModel : ViewModelBase
{
public ObservableCollection<DomainObject> LookupPanelItems { get; private set; }
public MainViewModel()
{
LookupPanelItems = // Fetch the data to display in the control.
}
}
<Window x:Class="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"
mc:Ignorable="d"
UseLayoutRounding="True">
<Grid>
<lookupPanelView:LookupPanelView Grid.Column="0" ItemsSource="{Binding LookupPanelItems}"/>
</Grid>
I would like to extend the custom control to have search functionality where you type in the TextBox
and it selects a matching item from the ListBox
. This logic should be contained in the control since it should be aware of how to search it's own items. I think I need to give the control it's own ViewModel to hold the logic but then how do I access the attached property ItemsSource
in the ViewModel to search the items? I would like to avoid using code-behind as much as possible for maintainability and testability.
c# wpf mvvm binding viewmodel
I would vote against the ViewModel for a UserControl. This functionality is specific to the UserControl and should never have any connection with ViewModel it should only expect data and filter. BTWLookupPanelView
reeks ofDevExpress
.
– XAMlMAX
Jan 3 at 15:29
@XAMlMAX Thanks for your suggestion. Would you implement it with old-school style events in the code behind then? I'm not sure what you mean "reeks of DevExpress"?
– Codemunkie
Jan 3 at 15:45
The idea behind the user controls is that they should operate without knowledge about view models. So your control should filter the items it has in it's collection, and that is it's ONLY concern. When I used UC's that's what I did with code behind. Just make sure to implement it for general purpose and not dependant on a specific type of objects in it's collection. And for Dx never mind :-)
– XAMlMAX
Jan 3 at 15:58
add a comment |
I have a custom control LookupPanelView
which consists of a TextBox
and a ListBox
. It has an attached property ItemsSource
which the ListBox binds to so the bound data can be set from outside the control.
public partial class LookupPanelView : UserControl
{
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(LookupPanelView));
public IEnumerable ItemsSource
{
get => (IEnumerable)GetValue(ItemsSourceProperty);
set => SetValue(ItemsSourceProperty, value);
}
public LookupPanelView()
{
InitializeComponent();
}
}
The control's ItemsSource
is bound to a property in my main ViewModel which decides what data to display.
public class MainViewModel : ViewModelBase
{
public ObservableCollection<DomainObject> LookupPanelItems { get; private set; }
public MainViewModel()
{
LookupPanelItems = // Fetch the data to display in the control.
}
}
<Window x:Class="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"
mc:Ignorable="d"
UseLayoutRounding="True">
<Grid>
<lookupPanelView:LookupPanelView Grid.Column="0" ItemsSource="{Binding LookupPanelItems}"/>
</Grid>
I would like to extend the custom control to have search functionality where you type in the TextBox
and it selects a matching item from the ListBox
. This logic should be contained in the control since it should be aware of how to search it's own items. I think I need to give the control it's own ViewModel to hold the logic but then how do I access the attached property ItemsSource
in the ViewModel to search the items? I would like to avoid using code-behind as much as possible for maintainability and testability.
c# wpf mvvm binding viewmodel
I have a custom control LookupPanelView
which consists of a TextBox
and a ListBox
. It has an attached property ItemsSource
which the ListBox binds to so the bound data can be set from outside the control.
public partial class LookupPanelView : UserControl
{
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(LookupPanelView));
public IEnumerable ItemsSource
{
get => (IEnumerable)GetValue(ItemsSourceProperty);
set => SetValue(ItemsSourceProperty, value);
}
public LookupPanelView()
{
InitializeComponent();
}
}
The control's ItemsSource
is bound to a property in my main ViewModel which decides what data to display.
public class MainViewModel : ViewModelBase
{
public ObservableCollection<DomainObject> LookupPanelItems { get; private set; }
public MainViewModel()
{
LookupPanelItems = // Fetch the data to display in the control.
}
}
<Window x:Class="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"
mc:Ignorable="d"
UseLayoutRounding="True">
<Grid>
<lookupPanelView:LookupPanelView Grid.Column="0" ItemsSource="{Binding LookupPanelItems}"/>
</Grid>
I would like to extend the custom control to have search functionality where you type in the TextBox
and it selects a matching item from the ListBox
. This logic should be contained in the control since it should be aware of how to search it's own items. I think I need to give the control it's own ViewModel to hold the logic but then how do I access the attached property ItemsSource
in the ViewModel to search the items? I would like to avoid using code-behind as much as possible for maintainability and testability.
c# wpf mvvm binding viewmodel
c# wpf mvvm binding viewmodel
asked Jan 3 at 12:19
CodemunkieCodemunkie
518
518
I would vote against the ViewModel for a UserControl. This functionality is specific to the UserControl and should never have any connection with ViewModel it should only expect data and filter. BTWLookupPanelView
reeks ofDevExpress
.
– XAMlMAX
Jan 3 at 15:29
@XAMlMAX Thanks for your suggestion. Would you implement it with old-school style events in the code behind then? I'm not sure what you mean "reeks of DevExpress"?
– Codemunkie
Jan 3 at 15:45
The idea behind the user controls is that they should operate without knowledge about view models. So your control should filter the items it has in it's collection, and that is it's ONLY concern. When I used UC's that's what I did with code behind. Just make sure to implement it for general purpose and not dependant on a specific type of objects in it's collection. And for Dx never mind :-)
– XAMlMAX
Jan 3 at 15:58
add a comment |
I would vote against the ViewModel for a UserControl. This functionality is specific to the UserControl and should never have any connection with ViewModel it should only expect data and filter. BTWLookupPanelView
reeks ofDevExpress
.
– XAMlMAX
Jan 3 at 15:29
@XAMlMAX Thanks for your suggestion. Would you implement it with old-school style events in the code behind then? I'm not sure what you mean "reeks of DevExpress"?
– Codemunkie
Jan 3 at 15:45
The idea behind the user controls is that they should operate without knowledge about view models. So your control should filter the items it has in it's collection, and that is it's ONLY concern. When I used UC's that's what I did with code behind. Just make sure to implement it for general purpose and not dependant on a specific type of objects in it's collection. And for Dx never mind :-)
– XAMlMAX
Jan 3 at 15:58
I would vote against the ViewModel for a UserControl. This functionality is specific to the UserControl and should never have any connection with ViewModel it should only expect data and filter. BTW
LookupPanelView
reeks of DevExpress
.– XAMlMAX
Jan 3 at 15:29
I would vote against the ViewModel for a UserControl. This functionality is specific to the UserControl and should never have any connection with ViewModel it should only expect data and filter. BTW
LookupPanelView
reeks of DevExpress
.– XAMlMAX
Jan 3 at 15:29
@XAMlMAX Thanks for your suggestion. Would you implement it with old-school style events in the code behind then? I'm not sure what you mean "reeks of DevExpress"?
– Codemunkie
Jan 3 at 15:45
@XAMlMAX Thanks for your suggestion. Would you implement it with old-school style events in the code behind then? I'm not sure what you mean "reeks of DevExpress"?
– Codemunkie
Jan 3 at 15:45
The idea behind the user controls is that they should operate without knowledge about view models. So your control should filter the items it has in it's collection, and that is it's ONLY concern. When I used UC's that's what I did with code behind. Just make sure to implement it for general purpose and not dependant on a specific type of objects in it's collection. And for Dx never mind :-)
– XAMlMAX
Jan 3 at 15:58
The idea behind the user controls is that they should operate without knowledge about view models. So your control should filter the items it has in it's collection, and that is it's ONLY concern. When I used UC's that's what I did with code behind. Just make sure to implement it for general purpose and not dependant on a specific type of objects in it's collection. And for Dx never mind :-)
– XAMlMAX
Jan 3 at 15:58
add a comment |
3 Answers
3
active
oldest
votes
CollectionViewSource with Filter will do the trick.
Here is the basic sample to use Filter on search using CollectionViewSource
Is it possible to use this technique to highlight the matching item without affecting the rest of the list? I.e. not filter the list but just select the matching item
– Codemunkie
Jan 3 at 13:02
The view doesn't return entries which are filtered. You might as well inject a predicate to decide which are to be highlighted.
– Andy
Jan 3 at 13:08
add a comment |
This logic should be contained in the control since it should be aware of how to search it's own items.
Why do you need a view model then? If the "logic should be contained in the control", then implement it there.
I think I need to give the control it's own ViewModel to hold the logic but then how do I access the attached property ItemsSource in the ViewModel to search the items?
This is in contradiction to your first sentence, but if the control really needs its own view model for some reason and the view model needs access to the control, you could simply inject with a reference to the control when you create the view model, e.g.:
public LookupPanelView()
{
InitializeComponent();
this.DataContext = new ViewModel(this);
}
But what you probably want is to create a custom control with a default template. This is just a class that inherit from Control
and has no code-behind or XAML file. Please refer to this tutorial for an example. A UserControl
is more like a composite view than a custom control with its own custom logic.
Just a note, if you set up the DataContext of the UC like this thenItemsSource
binding will look for that property in the UC and not the DataContext where it is being used. You need to preserve the DataContext inheritance so the Bindings can be resolved correctly.
– XAMlMAX
Jan 3 at 18:35
add a comment |
After a bit of thinking I came up with this sort of starting point for you.
First you create your control a bit like this:
<UserControl x:Class="SO_App.UC.SearchableListView"
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:local="clr-namespace:SO_App.UC"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid x:Name="root"><!-- This allows us to keep the Data Context inheritance -->
<Grid.Resources>
<CollectionViewSource Source="{Binding ItemsSource}" x:Key="Items"/> <!-- This is for us to use Filtering and so on -->
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox x:Name="txtSearch" Text="{Binding SearchTerm}"/>
<!-- Placeholder -->
<TextBlock IsHitTestVisible="False" Text="{Binding SearchTextPlaceHolder,TargetNullValue=Search, FallbackValue=Search}" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10,0,0,0" Foreground="DarkGray">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=txtSearch}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<ListView x:Name="lstItems" Grid.Row="1" ItemsSource="{Binding Source={StaticResource Items}}"/>
</Grid>
Root element keeps the Bidning to the user control in tact, while we can use the normal binding from the parent element in our main window.
Then in your MainWindow.xaml you would use it like this:
<Window x:Class="SO_App.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:vm="clr-namespace:VM;assembly=VM"
xmlns:model="clr-namespace:Model;assembly=Model"
xmlns:converter="clr-namespace:SO_App.Converters"
xmlns:uc="clr-namespace:SO_App.UC"
xmlns:local="clr-namespace:SO_App"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
<Grid>
<uc:SearchableListView SearchTextPlaceHolder="Search" ItemsSource="{Binding Users}">
<uc:SearchableListView.Resources>
<DataTemplate DataType="{x:Type model:User}">
<Grid>
<StackPanel>
<TextBlock Text="{Binding ID}"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</Grid>
</DataTemplate>
</uc:SearchableListView.Resources>
</uc:SearchableListView>
</Grid>
For the sake of this post here is the ViewModel
:
public class MainViewModel : BaseViewModel
{
public MainViewModel()
{
Users = new List<User>();
for (int i = 0; i < 6; i++)
{
Users.Add(new User
{
ID = i,
Name = $"John the {i + 1}",
State = i % 2 == 0 ? "CA" : "IL",
Cases = new List<Case>() { new Case { CaseID = (i + 1) * 10, Vendor = ((i + 1) * 10) - 2 }, new Case { CaseID = (i + 1) * 10, Vendor = ((i + 1) * 10) - 2 } }
});
}
}
}
And here is the user object:
namespace Model
{
public class User//Ideally you would have INPC implemented here
{
public int ID { get; set; }
public string Name { get; set; }
public string State { get; set; }
public List<Case> Cases { get; set; }
}
}
Hope this gives you enough information to start your implementation in the right direction and with as much MvvM as possible.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54022185%2faccessing-attached-property-collection-from-viewmodel%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
CollectionViewSource with Filter will do the trick.
Here is the basic sample to use Filter on search using CollectionViewSource
Is it possible to use this technique to highlight the matching item without affecting the rest of the list? I.e. not filter the list but just select the matching item
– Codemunkie
Jan 3 at 13:02
The view doesn't return entries which are filtered. You might as well inject a predicate to decide which are to be highlighted.
– Andy
Jan 3 at 13:08
add a comment |
CollectionViewSource with Filter will do the trick.
Here is the basic sample to use Filter on search using CollectionViewSource
Is it possible to use this technique to highlight the matching item without affecting the rest of the list? I.e. not filter the list but just select the matching item
– Codemunkie
Jan 3 at 13:02
The view doesn't return entries which are filtered. You might as well inject a predicate to decide which are to be highlighted.
– Andy
Jan 3 at 13:08
add a comment |
CollectionViewSource with Filter will do the trick.
Here is the basic sample to use Filter on search using CollectionViewSource
CollectionViewSource with Filter will do the trick.
Here is the basic sample to use Filter on search using CollectionViewSource
edited Jan 3 at 12:58
answered Jan 3 at 12:51


GopichandarGopichandar
1,75721338
1,75721338
Is it possible to use this technique to highlight the matching item without affecting the rest of the list? I.e. not filter the list but just select the matching item
– Codemunkie
Jan 3 at 13:02
The view doesn't return entries which are filtered. You might as well inject a predicate to decide which are to be highlighted.
– Andy
Jan 3 at 13:08
add a comment |
Is it possible to use this technique to highlight the matching item without affecting the rest of the list? I.e. not filter the list but just select the matching item
– Codemunkie
Jan 3 at 13:02
The view doesn't return entries which are filtered. You might as well inject a predicate to decide which are to be highlighted.
– Andy
Jan 3 at 13:08
Is it possible to use this technique to highlight the matching item without affecting the rest of the list? I.e. not filter the list but just select the matching item
– Codemunkie
Jan 3 at 13:02
Is it possible to use this technique to highlight the matching item without affecting the rest of the list? I.e. not filter the list but just select the matching item
– Codemunkie
Jan 3 at 13:02
The view doesn't return entries which are filtered. You might as well inject a predicate to decide which are to be highlighted.
– Andy
Jan 3 at 13:08
The view doesn't return entries which are filtered. You might as well inject a predicate to decide which are to be highlighted.
– Andy
Jan 3 at 13:08
add a comment |
This logic should be contained in the control since it should be aware of how to search it's own items.
Why do you need a view model then? If the "logic should be contained in the control", then implement it there.
I think I need to give the control it's own ViewModel to hold the logic but then how do I access the attached property ItemsSource in the ViewModel to search the items?
This is in contradiction to your first sentence, but if the control really needs its own view model for some reason and the view model needs access to the control, you could simply inject with a reference to the control when you create the view model, e.g.:
public LookupPanelView()
{
InitializeComponent();
this.DataContext = new ViewModel(this);
}
But what you probably want is to create a custom control with a default template. This is just a class that inherit from Control
and has no code-behind or XAML file. Please refer to this tutorial for an example. A UserControl
is more like a composite view than a custom control with its own custom logic.
Just a note, if you set up the DataContext of the UC like this thenItemsSource
binding will look for that property in the UC and not the DataContext where it is being used. You need to preserve the DataContext inheritance so the Bindings can be resolved correctly.
– XAMlMAX
Jan 3 at 18:35
add a comment |
This logic should be contained in the control since it should be aware of how to search it's own items.
Why do you need a view model then? If the "logic should be contained in the control", then implement it there.
I think I need to give the control it's own ViewModel to hold the logic but then how do I access the attached property ItemsSource in the ViewModel to search the items?
This is in contradiction to your first sentence, but if the control really needs its own view model for some reason and the view model needs access to the control, you could simply inject with a reference to the control when you create the view model, e.g.:
public LookupPanelView()
{
InitializeComponent();
this.DataContext = new ViewModel(this);
}
But what you probably want is to create a custom control with a default template. This is just a class that inherit from Control
and has no code-behind or XAML file. Please refer to this tutorial for an example. A UserControl
is more like a composite view than a custom control with its own custom logic.
Just a note, if you set up the DataContext of the UC like this thenItemsSource
binding will look for that property in the UC and not the DataContext where it is being used. You need to preserve the DataContext inheritance so the Bindings can be resolved correctly.
– XAMlMAX
Jan 3 at 18:35
add a comment |
This logic should be contained in the control since it should be aware of how to search it's own items.
Why do you need a view model then? If the "logic should be contained in the control", then implement it there.
I think I need to give the control it's own ViewModel to hold the logic but then how do I access the attached property ItemsSource in the ViewModel to search the items?
This is in contradiction to your first sentence, but if the control really needs its own view model for some reason and the view model needs access to the control, you could simply inject with a reference to the control when you create the view model, e.g.:
public LookupPanelView()
{
InitializeComponent();
this.DataContext = new ViewModel(this);
}
But what you probably want is to create a custom control with a default template. This is just a class that inherit from Control
and has no code-behind or XAML file. Please refer to this tutorial for an example. A UserControl
is more like a composite view than a custom control with its own custom logic.
This logic should be contained in the control since it should be aware of how to search it's own items.
Why do you need a view model then? If the "logic should be contained in the control", then implement it there.
I think I need to give the control it's own ViewModel to hold the logic but then how do I access the attached property ItemsSource in the ViewModel to search the items?
This is in contradiction to your first sentence, but if the control really needs its own view model for some reason and the view model needs access to the control, you could simply inject with a reference to the control when you create the view model, e.g.:
public LookupPanelView()
{
InitializeComponent();
this.DataContext = new ViewModel(this);
}
But what you probably want is to create a custom control with a default template. This is just a class that inherit from Control
and has no code-behind or XAML file. Please refer to this tutorial for an example. A UserControl
is more like a composite view than a custom control with its own custom logic.
answered Jan 3 at 16:10


mm8mm8
89.2k81934
89.2k81934
Just a note, if you set up the DataContext of the UC like this thenItemsSource
binding will look for that property in the UC and not the DataContext where it is being used. You need to preserve the DataContext inheritance so the Bindings can be resolved correctly.
– XAMlMAX
Jan 3 at 18:35
add a comment |
Just a note, if you set up the DataContext of the UC like this thenItemsSource
binding will look for that property in the UC and not the DataContext where it is being used. You need to preserve the DataContext inheritance so the Bindings can be resolved correctly.
– XAMlMAX
Jan 3 at 18:35
Just a note, if you set up the DataContext of the UC like this then
ItemsSource
binding will look for that property in the UC and not the DataContext where it is being used. You need to preserve the DataContext inheritance so the Bindings can be resolved correctly.– XAMlMAX
Jan 3 at 18:35
Just a note, if you set up the DataContext of the UC like this then
ItemsSource
binding will look for that property in the UC and not the DataContext where it is being used. You need to preserve the DataContext inheritance so the Bindings can be resolved correctly.– XAMlMAX
Jan 3 at 18:35
add a comment |
After a bit of thinking I came up with this sort of starting point for you.
First you create your control a bit like this:
<UserControl x:Class="SO_App.UC.SearchableListView"
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:local="clr-namespace:SO_App.UC"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid x:Name="root"><!-- This allows us to keep the Data Context inheritance -->
<Grid.Resources>
<CollectionViewSource Source="{Binding ItemsSource}" x:Key="Items"/> <!-- This is for us to use Filtering and so on -->
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox x:Name="txtSearch" Text="{Binding SearchTerm}"/>
<!-- Placeholder -->
<TextBlock IsHitTestVisible="False" Text="{Binding SearchTextPlaceHolder,TargetNullValue=Search, FallbackValue=Search}" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10,0,0,0" Foreground="DarkGray">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=txtSearch}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<ListView x:Name="lstItems" Grid.Row="1" ItemsSource="{Binding Source={StaticResource Items}}"/>
</Grid>
Root element keeps the Bidning to the user control in tact, while we can use the normal binding from the parent element in our main window.
Then in your MainWindow.xaml you would use it like this:
<Window x:Class="SO_App.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:vm="clr-namespace:VM;assembly=VM"
xmlns:model="clr-namespace:Model;assembly=Model"
xmlns:converter="clr-namespace:SO_App.Converters"
xmlns:uc="clr-namespace:SO_App.UC"
xmlns:local="clr-namespace:SO_App"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
<Grid>
<uc:SearchableListView SearchTextPlaceHolder="Search" ItemsSource="{Binding Users}">
<uc:SearchableListView.Resources>
<DataTemplate DataType="{x:Type model:User}">
<Grid>
<StackPanel>
<TextBlock Text="{Binding ID}"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</Grid>
</DataTemplate>
</uc:SearchableListView.Resources>
</uc:SearchableListView>
</Grid>
For the sake of this post here is the ViewModel
:
public class MainViewModel : BaseViewModel
{
public MainViewModel()
{
Users = new List<User>();
for (int i = 0; i < 6; i++)
{
Users.Add(new User
{
ID = i,
Name = $"John the {i + 1}",
State = i % 2 == 0 ? "CA" : "IL",
Cases = new List<Case>() { new Case { CaseID = (i + 1) * 10, Vendor = ((i + 1) * 10) - 2 }, new Case { CaseID = (i + 1) * 10, Vendor = ((i + 1) * 10) - 2 } }
});
}
}
}
And here is the user object:
namespace Model
{
public class User//Ideally you would have INPC implemented here
{
public int ID { get; set; }
public string Name { get; set; }
public string State { get; set; }
public List<Case> Cases { get; set; }
}
}
Hope this gives you enough information to start your implementation in the right direction and with as much MvvM as possible.
add a comment |
After a bit of thinking I came up with this sort of starting point for you.
First you create your control a bit like this:
<UserControl x:Class="SO_App.UC.SearchableListView"
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:local="clr-namespace:SO_App.UC"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid x:Name="root"><!-- This allows us to keep the Data Context inheritance -->
<Grid.Resources>
<CollectionViewSource Source="{Binding ItemsSource}" x:Key="Items"/> <!-- This is for us to use Filtering and so on -->
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox x:Name="txtSearch" Text="{Binding SearchTerm}"/>
<!-- Placeholder -->
<TextBlock IsHitTestVisible="False" Text="{Binding SearchTextPlaceHolder,TargetNullValue=Search, FallbackValue=Search}" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10,0,0,0" Foreground="DarkGray">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=txtSearch}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<ListView x:Name="lstItems" Grid.Row="1" ItemsSource="{Binding Source={StaticResource Items}}"/>
</Grid>
Root element keeps the Bidning to the user control in tact, while we can use the normal binding from the parent element in our main window.
Then in your MainWindow.xaml you would use it like this:
<Window x:Class="SO_App.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:vm="clr-namespace:VM;assembly=VM"
xmlns:model="clr-namespace:Model;assembly=Model"
xmlns:converter="clr-namespace:SO_App.Converters"
xmlns:uc="clr-namespace:SO_App.UC"
xmlns:local="clr-namespace:SO_App"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
<Grid>
<uc:SearchableListView SearchTextPlaceHolder="Search" ItemsSource="{Binding Users}">
<uc:SearchableListView.Resources>
<DataTemplate DataType="{x:Type model:User}">
<Grid>
<StackPanel>
<TextBlock Text="{Binding ID}"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</Grid>
</DataTemplate>
</uc:SearchableListView.Resources>
</uc:SearchableListView>
</Grid>
For the sake of this post here is the ViewModel
:
public class MainViewModel : BaseViewModel
{
public MainViewModel()
{
Users = new List<User>();
for (int i = 0; i < 6; i++)
{
Users.Add(new User
{
ID = i,
Name = $"John the {i + 1}",
State = i % 2 == 0 ? "CA" : "IL",
Cases = new List<Case>() { new Case { CaseID = (i + 1) * 10, Vendor = ((i + 1) * 10) - 2 }, new Case { CaseID = (i + 1) * 10, Vendor = ((i + 1) * 10) - 2 } }
});
}
}
}
And here is the user object:
namespace Model
{
public class User//Ideally you would have INPC implemented here
{
public int ID { get; set; }
public string Name { get; set; }
public string State { get; set; }
public List<Case> Cases { get; set; }
}
}
Hope this gives you enough information to start your implementation in the right direction and with as much MvvM as possible.
add a comment |
After a bit of thinking I came up with this sort of starting point for you.
First you create your control a bit like this:
<UserControl x:Class="SO_App.UC.SearchableListView"
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:local="clr-namespace:SO_App.UC"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid x:Name="root"><!-- This allows us to keep the Data Context inheritance -->
<Grid.Resources>
<CollectionViewSource Source="{Binding ItemsSource}" x:Key="Items"/> <!-- This is for us to use Filtering and so on -->
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox x:Name="txtSearch" Text="{Binding SearchTerm}"/>
<!-- Placeholder -->
<TextBlock IsHitTestVisible="False" Text="{Binding SearchTextPlaceHolder,TargetNullValue=Search, FallbackValue=Search}" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10,0,0,0" Foreground="DarkGray">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=txtSearch}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<ListView x:Name="lstItems" Grid.Row="1" ItemsSource="{Binding Source={StaticResource Items}}"/>
</Grid>
Root element keeps the Bidning to the user control in tact, while we can use the normal binding from the parent element in our main window.
Then in your MainWindow.xaml you would use it like this:
<Window x:Class="SO_App.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:vm="clr-namespace:VM;assembly=VM"
xmlns:model="clr-namespace:Model;assembly=Model"
xmlns:converter="clr-namespace:SO_App.Converters"
xmlns:uc="clr-namespace:SO_App.UC"
xmlns:local="clr-namespace:SO_App"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
<Grid>
<uc:SearchableListView SearchTextPlaceHolder="Search" ItemsSource="{Binding Users}">
<uc:SearchableListView.Resources>
<DataTemplate DataType="{x:Type model:User}">
<Grid>
<StackPanel>
<TextBlock Text="{Binding ID}"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</Grid>
</DataTemplate>
</uc:SearchableListView.Resources>
</uc:SearchableListView>
</Grid>
For the sake of this post here is the ViewModel
:
public class MainViewModel : BaseViewModel
{
public MainViewModel()
{
Users = new List<User>();
for (int i = 0; i < 6; i++)
{
Users.Add(new User
{
ID = i,
Name = $"John the {i + 1}",
State = i % 2 == 0 ? "CA" : "IL",
Cases = new List<Case>() { new Case { CaseID = (i + 1) * 10, Vendor = ((i + 1) * 10) - 2 }, new Case { CaseID = (i + 1) * 10, Vendor = ((i + 1) * 10) - 2 } }
});
}
}
}
And here is the user object:
namespace Model
{
public class User//Ideally you would have INPC implemented here
{
public int ID { get; set; }
public string Name { get; set; }
public string State { get; set; }
public List<Case> Cases { get; set; }
}
}
Hope this gives you enough information to start your implementation in the right direction and with as much MvvM as possible.
After a bit of thinking I came up with this sort of starting point for you.
First you create your control a bit like this:
<UserControl x:Class="SO_App.UC.SearchableListView"
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:local="clr-namespace:SO_App.UC"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid x:Name="root"><!-- This allows us to keep the Data Context inheritance -->
<Grid.Resources>
<CollectionViewSource Source="{Binding ItemsSource}" x:Key="Items"/> <!-- This is for us to use Filtering and so on -->
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox x:Name="txtSearch" Text="{Binding SearchTerm}"/>
<!-- Placeholder -->
<TextBlock IsHitTestVisible="False" Text="{Binding SearchTextPlaceHolder,TargetNullValue=Search, FallbackValue=Search}" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10,0,0,0" Foreground="DarkGray">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=txtSearch}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<ListView x:Name="lstItems" Grid.Row="1" ItemsSource="{Binding Source={StaticResource Items}}"/>
</Grid>
Root element keeps the Bidning to the user control in tact, while we can use the normal binding from the parent element in our main window.
Then in your MainWindow.xaml you would use it like this:
<Window x:Class="SO_App.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:vm="clr-namespace:VM;assembly=VM"
xmlns:model="clr-namespace:Model;assembly=Model"
xmlns:converter="clr-namespace:SO_App.Converters"
xmlns:uc="clr-namespace:SO_App.UC"
xmlns:local="clr-namespace:SO_App"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
<Grid>
<uc:SearchableListView SearchTextPlaceHolder="Search" ItemsSource="{Binding Users}">
<uc:SearchableListView.Resources>
<DataTemplate DataType="{x:Type model:User}">
<Grid>
<StackPanel>
<TextBlock Text="{Binding ID}"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</Grid>
</DataTemplate>
</uc:SearchableListView.Resources>
</uc:SearchableListView>
</Grid>
For the sake of this post here is the ViewModel
:
public class MainViewModel : BaseViewModel
{
public MainViewModel()
{
Users = new List<User>();
for (int i = 0; i < 6; i++)
{
Users.Add(new User
{
ID = i,
Name = $"John the {i + 1}",
State = i % 2 == 0 ? "CA" : "IL",
Cases = new List<Case>() { new Case { CaseID = (i + 1) * 10, Vendor = ((i + 1) * 10) - 2 }, new Case { CaseID = (i + 1) * 10, Vendor = ((i + 1) * 10) - 2 } }
});
}
}
}
And here is the user object:
namespace Model
{
public class User//Ideally you would have INPC implemented here
{
public int ID { get; set; }
public string Name { get; set; }
public string State { get; set; }
public List<Case> Cases { get; set; }
}
}
Hope this gives you enough information to start your implementation in the right direction and with as much MvvM as possible.
answered Jan 3 at 20:30
XAMlMAXXAMlMAX
1,8731920
1,8731920
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54022185%2faccessing-attached-property-collection-from-viewmodel%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
I would vote against the ViewModel for a UserControl. This functionality is specific to the UserControl and should never have any connection with ViewModel it should only expect data and filter. BTW
LookupPanelView
reeks ofDevExpress
.– XAMlMAX
Jan 3 at 15:29
@XAMlMAX Thanks for your suggestion. Would you implement it with old-school style events in the code behind then? I'm not sure what you mean "reeks of DevExpress"?
– Codemunkie
Jan 3 at 15:45
The idea behind the user controls is that they should operate without knowledge about view models. So your control should filter the items it has in it's collection, and that is it's ONLY concern. When I used UC's that's what I did with code behind. Just make sure to implement it for general purpose and not dependant on a specific type of objects in it's collection. And for Dx never mind :-)
– XAMlMAX
Jan 3 at 15:58