How to find a data-binded ListBoxItem position? - c#

I have a ListBox that its ItemsSource is given from a class based on the data binded items template. I want to find ListBox.SelectedItem position relative to the ListBox. Since I've used a class to feed ItemsSource, I'm not be able to cast ListBox.SelectedItem (which has a type of object) to the ListBoxItem. (Instead I should cast it to the source class type.)
What's the way? -Thanks
Details: (Arbitrary)
There is a ListBox which implements a Style like so:
<Style x:Key="MyListBoxStyle" TargetType="{x:Type ListBox}">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border ...>
<StackPanel ...>
<Image Source="{Binding Path=ItemImageSource}" .../>
<TextBlock Text="{Binding Path=ItemTitle}" .../>
</StackPanel>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
The ListBox has been used as follows:
<ListBox x:Name="MyListBox"
ItemsSource="{Binding}"
Style="{StaticResource ResourceKey=MyListBoxStyle}"/>
Also there is a class that supports MyListBox data-binding info:
internal class MyListBoxItemBinding
{
public string ItemTitle { get; set; }
public ImageSource ItemImageSource { get; set; }
}
And to feed the MyListBox:
MyListBox.ItemsSource = new List<MyListBoxItemBinding> { /* some items */ };
Now, how can I find MyListBox.SelectedItem location relative to the MyListBox?

Use ItemsControl.ItemContainerGenerator to get a reference to the item container generator for your ListBox (this is the object that creates wrappers for all your databound objects).
Then, use the ItemContainerGenerator.ContainerFromItem method to get a reference to the UIElement that represents the selected ListBoxItem.
Finally, see the answer to this question to for a way of getting the coordinates of the selected item relative to the ListBox.

Related

Grouping ListView by Property of ViewModel in DataTemplate

I have a problem that is not addressed by the numerous articles on MVVM grouping that I have read.
I am writing a WPF application. Here are some excepts from classes that are relevant to my question - first the MainViewModel:
public class MainViewModel
{
public ObservableCollection<Recipe_OverViewModel> RecipeOverViews {get ; set;}
....[omitted extraneous lines]....
The class that is used as the observable collection of Recipes in the MainViewModel:
public class Recipe_OverViewModel
{
public Recipe TargetRecipe { get; set; }
public override string ToString()
{
return TargetRecipe.Parent_Name;
}
....[omitted extraneous lines]....
and The Class that is taken from the database, that is the actual Recipe
public partial class Recipe
{
[Required]
[StringLength(1000)]
public string Parent_Name { get; set; }
[Required]
[StringLength(60)]
public string Recipe_Name { get; set; }
public override string ToString()
{
return Parent_Name;
}
public int CompareTo(object obj)
{
return Parent_Name.CompareTo(((Recipe)obj).Parent_Name);
}
....[omitted extraneous lines]....
Each class has more properties and methods and so on, but these are enough to explain what I am asking.
The Recipe_OverViewModel is the view model for a control (Recipe_OverView) that displays the properties of the recipe. In the MainViewModel, I have the following xaml (extracted from the larger file):
<Window x:Class="RecipeApp.UI.MainWindow"
....[omitted extraneous lines]....
xmlns:vm="clr-namespace:RecipeApp.UI.ViewModel"
>
<Window.Resources>
<DataTemplate DataType="{x:Type vm:Recipe_OverViewModel}" x:Key="Recipe_DT" x:Name="Recipe_DT">
<control:Recipe_OverView Width="{Binding ActualWidth,ElementName=ListWidth}"/>
</DataTemplate>
<CollectionViewSource x:Key="SortedRecipeOverViews" Source="{Binding RecipeOverViews}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="TargetRecipe"/>
</CollectionViewSource.SortDescriptions>
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="TargetRecipe"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
....[omitted extraneous lines]....
<ListView ItemsSource="{Binding Source={StaticResource SortedRecipeOverViews}}"
ItemTemplate="{StaticResource Recipe_DT}">
</ListView>
This list view correctly displays the list of recipes in the listview, with each row containing the Recipe_OverView control. However, I cannot get the grouping to work correctly. I would like to group the listview by the Parent_Name property of the Recipe associated with each Recipe_OverViewModel. My attempt looked like this, following the Microsoft HowTo:
<ListView Grid.Row="1" Grid.Column="1"
ItemsSource="{Binding Source={StaticResource SortedRecipeOverViews}}"
ItemTemplate="{StaticResource Recipe_DT}"
>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="true">
<Expander.Header>
<TextBlock Text="{Binding Path=ParentName}" />
</Expander.Header>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
However, all I get from that is as many empty (no ParentName populated) headers as there are recipes in the collection and a Binding Failure that tells me the "ParentName property not found on object of type CollectionViewGroupInternal." I get the expander buttons, but there is nothing within the expanded groups:
I thought I understand that that means that the binding is looking in the Recipe_OverViewModel for the ParentName property, but even when I added this as a property in the Recipe_OverViewModel and populated it, I still got this error, so now I am confused and have the following questions:
Where is the binding on the ListView actually looking?
How should I direct it to look at the Recipe_OverViewModel.TargetRecipe.ParentName (or is it impossible)?
I would really appreciate help on this matter, so many articles take so much simpler examples, and I cannot work out how to extend it to my case!
Where is the binding on the ListView actually looking?
It looks for a property of the CollectionViewGroupInternal class.
This class has a Name property that returns the value of the property that you group by, i.e. TargetRecipe, and an Items property that returns the collection of objects that belongs to the current group.
So, if I understand your setup correctly, you could try to bind to the Parent_Name property of the first item in the group:
<Expander.Header>
<TextBlock Text="{Binding Items[0].Parent_Name}" />
</Expander.Header>
The ItemsSource is bound to the SortedRecipeOverViews, which in turn is bound to the RecipeOverViews collection.
The item type of this collection is Recipe_OverViewModel.
And this type doesn't have a ParentName property.
There is a Parent_Name property, BUT not in the Recipe_OverViewModel type, but in the Recipe type.
And the Recipe_OverViewModel type has a property of this type.
In general, you have some kind of mess of types, their names and their properties, binding paths.
Perhaps you copied something wrong into the topic?
Based on my own guess, try applying a binding like this:
<Expander.Header>
<TextBlock Text="{Binding Path=TargetRecipe.Parent_Name}" />
</Expander.Header>

WPF Tree in ComboEditor - Infragistics WPF controls

I'm currently working on a WPF .NET 4.7 application and I use Infragistics WPF controls version 18.
I need to create a custom XamComboEditor which has a XamDataTree inside. Thus a ComboBox with a Tree selection inside.
The Tree selection works fine without the XamComboEditor and looks like this:
<iWPF:XamDataTree ItemsSource="{Binding Locations}">
<iWPF:XamDataTree.GlobalNodeLayouts>
<iWPF:NodeLayout Key="Locations" TargetTypeName="LocationViewModel" DisplayMemberPath="Name"/>
<iWPF:NodeLayout Key="ChildLocations" TargetTypeName="string"/>
</iWPF:XamDataTree.GlobalNodeLayouts>
</iWPF:XamDataTree>
My XamDataTree is bound to an observable collection Locations:
public ObservableCollection<LocationViewModel> Locations { get; set; } = new ObservableCollection<LocationViewModel>();
public class LocationViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public List<LocationViewModel> ChildLocations { get; set; } = new List<LocationViewModel>();
}
I need to use the style setter on my XamComboEditor to put the XamDataTree inside the combobox.
My problem is now, I don't know how to achieve this, or how to pass the context from the XamComboEditor further to the XamDataTree.
I tried the following, in vain:
<iWPF:XamComboEditor ItemsSource="{Binding Locations}">
<iWPF:XamComboEditor.ComboBoxStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<iXaml:XamDataTree ItemsSource="{Binding .}">
<iXaml:XamDataTree.GlobalNodeLayouts>
<iXaml:NodeLayout Key="Locations" TargetTypeName="LocationViewModel" DisplayMemberPath="{Binding Name}"/>
<iXaml:NodeLayout Key="ChildLocations" TargetTypeName="string"/>
</iXaml:XamDataTree.GlobalNodeLayouts>
</iXaml:XamDataTree>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</iWPF:XamComboEditor.ComboBoxStyle>
</iWPF:XamComboEditor>
Do you know how to solve this issue? Do you know how to pass the data context from the parent control to, let's say, the child control? Or rather, how to put the XamDataTree inside the XamComboEditor?
If I understood this correctly, the DataContext of your XamlDataTree is no what you expect it to be (the Locations bound in you XamComboEditor).
One way to solve this problem is to specify the source of the path in your Binding markup extension.
You can use the {x:Reference ...} markup extension to reference a named controled in your control tree.
<iWPF:XamComboEditor x:Name="comboEditor" ItemsSource="{Binding Locations}">
<iWPF:XamComboEditor.ComboBoxStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<iXaml:XamDataTree ItemsSource="{Binding Source={x:Reference Name=comboEditor}, Path=DataContext.Locations}">
<iXaml:XamDataTree.GlobalNodeLayouts>
<iXaml:NodeLayout Key="Locations" TargetTypeName="LocationViewModel" DisplayMemberPath="{Binding Name}"/>
<iXaml:NodeLayout Key="ChildLocations" TargetTypeName="string"/>
</iXaml:XamDataTree.GlobalNodeLayouts>
</iXaml:XamDataTree>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</iWPF:XamComboEditor.ComboBoxStyle>
</iWPF:XamComboEditor>
You can also achieve this without naming your controls with the RelativeSource property in the Binding (something like RelativeSource={RelativeSource AncestorType=iWPF:XamComboEditor}).

UWP TreeView ItemTemplateSelector not working

The WPF version of this question is here: But it hasn't been answered and I don't know if the UWP TreeView will have the same answer.
I'm trying to add a DataTemplateSelector to the new UWP TreeViews that were just added to windows 10 version 1803 but it isn't working. It is documented here how to use the XAML TreeView Control and even shows how to modify the template to change the Item Datatemplate which works fine. I need to use a datatemplate selector since each of my nodes is using different objects and I need them displayed differently. The TreeView.Node.Content is being set just fine and everything works except it is passing null over to the datatemplateselector in the Object parameter.
Here is my code: (same as the example from Microsoft just with using ItemTemplateSelector)
<Style TargetType="TreeView">
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeView">
<TreeViewList x:Name="ListControl"
ItemTemplateSelector="{StaticResource CardSelector}"
ItemContainerStyle="{StaticResource TreeViewItemStyle}"
CanDragItems="True"
AllowDrop="True"
CanReorderItems="True">
<TreeViewList.ItemContainerTransitions>
<TransitionCollection>
<ContentThemeTransition />
<ReorderThemeTransition />
<EntranceThemeTransition IsStaggeringEnabled="False" />
</TransitionCollection>
</TreeViewList.ItemContainerTransitions>
</TreeViewList>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Does anyone have any insight or experience on this? My datatemplateselector "CardSelector" works fine and I have been using it in several places without any trouble.
So the point of my question isn't to get anything that I have working but to see if the TreeViewControl works with a DataTemplateSelector. I only have "CardTemplateSelector" in there because I use it in several other places of my app and I know it works. My question is really a "yes, treeview works with a selector" or "no it doesn't" I'm really looking for someone else to try it with their own test template selector and to let me know if they can get it working. Any specific code from me is not relevant to the question. Just see if you can get it to work with whatever selector you want
Yes. The TreeView work well with ItemTemplateSelector.
I used the all code in the document and create a custom class like the following:
public class Test
{
public string Name { get; set; }
}
I made another DataTemplate like this:
<DataTemplate x:Key="TreeViewObjDataTemplate">
<Grid Height="44">
<TextBlock
Text="{Binding Content.Name}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{ThemeResource BodyTextBlockStyle}"/>
</Grid>
</DataTemplate>
My CardTemplateSelector class is the following:
public class CardTemplateSelector: DataTemplateSelector
{
public DataTemplate TreeViewItemDataTemplate { get; set; }
public DataTemplate TreeViewObjDataTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
TreeViewNode treeViewNode = item as TreeViewNode;
if (treeViewNode.Content is StorageFolder|| treeViewNode.Content is StorageFile)
{
return TreeViewItemDataTemplate;
}
if (treeViewNode.Content is Test)
{
return TreeViewObjDataTemplate;
}
return base.SelectTemplateCore(item);
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
return SelectTemplateCore(item);
}
}
I just add the new lines code in MainPage.xaml.cs:
TreeViewNode objnode = new TreeViewNode();
Test test = new Test() {Name="Parent"};
objnode.Content = test;
objnode.IsExpanded = true;
objnode.HasUnrealizedChildren = true;
sampleTreeView.RootNodes.Add(objnode);
The following is the whole xaml page resource code:
<Page.Resources>
<DataTemplate x:Key="TreeViewItemDataTemplate">
<Grid Height="44">
<TextBlock
Text="{Binding Content.DisplayName}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{ThemeResource BodyTextBlockStyle}"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="TreeViewObjDataTemplate">
<Grid Height="44">
<TextBlock
Text="{Binding Content.Name}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{ThemeResource BodyTextBlockStyle}"/>
</Grid>
</DataTemplate>
<local:CardTemplateSelector x:Name="CardTemplateSelector" TreeViewItemDataTemplate="{StaticResource TreeViewItemDataTemplate}" TreeViewObjDataTemplate="{StaticResource TreeViewObjDataTemplate}"></local:CardTemplateSelector>
<Style TargetType="TreeView">
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeView">
<TreeViewList x:Name="ListControl"
ItemTemplateSelector="{StaticResource CardTemplateSelector}"
ItemContainerStyle="{StaticResource TreeViewItemStyle}"
CanDragItems="True"
AllowDrop="True"
CanReorderItems="True">
<TreeViewList.ItemContainerTransitions>
<TransitionCollection>
<ContentThemeTransition />
<ReorderThemeTransition />
<EntranceThemeTransition IsStaggeringEnabled="False" />
</TransitionCollection>
</TreeViewList.ItemContainerTransitions>
</TreeViewList>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
So far I have answered your question. But I still want to let you know How to ask a good question. In my above comments, I asked you to provide the relevant code, then I could quickly reproduce your question and help you diagnose it. But you said I'm really looking for someone else to try it with their own test template selector and to let me know if they can get it working.. It's Ok. You could see that only I replied. You asked this question for many days. No other community members helped you on this question. That's why I ask you to post some code here. If you provide the relevant code here, I believe many community members will be glad to help you on this question. I really hope you could understand it.
There seems to be confusion about where to apply the DataTemplate. And the all important TargetType is ignored.
If you want a handle on the data item in your custom DataTemplateSelector, you need to:
OPTION 1
Apply the DataTemplateSelector on TreeView.ItemTemplateSelector
Make sure that the DataTemplates have TreeViewNode as the target type.
Only then the data item of the TreeViewNode is supplied to the SetTemplateCore(object item) and SetTemplateCore(object item, DependencyObject container) overrides of your custom DataTemplateSelector.
A working example is found here: Pictures and Music library tree view
OPTION 2
Apply the DataTemplateSelector on TreeViewItem.ContentTemplateSelector
Make sure that the DataTemplates have [YOUR-DATA-TYPE] as the target type
In the TreeView.ItemTemplate bind the DataContext AND Content property to [YOUR-DATA-TYPE], i.e.
<TreeView.ItemTemplate>
<DataTemplate x:DataType="[YOUR-DATA-TYPE]">
<TreeViewItem DataContext="{Binding}" ... Content="{Binding}">
<TreeViewItem.ContentTemplateSelector>
<YourDataTemplateSelector.TemplateA>
<DataTemplate x:DataType="[YOUR-DATA-TYPE]">
...
// YourDataTemplateSelector
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
if (item == null) return null;
return (([YOUR-DATA-TYPE])item).IsSomething ? TemplateA : TemplateB;
}

WPF ComboBox truncating items

I found a strange behavior when using ComboBox with enum items. I noticed that the popup that displays the entries when I click on the ComboBox truncates long items. I figured out that this happens because I define a TextBlock style with a fixed Width. What is strange is that, the Width only affects the ComboBox when I use enum items. It does not happen If I use string ones instead.
Here's a picture with what's going on. The third item should be "VeryLongTypeName".
Here is the code sample written according with the MVVM pattern.
The UserControl XAML:
<UserControl.DataContext>
<local:SampleViewModel/>
</UserControl.DataContext>
<StackPanel>
<StackPanel.Resources>
<Style TargetType="TextBlock">
<Setter Property="Width" Value="70"/>
<Setter Property="Margin" Value="0,0,5,0"/>
</Style>
</StackPanel.Resources>
<DockPanel>
<TextBlock Text="Items"/>
<ComboBox ItemsSource="{Binding ItemsList}" SelectedItem="{Binding Item}"/>
</DockPanel>
<DockPanel>
<TextBlock Text="String Items"/>
<ComboBox ItemsSource="{Binding StringItemsList}" SelectedItem="{Binding StringItem}"/>
</DockPanel>
</StackPanel>
The SampleViewModel code:
public class SampleViewModel
{
public enum SomeType { Type1, Type2, VeryLongTypeName };
public IEnumerable<SomeType> ItemsList
{
get { return (SomeType[])Enum.GetValues(typeof(SomeType)); }
}
public SomeType Item { get { return ItemsList.First(); } set { } }
public IEnumerable<string> StringItemsList
{
get { return ItemsList.Select(type => type.ToString()); }
}
public string StringItem { get { return StringItemsList.First(); } set { } }
}
If you build the code sample, in the second ComboBox below the one from the picture, things go smoothly with string values.
I have the following questions:
Why does changing the type affect the graphics?
How do I fix the ComboBox display when using enum?
Any help is welcomed.
Your textblock style is for all textblocks. The content of the combobox is also displayed with textblocks and you limited the width of textblocks to 70.
Use a key for your style or set another textblock style for the comboboxes.
The problem also happens when listing items with a ListBox. I used Live Property Explorer to see what's going on. Both cases render the content in a TextBlock, but only when using enum values the style defined as resource is applied. Don't know why this happens, but that's how it is.
To fix the problem for enum and possibly other types except string, I added the following style, based on #Mardukar's idea:
<Style TargetType="ComboBoxItem">
<Style.Resources>
<Style TargetType="TextBlock" BasedOn="{x:Null}"/>
</Style.Resources>
</Style>
#Fredrik's idea of changing the ComboBox.ItemTemplate also works.
For ListBox, the style needs to have TargetType either ListBoxItem or ListBox.

Passing Non-Item Values to Properties in ItemTemplate

Today I'm having trouble passing values from a parent control down to the properties of a child control in a list.
I have a custom control which I've made which functions as a Thumbnail Check Box. Essentially it's just a checkbox wrapped around an image with some nice borders. It's all wrapped up into a DLL and deployed as a custom control
If I want to use a single instance of the control, I can do so like this...
<tcb:ThumbnailCheckBox IsChecked="True"
ImagePath="D:\Pictures\123.jpg"
CornerRadius="10"
Height="{Binding ThumbnailSize}"
Margin="10" />
Code Listing 1 - Single Use
This works great, and easily binds to ThumbnailSize on my ViewModel so I can change the size of the image in the control however I want.
The problem is when I want to expand the use of this control into a list, I'm running into a few problems.
To begin, I've styled the ListBox control to meet my needs like so...
<Style TargetType="{x:Type ListBox}"
x:Key="WrappingImageListBox">
<!-- Set the ItemTemplate of the ListBox to a DataTemplate
which explains how to display an object of type BitmapImage. -->
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<tcb:ThumbnailCheckBox ImagePath="{Binding ImagePath}"
IsChecked="{Binding Selected}"
Height="{TemplateBinding utilities:MyAttachedProperties.ImageSize}"
CornerRadius="8"
Margin="10">
</tcb:ThumbnailCheckBox>
</DataTemplate>
</Setter.Value>
</Setter>
<!-- Swap out the default items panel with a WrapPanel so that
the images will be arranged with a different layout. -->
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<!-- Set this attached property to 'Disabled' so that the
ScrollViewer in the ListBox will never show a horizontal
scrollbar, and the WrapPanel it contains will be constrained
to the width of the ScrollViewer's viewable surface. -->
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility"
Value="Disabled" />
</Style>
Code Listing 2 - ListBox Style
And I call it like this from my main view...
<ListBox ItemsSource="{Binding DirectoryPictures}"
Grid.Row="1"
Style="{DynamicResource WrappingImageListBox}"
Background="Transparent"
util:MyAttachedProperties.ImageSize="500"/>
Code Listing 3 - Main Call
This works exactly as I'd like, except for the ImageSize property. Both ImagePath and Selected are properties of the individual list items being bound to the ListBox.
As you can see, I created an attached property to try to pass the value (500), but it doesn't seem to be working. I should note that I think the style I've created is correct because the elements use the default value.
public static class MyAttachedProperties
{
public static double GetImageSize(DependencyObject obj)
{
return (double)obj.GetValue(ImageSizeProperty);
}
public static void SetImageSize(DependencyObject obj, double value)
{
obj.SetValue(ImageSizeProperty, value);
}
public static readonly DependencyProperty ImageSizeProperty =
DependencyProperty.RegisterAttached(
"ImageSize",
typeof(double),
typeof(MyAttachedProperties),
new FrameworkPropertyMetadata(50D));
}
Code Listing 4 - Attached Property
The 50D specified on the last line is applying to the listed control. If I change it, and recompile, the end result changes. But the sent value of 500 I specified in my ListBox Main call (listing 3) is not ever sent. Of course, I would eventually like to change the 500 into a bound property on my view model, but I won't do that until I get it working with an explicit value.
Can someone help me figure out how to send a value from my main ListBox call (listing 3) and apply it to the individual items that are populated by the template? The other properties I have work, but they are a properties of each item in the List I'm binding to the ListBox, whereas ImageSize is not.
EDIT To address First Response
This seems to be working, but it's kind of peculiar. My listbox is now being called like so...
<ListBox ItemsSource="{Binding DirectoryPictures}"
Grid.Row="1"
Style="{DynamicResource WrappingImageListBox}"
Background="Transparent" />
And I've changed my style to the code you suggested...
<tcb:ThumbnailCheckBox ImagePath="{Binding ImagePath}"
IsChecked="{Binding Selected}"
Height="{Binding Path=DataContext.ThumbnailSize, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}}"
CornerRadius="8"
Margin="10">
My only concern is, now the style is accessing the ViewModel for that control directly rather than receiving a bound value.
Suppose I wanted to use the ListBox again, but on another UserControl whose ViewModel didn't have ThumbnailSize property, but used one by another name?
You see where I'm going with this... the current solution is not very extensible and is limited to the current classes as they are named exactly.
In fact, in a perfect world, I'd like to have variable names for the ImagePath and Selected properties, but that's a different discussion.
It's possible to use FindAncestor. The idea of that is, child traverses through logical tree, and tries to find parent with concrete type (in this case, ListBox), and then accesses attached property. See http://wpftutorial.net/BindingExpressions.html for more binding expressions.
In your ItemTemplate, this is how you could access ThumbnailSize property:
{Binding Path=(util:MyAttachedProperties.ImageSize),
RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType={x:Type ListBox}}}
Essentially, the question asked here was a little bit opposite, but results are same. "How could items in ListBox access ListBox (attached) properties.

Categories