I'm relatively new to WPF, I come from a WinForms background, I'm trying to implement a coverflow, and I don't fully understand the example, from I what I see, I add the paths to my images to a StringCollection.
This is what I have right now :
public MainWindow()
{
InitializeComponent();
elementFlow1.Layout = new CoverFlow();
StringCollection itemssource = new StringCollection();
itemssource.Add(#"Images\1.png");
itemssource.Add(#"Images\2.png");
elementFlow1.SelectedIndex = 0;
elementFlow1.ItemsSource = itemssource;
}
And I have the ElementFlow defined in XAML like so:
<fluidkit:ElementFlow Grid.Row="1" Height="194" Name="elementFlow1" VerticalAlignment="Top" Width="503" />
Lo and behold, when I run it, nothing happens.
Can someone please explain how I'm supposed to use ElementFlow? The example doesn't really "explain" it very well.
You're missing a key step. The ElementFlow control displays UIElements, not strings. You have a list of strings that contain the logical file location of the image files. Now you need to convert that collection of strings to a collection of DataTemplates. If you look in the sample xaml file, you'll see this section:
<DataTemplate x:Key="TestDataTemplate"
DataType="{x:Type sys:String}">
<Border x:Name="ElementVisual"
Background="White"
Padding="5"
BorderThickness="5"
BorderBrush="LightGray"
Grid.Row="0">
<Image Source="{Binding}"
Stretch="Fill" />
</Border>
</DataTemplate>
That section essentially takes a string input and converts it to a DataTemplate. This is done by setting the ItemTemplate property to this DataTemplate resource.
You'll probably be better off manipulating this control in XAML rather than code-behind. Things are easier that way (in my opinion anyways).
Hope this helps.
I would recommend following the Examples provided:
http://fluidkit.codeplex.com/SourceControl/latest#FluidKit.Samples/ElementFlow/ElementFlowExample.xaml.cs
This is my mod, Project named: ElementFlowExample
namespace ElementFlowExample
{
#region Using Statements:
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Navigation;
using System.Windows.Shapes;
using FluidKit.Controls;
using FluidKit.Showcase.ElementFlow;
#endregion
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
#region Fields:
private StringCollection _dataSource;
private LayoutBase[] _layouts = {
new Wall(),
new SlideDeck(),
new CoverFlow(),
new Carousel(),
new TimeMachine2(),
new ThreeLane(),
new VForm(),
new TimeMachine(),
new RollerCoaster(),
new Rolodex(),
};
private Random _randomizer = new Random();
private int _viewIndex;
#endregion
#region Properties:
#endregion
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_elementFlow.Layout = _layouts[3];
_currentViewText.Text = _elementFlow.Layout.GetType().Name;
_selectedIndexSlider.Maximum = _elementFlow.Items.Count - 1;
_elementFlow.SelectionChanged += EFSelectedIndexChanged;
_elementFlow.SelectedIndex = 0;
_dataSource = FindResource("DataSource") as StringCollection;
}
private void EFSelectedIndexChanged(object sender, SelectionChangedEventArgs e)
{
Debug.WriteLine((sender as ElementFlow).SelectedIndex);
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.F12)
{
_viewIndex = (_viewIndex + 1) % _layouts.Length;
_elementFlow.Layout = _layouts[_viewIndex];
_currentViewText.Text = _elementFlow.Layout.GetType().Name;
}
}
private void ChangeSelectedIndex(object sender, RoutedPropertyChangedEventArgs<double> args)
{
_elementFlow.SelectedIndex = (int)args.NewValue;
}
private void RemoveCard(object sender, RoutedEventArgs args)
{
if (_elementFlow.Items.Count > 0)
{
_dataSource.RemoveAt(_randomizer.Next(_dataSource.Count));
// Update selectedindex slider
_selectedIndexSlider.Maximum = _elementFlow.Items.Count - 1;
}
}
private void AddCard(object sender, RoutedEventArgs args)
{
Button b = sender as Button;
int index = _randomizer.Next(_dataSource.Count);
if (b.Name == "_regular")
{
_dataSource.Insert(index, "Images/01.jpg");
}
else
{
_dataSource.Insert(index, string.Format("Images/{0:00}", _randomizer.Next(1, 12)) + ".jpg");
}
// Update selectedindex slider
_selectedIndexSlider.Maximum = _elementFlow.Items.Count - 1;
}
} // END of Class...
} // END of Namespace...
<Window x:Class="ElementFlowExample.MainWindow"
xmlns:b="clr-namespace:ElementFlowExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:FluidKit.Showcase.ElementFlow"
xmlns:Controls="clr-namespace:FluidKit.Controls;assembly=FluidKit"
Loaded="Window_Loaded"
Title="ElementFlow - FluidKit"
WindowStartupLocation="CenterScreen"
Width="1280"
Height="720">
<Window.Resources>
<local:StringCollection x:Key="DataSource" />
<LinearGradientBrush x:Key="ReflectionBrush" StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="#7F000000" />
<GradientStop Offset=".5" Color="Transparent" />
</LinearGradientBrush>
<DataTemplate x:Key="TestDataTemplate"
DataType="{x:Type sys:String}">
<Border x:Name="ElementVisual"
Background="White"
Padding="5"
BorderThickness="5"
BorderBrush="LightGray"
Grid.Row="0">
<Image Source="{Binding}"
Stretch="Fill" />
</Border>
</DataTemplate>
<DataTemplate x:Key="TestDataTemplate_Reflection">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.5*" />
<RowDefinition Height="0.5*" />
</Grid.RowDefinitions>
<Border x:Name="ElementVisual"
BorderThickness="2"
BorderBrush="LightYellow"
Background="Black"
Padding="2">
<Image Source="{Binding}"
Stretch="Fill" />
</Border>
<Rectangle OpacityMask="{StaticResource ReflectionBrush}"
Grid.Row="1"
Height="{Binding ActualHeight, ElementName=ElementVisual}">
<Rectangle.Fill>
<VisualBrush Visual="{Binding ElementName=ElementVisual}">
<VisualBrush.RelativeTransform>
<ScaleTransform ScaleX="1"
ScaleY="-1"
CenterX="0.5"
CenterY="0.5" />
</VisualBrush.RelativeTransform>
</VisualBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
</DataTemplate>
<DataTemplate x:Key="ItemTemplate">
<Border BorderBrush="#FFB1B1B1"
BorderThickness="2"
Background="#7FFFFFFF"
Padding="0,20,0,0"
CornerRadius="3">
<Image Source="{Binding Image}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Stretch="Fill" />
</Border>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical"
Grid.Row="1"
Grid.Column="0"
Margin="5">
<Label Content="SelectedIndex" />
<Slider x:Name="_selectedIndexSlider"
Minimum="0"
Value="0"
ValueChanged="ChangeSelectedIndex" />
<Label Content="TiltAngle" />
<Slider x:Name="_tiltAngleSlider"
Minimum="0"
Maximum="90"
Value="45" />
<Label Content="ItemGap" />
<Slider x:Name="_itemGapSlider"
Minimum="0.25"
Maximum="3"
Value="0.65" />
</StackPanel>
<StackPanel Orientation="Vertical"
Grid.Row="1"
Grid.Column="1"
Margin="5">
<Label Content="FrontItemGap" />
<Slider x:Name="_frontItemGapSlider"
Minimum="0"
Maximum="4.0"
Value="1.5"/>
<Label Content="PopoutDistance" />
<Slider x:Name="_popoutDistanceSlider"
Minimum="-2.0"
Maximum="2.0"
Value="-0.3" />
<StackPanel Orientation="Horizontal"
Margin="0,10,0,0">
<Button x:Name="_regular"
Click="AddCard"
Margin="0,0,10,0"
Content="Add Type A" />
<Button x:Name="_alert"
Click="AddCard"
Margin="0,0,10,0"
Content="Add Type B" />
<Button Click="RemoveCard"
Margin="0,0,10,0"
Content="Remove" />
</StackPanel>
</StackPanel>
<Controls:ElementFlow x:Name="_elementFlow"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
ItemsSource="{DynamicResource DataSource}"
ItemTemplate="{DynamicResource TestDataTemplate}"
TiltAngle="{Binding Value, ElementName=_tiltAngleSlider}"
ItemGap="{Binding Value, ElementName=_itemGapSlider}"
FrontItemGap="{Binding Value, ElementName=_frontItemGapSlider}"
PopoutDistance="{Binding Value, ElementName=_popoutDistanceSlider}"
ElementWidth="300"
ElementHeight="200"
SelectedIndex="3">
<Controls:ElementFlow.Layout>
<Controls:CoverFlow />
</Controls:ElementFlow.Layout>
<Controls:ElementFlow.Background>
<LinearGradientBrush EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop Color="#FF181818" />
<GradientStop Color="#FF7A7A7A"
Offset="0.5" />
<GradientStop Color="#FF1A1A1A"
Offset="1" />
</LinearGradientBrush>
</Controls:ElementFlow.Background>
<Controls:ElementFlow.Camera>
<PerspectiveCamera FieldOfView="60"
Position="0,3,6"
LookDirection="0,-3,-6" />
</Controls:ElementFlow.Camera>
</Controls:ElementFlow>
<TextBlock Text="F12 to switch views"
Foreground="White"
FontWeight="Bold"
VerticalAlignment="Top"
HorizontalAlignment="Right"
Margin="10"
Grid.Row="0"
Grid.Column="1" />
<TextBlock x:Name="_currentViewText"
Foreground="White"
FontWeight="Bold"
VerticalAlignment="Top"
HorizontalAlignment="Right"
Margin="10,30,10,10"
Grid.Row="0"
Grid.Column="1" />
</Grid>
</Window>
Hope this helps!
Related
I'm trying to bind my Swipeview delete item to my DeleteBook method. When I press the button nothing happens so there is most likely something wrong with the binding. I tried changing bindingcontext.deletebook to bindingcontext.deletebookcommand and not having the 'bindingcontext.deletebook' part.
My Xaml
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:models="clr-namespace:eBooks.Models"
xmlns:effectsView="clr-namespace:Syncfusion.Maui.Core;assembly=Syncfusion.Maui.Core"
x:Class="eBooks.Library"
xmlns:viewmodel="clr-namespace:eBooks.ViewModel"
Title="Bibliotheek">
<ContentPage.BindingContext>
<viewmodel:LibraryViewModel />
</ContentPage.BindingContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Button
x:Name="addBookButton"
Grid.Row="0"
Background="White"
TextColor="Black"
Text="Voeg een boek toe"
Clicked="AddBookButton_Clicked"
Margin="0, 20, 0, 0"
HeightRequest="44"
WidthRequest="300">
<Button.Shadow>
<Shadow Brush="White" Radius="15" Opacity="0.8" />
</Button.Shadow>
</Button>
<CollectionView ItemsSource="{Binding Books}" Margin="36,20,36,20" Grid.Row="1">
<CollectionView.ItemTemplate>
<DataTemplate>
<SwipeView Margin="0, 5, 10, 0">
<SwipeView.RightItems>
<SwipeItem
x:Name="deleteButton"
Text="Delete"
IconImageSource="delete.png"
BackgroundColor="{StaticResource Gray950}"
Command="{Binding BindingContext.DeleteBook,Source={RelativeSource AncestorType={x:Type viewmodel:LibraryViewModel}}}"
CommandParameter="{Binding Id}" />
</SwipeView.RightItems>
<Border StrokeThickness="3">
<Border.Stroke>
<LinearGradientBrush EndPoint="0,1">
<GradientStop Color="White" Offset="0.1" />
<GradientStop Color="{StaticResource Gray950}" Offset="1.0" />
</LinearGradientBrush>
</Border.Stroke>
<effectsView:SfEffectsView ScaleFactor="1.15" LongPressEffects="Highlight">
<Grid HeightRequest="84" BackgroundColor="Black">
<Image Aspect="AspectFill" Source="{Binding ThumbnailSource}" Opacity="0.38"/>
<Label FontSize="18" TextColor="White" Text="{Binding Title}" FontAttributes="Bold" Margin="32, 24, 0, 0"/>
<ProgressBar WidthRequest="250" Margin="0, 46, 0, 0" ProgressColor="White" Progress="{Binding Progress}"/>
</Grid>
</effectsView:SfEffectsView>
</Border>
</SwipeView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
My ViewModel
namespace eBooks.ViewModel
{
public partial class LibraryViewModel : ObservableObject
{
readonly BookService bookService = new();
public LibraryViewModel()
{
using var db = new BooksContext();
db.RemoveRange(db.Books);
db.SaveChanges();
BookService.OnBooksChanged += RefreshLibrary;
RefreshLibrary();
}
public void RefreshLibrary(List<Book> books = null)
{
using var db = new BooksContext();
Books = new ObservableCollection<Book>(db.Books);
}
[ObservableProperty]
ObservableCollection<Book> _books;
[RelayCommand]
public void DeleteBook(int id) => bookService.Delete(id);
}
}
I have tried to find a good consistent folder structure in Visual Studio to capture all the possibilities. This so far has been what I've came up with for my project.
My Application looks like:
The xaml is pretty straight forward:
<Window x:Class="Check.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:SA_BOM_Check.ViewModels"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=viewModels:MainWindowViewModel, IsDesignTimeCreatable=True}"
Height="600" Width="800"
DataContext="{StaticResource ResourceKey=MainWindowViewModel}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="40"></RowDefinition>
<RowDefinition Height="40"></RowDefinition>
<RowDefinition Height="10"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Text="XA File: " Height="30" FontSize="20" FontWeight="Bold"/>
<TextBox x:Name="TxtXAFile" Grid.Row="1" Grid.Column="1" Text="{Binding Path=XAFile, Mode=TwoWay}" VerticalAlignment="Center" FontSize="15"></TextBox>
<Button x:Name="BtnXaBrowse" Grid.Row="1" Grid.Column="2" VerticalAlignment="Center" Margin="10,5,80,1" FontSize="20" FontWeight="DemiBold" Click="BtnXaBrowse_OnClick">Browse...</Button>
<TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Text="Inventor File: " Height="30" FontSize="20" FontWeight="Bold"/>
<TextBox Grid.Row="2" Grid.Column="1" x:Name="TxtInventorFile" Text="{Binding Path=InventorFile, Mode=TwoWay}" VerticalAlignment="Center" FontSize="15"/>
<Button x:Name="BtnInventorBrowse" Grid.Row="2" Grid.Column="2" VerticalAlignment="Center" Margin="10,0,80,0" FontSize="20" FontWeight="DemiBold" Click="BtnInventorBrowse_OnClick">Browse...</Button>
<Button x:Name="BtnDiff" Grid.Row="2" Grid.Column="3" VerticalAlignment="Center" Margin="10,5,80,1" FontSize="20" FontWeight="DemiBold" Command="{Binding GetDifferences}">Differences</Button>
<Line Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="4" X1="0" Y1="0" X2="1" Y2="0" Stroke="Black" StrokeThickness="2" Stretch="Uniform"></Line>
<Label Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="4" Content="Missing in Inventor (Inventor - XA)" FontSize="15" FontStyle="Normal" HorizontalAlignment="Center" FontWeight="Bold" Foreground="Black"/>
<DataGrid AutoGenerateColumns="True" Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="4" IsReadOnly="True"
FontSize="18" ItemsSource="{Binding Path=XADiffDataTable}"
ColumnWidth="*">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="FontWeight" Value="Bold"></Setter>
</Style>
</DataGrid.ColumnHeaderStyle>
</DataGrid>
<Label Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="4"
Content="Missing In XA (XA - Inventor)" FontSize="15" FontStyle="Normal"
HorizontalAlignment="Center" FontWeight="Bold" Foreground="Black"/>
<DataGrid Grid.Row="7" Grid.Column="0" Grid.ColumnSpan="4"
AutoGenerateColumns="True" IsReadOnly="True"
FontSize="18" ItemsSource="{Binding Path=InventorDiffDataTable}"
ColumnWidth="*">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="FontWeight" Value="Bold"></Setter>
</Style>
</DataGrid.ColumnHeaderStyle>
</DataGrid>
</Grid>
</Window>
Code Behind:
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;
using SA_BOM_Check.ViewModels;
namespace SA_BOM_Check.Views
{
public partial class MainWindow : Window
{
//private readonly MainWindowViewModel _vm;
public MainWindow()
{
InitializeComponent();
//_vm = (MainWindowViewModel) this.DataContext;
}
private void BtnXaBrowse_OnClick(object sender, RoutedEventArgs e)
{
TxtXAFile.Text = OpenFileDialog();
TxtXAFile.GetBindingExpression(TextBox.TextProperty)?.UpdateSource();
//_vm.XAFile = OpenFileDialog();
}
private void BtnInventorBrowse_OnClick(object sender, RoutedEventArgs e)
{
TxtInventorFile.Text = OpenFileDialog();
TxtInventorFile.GetBindingExpression((TextBox.TextProperty))?.UpdateSource();
}
private string OpenFileDialog()
{
OpenFileDialog openFileDialog = new();
return openFileDialog.ShowDialog() == true ? openFileDialog.FileName : "";
}
}
}
Keeping the ShowDialog inside the code behind was inspired by BionicCode https://stackoverflow.com/users/3141792/bioniccode
Where he answered the question about OpenFileDialogs Open File Dialog MVVM Actual Answer (which should have been the answer to the question) is at https://stackoverflow.com/a/64861760/4162851
The InventorAndXACompare class in summary is
private static readonly Dictionary<string, Part> INVENTOR_PARTS
= new Dictionary<string, Part>();
private static readonly Dictionary<string, Part> XA_PARTS = new Dictionary<string, Part>();
private static readonly Dictionary<string, Part> XA_PARTS_OMIT = new Dictionary<string, Part>();
private static readonly DataTable MISSING_IN_INVENTOR = new DataTable("XACompared");
private static readonly DataTable MISSING_IN_XA = new DataTable("InventorCompared");
public static DataTable[] CompareFiles(string xaFile, string inventorFile)
private static void ParseInventor(string inventorFile)
private static void ParseXA(string xaFile)
private static void CompareXAToInventor()
private static void CompareInventorToXA()
The compare files takes two files. It then parses those files into two dictionaries that are compared in both directions where there are differences it adds those rows to a datatable inside the MainWindowViewModel those are then binded to the View by
private DataTable _xaDiffDataTable;
public DataTable XADiffDataTable
{
get { return _xaDiffDataTable;}
set
{
_xaDiffDataTable = value;
OnPropertyChanged("XADiffDataTable");
}
}
private DataTable _inventorDiffDataTable;
public DataTable InventorDiffDataTable
{
get { return _inventorDiffDataTable;}
set
{
_inventorDiffDataTable = value;
OnPropertyChanged("InventorDiffDataTable");
}
}
I would like to know if there is a better way of structuring this and if InventorAndXACompare would be better placed in the Models folder?
In an MVVM architecture you would usually find parsers in the Model component. The View Model generally does not process data. Usually it may convert data to meet the constraints of the Model's interface or to prepare data for presentation in the View.
Also from an MVVM point of view the data source and sink is always part of the Model. It does not matter whether data comes from a database or from a file picked by the user.
I have viewlist in which contain elements. When I click on them, my ItemViewModel handler clicks. Then I can select information about that element. Afthe I must to open new page in which will be all information about it. For example like hypertext in browser.
<Border MaxHeight="300" MaxWidth="1140" CornerRadius="25" Margin="73,269,65,182">
<Grid x:Name="MainGrid" RenderTransformOrigin="0.5,0.5" Margin="0,0,10,-3">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ListView Width="1031" ItemsSource="{Binding GetTopItem}"
ScrollViewer.VerticalScrollBarVisibility="Disabled" HorizontalAlignment="Left" ScrollViewer.HorizontalScrollBarVisibility="Hidden"
Background="{x:Null}" BorderBrush="{x:Null}" Foreground="#DD000000"
x:Name="ListBook">
<ListView.DataContext>
<vm:BookMainVM/>
</ListView.DataContext>
<ListView.ItemTemplate>
<DataTemplate>
<Border HorizontalAlignment="Left" CornerRadius="25,25,25,25" BorderThickness="1" BorderBrush="#FF474747" Height="288" Margin="0,0,0,0" MouseDown="Border_MouseDown" >
<Grid Grid.Column="0" Height="Auto" Width="216" Margin="-1" IsEnabled="False">
<Grid.InputBindings>
<MouseBinding Gesture="LeftClick"
Command="{Binding DataContext.DelegateCommands,
RelativeSource={RelativeSource AncestorType=ListView}}"
CommandParameter="{Binding}">
</MouseBinding>
</Grid.InputBindings>
<Grid.RowDefinitions>
<RowDefinition Height="49*"/>
<RowDefinition Height="5*"/>
<RowDefinition Height="18*"/>
</Grid.RowDefinitions>
<Border CornerRadius="25,25,0,0" RenderTransformOrigin="0.5,0.5">
<Border.Background>
<ImageBrush ImageSource="{Binding Img_src}" Stretch="Fill" />
</Border.Background>
</Border>
<Label Content="{Binding Rate}" Background="#FFBFBFBF" RenderTransformOrigin="0.5,0.5" Grid.Row="1" FontSize="11" FontFamily="Meiryo UI" HorizontalContentAlignment="Center"/>
<Border CornerRadius="0,0,25,25" Grid.Row="2" Background="#FF8F8F8F">
<TextBlock Margin="6,0,0,0" Text="{Binding Name}" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Grid.Row="2" Height="61" Width="190"/>
</Border>
</Grid>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Border>
class ItemMainVM:ViewModel
{
private LibraryModel libraryModel;
private ItemDb itemsDb;
private const string Dir = "D:\\repos\\Frame\\Frame\\src";
public ItemMainVM()
{
libraryModel = new LibraryModel();
itemsDb = new BooksDb();
DelegateCommands = new DelegateCommand(o => EventHandler(o));
}
public ObservableCollection<BookPreviewInfo> GetTopItem
{
get
{
return libraryModel.GetTopItems();
}
}
public ICommand DelegateCommands { get; }
public void EventHandler(dynamic item)
{
itemDb.SelectItemId(item.Id);
}
}
Code Behind is empty.
When I click an element and executing EventHandler in ItemMainVM. And next must be create new page with new ElementViewModel.
ElementViewModel should to get information about element in ItemMainVM.
I have the following xaml, where you can see a GroupBox on top and other ones on the left and on the right.
Is there a way to set the GroupBox on top so that (when I resize the window) its left and right edges are aligned respectively with the left edge of the GroupBoxes on the left and the right edge of the GroupBoxes on the right?
Edit
I'm keeping fixed the width of the groupboxes in the tab controls because I've implemented a wpf zooming there: I've updated the xaml now (of course the zoom is implemented also in the code behind)
<?xml version="1.0" encoding="utf-8"?>
<Window
x:Class="MatchWidth.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MatchWidth"
Height="1000"
Width="1600">
<Grid>
<Grid.RowDefinitions>
<RowDefinition
Height="100" />
<RowDefinition
Height="*" />
</Grid.RowDefinitions>
<GroupBox
Header="Top Box"
Grid.Row="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Margin="25,5,35,25" />
<Grid
Grid.Row="1">
<Grid.LayoutTransform>
<ScaleTransform
CenterX="0" CenterY="0"
ScaleX="{Binding ElementName=uiScaleSliderL,Path=Value}"
ScaleY="{Binding ElementName=uiScaleSliderL,Path=Value}"/>
</Grid.LayoutTransform>
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="*" />
<ColumnDefinition
Width="5" />
<ColumnDefinition
Width="*" />
</Grid.ColumnDefinitions>
<TabControl
Name="LeftTabCtr"
Grid.Column="0">
<TabItem Header="LeftTabCtr">
<ScrollViewer
HorizontalScrollBarVisibility="Auto">
<Grid
Height="800">
<Slider
x:Name="uiScaleSliderL"
ToolTip="Determines the UI scale factor."
Value="1" Minimum="0.1" Maximum="4" Width="200" Height="10"
HorizontalAlignment="Center" VerticalAlignment="Top" />
<GroupBox
Header="Left Box 1"
Grid.Column="0"
Grid.Row="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Margin="25,20,25,25"
Width="720"
Height="180"/>
<GroupBox
Header="Left Box 2"
Grid.Column="0"
Grid.Row="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Width="720"
Margin="25,220,25,10" />
</Grid>
</ScrollViewer>
</TabItem>
</TabControl>
<GridSplitter
Grid.Column="1"
Width="5"
HorizontalAlignment="Stretch" />
<TabControl
Name="RightTabCtr"
Grid.Column="2">
<TabItem Header="RightTabCtr">
<ScrollViewer
HorizontalScrollBarVisibility="Auto">
<Grid
Height="800"> <Slider
x:Name="uiScaleSliderR"
ToolTip="Determines the UI scale factor."
Value="1" Minimum="0.1" Maximum="4" Width="200" Height="10"
HorizontalAlignment="Center" VerticalAlignment="Top" />
<GroupBox
Header="Right Box 1"
Grid.Column="0"
Grid.Row="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Margin="25,20,25,25"
Width="720"
Height="180"/>
<GroupBox
Header="Right Box 2"
Grid.Column="0"
Grid.Row="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Width="720"
Margin="25,220,25,10" />
</Grid>
</ScrollViewer>
</TabItem>
</TabControl>
</Grid>
</Grid>
</Window>
The code behind contains something like that:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
uiScaleSliderL.MouseDoubleClick +=
new MouseButtonEventHandler(RestoreScalingFactorL);
}
protected override void OnPreviewMouseWheel(MouseWheelEventArgs args)
{
base.OnPreviewMouseWheel(args);
if (Keyboard.IsKeyDown(Key.LeftCtrl) ||
Keyboard.IsKeyDown(Key.RightCtrl))
{
uiScaleSliderL.Value += (args.Delta > 0) ? 0.1 : -0.1;
}
}
protected override void OnPreviewMouseDown(MouseButtonEventArgs args)
{
base.OnPreviewMouseDown(args);
if (Keyboard.IsKeyDown(Key.LeftCtrl) ||
Keyboard.IsKeyDown(Key.RightCtrl))
{
if (args.MiddleButton == MouseButtonState.Pressed)
{
RestoreScalingFactorL(uiScaleSliderL, args);
}
}
}
void RestoreScalingFactorL(object sender, MouseButtonEventArgs args)
{
((Slider)sender).Value = 1.0;
}
}
You must specify correct margins and remove constant widths of groupboxes (maybe in your case it will be more flexibile to use minWidth, or just remove it completely)
I have two grids with three rows each. The first and last row of each grid has a fixed height while the middle rows have auto height and share their height using SharedSizeGroup.
First, the content of the right grid determines the height of the size group. When the content of the right grid shrinks so that the content of the left grid determines the height of the size group, the overall size of the left grid is not adjusted correctly.
See the following sample app. Click the increase button to increase the size of the textblock in the right grid. The size of the left grid changes accordingly. Now decrease the size. When the textblock becomes smaller than the textblock in the left grid, the total size of the left grid doesn't shrink. Is this a bug or am i missing something?
<StackPanel Orientation="Horizontal" Grid.IsSharedSizeScope="True">
<StackPanel Orientation="Vertical" Width="100">
<Grid Background="Green">
<Grid.RowDefinitions>
<RowDefinition Height="15" />
<RowDefinition SharedSizeGroup="Group1" />
<RowDefinition Height="15" />
</Grid.RowDefinitions>
<TextBlock Background="Blue" Grid.Row="0" />
<TextBlock Background="Red" Grid.Row="1" Name="textBlock1" Height="100" />
<TextBlock Background="Blue" Grid.Row="2" />
</Grid>
<TextBlock Text="{Binding Path=ActualHeight, ElementName=grid1}" />
</StackPanel>
<StackPanel Orientation="Vertical" Width="100">
<Grid Background="Green">
<Grid.RowDefinitions>
<RowDefinition Height="15" />
<RowDefinition SharedSizeGroup="Group1" />
<RowDefinition Height="15" />
</Grid.RowDefinitions>
<TextBlock Background="Blue" Grid.Row="0" />
<TextBlock Background="Red" Grid.Row="1" Name="textBlock2" Height="150" />
<TextBlock Background="Blue" Grid.Row="2" />
</Grid>
<TextBlock Text="{Binding Path=ActualHeight, ElementName=grid2}" />
</StackPanel>
<Button Height="24" Click="Button_Click_1" VerticalAlignment="Top">Increase</Button>
<Button Height="24" Click="Button_Click_2" VerticalAlignment="Top">Decrease</Button>
</StackPanel>
private void Button_Click_1(object sender, RoutedEventArgs e)
{
textBlock2.Height += 30;
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
textBlock2.Height -= 30;
}
The rows are staying the same height - the size of the second TextBlock is changing, while the size of the first TextBlock remains 100.
To demonstrate this, make the following changes:
Add ShowGridLines="True" to each of your Grids
Change your named TextBlocks to show their ActualHeight as their text:
<TextBlock Background="Red" Grid.Row="1" Name="textBlock2" Height="150"
Text="{Binding RelativeSource={RelativeSource Self}, Path=ActualHeight}"/>
You will see that the SharedSizeGroup row will be the maximum ActualHeight of the two TextBlocks.
Update: A Short Project To Show What's Happening
I've created a quick-n-dirty project to show what's happening. It turns out that when the right grid gets smaller than the original size, the left grid does an Arrange but not a Measure. I am not sure I understand this completely - I have posted a follow-up question with this same solution.
Here is the solution that I created, based on your original. It simply wraps the basic grid in a custom class that spews out info (via event) when Measure and Arrange are called. In the main window, I just put that info into a list box.
InfoGrid and InfoGridEventArgs classes
using System.Windows;
using System.Windows.Controls;
namespace GridMeasureExample
{
class InfoGrid : Grid
{
protected override Size ArrangeOverride(Size arrangeSize)
{
CallReportInfoEvent("Arrange");
return base.ArrangeOverride(arrangeSize);
}
protected override Size MeasureOverride(Size constraint)
{
CallReportInfoEvent("Measure");
return base.MeasureOverride(constraint);
}
public event EventHandler<InfoGridEventArgs> ReportInfo;
private void CallReportInfoEvent(string message)
{
if (ReportInfo != null)
ReportInfo(this, new InfoGridEventArgs(message));
}
}
public class InfoGridEventArgs : EventArgs
{
private InfoGridEventArgs()
{
}
public InfoGridEventArgs(string message)
{
this.TimeStamp = DateTime.Now;
this.Message = message;
}
public DateTime TimeStamp
{
get;
private set;
}
public String Message
{
get;
private set;
}
}
}
Main Window XAML
<Window x:Class="GridMeasureExample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:GridMeasureExample"
Title="SharedSizeGroup" Height="500" Width="500">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Column="0"
Grid.Row="0"
Orientation="Horizontal"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.IsSharedSizeScope="True">
<StackPanel Orientation="Vertical" Width="100">
<local:InfoGrid x:Name="grid1" Background="Green" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="15" />
<RowDefinition SharedSizeGroup="Group1" />
<RowDefinition Height="15" />
</Grid.RowDefinitions>
<TextBlock Background="Blue" Grid.Row="0" Text="Row 0"/>
<TextBlock Background="Red" Grid.Row="1" Name="textBlock1" Height="100"
Text="{Binding RelativeSource={RelativeSource Self}, Path=ActualHeight}"/>
<TextBlock Background="Blue" Grid.Row="2" Text="Row 2" />
</local:InfoGrid>
<TextBlock Text="{Binding Path=ActualHeight, ElementName=grid1}" />
</StackPanel>
<StackPanel Orientation="Vertical" Width="100">
<local:InfoGrid x:Name="grid2" Background="Yellow" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="15" />
<RowDefinition SharedSizeGroup="Group1" />
<RowDefinition Height="15" />
</Grid.RowDefinitions>
<TextBlock Background="Orange" Grid.Row="0" Text="Row 0" />
<TextBlock Background="Purple" Grid.Row="1" Name="textBlock2" Height="150"
Text="{Binding RelativeSource={RelativeSource Self}, Path=ActualHeight}"/>
<TextBlock Background="Orange" Grid.Row="2" Text="Row 2" />
</local:InfoGrid>
<TextBlock Text="{Binding Path=ActualHeight, ElementName=grid2}" />
</StackPanel>
</StackPanel>
<ListBox x:Name="lstInfo"
Grid.Column="1"
Grid.Row="0"
Margin="10,0,0,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
<UniformGrid Grid.Column="0"
Grid.Row="1"
Grid.ColumnSpan="2"
Columns="2"
HorizontalAlignment="Center"
Margin="5">
<Button x:Name="btnIncrease" Margin="4,0">Increase</Button>
<Button x:Name="btnDecrease" Margin="4,0">Decrease</Button>
</UniformGrid>
</Grid>
</Window>
Main Window Constructor (only code in code-behind)
public Window1()
{
InitializeComponent();
btnIncrease.Click += (s, e) =>
{
lstInfo.Items.Add(String.Format("{0} Increase Button Pressed", DateTime.Now.ToString("HH:mm:ss.ffff")));
textBlock2.Height += 30;
};
btnDecrease.Click += (s, e) =>
{
lstInfo.Items.Add(String.Format("{0} Decrease Button Pressed", DateTime.Now.ToString("HH:mm:ss.ffff")));
if (textBlock2.ActualHeight >= 30)
textBlock2.Height -= 30;
};
grid1.ReportInfo += (s, e) => lstInfo.Items.Add(String.Format("{0} Left Grid: {1}", e.TimeStamp.ToString("HH:mm:ss.ffff"), e.Message));
grid2.ReportInfo += (s, e) => lstInfo.Items.Add(String.Format("{0} Right Grid: {1}", e.TimeStamp.ToString("HH:mm:ss.ffff"), e.Message));
}