How to perform action when tab changes? - c#

I have a problem whereby I need to remove data from a DataGrid whenever a TabItem header is clicked (i.e. a new tab has been selected). Problem is, that by using a SelectionChanged is that the event is fired when the DataGrid is clicked on as well.
I tried finding different solutions, like using a label inside the TabItem.Header (per another thread on SO), but that caused it to loose the style used by (Metro MaHapps). I tried MouseLeftButtonDown, but that doesn't trigger on TabItem.
So is there any other event I can use?
Sample code:
<Controls:MetroAnimatedSingleRowTabControl Grid.Row="1">
<TabItem Header="shifts">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="0.5*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<DataGrid Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="5" Name="ShiftGridView" />
<Button Style="{DynamicResource SquareButtonStyle}" Width="100" Height="35" Content="Start shift" Grid.Column="2" Grid.Row="2" Click="StartButton_Click" />
<Button Style="{DynamicResource AccentedSquareButtonStyle}" Width="100" Height="35" Content="Stop shift" Grid.Column="4" Grid.Row="2" Click="StopButton_Click" />
</Grid>
</TabItem>
<TabItem Header="stats">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="0.40*" />
<RowDefinition Height="0.40*" />
<RowDefinition Height="0.40*" />
<RowDefinition Height="0.40*" />
<RowDefinition Height="3*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="Dates"
FontSize="14"
VerticalAlignment="Bottom"
Grid.Row="0" Grid.Column="1"/>
<DatePicker Width="120" Height="30"
HorizontalAlignment="Left"
FontSize="14"
Controls:TextboxHelper.Watermark="Start date"
Grid.Row="1" Grid.Column="1" Name="StartDatePicker" />
<DatePicker Width="120" Height="30"
HorizontalAlignment="Left"
FontSize="14"
Controls:TextboxHelper.Watermark="Stop date"
Grid.Row="2" Grid.Column="1" Name="StopDatePicker" />
<TextBlock Text="Name"
FontSize="14"
VerticalAlignment="Bottom"
Grid.Row="0" Grid.Column="2"/>
<ComboBox Width="200" Height="30"
HorizontalAlignment="Left"
SelectedIndex="0"
Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2" Name="NameComboBox"/>
<DataGrid Grid.Column="1" Grid.Row="4" Grid.ColumnSpan="5" Name="StatsGridView" />
<Button Style="{DynamicResource SquareButtonStyle}" Width="100" Height="35" Content="Show stats" HorizontalAlignment="Right" Grid.Column="3" Grid.Row="5" Click="ShowStatsButton_Click" />
<Button Style="{DynamicResource AccentedSquareButtonStyle}" Width="100" Height="35" Content="Print stats" Margin="10,0,0,0" HorizontalAlignment="Left" Grid.Column="4" Grid.Row="5" Click="PrintButton_Click" />
</Grid>
</TabItem>
</Controls:MetroAnimatedSingleRowTabControl>

SelectionChanged is Routed event that's why it routes from DataGrid to parent TabControl.
To distinguish between the events you can check e.OriginalSource which tells the actual element which is responsible for raising event.
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Sender will always be your TabControl.
// So, just check if OriginalSource is same as sender (TabControl).
if (e.OriginalSource == sender)
{
// Put your code here.
}
}

Related

Grid doesn't stretch inside StackPanel

I have two textboxes with constant height, I want to vertically stack the textboxes and a grid. I tried with stackpanel but then the grid doesn't stretch and it stays with same size all the time (smallest as possible).
<StackPanel Orientation="Vertical" MaxWidth="110">
<TextBox Background="White" Height="40" Text="some text1"/>
<TextBox Background="White" Height="40" Text="some text2"/>
<Grid x:Name="internalGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" MaxWidth="110"/>
<ColumnDefinition Width="1*" MaxWidth="110"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" MaxHeight="300"/>
<RowDefinition Height="1*" MaxHeight="300"/>
</Grid.RowDefinitions>
<Button Grid.Column="0" Grid.Row="0"/>
<Button Grid.Column="0" Grid.Row="1"/>
<Button Grid.Column="1" Grid.Row="0"/>
<Button Grid.Column="1" Grid.Row="1"/>
</Grid>
</StackPanel>
I also tried to use Grid instead of stackpanel but then when I make the app with full screen there is a margin between the textboxes and the internal grid
StackPanel doesn't behave like this. It occupies minimal required space. Use a Grid instead and define RowDefinitions. By default the space inside a Grid is equally distributed among the rows (Height is set to "*"), so you have to set the Height to "Auto" where you want the rows to occupy minimum space:
<Grid MaxWidth="110">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Background="White"
Height="40"
Text="some text1" />
<TextBox Grid.Row="1" Background="White"
Height="40"
Text="some text2" />
<Grid Grid.Row="2" x:Name="internalGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"
MaxWidth="110" />
<ColumnDefinition Width="1*"
MaxWidth="110" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"
MaxHeight="300" />
<RowDefinition Height="1*"
MaxHeight="300" />
</Grid.RowDefinitions>
<Button Grid.Column="0"
Grid.Row="0" />
<Button Grid.Column="0"
Grid.Row="1" />
<Button Grid.Column="1"
Grid.Row="0" />
<Button Grid.Column="1"
Grid.Row="1" />
</Grid>
</Grid>
Alternatively try a DockPanel:
<DockPanel MaxWidth="110" LastChildFill="True" >
<TextBox DockPanel.Dock="Top" Background="White"
Height="40"
Text="some text1" />
<TextBox DockPanel.Dock="Top" Background="White"
Height="40"
Text="some text2" />
<Grid DockPanel.Dock="Top" x:Name="internalGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"
MaxWidth="110" />
<ColumnDefinition Width="1*"
MaxWidth="110" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"
MaxHeight="300" />
<RowDefinition Height="1*"
MaxHeight="300" />
</Grid.RowDefinitions>
<Button Grid.Column="0"
Grid.Row="0" />
<Button Grid.Column="0"
Grid.Row="1" />
<Button Grid.Column="1"
Grid.Row="0" />
<Button Grid.Column="1"
Grid.Row="1" />
</Grid>
</DockPanel>
You can achieve this by using an IMultiValueConverter:
[ValueConversion(typeof(double), typeof(double))]
public class MyConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var total = (double)values.FirstOrDefault();
var subtract = values.Cast<double>().Sum();
return total + total - subtract;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
You can introduce your converter in XAML in the resources section:
<Window.Resources>
<local:MyConverter x:Key="Converter"></local:MyConverter>
</Window.Resources>
And your XAML will be changed to:
<StackPanel Orientation="Vertical" MaxWidth="110" Background="Red">
<TextBox Name="Label1" Background="White" Height="40" Text="some text1"/>
<TextBox Name="Label2" Background="White" Height="40" Text="some text2"/>
<Grid x:Name="internalGrid" Background="Yellow" >
<Grid.Height>
<MultiBinding Converter="{StaticResource Converter}">
<Binding RelativeSource="{RelativeSource AncestorType=StackPanel}" Path="ActualHeight"/>
<Binding ElementName="Label1" Path="ActualHeight"/>
<Binding ElementName="Label2" Path="ActualHeight"/>
</MultiBinding>
</Grid.Height>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" MaxWidth="110"/>
<ColumnDefinition Width="1*" MaxWidth="110"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" MaxHeight="300"/>
<RowDefinition Height="1*" MaxHeight="300"/>
</Grid.RowDefinitions>
</Grid>
</StackPanel>
Definitely, the backgrounds colors are just for more clarification and not necessary.

How to use templates in WPF multitab UI?

I'm new in WPF, but trying to learn it hard, as much as I can. Please help me overcome a problem I'm struggling with right now. I'm building a multitab UI, in which each tab supposed to have exactly the same control layout. In the same time inside a tab there is also repetitive chunk of controls (groups of labels). Controls' content will be filled by data coming from external source - apparently I'll use instances of data object to bind them to tabitem's DataContext property: one instance per tab item. My problem is, I can't figure out how to optimize the code by using templates. I think I should use 2 different templates, one inside the tab and another for whole tab, right? But how to bind the data then? Below the xaml markup I'm going to use for each tab and code-behind, so you can get the idea. The labels with numerical content should be bound to the properties of object instances (PLC).
XAML:
<Window x:Class="WpfPromholComplementary_1.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:loc = "clr-namespace:WpfPromholComplementary_1"
xmlns:wfi="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
xmlns:dvc="clr-namespace:System.Windows.Forms.DataVisualization.Charting;assembly=System.Windows.Forms.DataVisualization"
Title="Window2" Height="800" Width="1000">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="210" />
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Grid.Row="1" Grid.Column="0" BorderThickness="1" BorderBrush="Blue" Margin="2" CornerRadius="8,8,8,8">
<Grid Background="LightCyan">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="10" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="10" />
</Grid.RowDefinitions>
<Label Content="Module 1" Grid.Row="1" Grid.ColumnSpan="2" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="2" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="3" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="4" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="5" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="Channel 1:" Grid.Row="2" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 2:" Grid.Row="3" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 3:" Grid.Row="4" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 4:" Grid.Row="5" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Border>
<Border Grid.Row="1" Grid.Column="1" BorderThickness="1" BorderBrush="Blue" >
<Grid Background="LightCyan">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="10" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="10" />
</Grid.RowDefinitions>
<Label Content="Module 2" Grid.Row="1" Grid.ColumnSpan="2" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="2" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="3" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="4" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="5" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="Channel 1:" Grid.Row="2" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 2:" Grid.Row="3" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 3:" Grid.Row="4" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 4:" Grid.Row="5" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Border>
<Border Grid.Row="1" Grid.Column="2" BorderThickness="1" BorderBrush="Blue">
<Grid Background="LightCyan">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="10" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="10" />
</Grid.RowDefinitions>
<Label Content="Module 3" Grid.Row="1" Grid.ColumnSpan="2" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="2" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="3" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="4" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="5" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="Channel 1:" Grid.Row="2" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 2:" Grid.Row="3" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 3:" Grid.Row="4" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 4:" Grid.Row="5" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Border>
<Border Grid.Row="1" Grid.Column="3" BorderThickness="1" BorderBrush="Blue">
<Grid Background="LightCyan">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="10" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="10" />
</Grid.RowDefinitions>
<Label Content="Module 4" Grid.Row="1" Grid.ColumnSpan="2" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="2" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="3" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="4" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="5" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="Channel 1:" Grid.Row="2" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 2:" Grid.Row="3" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 3:" Grid.Row="4" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 4:" Grid.Row="5" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Border>
<Border Grid.Row="1" Grid.Column="4" BorderThickness="1" BorderBrush="Blue">
<Grid Background="LightCyan">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="10" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="10" />
</Grid.RowDefinitions>
<Label Content="Module 5" Grid.Row="1" Grid.ColumnSpan="2" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="2" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="3" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="4" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="5" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="Channel 1:" Grid.Row="2" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 2:" Grid.Row="3" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 3:" Grid.Row="4" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 4:" Grid.Row="5" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Border>
<Border Grid.Row="1" Grid.Column="5" BorderThickness="1" BorderBrush="Blue">
<Grid Background="LightCyan">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="10" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="10" />
</Grid.RowDefinitions>
<Label Content="Module 6" Grid.Row="1" Grid.ColumnSpan="2" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="2" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="3" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="4" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="123.4" Grid.Row="5" Grid.Column="1" Height="Auto" Width="Auto" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="Channel 1:" Grid.Row="2" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 2:" Grid.Row="3" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 3:" Grid.Row="4" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 4:" Grid.Row="5" Grid.Column="0" Height="Auto" Width="Auto" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Border>
<StackPanel Margin="5,5,5,5" Grid.Row="3" Grid.ColumnSpan="4">
<WindowsFormsHost>
<dvc:Chart x:Name="chart" />
</WindowsFormsHost>
</StackPanel>
<StackPanel Grid.Row="0" Grid.ColumnSpan="6" Orientation="Horizontal">
<Label Content="IP-address:" Height="33" Width="Auto" FontSize="20" Padding="5,0,5,5"/>
<Label Content="192.168.1.10" Height="33" Width="Auto" FontSize="20" Padding="5,0,5,5"/>
</StackPanel>
<DataGrid x:Name="dgDataGrid" Grid.Row="4" Grid.Column="4" Grid.ColumnSpan="2" IsSynchronizedWithCurrentItem="False"/>
</Grid>
Code-behind:
using System;
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.Shapes;
using System.Windows.Forms.DataVisualization.Charting;
using System.Drawing;
namespace WpfPromholComplementary_1
{
/// <summary>
/// Interaction logic for Window2.xaml
/// </summary>
public partial class Window2 : Window
{
public Window2()
{
InitializeComponent();
PLC plc1 = new PLC { ID = 1, Module_Number = "1", Channel_1 = "1234", Channel_2 = "5678", Channel_3 = "9012", Channel_4 = "3456" };
this.DataContext = plc1;
}
}
}
I have to decide to answer in 2 parts. One part will be clearly in Code-Behind approach, other will be in MVVM (Model-View-ViewModel).
Best idea to format the upper side of window is to use same component, where You will define source, instead of templating. Templating is useful at the places, where You have one control and You would like to change it's look (layout of controls).
At first You should create own UserControl (I called it MyModuleFrame in example):
XML:
<UserControl x:Class="WpfPromholComplementary_1.MyModuleFrame"
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:WpfPromholComplementary_1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
x:Name="mUserControl">
<Border BorderThickness="1" BorderBrush="Blue" CornerRadius="8,8,8,8">
<Grid Background="LightCyan">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="10" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="10" />
</Grid.RowDefinitions>
<Label Content="{Binding ItemSource.Number, ElementName=mUserControl}" Grid.Row="1" Grid.ColumnSpan="2" FontSize="20" HorizontalAlignment="Center"/>
<Label Content="{Binding ItemSource.Ch1, ElementName=mUserControl}" Grid.Row="2" Grid.Column="1" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="{Binding ItemSource.Ch2, ElementName=mUserControl}" Grid.Row="3" Grid.Column="1" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="{Binding ItemSource.Ch3, ElementName=mUserControl}" Grid.Row="4" Grid.Column="1" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="{Binding ItemSource.Ch4, ElementName=mUserControl}" Grid.Row="5" Grid.Column="1" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 1:" Grid.Row="2" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 2:" Grid.Row="3" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 3:" Grid.Row="4" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Channel 4:" Grid.Row="5" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Border>
</UserControl>
C#:
namespace WpfPromholComplementary_1
{
/// <summary>
/// Interaction logic for MyModuleFrame.xaml
/// </summary>
public partial class MyModuleFrame : UserControl
{
public MyModuleFrame()
{
InitializeComponent();
}
public Module ItemSource
{
get { return (Module)GetValue(ItemSourceProperty); }
set { SetValue(ItemSourceProperty, value); }
}
// Using a DependencyProperty as the backing store for ItemsSource. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ItemSourceProperty =
DependencyProperty.Register("ItemSource", typeof(Module), typeof(MyModuleFrame), new PropertyMetadata(default(Module)));
}
}
It is really imporant to define set the properties of all UserControls as DependencyProperty. Why? Because WPF is using them to do everything related to View handling. On the initialization, they are registered in the WPF framework & once somebody want to access them/they will call WPF (who returns the value), instead of direct approach.
Once You've defined the control, You can use it on the window. I have removed some code from start (I dont have references) & the end code just so You have an idea:
<Window x:Class="WpfPromholComplementary_1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:loc = "clr-namespace:WpfPromholComplementary_1"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
Title="Window2" Height="800" Width="1000">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="210" />
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<loc:MyModuleFrame Grid.Row="1" Grid.Column="0" ItemSource="{Binding Module1}"/>
<loc:MyModuleFrame Grid.Row="1" Grid.Column="1" ItemSource="{Binding Module2}"/>
<loc:MyModuleFrame Grid.Row="1" Grid.Column="2" ItemSource="{Binding Module3}"/>
<loc:MyModuleFrame Grid.Row="1" Grid.Column="3" ItemSource="{Binding Module4}"/>
<!-- other modules & stuff-->
</Grid>
</Window>
And once You get to the point above, You need to get the dynamical data, that can be obtained 3 ways:
Via insertion from code-behind (Win-forms approach e.g.: TextBox1.ModuleNumber="3" - is less abstract & not used in big applications)
Via Binding to Code-Behind (define property in Code-Behind, set dataContext of Window to this)
Via binding to the View-Model (following the MVVM pattern) - some tutorial here
Based on the choosen option, You have to update code above.
Also we should have defined Model for our App - Module class. This code below does not support View update. For support You must implement INotifyPropertyChanged interface (more below):
//Simplified
public class Module
{
public string Number { get; set; }
public double Ch1 { get; set; }
public double Ch2 { get; set; }
public double Ch3 { get; set; }
public double Ch4 { get; set; }
}
ViewModel:
public class MainViewModel
{
public Module Module1 { get; set; } = new Module()
{
Number = "1",
Ch1 = 123.4,
Ch2 = 123.4,
Ch3 = 123.4,
Ch4 = 123.4
};
/* other modules... */
}
MVVM approach:
App.config:
<Application x:Class="WpfPromholComplementary_1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfPromholComplementary_1"
StartupUri="MainWindow.xaml">
<Application.Resources>
<local:MainViewModel x:Key="MainViewModel"/>
</Application.Resources>
</Application>
Code-behind approach:
View.cs:
public partial class Window
{
public Window()
{
InitializeComponent();
this.DataContext = this;
}
public Module Module1 { get; set; } = new Module(); //in this case You do not need ViewModel
}
At this point You should have working application, where You cannot change anything.
Now there are 2 ways to update the values in View, one is following the proper manner of the MVVM, other is in again in code-behind.
I will describe both just for reference:
At first Your Modul needs to inherit from INotifyPropertyChange (example just for 2 propertie):
using System.ComponentModel;
public class Module : INotifyPropertyChanged
{
private string _number;
public string Number
{
get { return this._number; }
set
{
if (_number == value) return;
_number = value;
OnPropertyChanged(nameof(Number));
}
}
private double _ch1;
public double Ch1
{
get { return this._ch1; }
set
{
if (_ch1 == value) return;
_ch1 = value;
OnPropertyChanged(nameof(Ch1));
}
}
//other channels fits there
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string aNameOfProperty)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(aNameOfProperty));
}
}
Code-behind:
Now let's say we want to handle an event to the button click (XML):
<Button Click="MyButton_Click"/>
In code-behind, we can do (C#):
private void MyButton_Click(object sender, MouseEventArgs e)
{
//Your ViewModel is stored in DataContext, You can just cast to approach properties
var VM = (this.DataContext as MainViewModel);
VM.Module1.Number = "Module Number Xyz";
}
MVVM:
MVVM approach is a bit harder as You need to implement ICommand interface on some command class see relay command for reference.
Once You've got this, XML:
<Button Command="{Binding DoSomeWorkCmd}"/>
In Your ViewModel:
private ICommand _DoSomeWorkCmd;
public ICommand DoSomeWorkCmd
{
get
{
if (_DoSomeWorkCmd != null) return _DoSomeWorkCmd;
_DoSomeWorkCmd = new RelayCommand((object aParam)=> { return true; }, (object aParam) =>
{
this.Module1.Number = "MyNewNumber XyZ";
});
return this._DoSomeWorkCmd;
}
}
MVVM example of whole solution can be downloaded on my GIT: https://github.com/Tatranskymedved/WpfPromholComplementary_1

Responsive UI for WPF applications

I have been trying to adjust the screen based on different sizes to see if any components are reacting to that. Unfortunately they don't
I am not sure what I am missing. And it would be great if anyone can give a direct advice and tips for my example implementation.
Here is the code:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="1000" Width="800">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListView Grid.Column="0" Grid.RowSpan="3" Grid.ColumnSpan="3" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListViewItem Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="4" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Expander HorizontalAlignment="Stretch" Grid.Column="0" Grid.Row="1" VerticalAlignment="Stretch">
<Grid Width="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="20*"/>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Column="1" Grid.Row="0" Content="HJello World meeee"/>
<ListView Grid.Column="3" Grid.Row="0" Grid.RowSpan="4">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<Button Content="Hello Tourist fu"/>
<Button Content="Hello Tourist fu"/>
<Button Content="Hello Tourist fu"/>
<Button Content="Hello Tourist fu"/>
<Button Content="Hello Tourist fu"/>
<ListViewItem Content="Test"/>
</ListView>
<Button Grid.Column="4" Grid.Row="0" Content="Test"/>
</Grid>
</Expander>
</Grid>
</ListViewItem>
<ListViewItem Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="4">
<Expander >
<Grid Width="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="20*"/>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Column="1" Grid.Row="0" Content="HJello World meeee"/>
<ListView Grid.Column="3" Grid.Row="0" Grid.RowSpan="4">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<Button Content="Hello Tourist fu"/>
<Button Content="Hello Tourist fu"/>
<Button Content="Hello Tourist fu"/>
<Button Content="Hello Tourist fu"/>
<Button Content="Hello Tourist fu"/>
<ListViewItem Content="Test"/>
</ListView>
<Button Grid.Column="4" Grid.Row="0" Content="Test"/>
</Grid>
</Expander>
</ListViewItem>
</ListView>
</Grid>
</Window>
Set x:Name for your main grid to x:Name="Root"
Set for Expander attribute Width="{Binding ActualWidth, ElementName=Root}"

TextBlock not wrapping inside grid column windows phone

I've the following xaml definition. The textblock inside the stackpanel is not wrapping.
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<toolkit:PhoneTextBox x:Name="NotesText" Grid.Row="0" Grid.ColumnSpan="2" Hint="Add Notes" AcceptsReturn="True" Height="290" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" />
<StackPanel Orientation="Horizontal" Grid.Row="1" Grid.Column="0" >
<CheckBox x:Name="showRequester" FontSize="{StaticResource PhoneFontSizeSmall}" HorizontalAlignment="Left" />
<TextBlock TextWrapping="Wrap" VerticalAlignment="Center" HorizontalAlignment="Left" Text="option_show_to_requester" />
</StackPanel>
<CheckBox Grid.Row="1" Grid.Column="1" Content="Mail To Technicain" FontSize="{StaticResource PhoneFontSizeSmall}" HorizontalAlignment="Right" />
</Grid>
What I should do to make it wrap ? Thanks.
Update:
Problem with the alignment when using data template for check box content.
You can solve this by Providing Width of TextBlock.
You don't need to put a checkBox and a TextBlock into a StackPanel. To make the CheckBox's content Wrap, just use ContentTemplate of CheckBox.
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<toolkit:PhoneTextBox x:Name="NotesText" Grid.Row="0" Grid.ColumnSpan="2" Hint="Add Notes" AcceptsReturn="True" Height="290" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" />
<!--Use ContentTemplate of CheckBox-->
<CheckBox Grid.Row="1" Grid.Column="0">
<CheckBox.ContentTemplate>
<DataTemplate>
<TextBlock Text="option_show_to_requester" TextWrapping="Wrap"/>
</DataTemplate>
</CheckBox.ContentTemplate>
</CheckBox>
<CheckBox Grid.Row="1" Grid.Column="1" Content="Mail To Technicain" FontSize="{StaticResource PhoneFontSizeSmall}" HorizontalAlignment="Right" />
</Grid>
for a simple example:
<Grid Grid.Row="1" x:Name="ContentRoot" Tapped="ContentRoot_Tapped">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<CheckBox Grid.Column="0">
<CheckBox.ContentTemplate>
<DataTemplate>
<TextBlock TextAlignment="Center" Text="wrap123123123123wrap" TextWrapping="Wrap"/>
</DataTemplate>
</CheckBox.ContentTemplate>
</CheckBox>
<CheckBox Grid.Column="1">
<CheckBox.ContentTemplate>
<DataTemplate>
<TextBlock Text="nowrap" TextWrapping="Wrap"/>
</DataTemplate>
</CheckBox.ContentTemplate>
</CheckBox>
</Grid>
And the run image is:

No Scrollbar appearing for WrapGrid in Windows 8 application

I currently have a WrapGrid bound to an ObservableCollection of BitmapImages. What I wish is for these to be displayed, 4 items per row, extending downwards - and when the WrapGrid extends past the size of the users screen, allow the user to scroll downwards. Currently it is working - but no scrollbar appears and the user is unable to scroll downwards - so whenever it extends beyond the screen, the images are cut off and useless.
I believe something must be incorrect in how I have defined my grids ; but for the life of me I cannot figure out what I have done incorrectly after hours of searching.
Here is my code :
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="140" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="backButton"
Click="GoBack"
IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}"
Style="{StaticResource BackButtonStyle}" />
<TextBlock x:Name="pageTitle"
Grid.Column="1"
Text="Image Gallery"
Style="{StaticResource PageHeaderTextStyle}" />
</Grid>
<Grid Grid.Row="1" Grid.Column="1">
<Grid Margin="120,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="60" />
<RowDefinition Height="60" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
...
<ItemsControl Name="listOfImages" ItemsSource="{Binding Path=Images}" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="5" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid Orientation="Horizontal" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="5" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Stretch="Fill" Width="200" Height="200" Source="{Binding}" Margin="10,10,10,0" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="5" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Grid>
I thought this stuff was set by default but may not be the case, so this may prove useful.
<ItemsPanelTemplate>
<WrapGrid Orientation="Horizontal"
CanVerticallyScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto" />
</ItemsPanelTemplate>

Categories

Resources