RadCartesianChart didn't drawn because of null values for some points - windows-8

I use Telerik RadCartesianChart, Its ItemSource binding on ObservableCollection.
For example it has 3 Items:
Value 1 = 10
Value 2 = null
value 3 = 20
Its StrokeMode ="AllButPlotLine" ,
The line didn't drawn because of the null value.
Can I draw it?
Regards,

RadChart (RadCartesianChart) supports empty (null/NaN) values. Here is an example using the MVVM pattern for you to explore. Please note that there is no Value represented for Oranges.
There is also an example of Empty Values in your installation folder found here : C:\Program Files (x86)\Telerik\UI for Windows 8.1 XAML Q2 2014\Demos\Examples\Chart\EmptyValues
MainPage.xaml
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<chart:RadCartesianChart Width="700" Height="700">
<chart:RadCartesianChart.Grid>
<chart:CartesianChartGrid MajorLinesVisibility="XY" StripLinesVisibility="Y">
<chart:CartesianChartGrid.MajorXLineStyle>
<Style TargetType="Line">
<Setter Property="Stroke" Value="#B45121"/>
<Setter Property="StrokeDashArray" Value="4,2"/>
</Style>
</chart:CartesianChartGrid.MajorXLineStyle>
<chart:CartesianChartGrid.MajorYLineStyle>
<Style TargetType="Line">
<Setter Property="Stroke" Value="#58622D"/>
<Setter Property="StrokeDashArray" Value="10,2"/>
</Style>
</chart:CartesianChartGrid.MajorYLineStyle>
</chart:CartesianChartGrid>
</chart:RadCartesianChart.Grid>
<chart:RadCartesianChart.DataContext>
<local:ViewModel/>
</chart:RadCartesianChart.DataContext>
<chart:RadCartesianChart.HorizontalAxis>
<chart:CategoricalAxis/>
</chart:RadCartesianChart.HorizontalAxis>
<chart:RadCartesianChart.VerticalAxis>
<chart:LinearAxis/>
</chart:RadCartesianChart.VerticalAxis>
<chart:LineSeries ItemsSource="{Binding SeriesData}">
<chart:LineSeries.CategoryBinding>
<chart:PropertyNameDataPointBinding PropertyName="Category"/>
</chart:LineSeries.CategoryBinding>
<chart:LineSeries.ValueBinding>
<chart:PropertyNameDataPointBinding PropertyName="Value"/>
</chart:LineSeries.ValueBinding>
</chart:LineSeries>
</chart:RadCartesianChart>
</Grid>
CustomPoint.cs file
public class CustomPoint
{
public string Category { get; set; }
public double Value { get; set; }
}
ViewModel.cs
public class ViewModel
{
public ViewModel()
{
this.SeriesData = new List<CustomPoint>()
{
new CustomPoint{ Category = "Apples", Value = 10 },
new CustomPoint{ Category = "Oranges"},
new CustomPoint{ Category = "Pears", Value = 15 },
};
}
public List<CustomPoint> SeriesData { get; set; }
}

Related

Setting Entry Behaviors using Style attribute

I have defined my style as such:
<ContentView.Resources>
<ResourceDictionary>
<Style TargetType="Entry" x:Key="IntegralEntryBehavior">
<Setter Property="Behaviors" Value="valid:EntryIntegerValidationBehavior"/>
</Style>
</ResourceDictionary>
</ContentView.Resources>
And multiple similar Entries:
<StackLayout Grid.Column="0" Grid.Row="0">
<Entry Style="{StaticResource IntegralEntryBehavior}"/>
</StackLayout>
If I define Entry behavior like this, I get an error, that Entry.Behaviors property is readonly, but it's possible to define behavior without using Style attribute inside Entry as such:
<Entry.Behaviors>
<valid:EntryIntegerValidationBehavior/>
</Entry.Behaviors>
What is the difference between these approaches and why does only the second one work? Is it possible to modify the first approach to make it work? I'm looking for a shorter way to define this behavior for each entry than the second option.
You can checkout the example here:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/behaviors/creating#consuming-a-xamarinforms-behavior-with-a-style
Basically, add an attached property to your behavior and then set the style setter's property to that attached property. The attached property handles adding itself to the Entry that you attach it to.
public class EntryIntegerValidationBehavior : Behavior<Entry>
{
public static readonly BindableProperty AttachBehaviorProperty =
BindableProperty.CreateAttached ("AttachBehavior", typeof(bool), typeof(EntryIntegerValidationBehavior), false, propertyChanged: OnAttachBehaviorChanged);
public static bool GetAttachBehavior (BindableObject view)
{
return (bool)view.GetValue (AttachBehaviorProperty);
}
public static void SetAttachBehavior (BindableObject view, bool value)
{
view.SetValue (AttachBehaviorProperty, value);
}
static void OnAttachBehaviorChanged (BindableObject view, object oldValue, object newValue)
{
var entry = view as Entry;
if (entry == null) {
return;
}
bool attachBehavior = (bool)newValue;
if (attachBehavior) {
entry.Behaviors.Add (new EntryIntegerValidationBehavior ());
} else {
var toRemove = entry.Behaviors.FirstOrDefault (b => b is EntryIntegerValidationBehavior);
if (toRemove != null) {
entry.Behaviors.Remove (toRemove);
}
}
}
// Actual behavior code here
}
Finally edit your style to look like this:
<Style TargetType="Entry" x:Key="IntegralEntryBehavior">
<Setter Property="valid:EntryIntegerValidationBehavior.AttachBehavior" Value="true"/>
</Style>

Can a search result TextHighlighter or TextRange be bound to a DataTemplate in UWP XAML?

I have a SearchResult class that binds to a ListView. What I want to do specifically is highlight the snippet inside the search result text that matches the query the user entered.
The relevant XAML looks something like this (omitting the fluff):
<DataTemplate>
<StackPanel>
<!-- Search result -->
<RichTextBlock>
<!-- Would this idea work? -->
<RichTextBlock.TextHighlighters>
<TextHighlighter>
<TextHighlighter.Ranges>
<!-- Add the bound range here-->
<!-- {Binding Range} or text highlighter or something -->
</TextHighlighter.Ranges>
</TextHighlighter>
</RichTextBlock.TextHighlighters>
<Paragraph>
<Run Text="{Binding Text}"></Run>
</Paragraph>
</RichTextBlock>
</StackPanel>
</DataTemplate>
I can add whatever property from the SearchResult class, be it a TextHighlighter or a TextRange. I just don't know whether the XAML syntax allows plugging in that value.
I've also thought of doing this in code, but I do want to keep the search item template inside the XAML, and not put it in C#. However, it would be possible to do something like lvSearchResults.Items[i]... or whatever it takes to put in the highlighter or range. I just can't figure out the correct method at the moment.
If you are planning to create a locally highlighted search result list, you can try this way:
Create a search result class
public class SearchResult
{
public string DisplayText { get; set; }
public string HighlightText { get; set; }
}
Create a UserControl to show the result
SearchResultBlock.xaml
<Grid>
<TextBlock x:Name="ResultBlock" TextWrapping="Wrap" MaxLines="2"
TextTrimming="CharacterEllipsis"/>
</Grid>
SearchResultBlock.xaml.cs
public sealed partial class SearchResultBlock : UserControl
{
public SearchResultBlock()
{
this.InitializeComponent();
}
public SearchResult Result
{
get { return (SearchResult)GetValue(ResultProperty); }
set { SetValue(ResultProperty, value); }
}
public static readonly DependencyProperty ResultProperty =
DependencyProperty.Register("Result", typeof(SearchResult), typeof(SearchResultBlock), new PropertyMetadata(null,new PropertyChangedCallback(Result_Changed
private static void Result_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if(e.NewValue!=null && e.NewValue is SearchResult data)
{
var instance = d as SearchResultBlock;
instance.ResultBlock.Inlines.Clear();
var sp = data.DisplayText.Split(data.HighlightText);
instance.ResultBlock.Inlines.Add(new Run { Text = sp.First() });
instance.ResultBlock.Inlines.Add(new Run { Text = data.HighlightText, Foreground = new SolidColorBrush(Colors.Red) });
if (sp.Length > 1)
instance.ResultBlock.Inlines.Add(new Run { Text = sp.Last() });
}
}
}
Use it in DataTemplate
<DataTemplate x:DataType="SearchResult" x:Key="ResultItemTemplate">
<SearchResultBlock Result="{Binding}"/>
</DataTemplate>
By string splitting, create different types of Runs and merge them in the TextBlock. This can also achieve the highlighting effect.
Best regards.

How to Bind a column with a function which take the value of another column in parameter

For now, I have something like that (2 columns with dropboxes containing values independent from each other):
<xcdg:DataGridControl.Columns>
<xcdg:Column Title="A"
FieldName="A"
CellContentTemplate="{StaticResource ADT}"
GroupValueTemplate="{StaticResource ADT}"
Converter="{StaticResource AConverter}"
CellEditor="{StaticResource AEditor}"/>
<xcdg:Column Title="B"
FieldName="B"
CellContentTemplate="{StaticResource BDT}"
GroupValueTemplate="{StaticResource BDT}"
Converter="{StaticResource BConverter}"
CellEditor="{StaticResource BEditor}"/>
</xcdg:DataGridControl.Columns>
And I would like the B column to be a dropbox containing values depending on the value selected in the first column.
I don't know how to achieve that. I read about Binding.RelativeSource but I think it is not at all what I should use.
Thanks
I can think of two ways to do that, and since you didn't provide your exact case, i will provide a simple scenario and build my answer base on it,
let say you have a DataGrid with two editable columns (A and B), in the edit mode you can choose the A value from a combobox list, and then the B combobox will be filtered to show only the items whom their value starts with the A value for example, if A="aa", B should be {"aaaa","aabb"}, to implement that you need first a Model that represent the DataGrid Items
public class GridItem
{
public String A { get; set; }
public String B { get; set; }
}
In your codebehind / ViewModel define those properties (the DataGrid , and the comboboxes ItemSource Collections) :
private ObservableCollection<GridItem> _gridItemsCollection = new ObservableCollection<GridItem>()
{
new GridItem()
{
A="aa",
B="bbbb"
}
};
public ObservableCollection<GridItem> GridItemsCollection
{
get
{
return _gridItemsCollection;
}
set
{
if (_gridItemsCollection == value)
{
return;
}
_gridItemsCollection = value;
OnPropertyChanged();
}
}
//for the first Combobox
private ObservableCollection<String> _aCollection = new ObservableCollection<String>()
{
"aa",
"bb"
};
public ObservableCollection<String> ACollection
{
get
{
return _aCollection;
}
set
{
if (_aCollection == value)
{
return;
}
_aCollection = value;
OnPropertyChanged();
}
}
//for the second Combobox
private ObservableCollection<String> _bCollection ;
public ObservableCollection<String> BCollection
{
get
{
return _bCollection;
}
set
{
if (_bCollection == value)
{
return;
}
_bCollection = value;
OnPropertyChanged();
}
}
Define a full B collection from which your B combobox's itemsource will be populated
ObservableCollection<String> MainBCollection = new ObservableCollection<String>()
{
"aaaa",
"aabb",
"bbaa",
"bbbb"
};
Finally the population of the B combobox will be based on the selected item in the A combobox using this property,
private String _selectedAItem;
public String SelectedAItem
{
get
{
return _selectedAItem;
}
set
{
if (_selectedAItem == value)
{
return;
}
_selectedAItem = value;
OnPropertyChanged();
var returnedCollection = new ObservableCollection<String>();
foreach (var val in MainBCollection)
{
if (val.StartsWith(_selectedAItem))
{
returnedCollection.Add(value);
}
}
BCollection = new ObservableCollection<string>(returnedCollection);
}
}
You need of course to implement the INotifypropertyChanged Interface, so that the B Combobox Itemsource will be updated,
Now regarding the Xaml, due to some limitations in Xceed you need to specify the Combobox's ItemSource and SelectedItem using the RelativeSource and Ancestor binding,
<Grid >
<xcdg:DataGridControl ItemsSource="{Binding GridItemsCollection}" AutoCreateColumns="False" SelectionMode="Single" >
<xcdg:DataGridControl.Columns>
<xcdg:Column Title="A"
FieldName="A"
>
<xcdg:Column.CellContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</xcdg:Column.CellContentTemplate>
<xcdg:Column.CellEditor>
<xcdg:CellEditor>
<xcdg:CellEditor.EditTemplate>
<DataTemplate>
<ComboBox Name="AComboBox" SelectedItem="{Binding SelectedAItem, RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}}" SelectedValue="{xcdg:CellEditorBinding}"
ItemsSource="{Binding RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type wpfApplication3:MainWindow}},
Path=ACollection}">
</ComboBox>
</DataTemplate>
</xcdg:CellEditor.EditTemplate>
</xcdg:CellEditor>
</xcdg:Column.CellEditor>
</xcdg:Column>
<xcdg:Column Title="B"
FieldName="B"
>
<xcdg:Column.CellContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</xcdg:Column.CellContentTemplate>
<xcdg:Column.CellEditor>
<xcdg:CellEditor>
<xcdg:CellEditor.EditTemplate>
<DataTemplate>
<ComboBox Name="AComboBox" SelectedValue="{xcdg:CellEditorBinding}" ItemsSource="{Binding RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type Window}},
Path=BCollection}">
</ComboBox>
</DataTemplate>
</xcdg:CellEditor.EditTemplate>
</xcdg:CellEditor>
</xcdg:Column.CellEditor>
</xcdg:Column>
</xcdg:DataGridControl.Columns>
</xcdg:DataGridControl>
</Grid>
and the result is something like that
The Other way to do that is by using a MultivalueConverter and update the B Collection eachtime the A SelectedValue is changed,
something like that :
<xcdg:CellEditor.EditTemplate>
<DataTemplate>
<ComboBox Name="AComboBox" SelectedValue="{xcdg:CellEditorBinding}">
<ComboBox.ItemsSource>
<MultiBinding Converter="{StaticResource BCollectionConverter}">
<Binding Path="BCollection" RelativeSource="{RelativeSource AncestorType={x:Type Window}}"/>
<Binding Path="SelectedValue" ElementName="AComboBox" />
</MultiBinding>
</ComboBox.ItemsSource>
</ComboBox>
</DataTemplate>
</xcdg:CellEditor.EditTemplate>
And implement the converter to update the B Combobox's ItemSource,
public class BCollectionConverter:IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null)
return null;
var bCollection = (values[0] as ObservableCollection<String>);
var aSelectedItem = (values[1] as String);
if (aSelectedItem == null)
return null;
var returnedCollection = new ObservableCollection<String>();
foreach (var value in bCollection)
{
if (value.StartsWith(aSelectedItem))
{
returnedCollection.Add(value);
}
}
return returnedCollection;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I didn't try that last one, you might as well give it a try, I hope that did help.

Maximum number of lines for a Wrap TextBlock

I have a TextBlock with the following setting:
TextWrapping="Wrap"
Can I determine the maximum number of lines?
for example consider the following string TextBlock.Text:
This is a very good horse under the blackboard!!
It currently has been shows like this:
This is a very
good horse under
the blackboard!!
I need that to become something like:
This is a very
good horse ...
any solution?
Update (for UWP)
In UWP Apps you don't need this and can use the TextBlock property MaxLines (see MSDN)
Original Answer:
If you have a specific LineHeight you can calculate the maximum height for the TextBlock.
Example:
TextBlock with maximum 3 lines
<TextBlock
Width="300"
TextWrapping="Wrap"
TextTrimming="WordEllipsis"
FontSize="24"
LineStackingStrategy="BlockLineHeight"
LineHeight="28"
MaxHeight="84">YOUR TEXT</TextBlock>
This is all that you need to get your requirement working.
How to do this dynamically?
Just create a new control in C#/VB.NET that extends TextBlock and give it a new DependencyProperty int MaxLines.
Then override the OnApplyTemplate() method and set the MaxHeight based on the LineHeight * MaxLines.
That's just a basic explanation on how you could solve this problem!
Based tobi.at's and gt's answer I have created this MaxLines behaviour. Crucially it doesn't depend upon setting the LineHeight property by calculating the line height from the font. You still need to set TextWrapping and TextTrimming for it the TextBox to be render as you would like.
<TextBlock behaviours:NumLinesBehaviour.MaxLines="3" TextWrapping="Wrap" TextTrimming="CharacterEllipsis" Text="Some text here"/>
There in also a MinLines behaviour which can be different or set to the same number as the MaxLines behaviour to set the number of lines.
public class NumLinesBehaviour : Behavior<TextBlock>
{
TextBlock textBlock => AssociatedObject;
public static readonly DependencyProperty MaxLinesProperty =
DependencyProperty.RegisterAttached(
"MaxLines",
typeof(int),
typeof(NumLinesBehaviour),
new PropertyMetadata(default(int), OnMaxLinesPropertyChangedCallback));
public static void SetMaxLines(DependencyObject element, int value)
{
element.SetValue(MaxLinesProperty, value);
}
public static int GetMaxLines(DependencyObject element)
{
return (int)element.GetValue(MaxLinesProperty);
}
private static void OnMaxLinesPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBlock element = d as TextBlock;
element.MaxHeight = getLineHeight(element) * GetMaxLines(element);
}
public static readonly DependencyProperty MinLinesProperty =
DependencyProperty.RegisterAttached(
"MinLines",
typeof(int),
typeof(NumLinesBehaviour),
new PropertyMetadata(default(int), OnMinLinesPropertyChangedCallback));
public static void SetMinLines(DependencyObject element, int value)
{
element.SetValue(MinLinesProperty, value);
}
public static int GetMinLines(DependencyObject element)
{
return (int)element.GetValue(MinLinesProperty);
}
private static void OnMinLinesPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBlock element = d as TextBlock;
element.MinHeight = getLineHeight(element) * GetMinLines(element);
}
private static double getLineHeight(TextBlock textBlock)
{
double lineHeight = textBlock.LineHeight;
if (double.IsNaN(lineHeight))
lineHeight = Math.Ceiling(textBlock.FontSize * textBlock.FontFamily.LineSpacing);
return lineHeight;
}
}
If you have Height, TextWrapping, and TextTrimming all set, it will behave exactly like you want:
<TextBlock Height="60" FontSize="22" FontWeight="Thin"
TextWrapping="Wrap" TextTrimming="CharacterEllipsis">
The above code will wrap up to two lines, then use CharacterEllipsis beyond that point.
you need TextTrimming="WordEllipsis" setting in your TextBlock
Based on #artistandsocial's answer, I created a attached property to set the maximum number of lines programatically (rather than having to overload TextBlock which is discouraged in WPF).
public class LineHeightBehavior
{
public static readonly DependencyProperty MaxLinesProperty =
DependencyProperty.RegisterAttached(
"MaxLines",
typeof(int),
typeof(LineHeightBehavior),
new PropertyMetadata(default(int), OnMaxLinesPropertyChangedCallback));
public static void SetMaxLines(TextBlock element, int value) => element.SetValue(MaxLinesProperty, value);
public static int GetMaxLines(TextBlock element) =>(int)element.GetValue(MaxLinesProperty);
private static void OnMaxLinesPropertyChangedCallback(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
if (d is TextBlock textBlock)
{
if (textBlock.IsLoaded)
{
SetLineHeight();
}
else
{
textBlock.Loaded += OnLoaded;
void OnLoaded(object _, RoutedEventArgs __)
{
textBlock.Loaded -= OnLoaded;
SetLineHeight();
}
}
void SetLineHeight()
{
double lineHeight =
double.IsNaN(textBlock.LineHeight)
? textBlock.FontFamily.LineSpacing * textBlock.FontSize
: textBlock.LineHeight;
textBlock.MaxHeight = Math.Ceiling(lineHeight * GetMaxLines(textBlock));
}
}
}
}
By default, the LineHeight is set to double.NaN, so this value must first be set manually, otherwise a height is calculated from the FontFamily and FontSize of the TextBlock.
The attached property MaxLines and other relevant properties can then be set in a Style:
<Style TargetType="{x:Type TextBlock}"
BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="TextTrimming"
Value="CharacterEllipsis" />
<Setter Property="TextWrapping"
Value="Wrap" />
<Setter Property="LineHeight"
Value="16" />
<Setter Property="LineStackingStrategy"
Value="BlockLineHeight" />
<Setter Property="behaviors:LineHeightBehavior.MaxLines"
Value="2" />
</Style>
For anybody developing UWP or WinRT Applications, TextBlock has a MaxLines property you can set.
I doubt that is configurable, Wrapping is based on a number of factors such as font-size/kerning, available width of the textblock (horizontalalignment=stretch can make a big difference), parent's panel type (scrollviewer/stackpanel/grid) etc.
If you want the text to flow to the next line explicitly you should use "Run" blocks instead and then use wrapping of type ellipses for that run block.

Dynamically Create controls using ContentControl and Converters in silverlight4

I have a problem to create dynamic controls in silverlight 4.
My requirement is:
I have question table in database, which is like below.
QuestionText, AnswerControl, AnswerDefaultText, IsItmandatory
Question1 TextBox null Yes
QuestionText2, RadioButton, Yes, Yes
Question3, ComboBox, null, no
..........................................
I need to get this data into object and conver the question text into TextBlock, and based on answercontrol value, need to create controls dynamically.
I tried like as you mentioned in your post, but data is not binding and not able to send default values as parameter values to converter.
My Converter is not getting called. Is there any thing wrong in below code?
My Codes are:
1)My Xaml Code:
<UserControl x:Class="SilverlightApplication5.DynamicControls"
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:SilverlightApplication5.Converter"
xmlns:question="clr-namespace:SilverlightApplication5"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White" Width="400" Height="400">
<Grid.Resources>
<local:UILocatorConverter x:Key="UILocatorConverter" />
<question:Questions x:Key="Questions"/>
</Grid.Resources>
<ListBox ItemsSource="{Binding Questions}" Width="400" Height="400">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<ContentControl Content="{Binding Converter={StaticResource UILocatorConverter},ConverterParameter={Binding QuestionText},Path=QuestionControl}" Grid.Column="0" />
<ContentControl Content="{Binding Converter={StaticResource UILocatorConverter},ConverterParameter={Binding DefaultValue},Path=AnswerControl}" Grid.Column="1" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>
2) Code behind file code is:
namespace SilverlightApplication5
{
public partial class DynamicControls : UserControl
{
ObservableCollection<Questions> Question;
public DynamicControls()
{
InitializeComponent();
Question = new ObservableCollection<Questions>();
Question.Add(new Questions { QuestionControl = "TextBlock", QuestionText = "What is your name?", AnswerControl = "TextBox", AnswerValues = "", DefaultValue = "" });
Question.Add(new Questions { QuestionControl = "TextBlock", QuestionText = "What is your surname?", AnswerControl = "TextBox", AnswerValues = "", DefaultValue = "" });
Question.Add(new Questions { QuestionControl = "TextBlock", QuestionText = "Sex:", AnswerControl = "ComboBox", AnswerValues = "Male,Female,Others", DefaultValue = "Select a Value" });
Question.Add(new Questions { QuestionControl = "TextBlock", QuestionText = "Marital Status", AnswerControl = "RadioButton", AnswerValues = "", DefaultValue = "Not Married" });
this.DataContext = Question;
}
}
}
3) My converter is:
namespace SilverlightApplication5.Converter
{
public class UILocatorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
String param="This is control created dynamically";
if (parameter != null)
{
param = System.Convert.ToString(parameter);
}
switch (value.ToString())
{
case "TextBlock":
return new TextBlock() { Text = param, HorizontalAlignment=HorizontalAlignment.Center,TextWrapping=TextWrapping.NoWrap,Width=200 };
case "Button":
return new Button() { Content = param, Width=150 };
case "TextBox":
return new TextBox() { Text = param };
case "RadioButton":
return new TextBox() { };
case "ComboBox":
return new TextBox() { };
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
4) My Question Class is:
namespace SilverlightApplication5
{
public class Questions
{
private string _questionControl;
public string QuestionControl {
get
{
return _questionControl;
}
set
{
_questionControl = value;
}
}
private string _questionText;
public string QuestionText
{
get
{
return _questionText;
}
set
{
_questionText = value;
}
}
private string _answerControl;
public string AnswerControl
{
get
{
return _answerControl;
}
set
{
_answerControl = value;
}
}
private string _answerValues;
public string AnswerValues
{
get
{
return _answerValues;
}
set
{
_answerValues = value;
}
}
private string _defaultValue;
public string DefaultValue
{
get
{
return _defaultValue;
}
set
{
_defaultValue = value;
}
}
}
}
My converter is not getting called, is there any issues in this code?
You need to use this:
<ListBox ItemsSource="{Binding}" Width="400" Height="400">
As you want to access the collection of Questions you set in the DataContext.
What you were doing was creating a single Questions class in your Resources and telling the ListBox to use that.
So you won't need this at all:
<question:Questions x:Key="Questions"/>
(You might have to use BindsDirectlyToSource...because you are setting the DataContext to a collection directly...could be wrong on that!).
Alternatively, you can do this in your control:
public partial class DynamicControls : UserControl
{
public ObservableCollection<Questions> Question { get; set; }
...
Set the DataContext in this way:
DataContext = this;
And then use this Binding:
<ListBox ItemsSource="{Binding Question}" Width="400" Height="400">
I'd recommend you rename your Questions class to Question, and then rename the Property to Questions, to avoid confusion.