How to bind to a control element within a ResourceDictionary - wpf

I'm trying to refer to an element in my WPF Control from within a ResourceDictionary on that control. Here's an example:
<UserControl.Resources>
<ResourceDictionary>
<Behaviors:GridViewInteractionModel x:Key="gridViewInteraction" GridView="{Binding ElementName=myGridView}"/>
</ResourceDictionary>
</UserControl.Resources>
...
<SomeGridView x:Name="myGridView"/>
The value of the GridView dependency property on the GridViewInteractionModel object should be the SomeGridView object called myGridView.
The above code doesn't work. {Binding ElementName=myGridView} does not bind the element (the SetValue function of GridViewInteractionModel never gets called).
The WPF runtime error is:
Cannot find source for binding with reference 'ElementName=myGridView'.
BindingExpression:(no path); DataItem=null; target element is
'GridViewInteractionModel' (HashCode=15238415); target property is
'GridView' (type 'SomeGridView')
Does anyone know how to get an element within the control to be bound to a property of a resource within the ResourceDictionary?
The only way I've found to get the property set is by manually setting it in the code-behind constructor like this, after InitializeComponent() has been called:
(Resources["gridViewInteraction"] as GridViewInteractionModel).GridView = FindName("myGridView") as SomeGridView;
But that's really ugly (and error-prone).
Thx.

Not entirely sure what you are trying to achieve here. This is an example of how I have dealt with a listview and it's child items:
<Style x:Key="ListViewStyle" TargetType="ListView">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFD3D1CF" Offset="0"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect Opacity="0.7"/>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ListViewItemStyle" TargetType="ListViewItem">
<Setter Property="Background" Value="#FF494646"/>
<Setter Property="Foreground" Value="#FFFDFAFA"/>
<Setter Property="Height" Value="25"></Setter>
<Setter Property="Cursor" Value="Hand"></Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Black"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Black"/>
</Trigger>
</Style.Triggers>
</Style>
<ListView x:Name="lvwSettingsYears" x:Uid="lvwSettingsYears" Margin="10,77,10,50"
Style="{DynamicResource ListViewStyle}"
ItemContainerStyle="{DynamicResource ListViewItemStyle}"
SelectionChanged="lvwYears_SelectionChanged">
<ListView.View>
<GridView>
<GridViewColumn x:Name="SettingsYearListviewID" x:Uid="SettingsYearListviewID" DisplayMemberBinding="{Binding id}" Width="0"/>
<GridViewColumn x:Name="SettingsYearListviewCode" x:Uid="SettingsYearListviewCode" Header="Code" DisplayMemberBinding="{Binding Code}" Width="100"/>
<GridViewColumn x:Name="SettingsYearListviewDesc" x:Uid="SettingsYearListviewDesc" Header="Description" DisplayMemberBinding="{Binding Description}" Width="300"/>
</GridView>
</ListView.View>
</ListView>
What prompted me to post this is in your error message it mentions
target property is
'GridView' (type 'SomeGridView')
I think it is looking for the control type.

Related

GridViewColumn and header not set inside ListView

I have a list view that shows some logs (of type LogItem). The ListView.View is set to a GridView in XAML. The GridView has two columns where the data templates for each column is set to a textbox. The first column binds to a DateTime property of the LogItem, so the width of the first column could be set to Auto (preferred) or even a fixed width i required.
The second gridviewcolumn is binding to a log message string, so it could have any width.
My question is, how can I make sure all text is visible in the listview such that I get a scrollbar in the listview if the log message width is larger than the listview's width, and that all the text is visible?
At the moment the size of the second column seems to be set by the first item added to the collection that the ListView binds to, then the width never updates. So typically I just see a small part of the log messages and the second column header does not even span the complet ListView width.
I have looked around for a solution to the problem. There seems to be more people asking the same question, but so far none of the answers I have found has solved the problem. I hope someone could help to guide me in the right direction, what have I missed.
XAML code below
<ListView Grid.Row="1"
HorizontalAlignment="Stretch"
IsSynchronizedWithCurrentItem="False"
ItemsSource="{Binding LogItems}"
x:Name="LogListView"
FontSize="14">
<!--:GridViewColumnResize.Enabled="True" -->
<ListView.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Gray" Offset="1"/>
<GradientStop Color="White"/>
</LinearGradientBrush>
</ListView.Background>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Background" Value="{Binding BackColor}"/>
<Setter Property="TextElement.Foreground" Value="White"/>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true" />
</MultiTrigger.Conditions>
<Setter Property="Background" Value="Gold" />
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="TextElement.Foreground" Value="Black"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="true" />
</MultiTrigger.Conditions>
<Setter Property="Background" Value="Gold" />
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="TextElement.Foreground" Value="Black"/>
</MultiTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="{Binding TimeText}" Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="TimeLabel" Text="{Binding CreationTime, StringFormat='{}{0:hh:mm:ss.fff}'}" Grid.Column="0"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{Binding MessageText}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Message}" Grid.Column="1"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Edit:
The full xaml code
pastebin.com/24HgAcML

Change background/highlight-color of selected ListBox item based on data

I want to change the background/hightlight color of a selected ListBox item using data binding. This is what I have and tried, but it's not working. I'm not sure how to get the resources section to have the "current item" context.
Color is a property on every item displayed (and has a different value for each item).
<ListBox x:Name="Categorie" ItemsSource="{Binding Categories}" IsSynchronizedWithCurrentItem="True">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="{Binding /Color}" />
</Style.Resources>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="{Binding /Color}" />
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" HorizontalAlignment="Center"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You can use a Trigger to achieve that:
<Style TargetType="ListBoxItem">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="{Binding Color}" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Note that for this binding to work, you must have a property called Color on the data item objects that are set as the ListBox.ItemsSource.
UPDATE >>>
Ok, so that was my bad... I forgot that SolidColorBrush is not a FrameworkElement and is Freezable, so they cannot be used in a Binding... you have a few options:
Either create your colour(s) as StaticResource object(s):
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{StaticResource Color}" />
</Trigger>
Or you could bind the Background property to the Color object using a Converter of some kind:
<Style TargetType="ListBoxItem" Background="{Binding Color, Converter={StaticResource
SomeColourConverter}}" />
another work around can be to set the background using your color property and setting the HightlightBrushKey to Transparent.

Style Error In WPF ListView

I want to change the border color of ListView when it's got focused. I use This style
<Style TargetType="ListView">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListView">
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" Value="#FF9D9B9B" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here is the code for my ListView
<ListView Margin="49,91,61,148" Grid.Column="1">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" />
<GridViewColumn Header="Name"/>
</GridView>
</ListView.View>
</ListView>
But after I apply this style, the ListView was totally disappeared in run time. What was happened there.
Perhaps it's the <ControlTemplate> Could you simply declare your style without it?
<Style TargetType="ListView">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" Value="Lime" /><!--bright color for empahsis only-->
</Trigger>
</Style.Triggers>
</Style>
This works without issue in a test project/
Take a look here. Its about IsFocused property for ListBox but the same idea with ListView.

style triggers for alternating rows don't always update when scrolling virtualized WPF Datagrid

There are a few questions similar to this on SO, I've read this one and another I can't find the link for, but none of them seem to have a solution that's applicable.
I have a DataGrid defined below, and it has various styles triggered on AlternationIndex being either 0 or 1. When I scroll upwards, sometimes the a given cell will flip from one colour to the other.
Do you know of any way to stop this from happening without turning off virtualization?
(I've taken the column definitions out to save space, I don't think they're important for this. All of the DataTriggers -always- work, it's just the alternation that I'm having issues with.)
<DataGrid
ItemsSource="{Binding Path=LogItems, Mode=OneWay}"
Grid.Row="1"
AlternationCount="2"
Name="logDataGrid"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling">
<DataGrid.Resources>
<local:IsEntryExceptionConverter x:Key="isEntryExceptionConverter" />
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border Name="DataGridCellBorder">
<ContentControl Content="{TemplateBinding Content}">
<ContentControl.ContentTemplate>
<DataTemplate>
<TextBlock Background="Transparent" TextWrapping="WrapWithOverflow" TextTrimming="CharacterEllipsis"
Height="auto" Width="auto" Text="{Binding Text}"/>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="DataGridCell.IsSelected" Value="True">
<Setter Property="TextBlock.Foreground" Value="Blue" />
</Trigger>
</Style.Triggers>
</Style>
<SolidColorBrush x:Key="ExceptionBrush" Color="OrangeRed" Opacity="0.5"/>
<SolidColorBrush x:Key="ErrorBrush" Color="Red" Opacity="0.5"/>
<SolidColorBrush x:Key="WarningBrush" Color="Orange" Opacity="0.5"/>
<SolidColorBrush x:Key="AlternatingRowBackground0" Color="AliceBlue" Opacity="0.5" />
<SolidColorBrush x:Key="AlternatingRowBackground1" Color="LightBlue" Opacity="0.5" />
</DataGrid.Resources>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<Trigger Property="AlternationIndex" Value="0">
<Setter Property="Background" Value="{StaticResource AlternatingRowBackground0}" />
</Trigger>
<Trigger Property="AlternationIndex" Value="1">
<Setter Property="Background" Value="{StaticResource AlternatingRowBackground1}" />
</Trigger>
<DataTrigger Binding="{Binding Path=Level}" Value="Warning">
<Setter Property="Background" Value="{StaticResource WarningBrush}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Message, Converter={StaticResource isEntryExceptionConverter}}" Value="True">
<Setter Property="Background" Value="{StaticResource ExceptionBrush}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Level}" Value="Error">
<Setter Property="Background" Value="{StaticResource ErrorBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
</DataGrid>
That's the nature of virtualization. Only a set number of UI objects are actually rendered, and when you scroll you are changing the DataContext behind those objects.
So in your case, Rows are created and given a background color. When you scroll, the DataContext behind those rows change, so a data object might be in a row that was given Color A at a certain scroll position, or be in a row that was assigned color B at another scroll position.
Most of the time the alternating colors are only there to help identify what columns are in what row so it doesn't matter if they change, however if you want to maintain a consistent background color for the rows you will probably have to add something to the data object and base your background color off that property. That way when you scroll and the DataContext changes, the row color will also change.

Styling WPF Tree At All Levels

I have a tree in WPF that has no root node, but has defined TreeViewItems for separate categories. Each of these TreeViewItems have their ItemsSource bound to the display object. The data displays fine. Now I'm trying to make the tree appear like the Windows7 Explorer trees.
I've used some of the styling from this post: WPF TreeView: How to style selected items with rounded corners like in Explorer
Anyhow here is the TreeViewItem:
<TreeViewItem ItemsSource="{Binding Path=Configuration.CognosServers}"
IsExpanded="True"
Visibility="{Binding ItemsSource.Count, Converter={StaticResource ResourceKey=TreeViewItemVisibility1}, RelativeSource={RelativeSource Self}}">
<TreeViewItem.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True"/>
</Style>
</TreeViewItem.ItemContainerStyle>
<TreeViewItem.HeaderTemplate>
<DataTemplate>
<Border Margin="0,5,0,0">
<Border.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove" Click="TreeItemMenu_RemoveClick" />
<MenuItem Header="Add Client..." Click="TreeItemMenu_AddNewClient" />
</ContextMenu>
</Border.ContextMenu>
<StackPanel Orientation="Horizontal">
<Image Source="/WPF;component/Images/server_chart.png"
Margin="0,0,5,0"/>
<TextBlock Text="Cognos Servers" />
</StackPanel>
</Border>
</DataTemplate>
</TreeViewItem.HeaderTemplate>
<TreeViewItem.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Namespaces}">
<Border>
<TextBlock Text="{Binding DisplayName}" PreviewMouseRightButtonDown="OnPreviewMouseRightButtonDown" />
</Border>
<HierarchicalDataTemplate.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource ResourceKey=TreeViewItemStyle1}">
<Setter Property="IsExpanded" Value="True"/>
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Clients}">
<Border>
<TextBlock Text="{Binding DisplayName}" PreviewMouseRightButtonDown="OnPreviewMouseRightButtonDown" />
</Border>
<HierarchicalDataTemplate.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource ResourceKey=TreeViewItemStyle1}">
<Setter Property="IsExpanded" Value="True"/>
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<Border>
<TextBlock Text="{Binding DisplayName}"
ContextMenu="{StaticResource ResourceKey=ContextMenuTreeItem}"
PreviewMouseRightButtonDown="OnPreviewMouseRightButtonDown" />
</Border>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeViewItem.ItemTemplate>
</TreeViewItem>
The style I'm apply to the TreeView appears like this:
<TreeView x:Name="TreeViewLoadedItems"
Grid.Row="1"
VerticalAlignment="Stretch"
ItemContainerStyle="{DynamicResource TreeViewItemStyle1}"
MouseDoubleClick="TreeViewItem_MouseDoubleClick"
SelectedItemChanged="TreeViewLoadedItems_SelectedItemChanged" >
Finally the style I'm applying is this:
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type TreeViewItem}">
<!-- Style for the selected item -->
<Setter Property="BorderThickness" Value="1"/>
<Style.Triggers>
<!-- Selected and has focus -->
<Trigger Property="IsSelected" Value="True">
<Setter Property="BorderBrush" Value="#7DA2CE"/>
</Trigger>
<!-- Mouse over -->
<!--<Trigger Property="helpers:TreeView_IsMouseDirectlyOverItem.IsMouseDirectlyOverItem" Value="True">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFFAFBFD" Offset="0"/>
<GradientStop Color="#FFEBF3FD" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="BorderBrush" Value="#B8D6FB"/>
</Trigger>-->
<!-- Selected but does not have the focus -->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="True"/>
<Condition Property="IsSelectionActive" Value="False"/>
</MultiTrigger.Conditions>
<Setter Property="BorderBrush" Value="#D9D9D9"/>
</MultiTrigger>
</Style.Triggers>
<Style.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="2"/>
</Style>
</Style.Resources>
</Style>
</Setter.Value>
</Setter>
</Style>
No Matter what I've done I can't seem to get each item to look the same when selected. Only the leaf nodes seem to be picking up the style. I always have trouble when there are HierarchialDataTemplates and I need to style things. What gives?!
In your style you set the ItemContainerStyle, why? That way the immediate TreeViewItem the style is applied to will not have the style, maybe that somehow even propagates down to the leaf; you should not need to set that property. Just place a style for TreeViewItems in the Resources of the TreeView and it will automatially apply to each item, move everything in the ItemContainerStyle up to the actual main style.

Resources