I create WPF app, added chart to markup, made bindings.
When I add new points to the graph data, axis changes their max values, but graph line doesn't displayed.
I can't understand what is wrong.
Here is markup of my chart:
<chartingToolkit:Chart x:Name="chart"
BorderThickness="1"
VerticalAlignment="Stretch"
Grid.Row="1">
<chartingToolkit:LineSeries Title="Options Count"
Visibility="Visible"
Background="Transparent"
ItemsSource="{Binding MyGraph}"
IndependentValuePath="Key"
DependentValuePath="Value"
DataPointStyle="{StaticResource DataPointStyle1}"
/>
<chartingToolkit:Chart.Axes>
<chartingToolkit:LinearAxis Orientation="Y"
Minimum="0"
Maximum="{Binding MaxValueForAxis}"
ShowGridLines="True" />
<chartingToolkit:DateTimeAxis Orientation="X"
ShowGridLines="True"
Minimum="{Binding MinDateForAxis}"
Maximum="{Binding MaxDateForAxis}"
IntervalType="Auto"
AxisLabelStyle="{StaticResource AxisStyle}"/>
</chartingToolkit:Chart.Axes>
</chartingToolkit:Chart>
And ViewModel code that adds values
public void AddNew()
{
MyGraph.Add(DateTime.Now.AddDays(i), i * 100);
i++;
OnPropertyChanged("MyGraph");
OnPropertyChanged("MaxValueForAxis");
OnPropertyChanged("MinDateForAxis");
OnPropertyChanged("MaxDateForAxis");
}
Here is how I set DataContext
ViewModel vm = new ViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = vm;
}
Use ObservableCollection<KeyValuePair<DateTime,int>> in your view model, reason being that this collection already implements INotifyCollectionChanged and INotifyPropertyChanged, while Dictionary<> doesn't.
XAML:
<Window x:Class="WpfApplication339.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
xmlns:local="clr-namespace:WpfApplication339"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="10*"></RowDefinition>
</Grid.RowDefinitions>
<Button Content="Add" Grid.Row="0" Click="Button_Click" Width="75" HorizontalAlignment="Left"/>
<chartingToolkit:Chart x:Name="chart"
BorderThickness="1"
VerticalAlignment="Stretch"
Grid.Row="1">
<chartingToolkit:LineSeries Title="Options Count"
Visibility="Visible"
Background="Transparent"
ItemsSource="{Binding MyGraph}"
IndependentValuePath="Key"
DependentValuePath="Value"
/>
<chartingToolkit:Chart.Axes>
<chartingToolkit:LinearAxis Orientation="Y"
Minimum="0"
Maximum="{Binding MaxValueForAxis}"
ShowGridLines="True" />
<chartingToolkit:DateTimeAxis Orientation="X"
ShowGridLines="True"
Minimum="{Binding MinimumDateForAxis}"
Maximum="{Binding MaxDateForAxis}"
IntervalType="Auto"
/>
</chartingToolkit:Chart.Axes>
</chartingToolkit:Chart>
</Grid>
</Window>
MainWindow:
public partial class MainWindow : Window
{
MyViewModel vm;
int i;
public MainWindow()
{
InitializeComponent();
vm = new MyViewModel();
DataContext = vm;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
vm.MyGraph.Add(new KeyValuePair<DateTime, int>(DateTime.Now.AddDays(i), i * 100));
i++;
}
}
ViewModel:
public class MyViewModel
{
public ObservableCollection<KeyValuePair<DateTime,int>> MyGraph { get; set; }
public MyViewModel()
{
MyGraph = new ObservableCollection<KeyValuePair<DateTime, int>>();
}
}
Related
I am creating a C# based WPF demonstration application that features a user defined control (User Control) "card" that features two labels and a chart (LiveCharts).
How do I correctly have the data bound to the LiveCharts control inside the card user control so the chart displays?
I have tried a variety of possible solutions including the DataContext={Binding RelativeSource={RelativeSource Self}}.
Without using the user control, the chart displays correctly, but as I have more than one instance required, I wish to have a user control for reuse.
Picture: Sample of current application when running
Repository
https://github.com/PWA-GouldA/C4Prog-DotNet-WPF-LiveChartDemo
Code Extract:
Interaction logic for CardLineChart.xaml
public partial class CardLineChart : UserControl
{
public CardLineChart()
{
InitializeComponent();
CardGrid.DataContext = this;
}
#region SeriesData DP
public SeriesCollection SeriesData
{
set { SetValue(DataProperty, value); }
}
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("SeriesData",
typeof(SeriesCollection), typeof(CardLineChart),
new PropertyMetadata(new SeriesCollection()));
#endregion
#region BackgroundColour DP
public string BackgroundColour
{
set { SetValue(ColourBG, value); }
}
public static readonly DependencyProperty ColourBG =
DependencyProperty.Register("BackgroundColour",
typeof(string), typeof(CardLineChart), new PropertyMetadata(""));
#endregion
#region BottomLabel DP
public string BottomLabel
{
set { SetValue(LabelAtBottom, value); }
}
public static readonly DependencyProperty LabelAtBottom =
DependencyProperty.Register("BottomLabel",
typeof(string), typeof(CardLineChart), new PropertyMetadata(null));
#endregion
#region TopLabel DP
public string TopLabel
{
set { SetValue(LabelAtTop, value); }
}
public static readonly DependencyProperty LabelAtTop =
DependencyProperty.Register("TopLabel",
typeof(string), typeof(CardLineChart), new PropertyMetadata(null));
#endregion
}
CardLineChart.xaml
<UserControl x:Class="WPF_With_LiveCharts.CardLineChart"
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:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
mc:Ignorable="d"
d:DesignHeight="200" d:DesignWidth="200"
>
<Grid x:Name="CardGrid" Margin="5,5,5,5" MaxHeight="200" MaxWidth="200">
<Grid.Effect>
<DropShadowEffect BlurRadius="15" Direction="-90" RenderingBias="Quality" Opacity=".2" ShadowDepth="2"/>
</Grid.Effect>
<Grid.OpacityMask>
<VisualBrush Visual="{Binding ElementName=Border1}" />
</Grid.OpacityMask>
<Grid.Resources>
<Style TargetType="lvc:LineSeries">
<Setter Property="StrokeThickness" Value="1"></Setter>
<Setter Property="Stroke" Value="White"></Setter>
<Setter Property="Fill" Value="#00ffffff"></Setter>
<Setter Property="PointGeometrySize" Value="0"></Setter>
<Setter Property="LineSmoothness" Value="0.25"></Setter>
</Style>
<Style TargetType="lvc:Axis">
<Setter Property="ShowLabels" Value="False"></Setter>
<Setter Property="IsEnabled" Value="False"></Setter>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="60"></RowDefinition>
<RowDefinition Height="80*"></RowDefinition>
</Grid.RowDefinitions>
<Border x:Name="Border1" Grid.Row="0" Grid.RowSpan="3" CornerRadius="5"
Background="{Binding Path=BackgroundColour}" />
<TextBlock Grid.Row="0" TextAlignment="Center" Padding="5, 5, 0, 5"
Foreground="#ccFFFFFF" FontSize="12"
Text="{Binding Path=TopLabel}" />
<lvc:CartesianChart Grid.Row="1"
Margin="0,0,0,0"
Series="{Binding Path=SeriesData}"
Hoverable="False"
DataTooltip="{x:Null}">
<lvc:CartesianChart.AxisX>
<lvc:Axis MinValue="0"></lvc:Axis>
</lvc:CartesianChart.AxisX>
</lvc:CartesianChart>
<TextBlock Grid.Row="2" x:Name="ChartValue"
Foreground="#ccFFFFFF" FontSize="48"
VerticalAlignment="Center" TextAlignment="Center"
Margin="8,0,8,6" Text="{Binding Path=BottomLabel}"/>
</Grid>
</UserControl>
WindowMain.cs
public partial class MainWindow : Window
{
public SeriesCollection theData;
public SeriesCollection theData2;
public string BackgroundColour;
public MainWindow()
{
InitializeComponent();
theData = new SeriesCollection
{
new LineSeries
{
Values = new ChartValues<decimal> { 7, 3, 2, 3, 5, 7, 4 }
}
};
theData2 = new SeriesCollection
{
new LineSeries
{
Values = new ChartValues<decimal> { 100, 90, 70, 40, 10 }
}
};
BackgroundColour = "#FFCE2156";
DataContext = this;
}
private void ButtonLineChart_Click(object sender, RoutedEventArgs e)
{
}
}
WindowMain.xaml
<Window x:Class="WPF_With_LiveCharts.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPF_With_LiveCharts"
xmlns:control = "clr-namespace:WPF_With_LiveCharts"
mc:Ignorable="d"
Title="MainWindow" Height="460" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="45"/>
<RowDefinition Height="200"/>
<RowDefinition Height="200"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="200*"/>
<ColumnDefinition Width="200*"/>
<ColumnDefinition Width="200*"/>
</Grid.ColumnDefinitions>
<Button x:Name="ButtonLineChart" Content="Line Chart" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="ButtonLineChart_Click" Height="25"/>
<Button x:Name="ButtonPieChart" Content="Pie Chart" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Grid.Column="2" Height="25"/>
<control:CardLineChart
Grid.Column="0" Grid.Row="1"
x:Name="TestingCardLineChart"
SeriesData="{Binding theData}"
BackgroundColour="#ffc22735"
TopLabel="Testing"
BottomLabel="123"
/>
<control:CardLineChart
Grid.Column="1"
Grid.Row="1"
x:Name="TestingCardLineChart2"
SeriesData="{Binding theData2}"
BackgroundColour="#FF000000"
TopLabel="Oh Yes!"
BottomLabel="9999"
/>
</Grid>
</Window>
Binding doesn't work on fields in WPF. If you change the series collection on MainWindow.xaml.cs to use properties instead you should be able to see the graphs.
eg
public SeriesCollection theData { get; set; }
public SeriesCollection theData2 { get; set; }
I'm tring to databind properties of an ObservableCollection to a ListBox (Just the Title property for example).
By clicking on one of the ListItem (with an event ), i'd like to display all the properties of the Collection into a StackPanel. After many tries, I still don't know how can I figure it out...
Here is my code behind :
public partial class TestListView : Window
{
public TestListView()
{
ObservableCollection<Programme> pgr = new ObservableCollection<Programme>();
pgr = readfile();
InitializeComponent();
}
public class Programme
{
public String Title { get; set; }
public String Date { get; set; }
public String Chaine { get; set; }
public Programme(String Title, String Date, String Chaine)
{
this.Title = Title;
this.Date = Date;
this.Chaine = Chaine;
}
}
Here is my XAML :
<Window x:Class="Test.TestListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Test;assembly=Test"
Title="TestListView" Height="500" Width="1000" x:Name="Window">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="249*"/>
<ColumnDefinition Width="743*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20*"/>
<RowDefinition Height="428*"/>
<RowDefinition Height="21*"/>
</Grid.RowDefinitions>
<ListBox Name="l1" ItemsSource="{Binding pgr}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Title}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel Grid.Column="1" Grid.Row="1">
<TextBox Margin="343,0,0,0" x:Name="Recherche"></TextBox>
<Button Height="37" Margin="669,0,0,0" ></Button>
<TextBlock x:Name="t1" Margin="214,0,293,0" Height="33" />
</StackPanel>
</Grid>
</Window>
You need to bind your data to (public) properties. Also, you don't need to use ObservableCollection; any selection changes will be picked up anyhow.
Here's a working sample, with layout and other bits and pieces changed to make it compile for me:
public partial class MainWindow
{
public IList<Programme> pgr { get; }
public MainWindow()
{
pgr = new List<Programme>
{
new Programme("First", "FirstDate", "FirstChaine"),
new Programme("Second", "SecondDate", "SecondChaine"),
new Programme("Third", "ThirdDate", "ThirdChaine"),
};
InitializeComponent();
}
public class Programme
{
// No changes
}
}
...and the XAML:
<Window
x:Name="self"
x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow"
Height="350"
Width="525">
<StackPanel DataContext="{Binding ElementName=self}" Orientation="Horizontal">
<ListBox Name="l1" ItemsSource="{Binding pgr}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Title}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel Orientation="Vertical">
<TextBox Margin="10" Text="{Binding ElementName=l1,Path=SelectedItem.Title}" />
<Button Height="37" Margin="0" Content="{Binding ElementName=l1,Path=SelectedItem.Date}"></Button>
<TextBlock Margin="10" Height="33" Text="{Binding ElementName=l1,Path=SelectedItem.Chaine}" />
</StackPanel>
</StackPanel>
</Window>
Note the bindings that reference the selected item:
Text="{Binding ElementName=l1,Path=SelectedItem.Title}"
I'm searching for hours now but could not find the correct way how to do that.
I build a UserControl "MyToolbarGroup" having a GroupText and an empty Stackpanel inside.
Now I want to use the control MyToolbarGroup on my other UserControl "MyUserControl" and create some Buttons inside the Stackpanel of the MyToolbarGroup control.
MyToolbarGroup-XAML
<UserControl x:Class="TestUi.MyToolbarGroup"
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"
mc:Ignorable="d" d:DesignWidth="153" d:DesignHeight="103">
<Grid>
<Border BorderBrush="Black" BorderThickness="2">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center" Margin="5,5,5,5" />
<Label Grid.Row="1" HorizontalContentAlignment="Center" Content="{Binding Path=GroupText}" Background="LightBlue" />
</Grid>
</Border>
</Grid>
</UserControl>
MyToolbarGroup-Code
public partial class MyToolbarGroup : UserControl
{
public static readonly DependencyProperty GroupTextProperty = DependencyProperty.Register("GroupText", typeof(string), typeof(MyToolbarGroup));
public String GroupText
{
get { return (String)GetValue(GroupTextProperty); }
set { SetValue(GroupTextProperty, value); }
}
public MyToolbarGroup()
{
InitializeComponent();
DataContext = this;
}
}
MyUserControl-XAML
<UserControl
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:TestUi" x:Class="TestUi.MyUserControl"
mc:Ignorable="d"
d:DesignHeight="224" d:DesignWidth="343">
<Grid>
<local:MyToolbarGroup HorizontalAlignment="Left" Margin="40,30,0,0" VerticalAlignment="Top" Height="148" Width="238" GroupText="Test-Group">
<!-- Something like that
<Stackpanel-Inside-MyToolbarGroup>
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Height="65" Width="65" Content="Button 1"/>
</Stackpanel-Inside-MyToolbarGroup>
-->
</local:MyToolbarGroup>
</Grid>
</UserControl>
Any ideas how to set some buttons inside the stackpanel?
Thanx for any help!
include a ContentPresenter in MyToolbarGroup template to accept user Content
<UserControl x:Class="TestUi.MyToolbarGroup"
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:testUi="clr-namespace:TestUi"
mc:Ignorable="d" d:DesignWidth="153" d:DesignHeight="103">
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Grid>
<Border BorderBrush="Black" BorderThickness="2">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<ContentPresenter Content="{TemplateBinding Content}"/>
<Label Grid.Row="1" HorizontalContentAlignment="Center"
Content="{Binding GroupText, RelativeSource={RelativeSource AncestorType=testUi:MyToolbarGroup}}"
Background="LightBlue" />
</Grid>
</Border>
</Grid>
</ControlTemplate>
</UserControl.Template>
</UserControl>
and then use it like this:
<testUi:MyToolbarGroup Grid.Row="2"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Height="148" Width="238" GroupText="Test-Group">
<!--any content, e.g. -->
<StackPanel Orientation="Horizontal">
<TextBlock Text="A" Margin="5"/>
<TextBlock Text="B" Margin="5"/>
</StackPanel>
</testUi:MyToolbarGroup>
result:
A stack panel doesn't have the functionality you want (if I understand you correctly). What you want is a dynamic collection of controls based on some data right?
What you need is an ItemsControl:
<ItemsControl ItemsSource="{Binding MyButtonDataCollection}" >
<ItemsControl.ItemTemplate >
<DataTemplate >
<Button Content="{Binding ButtonName}"
Command="{Binding ButtonClick}"
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
bound to a collection of data objects that have the properties and commands you want to bind to:
class MyButtonData : INotifyPropertyChanged
{
String ButtonName { get; set; } //notify property changed and all that
public ICommand ButtonClick
{
get;
internal set;
}
private bool CanExecuteButtonClick()
{
//can this execute?
return true;
}
private void CreateButtonClick()
{
ButtonClick = new RelayCommand(SaveExecute, CanExecuteSaveCommand);
}
public void ButtonClickExecute()
{
//do my logic for click
}
}
If you want layout inside MyToolbarGroup to be predefined, you need to replace StackPanel with ItemsControl having StackPanel as ItemsPanel.
Here's MyToolbarGroup XAML:
<UserControl x:Class="WpfApplication2.MyToolbarGroup"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication2">
<Border BorderBrush="Black" BorderThickness="2">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<ItemsControl Grid.Row="0" HorizontalAlignment="Center" Margin="5,5,5,5"
ItemsSource="{Binding GroupItems, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<Label Grid.Row="1" HorizontalContentAlignment="Center"
Content="{Binding GroupText, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"
Background="LightBlue" />
</Grid>
</Border>
</UserControl>
and code-behind:
public partial class MyToolbarGroup : UserControl
{
public MyToolbarGroup()
{
InitializeComponent();
}
public string GroupText
{
get { return (string)GetValue(GroupTextProperty); }
set { SetValue(GroupTextProperty, value); }
}
public static readonly DependencyProperty GroupTextProperty =
DependencyProperty.Register("GroupText", typeof(string), typeof(MyToolbarGroup), new PropertyMetadata(null));
public IEnumerable GroupItems
{
get { return (IEnumerable)GetValue(GroupItemsProperty); }
set { SetValue(GroupItemsProperty, value); }
}
public static readonly DependencyProperty GroupItemsProperty =
DependencyProperty.Register("GroupItems", typeof(IEnumerable), typeof(MyToolbarGroup), new PropertyMetadata(null));
}
Now, you can use it like this:
<Window x:Class="WpfApplication2.MainWindow"
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:WpfApplication2"
Title="MainWindow">
<Grid>
<local:MyToolbarGroup HorizontalAlignment="Left" Margin="40,30,0,0" VerticalAlignment="Top" Height="148" Width="238" GroupText="Test-Group">
<local:MyToolbarGroup.GroupItems>
<x:Array Type="{x:Type sys:Object}">
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Height="65" Width="65" Content="Button 1"/>
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Height="65" Width="65" Content="Button 2"/>
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Height="65" Width="65" Content="Button 3"/>
</x:Array>
</local:MyToolbarGroup.GroupItems>
</local:MyToolbarGroup>
</Grid>
</Window>
Screenshot of result:
can I create something like this in silverlight? A box with editable title and the rest of the text
http://docs.jboss.org/seam/3/latest/reference/en-US/html/images/remoting-model-customer-address-uml.png
You could create a custom user control:
XAML:
<UserControl x:Class="WpfApplication1.MyBox"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Text="{Binding Header,UpdateSourceTrigger=PropertyChanged}"
BorderBrush="Black" BorderThickness="1" Margin="2" />
<TextBox Text="{Binding Text,UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto"
AcceptsReturn="True"
BorderBrush="Black" BorderThickness="1" Margin="2" Grid.Row="1" />
</Grid>
</UserControl>
Code behind:
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
public partial class MyBox : UserControl
{
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(string), typeof(MyBox));
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Content", typeof(string), typeof(MyBox));
public string Header
{
get { return GetValue(HeaderProperty) as string; }
set { SetValue(HeaderProperty, value); }
}
public string Text
{
get { return GetValue(TextProperty) as string; }
set { SetValue(TextProperty, value); }
}
public MyBox()
{
InitializeComponent();
this.DataContext = this;
}
}
}
A sample:
XAML:
<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="350" Width="525"
xmlns:local="clr-namespace:WpfApplication1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<local:MyBox x:Name="box1" Header="Type a header..." Text="Type a content..." Grid.Row="0" Grid.Column="0" BorderBrush="Black" BorderThickness="1" Margin="10" />
<local:MyBox x:Name="box2" Header="Type a header..." Text="Type a content..." Grid.Row="0" Grid.Column="1" BorderBrush="Black" BorderThickness="1" Margin="10" />
<Button Content="Show" Grid.Row="1" Grid.Column="0" Click="Button_Click" />
</Grid>
</Window>
Code behind:
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(string.Format("{0}\n{1}\n\n{2}\n{3}", box1.Header, box1.Text, box2.Header, box2.Text));
}
}
}
This is WPF but should be fine in Silverlight too, except the MessageBox stuff but it's only for debugging purposes...
EDIT:
Here is a sample for dynamic generation:
XAML:
<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="350" Width="525"
xmlns:local="clr-namespace:WpfApplication1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel x:Name="panel" Orientation="Horizontal">
<local:MyBox x:Name="box1" Header="Type a header..." Text="Type a content..." Grid.Row="0" Grid.Column="0" BorderBrush="Black" BorderThickness="1" Margin="10" />
</StackPanel>
<Button Content="Add" Grid.Row="1" Grid.Column="0" Click="Button_Click" />
</Grid>
</Window>
CodeBehind:
using System.Windows;
using System.Windows.Media;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
panel.Children.Add(new MyBox
{
Header = "Another box",
Text = "...",
BorderBrush = Brushes.Black,
BorderThickness = new Thickness(1),
Margin = new Thickness(10)
});
}
}
}
I am developing a UserControl that consists of a block with a heading and a list of items (ItemsControl). The problem is that the user control contents gets clipped off when I dynamically add the usercontrol to a canvas as shown below. I am not setting a size for the usercontrol internally. What can be done to avoid this.
Clipping is happening even when I drag and drop the usercontrol to canvas. I need the contents to get scaled.
<UserControl x:Class="MyTools.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid x:Name="LayoutRoot" Background="White">
<Border Name="MainBorder" CornerRadius="5" BorderThickness="2" BorderBrush="Black">
<Grid Name="grid1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" >
<Grid.RowDefinitions>
<RowDefinition Height="34" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Name="titleGrid" Grid.Row="0" Background="#FF727272">
<TextBlock Name="titleText" HorizontalAlignment="Center" Text="{Binding ControlName}" VerticalAlignment="Center" FontSize="13" FontWeight="Bold" Foreground="Beige" />
</Grid>
<Grid Name="gridpr" Grid.Row="1" Background="#12C48F35">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Name="borderPr" CornerRadius="3" Margin="10" BorderThickness="1" BorderBrush="LightGray" Grid.Row="0">
<Grid Name="gridPr" Background="#FFC1C1C1" MouseLeftButtonUp="gridPr_MouseLeftButtonUp">
<StackPanel>
<TextBlock HorizontalAlignment="Center" Name="txtPr" Text="SubItems" VerticalAlignment="Center" Foreground="#FF584848" FontSize="12" />
<ItemsControl x:Name="pitems" ItemsSource="{Binding MyItems}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="15,0,0,0">
<TextBlock Text="{Binding MyVal}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
</Border>
</Grid>
</Grid>
</Border>
</Grid>
</UserControl>
Code-behind for UserControl:
namespace MyTools
{
public partial class MyControl : UserControl
{
public MyControl()
{
InitializeComponent();
}
public string ControlName { get; set; }
public object MyItems { get; set; }
public class Row
{
public string MyVal { get; set; }
}
protected override Size MeasureOverride(Size availableSize)
{
var desiredSize = base.MeasureOverride(availableSize);
var sideLength = Math.Min(desiredSize.Width, desiredSize.Height);
desiredSize.Width = sideLength;
desiredSize.Height = sideLength;
return desiredSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
var sideLength = Math.Min(this.DesiredSize.Width, this.DesiredSize.Height);
return base.ArrangeOverride(new Size(sideLength, sideLength));
}
private void gridPr_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
pitems.Visibility = pitems.Visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
}
}
}
Host Client Code:
namespace TestProject
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
MyControl control1 = new MyControl();
control1.ControlName = "Test Name";
var test = new List<MyControl.Row>(
new MyControl.Row[]
{
new MyControl.Row {MyVal = "Item1"},
new MyControl.Row {MyVal = "Item2"},
new MyControl.Row {MyVal = "Item3"}
});
control1.MyItems = test;
control1.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
MessageBox.Show(control1.DesiredSize.Height.ToString());
canvas1.Children.Add(control1);
}
}
}
Layout of host:
<UserControl x:Class="TestProject.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="503" d:DesignWidth="758" xmlns:my="clr-namespace:MyTools">
<Grid x:Name="LayoutRoot" Background="White" Height="507" Width="757">
<Canvas Height="503" Name="canvas1" HorizontalAlignment="Left" Margin="-1,-1,0,0" VerticalAlignment="Top" Width="758">
</Canvas>
</Grid>
</UserControl>
EDIT:
Turns out that the issue is because of MeasureOverride. The clipping is not there when I removed it. Thanks for the suggestions.