Why does no WPF ListView Theme work? - wpf

I am no graphic designer but I want a nice looking application. I searched the Internet for WPF Themes and I found i.e. these:
https://visualstudiogallery.msdn.microsoft.com/30e8b37d-01a0-4749-abcb-a5d7631e7646
The themes work fine with Buttons and Textboxes and many controls but not with ListView.
This is how my sample ListView looks without Theme:
And this is how it looks with Theme ShinyBlue (other Themes look similar):
It does not matter which Theme I use (I downloaded many). There is always the problem that the ListView with Theme does not show the items. It just shows some thick lines instead of the items.
Here is the code:
<Window
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" x:Class="SahaWpfTheme20131.TestWindow1"
Title="Test Window" Width="250" Height="200"
>
<Grid>
<ListView x:Name="ListView1" HorizontalAlignment="Left"
VerticalAlignment="Top" Width="200" Height="150">
<ListViewItem Content="Coffee"/>
<ListViewItem Content="Tea"/>
<ListViewItem Content="Orange Juice"/>
<ListViewItem Content="Milk"/>
<ListViewItem Content="Iced Tea"/>
<ListViewItem Content="Mango Shake"/>
</ListView>
</Grid>
</Window>
Am I doing something wrong or do many Themes just not work with ListView? I am confused why this does not work.
I used a ListView sample from here: http://www.c-sharpcorner.com/uploadfile/mahesh/listview-in-wpf/

When I create a ListView with columns and an ItemsSource, it works (but the colors are messed up, probably a different issue):
<ListView x:Name="ListView1" HorizontalAlignment="Left"
VerticalAlignment="Top" Width="200" Height="150">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn DisplayMemberBinding="{Binding A}" />
<GridViewColumn DisplayMemberBinding="{Binding B}" />
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
And in code-behind (of course this is not the proper way to do this, but it is the shortest):
ListView1.ItemsSource = new[]
{
new { A = "qqq", B = "rrr" },
new { A = "qqqq", B = "rrr" }
};
I also got your code to work, but for this I changed the ListViewItem template in BureauBlack.xaml (the theme that is in use):
<GridViewRowPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Margin="0,2,0,2" VerticalAlignment="Stretch" />
to
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Margin="0,2,0,2" VerticalAlignment="Stretch" />
And now the content in the list from your code is shown. But for what you're trying to do, like suggested in a comment, you probably want a ListBox, not ListView.

Related

How to define an ItemTemplate for GridView (inside a ListView) so it can be used in multiple different ListViews?

I have some ListView's which bind to collections in the ViewModel. The type of items in those collections are the same (let's call them TypeA) which is a class exposing multiple simple type properties. I would like to display them in a GridView inside the ListView. Naturally, I would want to define a DataTemplate for this TypeA so that I don't have to duplicate the same XAML for each of the ListView's. All of the examples I've found so far define the ItemTemplate inside the ListView. How can I make a resource and let different ListView's refer to this single resource?
UPDATE:
I am posting my XAML code for better clarification. My original XAML code (simplified) looks like this:
<ListView ItemsSource="{Binding MYCOLLECTION}" SelectionMode="Extended" >
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Prop1}" >
<GridViewColumn.Header>
<Border >
<TextBlock Text="Prop1" />
</Border>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Prop2}" >
<GridViewColumn.Header>
<Border >
<TextBlock Text="Prop2" />
</Border>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Prop3}" >
<GridViewColumn.Header>
<Border >
<TextBlock Text="Prop3" />
</Border>
</GridViewColumn.Header>
</GridViewColumn>
...
</GridView>
</ListView.View>
</ListView>
I have many dependency properties set to the headers and that's why I put individual Header items as well as why my code is really long--hence why I'm seeking to use a datatemplate.
So my idea is that I can show different selections of the same type in the same way in different GridView's (because we want the column headers to display the names of the properties so we use GridView).
BTW those are not the only places I am presenting this data type, so I definitely need to specify a Resource key and restrict this to be used only for GridView. And because I want to display in a Grid way, I assume can't define a DataTemplate for my type and use it as ItemTemplate in a ListView.
You do not even have to define a resource key just set the DataType because that will be used as a key internally by WPF. Just make sure your datatemplates are visible from any control where you want to use it, they will be automatically applied. (Just for example you can define them at application level in the resources of App.xaml, but you probably have separate resource dictionaries):
<Application x:Class="WpfTest.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dataModel="clr-namespace:DataModel"
StartupUri="MainWindow.xaml">
<Application.Resources>
<DataTemplate DataType="{x:Type dataModel:GreekGod}">
<TextBlock Text="{Binding Path=Name}" Foreground="Gold"/>
</DataTemplate>
</Application.Resources>
</Application>
For your code you need to define templates for each property because you are using it as a grid and you need to set the cell template for each column after removing the DisplaymemberBinding:
<GridViewColumn CellTemplate="{StaticResource prop1Template}">
<GridViewColumn.Header>
<Border >
<TextBlock Text="Prop1" />
</Border>
</GridViewColumn.Header>
</GridViewColumn>
...
And put the resource in a visible place just as mentioned before like in the Application resources:
<Application.Resources>
<DataTemplate x:Key="prop1Template">
<TextBlock Text="{Binding Prop1}" Foreground="Red"/>
</DataTemplate>
</Application.Resources>
You can use a ColumnHeaderTemplate and a ColumnContainerStyle like this:
<GridView
ColumnHeaderTemplate="{StaticResource myHeaderTemplate}"
ColumnHeaderContainerStyle="{StaticResource myHeaderStyle}"
>
<GridViewColumn Header="Prop1" CellTemplate="{StaticResource prop1Template}"/>
...
where the resources are for example:
<Style x:Key="myHeaderStyle" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Background" Value="LightBlue"/>
</Style>
<DataTemplate x:Key="myHeaderTemplate">
<DockPanel>
<CheckBox/>
<TextBlock FontSize="16" Foreground="DarkBlue">
<TextBlock.Text>
<Binding/>
</TextBlock.Text>
</TextBlock>
</DockPanel>
</DataTemplate>
Just create the DataTemplate in the Controls/Windows resources as you would do in the ListViews ItemTemplate and add x:Key="someKey" to it.
Now you can refer to it like so:
<ListView ItemTemplate="{StaticResource someKey}"/>

WPF Expander and Window resizing after collapse?

I am dealing with one problem regarding to main window resizing after the expander is collapsed and window was manually resized to bigger size by drag/drop before that. The expander is collapsed but the main window is not resized to "fit" the inner component size.
The components are placed to auto sized grid columns and main window is set to WidhtAndHeight size content.
Main window property set:
SizeToContent="WidthAndHeight"
I have done solution via code behind and event handlers (on collapse and expand events). But I think the WPF has better approach ...
Expander XAML implementation:
<Expander Name="expander" Grid.Column="2" Grid.Row="0" Grid.RowSpan="5" ExpandDirection="Right" ToolTip="Expand window for history details" Expanded="Expander_Expanded" Collapsed="Expander_Collapsed" SizeChanged="expander_SizeChanged" >
<Expander.Header>
<TextBlock RenderTransformOrigin="0.3,1.5">
<TextBlock.RenderTransform>
<TransformGroup>
<RotateTransform Angle="90" />
</TransformGroup>
</TextBlock.RenderTransform>
Show history
</TextBlock>
</Expander.Header>
<StackPanel>
<ListView ItemsSource="{Binding Path=HistoryList}" ScrollViewer.CanContentScroll="True" ScrollViewer.HorizontalScrollBarVisibility="Auto" MaxHeight="350" >
<ListView.View>
<GridView>
<GridViewColumn Header="Operation" DisplayMemberBinding="{Binding Operation}" />
<GridViewColumn Header="Result" DisplayMemberBinding="{Binding Result}" />
</GridView>
</ListView.View>
</ListView>
</StackPanel>
</Expander>
Does anyone have a clue how to intelligent solve this case?
Thanks for advise.
The SizeToContent property seems to lose its value as soon as you resize the Window manually, to fix this just subscribe to the OnSizeChanged event of your Window, and reset the SizeToContent property:
XAML:
<Window SizeToContent="WidthAndHeight" SizeChanged="MainWindow_OnSizeChanged">
Code-Behind:
private void MainWindow_OnSizeChanged(object sender, SizeChangedEventArgs e)
{
SizeToContent = SizeToContent.WidthAndHeight;
}

Not able to enter text in a TextBox inside a GridView/ListView (WPF)

I have a TextBox and a DropDown inside a ListView which is binded to a viewModel.
While comboBox is working fine, i am not able to "enter" any text inside the TextBox. Backspace/SpaceBar/Ctrl+C/Ctrl+V are working just fine, but as soon as i press any alphanumeric key, it doesn;t shows any text in the TextBox.
Have also checked using empty KeyUp/KeyDown/TextChange event handler. It raises KeyUp/KeyDown event for all type of key press but TextChange is not triggered on pressing any alphanumeric key.
Please suggest if anyone has faced this problem ever. Or if there is a way to debug and find the actual problem.
This is my XAML - nothing in code behind.
<Window x:Class="Ion.MarketView.Mmi.Plugins.AlertConfigurator.View.AlertConditionItemViewDebug"
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"
x:Name="aletConditionItems"
mc:Ignorable="d" >
<Grid >
<Grid.Resources>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="75"></ColumnDefinition>
</Grid.ColumnDefinitions>
<ListView Grid.Column="0" x:Name="lstViewConditionItems"
ItemsSource="{Binding ElementName=aletConditionItems, Path=DataContext.Items}"
SelectedItem="{Binding ElementName=aletConditionItems, Path=DataContext.SelectedItem, Mode=TwoWay}">
<ListView.View>
<GridView>
<GridViewColumn Header="Column Id" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox SelectedValue="{Binding Path=ColumnId}" Margin="-6,-2,-6,-2"
ItemsSource="{Binding ElementName=aletConditionItems, Path=DataContext.ColumnIds}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Value" Width="100" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Text="Only backSpace and SpaceBar works" ></TextBox>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<StackPanel Orientation="Horizontal" Grid.Column="1" VerticalAlignment="Top" >
<Button Content="+" Width="30" Command="{Binding ElementName=aletConditionItems, Path=DataContext.OnAddConditionItem}"></Button>
</StackPanel>
</Grid>
</Window>
Thanks for your interest.
Note:
1) I am loading this WPF window from a WinForm application.
2) The problem is NOT in the binding of textBox with viewModel. I am not even able to edit a simple text that is hardcoded in the Text property (as in the code above)
3) I have not registered "any" event handler in any parent control.
Solution:
As per the links suggested by #HCL, the following code fixed my problem.
Window window1 = new Window();
ElementHost.EnableModelessKeyboardInterop(window1); //This is needed for Sharing Message Loops Between Win32 and WPF
window1.Show();
I've seen such a behaviour if a wpf-window integrated into a win-forms-application. Make a comment if it's this.
If not, check if you have registered a PreviewKeyDown-event handler in a parent-element (window, usercontrol, grid) that sets the e.Handled-property to true (or any other registered preview-event-handler that deals with keyboard-input).
Because you wrote that copy-paste and space works, I assume that you not have set TextBox.IsReadOnly in a parent-element or a style or control-template of a parent-element or of an implicit style.
One thing more: Is the line
<TextBox Text="Only backSpace and SpaceBar works" ></TextBox>
really the line that does not work or do you have a binding that not works?
Update:
Ok, because it's a win-forms-application, you must redirect the messages from the win32 message-loop. Look here, here and here.
An additonal tip: Take care on creating new windows from within an integrated WPF-window. As far as I remember from an elder project, you must also forward messages to any new child-window.

How can I display different ContextMenus in WPF ListView GridView?

I have a ListView GridView with ListViewItems that represent different categories of items. I'd like to display a different ContextMenu for each category of item. I was hoping to do this using DataTemplates but I'm struggling. My TreeView has a DataTemplate per category and I can see how I can set a different ContextMenu for each there but I can't seem to get similar DataTemplates to work for my ListView. Am I barking up the wrong tree?
E.g. this is one of my DataTemplates for the TreeView:
<DataTemplate DataType="{x:Type viewModel:Cat1ViewModel}">
<StackPanel Orientation="Horizontal">
<Image Width="16" Height="16" Margin="3,0"
Source="..\Images\cat1.png"/>
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
and I can add my ContextMenu to the StackPanel (I hope) and Bob's my uncle.
But the guts of the GridView looks like this:
<ListView.Resources>
<DataTemplate x:Key="image">
<Image Width="16" Height="16" Margin="-3,0,-3,0"
HorizontalAlignment="Center"
Source="{Binding Path=ObjectClass,
Converter={StaticResource imageConverter}}" />
</DataTemplate>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn Width="20"
CellTemplate="{StaticResource image}"/>
<GridViewColumn Width="140" Header="Name"
DisplayMemberBinding="{Binding Path=Name}"
infrastructure:GridViewSort.PropertyName="Name"/>
<GridViewColumn Width="140" Header="Type"
DisplayMemberBinding="{Binding Path=Category}"
infrastructure:GridViewSort.PropertyName="Category"/>
<GridViewColumn Width="400" Header="Description"
DisplayMemberBinding="{Binding Path=Description}"
infrastructure:GridViewSort.PropertyName="Description"/>
</GridView>
</ListView.View>
This imageConverter in the DataTemplate resource displays the appropriate icon for the category of the listViewItem.
I'm not sure where to start. So, first, is what I want to do possible? If so, can you get me started, please.
Also:
At the moment, each ListViewItem is backed by a viewModel - all categories use the same viewModel class.
Background:
The reason I want to display a different ContextMenu rather than changing the ContextMenu is that I'm using Prism and the ContextMenus will be Regions populated automatically by various modules.
I think you can do this with an ItemTemplateSelector, rather than setting the ItemTemplate property on your ListView, use the ItemTemplateSelector property. You have to create your own implementation of the ItemTemplateSelector class and define the logic so that it knows which template to use for each set of conditions, then you just need to create a set of templates and you should be good to go! There's a good tutorial on how to do this here.

Find an element in DataTemplate applied to TabItem

I got a problem trying to find an element declared in DataTemplate, that after was applied like a ContentTemplate to TabItem object.
I saw that there is already some solutions in regard of this problem, but no one of them actually works in my case, and I would like to understand why (obviously I make mistake in some place)
Here is a sample code:
<DataTemplate x:Key="TabItemDataTemplate">
<Grid HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Name="templateGrid">
<Grid.RowDefinitions>
<RowDefinition Height="6.0*"> </RowDefinition>
<RowDefinition Height="6" ></RowDefinition>
<RowDefinition Height="6.0*" ></RowDefinition>
<RowDefinition Height="*" ></RowDefinition>
</Grid.RowDefinitions>
<ListView x:Name="repoView" Grid.Row="0"
VerticalAlignment="Stretch"
ItemsSource="{Binding Source={StaticResource DataProviderForListView}}">
<GridView>
<GridViewColumn Header="State"
DisplayMemberBinding="{Binding Path=RepositoryItemState}"/>
<GridViewColumn Header="Working Copy Rev num."
DisplayMemberBinding="{Binding Path=WCRevision}"/>
<GridViewColumn Header="Repository Rev num."
DisplayMemberBinding="{Binding Path=RepoRevision}"/>
<GridViewColumn Header="User"
DisplayMemberBinding="{Binding Path=Account}"/>
<GridViewColumn Header="Item"
DisplayMemberBinding="{Binding Path=ItemName}"/>
</GridView>
</ListView>
<GridSplitter x:Name="gridSplitter" Grid.Row="1"
ResizeDirection="Rows" Background="Gray"
Height="4" HorizontalAlignment="Stretch"
Style="{StaticResource gridSplitterStyle}"/>
<RichTextBox x:Name="rowView" Grid.Row="2"
BorderBrush="Bisque" VerticalAlignment="Stretch"
IsReadOnly="True" Background="YellowGreen"
FontFamily="Comic Sans Serif"/>
<ToggleButton x:Name="rbWorkingCopy"
Template="{StaticResource ToggleButtonControlTemplate}"
Grid.Row="3" Width="100" Height="22"
Content="{StaticResource WorkingCopyTitle}"
HorizontalAlignment="Left" VerticalAlignment="Bottom"
Command="repoManager:AppCommands.GetWorkingCopyInfoCommand" />
<ToggleButton x:Name="rbRepository"
Template="{StaticResource ToggleButtonControlTemplate}"
Grid.Row="3" Width="100" Height="22"
Content="{StaticResource RepositoryTitle}"
HorizontalAlignment="Left"
VerticalAlignment="Bottom" Margin="120,0,0,0"
Command="repoManager:AppCommands.GetRepoInfoCommand" />
<ProgressBar x:Name="checkRepositoryProgress" Grid.Row="3"
Width="220" Height="22" HorizontalAlignment="Right"
VerticalAlignment="Bottom" Margin="250,0,10,0"
IsIndeterminate="True"
IsEnabled="{Binding repoManager:ExecutingCommand}" />
</Grid>
</DataTemplate>
This code is porgrammatically applied to the given TabItem object in following way :
this.ContentTemplate = FindResource("TabItemDataTemplate") as DataTemplate;
After I need access to the ListView element declared in DataTemplate, so I execute the codes found around in internet, and also on this site. Here is a short example:
/* Getting the ContentPresenter of myListBoxItem*/
ContentPresenter myContentPresenter =
FindVisualChild<ContentPresenter>(this);
// this.GetVisualChild(0)
/* Finding textBlock from the DataTemplate that is set on that ContentPresenter*/
DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;
ListView repoListView = (ListView)myDataTemplate.FindName("repoView",
myContentPresenter);
Problem1: In this case ContentTemplate of ContentPresenter is Null, so code execution crashes.
Prolem2: Ok, I think, may be I need to navigate throw TabItem content directly, so the code becomes, more or less:
/* Getting the ContentPresenter of myListBoxItem*/
ContentPresenter myContentPresenter =
FindVisualChild<ContentPresenter>(this);
// this.GetVisualChild(0)
/* Finding textBlock from the DataTemplate that is set on that ContentPresenter*/
DataTemplate myDataTemplate = this.ContentTemplate;
ListView repoListView = (ListView)myDataTemplate.FindName("repoView",
myContentPresenter);
this is TabItem object. But the strage things, that the ContentTemplate of this is completely different from that one assigned above. I'm sure that I missed something somewhere, can you help me to figure out the problem ?
Thank you.
You don't want to use any of the template properties of the TabItem, since those are used to create the actual controls, rather than storing them. You should be able to search the visual tree for the ListView directly, rather than going through the DataTemplate.
Ok, here we come :)
I resolve the problem, in not very nice way, but it seems that works correctly.
As I mentioned above I used LoadContent method and it returns me the ListView object, but by the way it wasn't the ListView that UI actually uses. So to resolve that problem I add static property to hold my REAL ListView object (static as I have single DataTemplate that contains ListView shared across multiple TabItems, so the ListView shared too) and add event handler to my DataTemplate -> Loaded. Catching this event, that in my case raises only ones in lifetime of application, in RoutedEvent's OriginalSource I got the REAL ListView object that WPF engine uses for rendering on UI.
Hope my solution will help someone.
Thank you all.
Simply, if you have a DataGrid, and a TemplateColumn which contains a data template, you can use the following code sample:
<DataGridTemplateColumn x:Name="photoPathColumn" Header="{x:Static resx:FrmResource.Photo}" Width="Auto">
<DataGridTemplateColumn.CellEditingTemplate x:Uid="keyelm">
<DataTemplate x:Name="dodo">
<StackPanel Orientation="Horizontal" Height="Auto">
<TextBlock x:Name="photo" x:Uid="imageFile" Text="{Binding Path=PhotoPath}"></TextBlock>
<Button x:Name="Browse" Content="..." Click="Browse_Click"></Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
TextBlock tBlock = (TextBlok)photoPathColumn.CellEditingTemplate.FindName(
"photo",
photoPathColumn.GetCellContent(CustomersDataGrid.CurrentItem));
Where photo is the name of text block
Where photoPathColumn is the DataGrid's TemplateColumn.

Resources