I am developing a WPF application using MVVM software architecture. In my ViewModel I have a property called SelectedAttributes.
private ObservableCollection<NodeAttributeViewModel> _selectedAttributes;
public ObservableCollection<NodeAttributeViewModel> SelectedAttributes
{
get
{
return _selectedAttributes;
}
set
{
_selectedAttributes = value;
OnPropertyChanged("SelectedAttributes");
}
}
NodeAttributeViewModel is defined as
class NodeAttributeViewModel : ViewModelBase
{
public enum ElementType { BOOL, STRING }
public ElementType Type { get; set; }
public NodeAttribute Attribute { get; set; }
public string AttributeName
{
get
{
return Attribute.Attribute;
}
set
{
Attribute.Attribute = value;
OnPropertyChanged("AttributeName");
}
}
public string AttributeValue
{
get
{
return Attribute.Value;
}
set
{
if (!Attribute.Value.Equals(value))
{
Attribute.Value = value;
OnPropertyChanged("AttributeValue");
}
}
}
}
I want to bind the SelectedAttributes list to a ItemsControl. Depending on the Type of element of list element, I want to display a checkbox(for boolean), TextBox ( for String). Currently I am able display all the elements in a TextBox. I dont know how to display checkbox for elements whose type is Boolean
Here is my Xaml
<ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto" Grid.Column="2" Margin="9,6,9,6">
<StackPanel>
<ItemsControl ItemsSource="{Binding Path=SelectedAttributes}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid Margin="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding AttributeName}" />
<TextBox Text="{Binding AttributeValue}" Grid.Column="1" />
</Grid>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" Grid.Row="1"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
here you go
you can make use of DataTrigger to control what type of editor should be displayed for different type of attribute
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid Margin="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding AttributeName}" />
<TextBox x:Name="text"
Text="{Binding AttributeValue}"
Grid.Column="1" />
<CheckBox x:Name="check"
IsChecked="{Binding AttributeValue}"
Grid.Column="1"
Visibility="Collapsed" />
</Grid>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}"
Grid.Row="1" />
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Type}"
Value="BOOL">
<Setter Property="Visibility"
TargetName="check"
Value="Visible" />
<Setter Property="Visibility"
TargetName="text"
Value="Collapsed" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
I have added a CheckBox in the same column as TextBox and set it's Visibility to Collapsed by default
when the value of Type is BOOL the trigger setters will swap the Visibility of CheckBox and TextBox hence making CheckBox appear and TextBox disappear and will also reset it back when value is not BOOL
You can put Trigger on your Checkbox visiblity depending on your Type property
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid Margin="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<CheckBox>
<CheckBox.Style>
<Style TargetType="CheckBox">
<Style.Triggers>
<DataTrigger Binding="{Binding Type}" Value="BOOL">
<Setter Property="Visibility" Value="Collapsed"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
<TextBlock Grid.Column="2" Text="{Binding AttributeName}" />
<TextBox Text="{Binding AttributeValue}" Grid.Column="2" />
</Grid>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" Grid.Row="1"/>
</Grid>
</DataTemplate>
Related
Overview
I'm trying to create a custom expander which contains a visual tree where the user can select or deselect nodes. But the tree is not important for now. Important is the header which I had to overwrite so I can show all the information the user needs.
Issue
Somehow the Binding of the textboxes inside the DataTemplate doesn't work at all. No matter what I enter into the fields are always empty and the setter of the DependencyProperty doesn't get called.
Code
<UserControl x:Class="WPF_Test_project.CheckableTree"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Grid>
<Grid.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="ExpanderToggleButton" TargetType="ToggleButton">
<Path Name="Chevron"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 0 0 L 10 10 L 20 0 Z"
Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Foreground}"
/>
<!-- Change appearance when is expanded -->
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter TargetName="Chevron" Property="Data" Value="M 0 10 L 10 0 L 20 10 Z" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="MainViewExpander" TargetType="Expander">
<Setter Property="Foreground" Value="Black" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Expander">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Name="ContentRow" Height="0" />
</Grid.RowDefinitions>
<Border Name="HeaderBorder"
Grid.Row="0"
BorderThickness="0"
Background="#FFE1E1E1"
>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<ContentPresenter
Grid.Column="0"
Margin="0"
ContentSource="Header"
RecognizesAccessKey="True"
/>
<ToggleButton
Grid.Column="2"
Margin="4 4 8 4"
IsChecked="{Binding Path=IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
OverridesDefaultStyle="True"
Template="{StaticResource ExpanderToggleButton}"
Background="Black"
/>
</Grid>
</Border>
<Border Name="ContentBorder" Grid.Row="1" BorderThickness="0">
<ContentPresenter Margin="0" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Setter TargetName="ContentRow" Property="Height" Value="{Binding ElementName=Content, Path=DesiredHeight}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0"
Margin="4"
/>
<TextBlock Grid.Column="1"
Margin="2"
Text="{Binding ElementName=CT, Path=Header, FallbackValue=Header}"
Foreground="Black"
FontWeight="Bold"
FontSize="14"
/>
<TextBlock Grid.Column="2"
Margin="2"
Text="{Binding ElementName=CT, Path=NrOfFeaturesSelected, FallbackValue=5}"
Foreground="Black"
FontWeight="Bold"
FontSize="14"
HorizontalAlignment="Right"
/>
<TextBlock Grid.Column="3"
Margin="2"
Text="/"
Foreground="Black"
FontWeight="Bold"
FontSize="14"
HorizontalAlignment="Right"
/>
<TextBlock Grid.Column="4"
Margin="2"
Text="{Binding ElementName=CT, Path=NrOfFeaturesAvailable, FallbackValue=5}"
Foreground="Black"
FontWeight="Bold"
FontSize="14"
HorizontalAlignment="Right"
/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="TreeViewItemStyle" TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding IsExpanded}" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ResourceDictionary>
</Grid.Resources>
<Expander IsExpanded="True" Style="{StaticResource MainViewExpander}">
<TreeView ItemsSource="{Binding ElementName=CT, Path=Items}"
BorderThickness="0"
ItemContainerStyle="{StaticResource TreeViewItemStyle}"
Padding="4"
>
<TreeView.Resources>
<HierarchicalDataTemplate
x:Key="CheckableTreeItemTemplate"
ItemsSource="{Binding ElementName=CT, Path=Items}"
>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0"
IsChecked="{Binding IsChecked}"
VerticalAlignment="Center"
Visibility="{Binding IsCheckable, Converter={StaticResource BooleanToVisibilityConverter}}"
/>
<Label Grid.Column="1"
Content="{Binding Title}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
/>
<Label Grid.Column="3"
Content="{Binding TagCountDisplayValue}"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Visibility="{Binding ShowTagCountDisplayValue, Converter={StaticResource BooleanToVisibilityConverter}}"
/>
</Grid>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
</Expander>
</Grid>
</UserControl>
Class
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace WPF_Test_project
{
/// <summary>
/// Interaction logic for CheckableTree.xaml
/// </summary>
public partial class CheckableTree : UserControl
{
public CheckableTree()
{
InitializeComponent();
}
public int NrOfFeaturesSelected
{
get { return (int)GetValue(NrOfFeaturesSelectedProperty); }
set { SetValue(NrOfFeaturesSelectedProperty, value); }
}
public static readonly DependencyProperty NrOfFeaturesSelectedProperty =
DependencyProperty.Register("NrOfFeaturesSelected", typeof(Int32), typeof(CheckableTree), new UIPropertyMetadata(null));
public int NrOfFeaturesAvailable
{
get { return (int)GetValue(NrOfFeaturesSelectedProperty); }
set { SetValue(NrOfFeaturesSelectedProperty, value); }
}
public static readonly DependencyProperty NrOfFeaturesAvailableProperty =
DependencyProperty.Register("NrOfFeaturesAvailable", typeof(Int32), typeof(CheckableTree), new UIPropertyMetadata(null));
public IEnumerable<object> Items
{
get { return (IEnumerable<object>)GetValue(ItemsProperty); }
set { SetValue(NrOfFeaturesSelectedProperty, value); }
}
public static readonly DependencyProperty ItemsProperty =
DependencyProperty.Register("Items", typeof(IEnumerable<object>), typeof(CheckableTree), new UIPropertyMetadata(null));
public string Header
{
get { return (string)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(string), typeof(CheckableTree), new UIPropertyMetadata(null));
}
}
Usage
<local:CheckableTree Header="Test" NrOfFeaturesSelected="9">
</local:CheckableTree>
But I always get the Fallback Values. Does anybody know why this happens? Do I have to link the DataTemplate to the Control Class or something?
Solution (Thanks to mm8)
For every binding in the DataTemplate refer to the parent UserControl
<Textbox
...
Text={Binding Path=XY, RelativeSource={RelativeSource AncestorType=UserControl}, FallbackValue=...}"
... />
Try to bind to the Header property of the parent UserControl using a {RelativeSource}:
<TextBlock Grid.Column="1"
Margin="2"
Text="{Binding Path=Header, RelativeSource={RelativeSource AncestorType=UserControl}, FallbackValue=Header}"
Foreground="Black"
FontWeight="Bold"
FontSize="14"
/>
The picture shows an example of some items added in my datagrid. Right now I can only change each rows checkbox by clicking on it but I would like to be able to click anywhere on each row to change that rows checkbox.
XAML of datagrid and row template:
<DataGrid Grid.Row="1" SnapsToDevicePixels="True" BorderThickness="0" SelectedItem="{Binding Selected}" ItemsSource="{Binding Source={StaticResource ColViewSource},Mode=OneWay}" AutoGenerateColumns="False" x:Name="dataGrid" HeadersVisibility="None" ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<DataGrid.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource GroupHeaderStyle}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter></DataGridRowsPresenter>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding Type}" Value="TTC">
<Setter Property="Template" Value="{StaticResource ResourceKey=TTC}"/>
</DataTrigger>
</Style.Triggers>
</Style>
<ControlTemplate x:Key="TTC">
<Grid Style="{StaticResource rowGridStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="30"/>
<ColumnDefinition />
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Style="{StaticResource commentboxStyle}" Text="{Binding Comment,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Column="0" Grid.ColumnSpan="3" ></TextBox>
<TextBlock Style="{StaticResource textblockStyle}" Text="{Binding Text1,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Grid.ColumnSpan="2"/>
<Label Style="{StaticResource labelStyle}" Content="{Binding Text2,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Column="2" HorizontalAlignment="Right" />
<CheckBox Style="{StaticResource RectBox}" IsChecked="{Binding IsChecked,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Column="3" HorizontalAlignment="Center" IsThreeState="True"/>
<Path Style="{StaticResource dottedpathStyle}"/>
</Grid>
</ControlTemplate>
Any tips on how to achieve this?
You could add a handler to your DataGridRow style that sets the IsChecked property of the data object to true:
<Style TargetType="DataGridRow">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="OnPreviewMouseLeftButtonDown" />
<Style.Triggers>
<DataTrigger Binding="{Binding Type}" Value="TTC">
<Setter Property="Template" Value="{StaticResource ResourceKey=TTC}"/>
</DataTrigger>
</Style.Triggers>
</Style>
private void OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (!(e.Source is CheckBox))
{
DataGridRow row = sender as DataGridRow;
YourDataClass dataObject = row.DataContext as YourDataClass;
if (dataObject != null)
dataObject.IsChecked = true;
}
}
Make sure that YourDataClass implements the INotifyPropertyChanged interface and raises the PropertyChanged event in the setter of the IsChecked property.
Prevent Code behind and use a System.Windows.Interactivity.Behaviour.
public class SelectedCheckBoxBehaviour : System.Windows.Interactivity.Behavior<FrameworkElement>
{
protected override void OnAttached()
{
AssociatedObject.MouseDown += AssociatedObject_MouseDown;
base.OnAttached();
}
private void AssociatedObject_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
FrameworkElement self = sender as FrameworkElement;
if(self != null)
{
MyViewModel dataContext = self.DataContext as MyViewModel;
dataContext.IsChecked = !dataContext.IsChecked;
}
}
protected override void OnDetaching()
{
AssociatedObject.MouseDown -= AssociatedObject_MouseDown;
base.OnDetaching();
}
}
Namespaces
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:behaviour="clr-namespace:WpfApplication.Behaviour"
<!-- ... --->
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="30"/>
<ColumnDefinition />
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Text="{Binding Comment,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Column="0" Grid.ColumnSpan="3" ></TextBox>
<TextBlock Text="{Binding Text1,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Grid.ColumnSpan="2"/>
<Label Content="{Binding Text2,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Column="2" HorizontalAlignment="Right" />
<CheckBox IsChecked="{Binding IsChecked,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Column="3" HorizontalAlignment="Center" IsThreeState="True"/>
<Path />
<i:Interaction.Behaviors>
<behaviour:SelectedCheckBoxBehaviour />
</i:Interaction.Behaviors>
</Grid>
This should work - Tut
My itemscontrol is currently loading each row correctly. I am trying to get it to change the background color of each row when the user selects it.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100" />
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Row="0">
<Border BorderBrush="#BBBDBF" Background="#F4F4F4" BorderThickness="0,1,0,1" Margin="10,10,10,10"/>
<Image HorizontalAlignment="Left" Margin="10,0,0,0" Height="38" Width="38" Source="C:\Users\linda_l\Pictures\Cloud upload\database (1).png" />
<TextBlock FontSize="50" Foreground="#4092C2" Margin="60,0,0,0" HorizontalAlignment="left" Height="69" >Databases</TextBlock>
</Grid>
<Grid Background="White" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="70" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<Border BorderBrush="#BBBDBF" BorderThickness="0,0,0,1" Grid.Column="1" />
<Label Grid.Column="1" Content="Server Name" VerticalAlignment="Bottom" FontWeight="Bold" Foreground="#4092C2" />
<Border BorderBrush="#BBBDBF" BorderThickness="1,0,0,1" Grid.Column="2" />
<Label Grid.Column="2" Content="Source Database" VerticalAlignment="Bottom" FontWeight="Bold" Foreground="#4092C2" />
<Border BorderBrush="#BBBDBF" BorderThickness="1,0,0,1" Grid.Column="3" />
<Label Grid.Column="3" Content="Destination Database" VerticalAlignment="Bottom" FontWeight="Bold" Foreground="#4092C2" />
<Border BorderBrush="#BBBDBF" BorderThickness="1,0,0,1" Grid.Column="4" />
<Label Grid.Column="4" Content="Status" VerticalAlignment="Bottom" FontWeight="Bold" Foreground="#4092C2" />
</Grid>
<ItemsControl x:Name="itemscntrl" ItemsSource="{Binding DatabaseServers}" Background="White" BorderBrush="WhiteSmoke" BorderThickness="0" Grid.Row="2" Margin="0,5,0,0">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid x:Name="grd" Background="White" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="70" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<Image Source="{Binding StatusImage}" Height="10" Width="10" />
<Label Grid.Column="1" HorizontalAlignment="Left" Content="{Binding ServerName}" />
<Label Grid.Column="2" HorizontalAlignment="Left" Content="{Binding SourceDatabase}" />
<TextBox x:Name="dst" Grid.Column="3" Text="{Binding DestinationDatabase , Mode=TwoWay, UpdateSourceTrigger=LostFocus}" VerticalAlignment="Top" />
<Label Grid.Column="4" Content="{Binding Status}" VerticalAlignment="Top" />
<Button Grid.Column="4" BorderThickness="0" HorizontalAlignment="Center" Width="50" Margin="3" Content="{Binding Status}" Command="{Binding EnabledCommand}" CommandParameter="{Binding}" />
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding selected }" Value="True">
<Setter Property="Background" Value="Yellow" TargetName="dst" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Which currently looks like this:
I tried adding a DataTemplate.Triggers but it doesn't seam to do anything. How exactly do you detect that a row in a itemscontrol has been selected? The only examples I have found use a datagrid. I tried changing mine to a datagrid instead of the itemscontrol, but then the it wouldn't load the data.
Datagrid:
<DataGrid x:Name="grd" Background="White" DataContext="{Binding DatabaseServers}" Grid.Row="2">
<Image Source="{Binding StatusImage}" Height="10" Width="10" />
<Label Grid.Column="1" HorizontalAlignment="Left" Content="{Binding ServerName}" />
<Label Grid.Column="2" HorizontalAlignment="Left" Content="{Binding SourceDatabase}" />
<TextBox x:Name="dst" Grid.Column="3" Text="{Binding DestinationDatabase , Mode=TwoWay, UpdateSourceTrigger=LostFocus}" VerticalAlignment="Top" />
<Label Grid.Column="4" Content="{Binding Status}" VerticalAlignment="Top" />
<Button Grid.Column="4" BorderThickness="0" HorizontalAlignment="Center" Width="50" Margin="3" Content="{Binding Status}" Command="{Binding EnabledCommand}" CommandParameter="{Binding}" />
</DataGrid>
Just shows a bunch of lines there is no data in each row.
I am very new to WPF so I cant really figure out what I am doing wrong here.
Here is what you want using DataGrid i m using MVVM
Window.xaml
<Grid Margin="10">
<StackPanel Orientation="Vertical">
<Label Content="DataBases" Width="150" Height="50" HorizontalAlignment="Left" FontSize="20"/>
<DataGrid Name="DgDataSource" AutoGenerateColumns="False" CanUserAddRows="False" ItemsSource="{Binding SourceData}">
<DataGrid.Columns>
<DataGridTextColumn Header="ServerName" Binding="{Binding ServerName}" Width="2*"/>
<DataGridTextColumn Header="SourceDatabase" Binding="{Binding SourceDatabase}" Width="2*"/>
<DataGridTextColumn Header="DestinationDatabase" Binding="{Binding DestinationDatabase}" Width="2*"/>
<DataGridTemplateColumn Width="*" Header="Status" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="{Binding Status}" Command="{Binding EnabledCommand}"></Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</Grid>
View Model
public class WindowViewModel
{
public ObservableCollection<DataSource> SourceData { get; set; }
public WindowViewModel()
{
Initialize();
}
private void Initialize()
{
SourceData = new ObservableCollection<DataSource>
{
new DataSource() {Status = "Stop", ServerName = "Test 1", SourceDatabase = "Unknown",DestinationDatabase = "blabla....."},
new DataSource() {Status = "Work", ServerName = "Test 2", SourceDatabase = "Unknown",DestinationDatabase = "blabla....."},
new DataSource() {Status = "Stop", ServerName = "Test 3", SourceDatabase = "Unknown",DestinationDatabase = "blabla....."}
};
}
}
Model
public class DataSource
{
public string Status { get; set; }
public string ServerName { get; set; }
public string SourceDatabase { get; set; }
public string DestinationDatabase { get; set; }
}
I'm trying to postion views to the window in layout which is rectangle base while using MVVM pattern.
In WinForms I was able to use width, height, x and y of rectagle to position controls easily by just setting same properties on control.
Now I'm rewriting this code to wpf using MVVM and I'm lost.
this is what I'm trying to do:
This is something I thought might work but it does not.
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ItemsControl ItemsSource="{Binding VirtualScreens}" Grid.IsSharedSizeScope="True" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Grid.Row="{Binding Row}" Grid.Column="{Binding Column}" Content="{Binding Name}"></Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
public class VirtualScreen : ObservableObject
{
string name;
int row;
int column;
public string Name
{
get { return name; }
set
{
name = value;
RaisePropertyChanged(() => Name);
}
}
public int Row
{
get { return row; }
set
{
row = value;
RaisePropertyChanged(() => Row);
}
}
public int Column
{
get { return column; }
set
{
this.column = value;
RaisePropertyChanged(() => Column);
}
}
}
Thank you for any type of help
you could use ItemsControl ItemsPanel, ItemsTemplate and ItemContainerStyle.
Here is an example for you
<ItemsControl ItemsSource="{Binding VirtualScreens}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style>
<Style.Setters>
<Setter Property="Grid.Row" Value="{Binding Row}" />
<Setter Property="Grid.Column" Value="{Binding Column}" />
</Style.Setters>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
You can use a WPF Grid to layout the elements as shown in your UI. A three-row, three-column grid would work fine for you:
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Grid.RowSpan="2">This is the big top left section</Button>
<Button Grid.Row="1" Grid.Column="2">Top right</Button>
<Button Grid.Row="2" Grid.Column="2">Middle right</Button>
<Button Grid.Row="3" Grid.Column="1">Bottom left</Button>
<Button Grid.Row="3" Grid.Column="2">Bottom center</Button>
<Button Grid.Row="3" Grid.Column="2">Bottom right</Button>
</Grid>
Checkout Grid Row and Column Spanning for more info.
My TABLE code
ItemS Control Working Perfectly But I need only one listview inside listview help i get problem in
c Get Set Class I need a Single List
Hi I Need To Generate A Table In My Metro APP BUT I GET WRONG OUTPUT PLEASE HELP I BIND HEADER AND CONTENTS SEPERATELY USING LIST
C# CODE
foreach (var item in itemsreceiveds)
{
variable2.Add(new contentdata() { firstdata = item.getFirstData, seconddata = item.getSecondData, thirddata = item.getThirdData, headers = item.getFieldName });
}
var groupedPersons = variable2.Select((emp) => new { sectionName = emp.headers }).ToList().Distinct();
foreach (var s in groupedPersons)
{
firstheader = s.sectionName;
string[] sepword = firstheader.Split('#');
firstheader = sepword[0].ToUpper();
secondheader = sepword[1].ToUpper();
thirdheader = sepword[2].ToUpper();
variableheader.Add(new contentdataheader(firstheader,secondheader,thirdheader));
groupListView.ItemsSource = variableheader;
}
//SUBITEM
foreach (var person in variable2)
{
subdata.Add(new subitems(person.firstdata, person.seconddata, person.thirddata));
}
itemListViewss.ItemsSource = subdata;
XAML
<ListView Name="groupListView" CanDragItems="True" CanReorderItems="True" AllowDrop="True" IsSwipeEnabled="True" SelectionMode="None" Grid.ColumnSpan="3" Grid.Row="0">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<Border x:Name="bordermenu" BorderBrush="Black" BorderThickness="1" Grid.Column="1" Grid.Row="0" Width="150">
<TextBlock Foreground="Red" Text="{Binding Firstheader}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<Border x:Name="bordermenu2" BorderBrush="Black" BorderThickness="1" Grid.Column="2" Grid.Row="0" Width="150">
<TextBlock Foreground="Red" Text="{Binding Secondheader}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<Border x:Name="bordermenu3" BorderBrush="Black" BorderThickness="1" Grid.Column="3" Grid.Row="0" Width="150">
<TextBlock Foreground="Red" Text="{Binding Thirdheader}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView Name="itemListViewss" CanDragItems="True" CanReorderItems="True" AllowDrop="True" IsSwipeEnabled="True" SelectionMode="None" Grid.ColumnSpan="3" Grid.Row="1">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<Border x:Name="bordersubmenu" BorderBrush="Black" BorderThickness="1" Grid.Column="1" Grid.Row="1" Width="150">
<TextBlock Foreground="Blue" Text="{Binding dynamic}" x:Name="submenu" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<Border x:Name="bordersubmenu2" BorderBrush="Black" BorderThickness="1" Grid.Column="2" Grid.Row="1" Width="150">
<TextBlock Foreground="Blue" Text="{Binding p1}" x:Name="submenu2" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<Border x:Name="bordersubmenu3" BorderBrush="Black" BorderThickness="1" Grid.Column="3" Grid.Row="1" Width="150">
<TextBlock Foreground="Blue" Text="{Binding p2}" x:Name="submenu3" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I Get Ouput As
But I Need Output As This
Here's the simplest answer - a working demo.
I didn't do everything for you, mate, but I sure did a lot. You'll have to code a little to get it just how you like. If you are using a custom control suite, most of this might be done for you. If not, this will get you down the road. Far down the road.
Take this code behind:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
}
public class Datum
{
public DateTime Date { get; set; }
public string Year { get { return Date.ToString("yyy"); } }
public string Month { get { return Date.ToString("MMMM"); } }
public string Day { get { return Date.ToString("dd"); } }
public string Weekday { get { return Date.ToString("dddd"); } }
}
public class ViewModel
{
public ViewModel()
{
// data
var _Data = Enumerable.Range(1, 20)
.Select(x => new Datum { Date = DateTime.Now.Add(TimeSpan.FromDays(x * 14)) });
Data = new ObservableCollection<Datum>(_Data);
}
public ObservableCollection<Datum> Data { get; private set; }
}
And then try this XAML:
<Page.DataContext>
<local:ViewModel/>
</Page.DataContext>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<Grid Width="400">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.Resources>
<Style TargetType="Border">
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="BorderThickness" Value="2" />
<Setter Property="Background" Value="White" />
<Setter Property="Padding" Value="5" />
</Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Black" />
</Style>
</Grid.Resources>
<Border Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="4">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" >
<TextBlock VerticalAlignment="Center" TextAlignment="Right">
<Run Text="Search" />
<LineBreak />
<Run Text="Data" />
</TextBlock>
<TextBox Width="100" />
</StackPanel>
</Border>
<Border Grid.Column="0" Grid.Row="1"><TextBlock Text="Year" /></Border>
<Border Grid.Column="1" Grid.Row="1"><TextBlock Text="Month" /></Border>
<Border Grid.Column="2" Grid.Row="1"><TextBlock Text="Day" /></Border>
<Border Grid.Column="3" Grid.Row="1"><TextBlock Text="Weekday" /></Border>
</Grid>
<ItemsControl ItemsSource="{Binding Data}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Width="400">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="Margin" Value="5,0" />
</Style>
</Grid.Resources>
<TextBlock Grid.Column="0" Text="{Binding Year}" />
<TextBlock Grid.Column="1" Text="{Binding Month}" />
<TextBlock Grid.Column="2" Text="{Binding Day}" />
<TextBlock Grid.Column="3" Text="{Binding Weekday}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Grid Width="400">
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.Resources>
<Style TargetType="Border">
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="BorderThickness" Value="2" />
<Setter Property="Background" Value="White" />
<Setter Property="Padding" Value="5" />
</Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Black" />
</Style>
</Grid.Resources>
<Border Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="4">
<TextBlock Text="Showing 1 to 10 of 371" HorizontalAlignment="Right" />
</Border>
</Grid>
</StackPanel>
</Grid>
You should get something like this:
To add to Jerry's XAML in his answer. You can replace the ItemsControl with a ListBox (same template/itemTemplate modifications) to get the same view, but also the ability to use SelectedIndex, but I don't know if that applies to this question.
Note: I did find you need to add a Width to the ListBox. You can't just let the Grid in the ItemTemplate do it.
Maybe you're looking for something like this.
XAML:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition />
</Grid.RowDefinitions>
<Rectangle Fill="Black" Grid.ColumnSpan="2" Grid.Row="0" />
<TextBlock Text="Integer" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="5" Grid.Row="0" Grid.Column="0" FontSize="14" />
<TextBlock Text="String" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="5" Grid.Row="0" Grid.Column="1" FontSize="14" />
<ListView x:Name="ListViewDisplay" ItemsSource="{Binding}" Grid.Row="1" Grid.ColumnSpan="2" BorderThickness="1" BorderBrush="Black" Background="White" RequestedTheme="Light">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Integer}" Margin="5" Grid.Column="0" FontSize="14" />
<TextBlock Text="{Binding String}" Margin="5" Grid.Column="1" FontSize="14" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
Behind code:
public sealed partial class SamplePage : Page
{
ObservableCollection<ROWS> r = new ObservableCollection<ROWS>();
public SamplePage()
{
this.InitializeComponent();
r.Add(new ROWS { Integer = 1, String = "ONE" });
r.Add(new ROWS { Integer = 2, String = "TWO" });
r.Add(new ROWS { Integer = 3, String = "THREE" });
r.Add(new ROWS { Integer = 4, String = "FOUR" });
r.Add(new ROWS { Integer = 5, String = "FIVE" });
ListViewDisplay.ItemsSource = r;
}
}
public class ROWS {
public int Integer { get; set; }
public string String { get; set; }
}
Result: