I am working in Visual Studio 2013 in WPF (C#) and I have the following code to create an expander from my xml. It is currently working perfectly right now but I want to include an expand all and collapse all buttons. I have looked all over and can't seem to find a solution.
Here is where the expander is created. I know I just have to iterate through a list of items and change the Property="IsExpanded" to Value="True" to create an expand all.
<DataTemplate x:Key="dtListTemplate" >
<StackPanel>
<Expander LostFocus="CollapseExpander" ExpandDirection="Down" Width="Auto">
<Expander.Style>
<Style TargetType="Expander">
<Setter Property="IsExpanded" Value="False" />
<Setter Property="Header" Value="{Binding XPath=#Name}" />
<Setter Property="FontWeight" Value="Bold"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsExpanded,RelativeSource={RelativeSource Self}}" Value="True">
</DataTrigger>
</Style.Triggers>
</Style>
</Expander.Style>
<ListBox Name="itemsList"
ItemsSource="{Binding XPath=UpgradeAction}"
ItemTemplate="{StaticResource dtListItemTemplate}"
SelectionChanged="listItems_SelectionChanged"
Style="{StaticResource styleListBoxUpgradeAction}"
ItemContainerStyle="{StaticResource styleListBoxItemUpgradeAction}">
</ListBox>
</Expander>
</StackPanel>
</DataTemplate>
Here's the code that calls the DataTemplate which has information from an Xml.
<StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Border Grid.Column="0" Grid.Row="0" Width="790" Height="40" Padding="5" Background="#4E87D4">
<Label VerticalAlignment="Center" FontSize="16" FontWeight="Bold" Foreground="White">Test</Label>
</Border>
<Button Name="ExpandBttn" Width="100" Height="40" FontSize="16" FontWeight="Bold" Content="Expand All" DataContext="{Binding}" Click="Expand_Button_Click"/>
<Button Name="ColapseBttn" Width="100" Height="40" FontSize="16" FontWeight="Bold" Content="Colapse All" DataContext="{Binding}" Click="Collapse_Button_Click"/>
</StackPanel>
<ListView Name="listItems" Grid.Column="0" Grid.Row="1" Background="Wheat"
ItemsSource="{Binding Source={StaticResource xmldpUpgradeActions}, XPath=ActionGroup}"
ItemTemplate="{StaticResource dtListTemplateRichards}"
SelectionChanged="listItems_SelectionChanged">
</ListView>
</StackPanel>
Here's what I tried in the .cs file for the expand all portion.
private void Expand_Button_Click(object sender, RoutedEventArgs e)
{
foreach(var item in listItems.Items)
{
var listBoxItem = listItems.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem;
var itemExpander = (Expander)GetExpander(listBoxItem);
if (itemExpander != null)
itemExpander.IsExpanded = true;
}
}
private static DependencyObject GetExpander(DependencyObject container)
{
if (container is Expander) return container;
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(container); i++)
{
var child = VisualTreeHelper.GetChild(container, i);
var result = GetExpander(child);
if (result != null)
{
return result;
}
}
return null;
}
Any help is greatly appreciated!
Is xmldpUpgradeActions a CollectionViewSource?
Whatever class is in the collection, it should implement INotifyPropertyChanged.
Give it an IsExpanded property that raises PropertyChanged in its setter when its value changes, and bind that to Expander.IsExpanded in the template:
<Expander
IsExpanded="{Binding IsExpanded}"
LostFocus="CollapseExpander"
ExpandDirection="Down"
Width="Auto">
Write a command that loops through all the items in the collection and sets item.IsExpanded = false; on each one.
I have ItemControl
<ItemsControl ItemsSource="{Binding CanvasCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Width="{Binding CanvasSize}" Height="{Binding CanvasSize}" Background="RoyalBlue" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X}" />
<Setter Property="Canvas.Top" Value="{Binding Y}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type viewModels:VertexViewModel}">
<Thumb Width="11" Height="11">
<Thumb.Template>
<ControlTemplate>
<Ellipse Width="11" Height="11" Fill="{Binding Fill}" />
</ControlTemplate>
</Thumb.Template>
</Thumb>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And composite collection with currently one ObservableCollection:
private ObservableCollection<VertexViewModel> Points { get; set; }
public CompositeCollection CanvasCollection { get; set; }
While debugging, I see that collection contains two elements, as I accepted, but only first is displaying on Canvas. When I call Refresh() method in model, I see that binding working, but only for first element.
Adding Point to CompositeCollection:
Points = new ObservableCollection<VertexViewModel>();
CanvasCollection = new CompositeCollection()
{
Points
};
I had to use container for collectoin:
CanvasCollection = new CompositeCollection
{
new CollectionContainer() {Collection = Points},
Polygon,
};
I have listbox in which i have an ItemTemplate and in ItemTemplate i have a DataTemplate in that i have a Canvas which acts as a button, so my requirement is when an item i.e. Canvas gets selected background should be changed, by default the selection should be the first item and when the selection is changed i need the selected canvas background color to be changed accordingly how can i achieve this looking for a genuine help thanks in advance.
I've Tried The below code :-
This is my XAML :-
<Canvas x:Name="Canvas_Main" Margin="23,191,27,75" Tap="Canvas_Main_Tap">
<ListBox x:Name="Listbox_Main" Height="534" Width="430" ItemsSource="{Binding}" SelectionChanged="Listbox_Main_SelectionChanged" Tap="Listbox_Main_Tap" Canvas.Left="10" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Padding" Value="5"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Canvas x:Name="cnv_Items" Height="100" Width="200">
<Border Height="100" Width="200" BorderThickness="2" BorderBrush="#FFD0D0D0"/>
<TextBlock x:Name="Tb_Value" Text="{Binding Value}" TextWrapping="NoWrap" Foreground="Black" TextAlignment="Right" FontSize="26" Height="40" Width="195" Canvas.Top="10" Canvas.Left="2"/>
<TextBlock x:Name="Tb_UnitName" Text="{Binding Key}" Foreground="Black" TextAlignment="Right" FontSize="19" Height="40" Width="180" Canvas.Top="55" Canvas.Left="10"/>
</Canvas>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Canvas>
And this is what i've tried in my Code Behind :-
private void Listbox_Main_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (Canvas_KeyBoard.Visibility == Visibility.Visible)
OutAnimation();
if (Listbox_Main.SelectedItem != null)
{
myitem = (KeyValuePair<string, string>)Listbox_Main.SelectedItem;
ListBoxItem myitem1 = Listbox_Main.SelectedItem as ListBoxItem;
SolidColorBrush brush = new SolidColorBrush(Color.FromArgb(255, 255, 0, 0));
myitem1.Background = brush;
Conversion_Logic();
}
}
I'm trying to create a simple photo album (Windows Store App) using Flip View.
I have the Image element embedded within a ScrollViewer. I'm able to browse through the photos, but I'm looking to do the following things.
The image should fill the height of the screen uniformly [when the image is not zoomed]. I get vertical scrollbars for few items. I dont have this problem when the height of all the images are the same.
When I change the orientation of the screen, a part of the image is clipped on the right side.
The scrollviewer should forget the zoom level (reset zoom factor to 1) when I move between pages.
This is the code I have right now. What Am I doing wrong? And what should I add in my EventHandler to reset my ScrollViewer's zoom factor.
<FlipView
Name="MainFlipView"
Margin="0"
Height="{Binding ActualHeight, ElementName=pageRoot, Mode=OneWay}"
Width="{Binding ActualWidth, ElementName=pageRoot, Mode=OneWay}"
Background="Black">
<FlipView.ItemTemplate>
<DataTemplate>
<ScrollViewer Name="myScrollViewer" ZoomMode="Enabled"
Height="{Binding ActualHeight, ElementName=pageRoot, Mode=OneWay}"
Width="{Binding ActualWidth, ElementName=pageRoot, Mode=OneWay}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
MinZoomFactor="0.5"
MaxZoomFactor="2.5"
Margin="0" >
<Image Source="{Binding Path=Image}"
Name="MainImage" Stretch="Uniform" />
</ScrollViewer>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
What user2199147 said should solve your first bullet point, the other two I had to fix programmatically, though it should be noted that I also had to use the VisualTreeHelper class which you'll have to import, and an extension method to help me use the helper class.
First of all, I had to a method from the VisualTreeHelper extension, which finds the first element in the FlipView that is of any type:
private T FindFirstElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject
{
if (parentElement != null)
{
var count = VisualTreeHelper.GetChildrenCount(parentElement);
if (count == 0)
return null;
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(parentElement, i);
if (child != null && child is T)
return (T)child;
else
{
var result = FindFirstElementInVisualTree<T>(child);
if (result != null)
{
return result;
}
}
}
}
return null;
}
For going into portrait mode, I added a callback handler for WindowSizeChanged, and simply reset all the ScrollViewers in the flip view back to their default
private void WindowSizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
//Reset scroll view size
int count = MainFlipView.Items.Count;
for(int i = 0; i < count; i++)
{
var flipViewItem = MainFlipView.ItemContainerGenerator.ContainerFromIndex((i));
var scrollViewItem = FindFirstElementInVisualTree<ScrollViewer>(flipViewItem);
if (scrollViewItem is ScrollViewer)
{
ScrollViewer scroll = (ScrollViewer)scrollViewItem;
scroll.Height = e.Size.Height; //Reset width and height to match the new size
scroll.Width = e.Size.Width;
scroll.ZoomToFactor(1.0f);//Zoom to default factor
}
}
}
And then in your constructor you need Window.Current.SizeChanged += WindowSizeChanged; in order for the callback to ever be called.
Now, for setting each ScrollViewer back to their default positions, we do a similar process, only whenever the FlipView selection is changed, we reset the ScrollViewer back to its default zoom factor
private void FlipViewSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender is FlipView)
{
FlipView item = (FlipView)sender;
var flipViewItem = ((FlipView)sender).ItemContainerGenerator.ContainerFromIndex(((FlipView)sender).SelectedIndex);
var scrollViewItem = FindFirstElementInVisualTree<ScrollViewer>(flipViewItem);
if (scrollViewItem is ScrollViewer)
{
ScrollViewer scroll = (ScrollViewer)scrollViewItem;
scroll.ScrollToHorizontalOffset(0);
scroll.ScrollToVerticalOffset(0);
scroll.ZoomToFactor(1.0f);
}
}
}
And again, we have to have a call in the constructor that looks like MainFlipView.SelectionChanged += FlipViewSelectionChanged;
I know these methods seem really hackish and roundabout, because they are, but it's what worked for me, and I hope this helps.
try changing the height and width bindings from the scrollviewer to the image.
<FlipView
Name="MainFlipView"
Margin="0"
Height="{Binding ActualHeight, ElementName=pageRoot, Mode=OneWay}"
Width="{Binding ActualWidth, ElementName=pageRoot, Mode=OneWay}"
Background="Black">
<FlipView.ItemTemplate>
<DataTemplate>
<ScrollViewer Name="myScrollViewer" ZoomMode="Enabled"
HorizontalAlignment="Center"
VerticalAlignment="Center"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
MinZoomFactor="0.5"
MaxZoomFactor="2.5"
Margin="0" >
<Image Source="{Binding Path=Image}"
Height="{Binding ActualHeight, ElementName=pageRoot, Mode=OneWay}"
Width="{Binding ActualWidth, ElementName=pageRoot, Mode=OneWay}"
Name="MainImage" Stretch="Uniform" />
</ScrollViewer>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
Good practice for WinRT is:
1) Make Attached Property for ScrollViewer, which will change ZoomFactor
public class ScrollViewerExtension : DependencyObject
{
public static readonly DependencyProperty ScrollViewerZoomFactorProperty = DependencyProperty.RegisterAttached(
"ScrollViewerZoomFactor", typeof(double), typeof(ScrollViewerExtension), new PropertyMetadata(default(double), OnZoomFactorChanged));
public static void SetScrollViewerZoomFactor(DependencyObject element, double value)
{
element.SetValue(ScrollViewerZoomFactorProperty, value);
}
public static double GetScrollViewerZoomFactor(DependencyObject element)
{
return (double)element.GetValue(ScrollViewerZoomFactorProperty);
}
private static void OnZoomFactorChanged(DependencyObject depObject, DependencyPropertyChangedEventArgs args)
{
if (depObject is ScrollViewer)
{
var scrollViewer = (ScrollViewer)depObject;
var zoomValue = (double)args.NewValue;
if (!Double.IsNaN(zoomValue))
scrollViewer.ZoomToFactor((float)zoomValue);
}
else
{
throw new Exception("ARE YOU KIDDING ME ? ITS NOT SCROLLVIEWER");
}
}
}
2) Changer FlipViewItem Template
<Style TargetType="FlipViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Width="1040">
<ScrollViewer HorizontalAlignment="Stretch"
HorizontalScrollBarVisibility="Auto"
MaxZoomFactor="4"
MinZoomFactor="1"
Tag="{Binding IsSelected}"
VerticalScrollBarVisibility="Auto"
VerticalScrollMode="Auto"
ZoomMode="Enabled"
extension:ScrollViewerExtension.ScrollViewerZoomFactor="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected, Converter={StaticResource IsSelectedToZoom}}">
<ContentPresenter />
</ScrollViewer>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
3) Create converter, which will change ScrollViewerZoomFactor to default value if item isnt selected.
public class IsSelectedToZoomConverter :DependencyObject, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var val = (bool) value;
return val ? Double.NaN : 1.0;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
4) FlipView code will look like this:
<FlipView x:Name="FlipView"
Grid.Row="5"
Width="1040"
MinHeight="392"
MaxHeight="600"
ItemsSource="{Binding Path=CurrentSession.Photos}"
Visibility="{Binding CurrentSession.HasContent,
Converter={StaticResource BoolToVisibility}}">
<FlipView.ItemContainerStyle>
<Style TargetType="FlipViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Width="1040">
<ScrollViewer HorizontalAlignment="Stretch"
HorizontalScrollBarVisibility="Auto"
MaxZoomFactor="4"
MinZoomFactor="1"
Tag="{Binding IsSelected}"
VerticalScrollBarVisibility="Auto"
VerticalScrollMode="Auto"
ZoomMode="Enabled"
extension:ScrollViewerExtension.ScrollViewerZoomFactor="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=IsSelected,
Converter={StaticResource IsSelectedToZoom}}">
<ContentPresenter />
</ScrollViewer>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</FlipView.ItemContainerStyle>
<FlipView.ItemTemplate>
<DataTemplate>
<Image HorizontalAlignment="Stretch" Source="{Binding Path=Path}" />
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
why do you have a ScrollViewer within you FlipViewItemTemplate?
Thie template will be used for each Item, so for each Image you add to your ItemList.
that said it shoud be enough to have the Image element within your Template.
this should at least avoid the scrollbars for images that are bigger than your screen, cause then the Stretch="Uniform" should handle the resizing...
So I have a grid inside a viewbox. Now the grid scales with the viewbox fine. However, I need to know the height and width of the grid in my ViewModel. However it doesn't seem to ever set the Height to anything?
<Viewbox VerticalAlignment="Top" Margin="5,20,5,0">
<Border BorderThickness="6" BorderBrush="Black" CornerRadius="2">
<Grid MinHeight="300" MinWidth="400" Height="{Binding Height, Mode=TwoWay}" Width="{Binding Width, Mode=TwoWay}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="0" >
<ItemsControl ItemsSource="{Binding Viewers}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Left" Value="{Binding X}" />
<Setter Property="Canvas.Top" Value="{Binding Y}"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</Grid>
</Border>
</Viewbox>
And in my ViewModel:
private int _height;
public int Height
{
get
{
return _height;
}
set
{
_height = value;
OnPropertyChanged("Height");
}
}
private int _width;
public int Width
{
get
{
return _width;
}
set
{
_width = value;
OnPropertyChanged("Width");
}
}
Any ideas?
You would need a OneWayToSource binding on ActualWidth/Height as those properties are readonly, so far i have seen any good solutions to that as WPF reject bindings outright if set on a readonly dependency property.