I have the following piece of XAML that creates a treeview and populates it with TreeViewItems.
The Converter simply takes the name and spits back a StackPanel with 2 different coloured strings.
The only way I've found that I can actually use that stackpanel visually is by setting it in the header of a TreeViewItem, this however doesn't work optimally as a TreeViewItem is created programatically already.
The result is that I can't click the label(header) but it looks fancy, however I discovered that there's a big space in front of the label that I can click, which must then be from the generated TreeViewItem.
I really need the label to contain a stackpanel of 2 textblocks, is there a solution for this?
<UserControl.Resources>
<XmlDataProvider x:Key="MyXmlProvider" Source="LogansTest.xml" XPath="/Items"/>
<customScripts:NameGeneration x:Key="NameGeneration"/>
<HierarchicalDataTemplate x:Key="NodeTemplate" ItemsSource="{Binding XPath=./*}">
<TreeViewItem x:Name="nodetext"/>
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=NodeType}" Value="Element">
<Setter TargetName="nodetext" Property="Header" Value="{Binding Converter={StaticResource NameGeneration}}"/>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
</HierarchicalDataTemplate>
</UserControl.Resources>
EDIT
Following mm8's suggestion I've edited my code, I've uploaded my XAML in its entirety, it is no longer generating the tree, I'm pretty new to XAML so I can't see what I'm doing wrong, heh.
Ran a few tests, the converter isn't being called and the treeview is just empty where before it had all the nodes of the XML file
<UserControl x:Class="XmlOutline.OutlineWindowControl"
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:vsshell="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.15.0"
xmlns:customScripts="clr-namespace:XmlOutline.CustomScripts"
Background="{DynamicResource {x:Static vsshell:VsBrushes.WindowKey}}"
Foreground="{DynamicResource {x:Static vsshell:VsBrushes.WindowTextKey}}"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Name="MyToolWindow">
<UserControl.Resources>
<XmlDataProvider x:Key="MyXmlProvider" Source="LogansTest.xml" XPath="/Items"/>
<customScripts:NameGeneration x:Key="NameGeneration"/>
</UserControl.Resources>
<Grid x:Name="TreeGrid" DataContext="MyXmlProvider">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TreeView Name="TreeItems" Visibility="Hidden"
ItemsSource="{Binding Source={StaticResource MyXmlProvider}}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
VirtualizingStackPanel.IsVirtualizing="False"
VirtualizingStackPanel.VirtualizationMode="Standard"
Background="#252525"
SelectedItemChanged="TreeView_OnSelectedItemChanged">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding XPath=./*}"/>
</TreeView.ItemTemplate>
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=NodeType}" Value="Element">
<Setter Property="Header" Value="{Binding Converter={StaticResource NameGeneration}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
</Grid>
</UserControl>
EDIT
This is the code that sets the new datasource whenever a new XML document is opened.
var provider = new XmlDataProvider()
{
Source = new Uri(gotFocus.Document.Path + gotFocus.Document.Name),
XPath = "./*"
};
OutlineWindowInstance.TreeItems.DataContext = provider;
By the way, the entire GIT repo can be found here:
https://github.com/LoganLabster/VsXmlOutline
You are not supposed to create another TreeViewItem container in an HierarchicalDataTemplate. Try to define an ItemContainerStyle that sets the Header property:
<TreeView ItemsSource="{Binding Source={StaticResource MyXmlProvider}}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding XPath=./*}" />
</TreeView.ItemTemplate>
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=NodeType}" Value="Element">
<Setter Property="Header" Value="{Binding Converter={StaticResource NameGeneration}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
Thanks to #mm8 I managed to find the answer, it was really quite simple once I figured it out (which took way too long, doh).
Rather than set the StackPanel to the treeviewitem header, I built the StackPanel in XAML and set the values there one at a time, and voila, it worked.
<UserControl x:Class="XmlOutline.OutlineWindowControl"
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:vsshell="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.15.0"
xmlns:customScripts="clr-namespace:XmlOutline.CustomScripts"
Background="{DynamicResource {x:Static vsshell:VsBrushes.WindowKey}}"
Foreground="{DynamicResource {x:Static vsshell:VsBrushes.WindowTextKey}}"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Name="MyToolWindow">
<UserControl.Resources>
<XmlDataProvider x:Key="MyXmlProvider" Source="LogansTest.xml" XPath="/Items"/>
<customScripts:NameGeneration x:Key="NameGeneration"/>
</UserControl.Resources>
<Grid x:Name="TreeGrid" DataContext="MyXmlProvider">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TreeView Name="TreeItems" Visibility="Hidden"
ItemsSource="{Binding}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
VirtualizingStackPanel.IsVirtualizing="False"
VirtualizingStackPanel.VirtualizationMode="Standard"
Background="#252525"
SelectedItemChanged="TreeView_OnSelectedItemChanged"
TreeViewItem.Expanded="TreeViewItem_Expanded"
TreeViewItem.Collapsed="TreeViewItem_Collapsed">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate x:Name="myTest" ItemsSource="{Binding XPath=./*}">
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="Title" Foreground="LightSkyBlue" FontSize="14"/>
<TextBlock x:Name="SubTitle" Foreground="YellowGreen" FontSize="13"/>
</StackPanel>
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=NodeType}" Value="Element">
<Setter TargetName="Title" Property="Text" Value="{Binding Path=Name}"/>
<Setter TargetName="SubTitle" Property="Text" Value="{Binding Converter={StaticResource NameGeneration}}" />
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</UserControl>
Related
I am trying to figure out how to get data triggers to work between user controls - either between a window and a child user control (a user control embedded in the window), or between a user control that has a child user control.
The button control has 5 buttons but by default the 5th button is collapsed. When the combobox item "Fifth Button" is selected I want the Fourth button to collapse and the Fifth button to become visible. As you can see I have the triggers set to update the Label on the Mainwindow based on the combobox selection. I have no issue using triggers within the same window but I don't know how to make them work to communicate to a user control that is embedded in the same window. Or from one control to another.
<Window x:Class="ComboboxControlChange.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ComboboxControlChange"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ComboBox Grid.Row="0" x:Name="ButtonSelectCombobox" SelectedValuePath="Content" SelectedValue="{Binding ButtonSelection}" Height="24" Margin="150,0">
<ComboBoxItem x:Name="FirstButtonSelection" >First Button</ComboBoxItem>
<ComboBoxItem x:Name="SecondButtonSelection">Second Button</ComboBoxItem>
<ComboBoxItem x:Name="ThirdButtonSelection">Third Button</ComboBoxItem>
<ComboBoxItem x:Name="FourthButtonSelection">Fourth Button</ComboBoxItem>
<ComboBoxItem x:Name="FifthButtonSelection">Fifth Button</ComboBoxItem>
</ComboBox>
<StackPanel Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" Orientation="Vertical">
<Label>You have selected button:</Label>
<Label HorizontalAlignment="Center">
<Label.Style>
<Style TargetType="{x:Type Label}">
<Setter Property="Content" Value=""/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=FirstButtonSelection, Path=IsSelected}" Value="true">
<Setter Property="Content" Value="One" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=SecondButtonSelection, Path=IsSelected}" Value="true">
<Setter Property="Content" Value="Two" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=ThirdButtonSelection, Path=IsSelected}" Value="true">
<Setter Property="Content" Value="Three" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=FourthButtonSelection, Path=IsSelected}" Value="true">
<Setter Property="Content" Value="Four" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=FifthButtonSelection, Path=IsSelected}" Value="true">
<Setter Property="Content" Value="Five" />
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
</StackPanel>
</Grid>
</Grid>
<Grid Grid.Row="1">
<local:ButtonControl />
</Grid>
</Grid>
</Window>
<UserControl x:Class="ComboboxControlChange.ButtonControl"
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:ComboboxControlChange"
mc:Ignorable="d"
d:DesignHeight="160" d:DesignWidth="517">
<Grid Name="Link1MainGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" VerticalAlignment="Center" Margin="5,0" >
<TextBlock TextAlignment="Center">
First<LineBreak/>Button
</TextBlock>
</Button>
<Button Grid.Column="1" VerticalAlignment="Center" Margin="5,0">
<TextBlock TextAlignment="Center">
Second<LineBreak/>Button
</TextBlock>
</Button>
<Button Grid.Column="2" VerticalAlignment="Center" Margin="5,0">
<TextBlock TextAlignment="Center">
Third<LineBreak/>Button
</TextBlock>
</Button>
<Button Grid.Column="3" VerticalAlignment="Center" Margin="5,0" >
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=FifthButtonSelected, Path=IsSelected}" Value="true">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
<TextBlock TextAlignment="Center">
Fourth<LineBreak/>Button
</TextBlock>
</Button>
<Button Grid.Column="3" Margin="4,4,4,50" Visibility="Collapsed">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=FifthButtonSelected, Path=IsSelected}" Value="true">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
<TextBlock TextAlignment="Center">
Fifth<LineBreak/>Button
</TextBlock>
</Button>
</Grid>
</UserControl>
I've tried binding the buttons with ElementName, Path, and even relativeSource but have't had any success. I've also tried adding the triggers in the ButtonControl.Resources section of the control.
<DataTrigger Binding="{Binding ElementName=FifthButtonSelected, Path=IsSelected}" Value="true">
<DataTrigger Binding="{Binding RelativeSource={RelatvieSource FindAncestorType={x:Type ComboBoxItem}}, Path=IsSelected}" Value="true">
Any help would be appreciated!
This won't work because the element names that are in the window will not be in scope for the user control. MSDN says:
[...] the primary XAML namescope is defined at the XAML root element of a
single XAML production, and encompasses the elements that are
contained in that XAML production.
What that means, practically, is that when you define an x:Name for an element in a file, it can only be referenced in that file, and will be unknown outside of it.
Another way to go about this would be to create a Dependency Property on the user control, and use that as a way to pass information between the window and the control. A nice side affect is that this creates some abstraction and allows for more flexibility.
ButtonControl.xaml.cs: (Rename 'Feature' to something relevant)
public partial class ButtonControl : UserControl
{
...
public bool IsFeatureVisible
{
get { return (bool)GetValue(IsFeatureVisibleProperty); }
set { SetValue(IsFeatureVisibleProperty, value); }
}
// Using a DependencyProperty as the backing store for IsFeatureVisible. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsFeatureVisibleProperty =
DependencyProperty.Register("IsFeatureVisible", typeof(bool), typeof(ButtonControl), new UIPropertyMetadata(false));
...
}
Now you could wire up the trigger to use this property, but we're lucky in this case that you're dealing with booleans and Visibility, so we can make it simpler:
ButtonControl.xaml:
<UserControl x:Class="ComboboxControlChange.ButtonControl"
x:Name="Myself"
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:ComboboxControlChange"
mc:Ignorable="d"
d:DesignHeight="160" d:DesignWidth="517">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="mBooleanToVisibilityConverter"/>
</UserControl.Resources>
<Grid Name="Link1MainGrid">
...
<Button Grid.Column="3" VerticalAlignment="Center" Margin="5,0" Visibility="{Binding ElementName=Myself, Path=IsFeatureVisible, Converter={StaticResource mBooleanToVisibilityConverter}}">
<TextBlock TextAlignment="Center">
Fourth<LineBreak/>Button
</TextBlock>
</Button>
...
</Grid>
</UserControl>
Lastly, in the Window, we need to provide a value for that property on the instance of our button control. We can use the FifthButtonSelection element name here just like you are in other parts of the file:
MainWindow.xaml
<local:ButtonControl IsFeatureVisible="{Binding ElementName=FifthButtonSelection, Path=IsSelected}"/>
I have this xaml with grid of accounts:
<UserControl x:Class="SpectroCoin.Controls.AccountInfo"
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"
xmlns:effects="clr-namespace:SpectroCoin.Effects"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="130" d:DesignWidth="480">
<UserControl.Resources>
<Style x:Key="MainInfoStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="32"/>
<Setter Property="VerticalAlignment" Value="Bottom"/>
</Style>
<Style x:Key="ReservedInfoStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="20"/>
<Setter Property="VerticalAlignment" Value="Bottom"/>
</Style>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Margin="0,0,0,0" >
<StackPanel Orientation="Vertical" Grid.Column="0" Margin="0,0,0,0">
<TextBlock FontSize="24" Text="Label" x:Name="txtLabel" Margin="0"/>
<TextBlock FontSize="50" Text="{Binding Account.AvailableStr}" Margin="50,-10,0,0" Foreground="#FFF9AF28"/>
<TextBlock FontSize="24" Margin="50,-15,0,0" Visibility="{Binding ReservedVisibility}">
<Run Foreground="Gainsboro" Text="{Binding LocalizedResources.reserved, Source={StaticResource LocalizedStrings}, StringFormat='\{0\} '}"/>
<Run Foreground="Gainsboro" Text="{Binding Account.ReservedStr}"/>
</TextBlock>
</StackPanel>
</Grid>
</UserControl>
And I am adding this layout programatically for every account I have using foreach:
foreach (Account.Account account in GetModel().BalancePageModel.Accounts)
{
var myAccountInfoControl = new AccountInfo(account);
//myAccountInfoControl.txtLabel.SetBinding()
AccountsInfo.Children.Add(myAccountInfoControl);
}
My layout is created, but the values of AvailableStr, txtLabel and ReservedStr doesn't change because I haven't enabled Databinding programatically, how do I do that?
You have to set the DataContext of myAccountInfoControl to the account object.
myAccountInfoControl.DataContext = account;
If you do this the bindings that you have done in the XAML should be changed by removing the "Account." part like this:
Hope this help.
I have a listbox that contains a control chooser I'm trying to develop. Basically, the datasource is XML and I want to read the current context to decide which element control to display.
For this purpose I want to grab the XmlDataProvider with the current item's context, and evaluate that XML. Within XAML I would write {Binding Path=#label} to retrieve a label attribute from the curretn XML element. From code behind, I cant even figure where to get this XML, as it's passed to the class by the list control to this control, but not as an accessible property so far as I can find.
Anyway getting #label isn't sufficient; I want the XmlElement object in class ControlChooser, instantiated below.
<ListBox
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding XPath=*[not(self::units)]}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<W3V:ControlChooser/>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<!-- Force the items to fill all available space. -->
<Style TargetType="ListBoxItem">
<Setter
Property="VerticalContentAlignment"
Value="Stretch"
/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Or, if you can suggest another way to get the job (switching what control is displayed) done....
You can use multiple DataTemplates to style the different element types. If you are familiar with XSLT, DataTemplates are the functional equivalent of xsl:template.
Example to style:
<Window x:Class="ZoomingScrollViewer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<XmlDataProvider x:Key="testData" XPath="/Contacts/*">
<x:XData>
<Contacts xmlns="">
<Person Name="John" />
<Person Name="Robby" />
<Business>
<ContactName>Jemma</ContactName>
<BusinessName>Ars</BusinessName>
</Business>
<Business>
<BusinessName>The other one</BusinessName>
</Business>
</Contacts>
</x:XData>
</XmlDataProvider>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding Source={StaticResource testData}}">
<ListBox.Resources>
<DataTemplate DataType="Person">
<TextBlock Text="{Binding XPath=#PersonName}" />
</DataTemplate>
<DataTemplate DataType="Business">
<StackPanel>
<TextBlock Text="{Binding XPath=ContactName}" />
<TextBlock Text="{Binding XPath=BusinessName}" />
</StackPanel>
</DataTemplate>
</ListBox.Resources>
</ListBox>
</Grid>
</Window>
If you wanted to select the DataTemplate based off of an attribute, rather than an element, you can use a DataTemplateSelector to run arbitrary code as explained in this question.
I found "Different views / data template based on member variable" as the closest to an answer. With the idea there, I could make a standalone control that made sense to me. This is the key bit:
<DataTrigger Binding="{Binding XPath=#kind}" Value="Number">
<Setter Property="ContentTemplate" Value="{StaticResource SmallInt}" />
</DataTrigger>
Here's the whole control:
<ContentControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:W3V="clr-namespace:W3.Views"
x:Class="W3.Views.ControlChooser">
<ContentControl.Resources>
<DataTemplate x:Key="StringChoice" >
<W3V:ComboView />
</DataTemplate>
<DataTemplate x:Key="SmallInt" >
<W3V:SpinView />
</DataTemplate>
</ContentControl.Resources>
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource StringChoice}" />
<Style.Triggers>
<DataTrigger Binding="{Binding XPath=#kind}" Value="Number">
<Setter Property="ContentTemplate" Value="{StaticResource SmallInt}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
I am new to using XAML and C# in general so this is probably an easy question but I have my XAML as so
<Page
x:Class="Tournament_Director_Windows.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Tournament_Director_Windows"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="LightGray">
<Button Style="{StaticResource AddAppBarButtonStyle}" Foreground="#FF094AB2" Click="onAddNewBowlerClick" HorizontalAlignment="Right" RenderTransformOrigin="0.4,0.508" Margin="0,10,115,679"/>
<ListView Height="648" Width="377" HorizontalAlignment="Left" VerticalAlignment="Top" x:Name="itemListView" ItemClick="itemListView_ItemClick" ItemsSource="{Binding}" IsItemClickEnabled="True" Margin="225,110,0,0">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<TextBlock TextWrapping="Wrap" Text="Bowlers" Height="54" Width="177" FontSize="50" Foreground="#FF094AB2" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="225,10,964,704"/>
<Button Style="{StaticResource RefreshAppBarButtonStyle}" Click="onSyncClick" Background="#FFF8FCFD" HorizontalAlignment="Right" Foreground="#FF094AB2" BorderBrush="#FFFBF9F9" Margin="0,10,10,679"/>
<ListView HorizontalAlignment="Left" Height="Auto" Width="220" Background="Silver" SelectionChanged="MenuListView_SelectionChanged">
<!--<ListView.Resources>
<Style TargetType="ListViewItem">
<Setter Property="Foreground" Value="#FF094AB2" />
<Setter Property="FontSize" Value="30" />
<Setter Property="Height" Value="75"/>
</Style>
</ListView.Resources>-->
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Foreground" Value="#FF094AB2" />
<Setter Property="FontSize" Value="25" />
<Setter Property="Height" Value="75"/>
<Setter Property="Padding" Value="10"/>
</Style>
</ListView.ItemContainerStyle>
<x:String>Bowlers</x:String>
<x:String>Brackets</x:String>
<x:String>Scores</x:String>
</ListView>
<ScrollViewer Height="Auto" HorizontalAlignment="Stretch" Width="754" Margin="602,110,0,10">
</ScrollViewer>
</Grid>
my question is about the ScrollViewer at the end, I have it as a set width but what I want to do is have the width fill the rest of the screen from its set position next to my ListView so no matter what screen size you have it looks the same and there is not a big space if you have a bigger screen or it gets cut off because the screen is smaller.
How can I do that?
Try to use <ColumnDefinitions> with width property "Auto" or "*" and <RowDefinitions> with height property "Auto" or "*" for grid. In this case you can manage what part of your content has permanent size and what part will resize with a window.
I have a list view and 2 resources for display the list's view: BooksGridView & ImageDetailView.
The ViewModel has a string property named ViewMode, which contains the name of the view i currently want to display. (It is changed from another control, using toolbars)
I am trying to change the selected view by using DataTrigger, but I cant seem to get the View property to change.
When i set the View resource directly, the correct view is displayed. I also added background changes to make sure the data trigger is activated, and the background did change.
So I'm obviously missing something here...
<UserControl x:Class="eLibrary.View.FilteredBooksView"
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:Converters="clr-namespace:eLibrary.Converters"
xmlns:Controls="clr-namespace:eLibrary.Controls"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
xmlns:local="clr-namespace:eLibrary"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<Converters:CoverImageConverter x:Key="CoverImageConverter"/>
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
<GridView x:Key="BooksGridView">
...
</GridView>
<Controls:TileView x:Key="ImageDetailView">
...
</Controls:TileView>
<CollectionViewSource x:Key="sortedBooks" Source="{Binding Books}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Title" Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<Style TargetType="{x:Type ListView}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ViewMode}" Value="BooksGridView">
<Setter Property="View" Value="{StaticResource BooksGridView}"/>
<Setter Property="Background" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=ViewMode}" Value="ImageDetailView">
<Setter Property="View" Value="{StaticResource ImageDetailView}" />
<Setter Property="Background" Value="Blue"/>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<ListView
VerticalAlignment="Stretch"
Name="BooksListView"
View="{StaticResource BooksGridView}"
SelectionMode="Extended"
ItemsSource="{Binding Source={StaticResource sortedBooks}}">
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" />
<Setter Property="Visibility" Value="{Binding Path=ShouldDisplay, Converter={StaticResource BoolToVisConverter} }" />
</Style>
</ListView.Resources>
</ListView>
</UserControl>
Thanks
Based off the sample on MSDN, the following works at changing the view based on a change in the ViewModel. The only difference I can see with your code is the use of DynamicResource:
<Window x:Class="SDKSample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Custom View"
xmlns:l="clr-namespace:SDKSample"
Width="400" Height="500"
SourceInitialized="Window_SourceInitialized">
<Window.Resources>
<DataTemplate x:Key="centralTile">
<StackPanel Height="100" Width="90">
<Grid Width="70" Height="70" HorizontalAlignment="Center">
<Image Source="{Binding XPath=#Image}" Margin="6,6,6,9"/>
</Grid>
<TextBlock Text="{Binding XPath=#Name}" FontSize="13"
HorizontalAlignment="Center" Margin="0,0,0,1" />
<TextBlock Text="{Binding XPath=#Type}" FontSize="9"
HorizontalAlignment="Center" Margin="0,0,0,1" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="iconTemplate">
<DockPanel Height="33" Width="150">
<Image Source="{Binding XPath=#Image}" Margin="2"/>
<TextBlock DockPanel.Dock="Top" Text="{Binding XPath=#Name}"
FontSize="13" HorizontalAlignment="Left"
Margin="0,0,0,1" />
<TextBlock Text="{Binding XPath=#Type}" FontSize="9"
HorizontalAlignment="Left" Margin="0,0,0,1" />
</DockPanel>
</DataTemplate>
<DataTemplate x:Key="checkbox">
<CheckBox IsChecked="{Binding IsSelected, RelativeSource= {RelativeSource AncestorType=ListViewItem}}"
Margin="0,1,1,1" >
</CheckBox>
</DataTemplate>
<XmlDataProvider x:Key="myXmlDataBase" XPath="/myXmlData">
<x:XData>
<myXmlData xmlns="">
<Item Name = "Fish" Type="fish" Image="images\fish.png"/>
<Item Name = "Dog" Type="animal" Image="images\dog.png"/>
<Item Name = "Flower" Type="plant" Image="images\flower.jpg"/>
<Item Name = "Cat" Type="animal" Image="images\cat.png"/>
</myXmlData>
</x:XData>
</XmlDataProvider>
<DataTemplate x:Key="DisplayImage">
<StackPanel Width="50">
<Image Source="{Binding XPath=#Image}"/>
</StackPanel>
</DataTemplate>
<GridView x:Key="gridView">
<GridViewColumn CellTemplate="{StaticResource checkbox}"/>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding XPath=#Name}"/>
<GridViewColumn Header="Type" DisplayMemberBinding="{Binding XPath=#Type}"/>
<GridViewColumn Header="Image" CellTemplate="{StaticResource DisplayImage}"/>
</GridView>
<l:PlainView x:Key="tileView" ItemTemplate="{StaticResource centralTile}" ItemWidth="100"/>
<l:PlainView x:Key="iconView" ItemTemplate="{StaticResource iconTemplate}" ItemWidth="150"/>
<Style TargetType="{x:Type ListView}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ViewName}" Value="iconView">
<Setter Property="View" Value="{DynamicResource iconView}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=ViewName}" Value="tileView">
<Setter Property="View" Value="{DynamicResource tileView}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ViewName}" Value="gridView">
<Setter Property="View" Value="{DynamicResource gridView}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<ListView Name="lv"
ItemsSource="{Binding Source={StaticResource myXmlDataBase}, XPath=Item}"
FontSize="12"
Background="LightBlue" >
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="gridView" Click="SwitchViewMenu"/>
<MenuItem Header="iconView" Click="SwitchViewMenu"/>
<MenuItem Header="tileView" Click="SwitchViewMenu"/>
</ContextMenu>
</ListView.ContextMenu>
</ListView>
<TextBlock FontSize="16" Foreground="Blue">
CurrentView: <TextBlock Name="currentView" Text="{Binding Path=ViewName}"/>
</TextBlock>
<TextBlock>
Right-click in the content window to change the view.
</TextBlock>
</StackPanel>
</Window>
Code behind file:
using System;
using System.Windows;
using System.Windows.Controls;
namespace SDKSample
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
public MainViewModel ViewModel
{
get { return this.DataContext as MainViewModel; }
}
void SwitchViewMenu(object sender, RoutedEventArgs args)
{
MenuItem mi = (MenuItem)sender;
ViewModel.ViewName = mi.Header.ToString();
}
private void Window_SourceInitialized(object sender, EventArgs e)
{
ViewModel.ViewName = "gridView";
}
}
}
And finally the ViewModel class:
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
namespace SDKSample
{
public class MainViewModel : INotifyPropertyChanged
{
public string ViewName
{
get { return viewName; }
set
{
if (viewName == value)
return;
viewName = value;
NotifyPropertyChanged("ViewName");
}
}
private string viewName;
public event PropertyChangedEventHandler PropertyChanged;
void NotifyPropertyChanged(string name)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
I cannot see any obvious issue with your code you provided. I would usually suggest checking that the DataTrigger is being trigger, however you have already tested that with the Background property.
Looking at sample on MSDN (link) the only difference in implementation is that, in the sample, switch the ListView.View is changed in code.
BookListView.View = this.FindResource("BooksGridView") as ViewBase;
...
Hmm, perhaps the view resource may not be able to found and it is failing.
...
All I can suggest is look at the sample. Sorry couldn't be much more help.