I'm trying to get a ValidationRule to display text over an offending combobox, if the user has not specified a value yet. I can get it to display, but I can't seem to get the text to fit to the size of the combobox using TextTrimming="CharacterEllipsis". How can I get the TextBlock to fit the combobox, and also correct itself if the user resizes the window?
Here's my MainWindow.xaml:
<Window x:Class="PocAdornedElementPlaceholder.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PocAdornedElementPlaceholder"
Title="MainWindow" Height="200" Width="150">
<Window.Resources>
<ControlTemplate x:Key="ValidationTemplate">
<Grid HorizontalAlignment="Center">
<AdornedElementPlaceholder/>
<TextBlock Foreground="Red"
TextTrimming="CharacterEllipsis"
Text="{Binding ErrorContent}"
IsHitTestVisible="False"
VerticalAlignment="Center"
Margin="5,0,0,0"/>
</Grid>
</ControlTemplate>
</Window.Resources>
<Grid>
<ComboBox Margin="10"
Validation.ErrorTemplate="{StaticResource ValidationTemplate}"
VerticalAlignment="Center"
ItemsSource="{Binding Options}">
<ComboBox.Text>
<Binding Path="SelectedValue">
<Binding.ValidationRules>
<local:MyValidationRule ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</ComboBox.Text>
</ComboBox>
</Grid>
</Window>
Here's my MainWindow.xaml.cs:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Options = new List<string>() { "Value 1", "Value 2", "Value 3", "" };
this.DataContext = this;
}
public string SelectedValue { get; set; }
public List<string> Options { get; set; }
}
And here's my MyValidationRule.cs file:
public class MyValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (string.IsNullOrEmpty((string)value))
return new ValidationResult(false, "Value cannot be empty!");
return new ValidationResult(true, null);
}
}
Any help would be much appreciated!
Thanks,
Tam
Try below, TextBlock should be the content of the adorner. I also had to change the margin of the textblock to count for the dropdown arrow button.
<ControlTemplate x:Key="ValidationTemplate">
<Grid HorizontalAlignment="Center">
<AdornedElementPlaceholder>
<TextBlock Foreground="Red" TextTrimming="CharacterEllipsis" Text="{Binding ErrorContent}" IsHitTestVisible="False" VerticalAlignment="Center" Margin="5,0,20,0" />
</AdornedElementPlaceholder>
</Grid>
</ControlTemplate>
Related
This question already has answers here:
Issue with DependencyProperty binding
(3 answers)
Datacontext conflicts
(1 answer)
How to correctly bind to a dependency property of a usercontrol in a MVVM framework
(4 answers)
Closed 5 years ago.
I've created a user control that have a label and textbox.
i added two DependencyProperties (Text and Label) and bind them to textbox.text and label.content.
however, i'm not able to see the text of textbox.
in the main window, when i'm not binding to any element the label is shown but if i binding the element is not shown. the textbox not showing either way.
here's the xaml:
<UserControl x:Class="TestNewLabeltextbox.UserControl1"
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">
<StackPanel Orientation="Horizontal" Background="White" FlowDirection="RightToLeft">
<Label x:Name="lbl" Content="{Binding Label, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="100" HorizontalAlignment="Left" Background="blue">
<Label.Style>
<Style TargetType="Label">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<StackPanel Orientation="Horizontal">
<Border Background="Blue" Width="200" BorderThickness="0,0,0,0">
<StackPanel Orientation="Horizontal">
<Viewbox StretchDirection="DownOnly" Stretch="Uniform">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True" TextBlock.FontSize="14" TextBlock.Foreground="#FFFFFF" Margin="5">
<ContentPresenter.Effect>
<DropShadowEffect BlurRadius="0.0"
Color="#032A6B"
Direction="90"
Opacity="1"
ShadowDepth="1" />
</ContentPresenter.Effect>
</ContentPresenter>
</Viewbox>
</StackPanel>
</Border>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Label.Style>
</Label>
<TextBox x:Name="txt" Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="120" HorizontalAlignment="Right">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border CornerRadius="0,0,0,50" BorderBrush="Black" Background="White" BorderThickness="0">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True" TextBlock.FontSize="14" TextBlock.Foreground="#FFFFFF" Margin="5">
<ContentPresenter.Effect>
<DropShadowEffect BlurRadius="0.0"
Color="#032A6B"
Direction="90"
Opacity="1"
ShadowDepth="1" />
</ContentPresenter.Effect>
</ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TextBox.Style>
</TextBox>
</StackPanel>
Here'sUserControl1.cs:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
this.DataContext = this;
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
}
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register("Label", typeof(string), typeof(UserControl1), new PropertyMetadata(null));
public string Label
{
get { return (string)this.GetValue(LabelProperty); }
set { this.SetValue(LabelProperty, value); }
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(UserControl1), new PropertyMetadata(null));
public string Text
{
get { return (string)this.GetValue(TextProperty); }
set { this.SetValue(TextProperty, value); }
}
}
here's the window xaml + cs:
<Window x:Class="TestNewLabeltextbox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:TestNewLabeltextbox"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel Orientation="Vertical" Height="150">
<controls:UserControl1 Text="hello" Height="50" Label="{Binding Hello, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<controls:UserControl1 Text="hello" Height="50" Label="world" />
<Label BorderBrush="Black" BorderThickness="2" Width="100" Height="50" Content="{Binding Hello, Mode=TwoWay}"/>
</StackPanel>
</Grid>
public partial class MainWindow : Window
{
ViewModel vm = new ViewModel();
public MainWindow()
{
InitializeComponent();
vm.Hello = "555";
this.DataContext = vm;
}
}
viewmodel.cs
public class ViewModel : INotifyPropertyChanged
{
private string h = "Hello";
public string Hello
{
get
{
return h;
}
set
{
h = value;
NotifyPropertyChanged("Hello");
}
}
#region "PropertyChanged Event"
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
Default Source of binding is DataContext. But your Label and Text dependency properties defined in the control rather than in view-model. Change binding of Label to
{Binding Path=Label, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}
and binding of TextBox to
{Binding Path=Text, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
Please read about Mode and UpdateSourceTrigger properties of Binding. It seems that you don't know how they work. Mode=TwoWay, UpdateSourceTrigger=PropertyChanged doesn't make any sense for Content property.
I want to bind 'SomeText' from my UserControl, into the Content of my Label.
I currently have a UserControl which just displays my 'SomeText'. The XAML, and Code Behind file can be seen below.
<UserControl x:Class="TabHeader.UserControl1"
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="183" d:DesignWidth="235"
x:Name="uc">
<Grid>
<Label Height="43" HorizontalAlignment="Left" Margin="57,102,0,0" Name="textBlock1" Content="{Binding Path=SomeText, ElementName=uc}" VerticalAlignment="Top" Width="86" />
</Grid>
</UserControl>
namespace TabHeader
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
private string someText;
public UserControl1()
{
this.SomeText = "23";
InitializeComponent();
}
public string SomeText
{
get
{
return someText;
}
set
{
someText = value;
}
}
}
}
I then have my main XAML page where I have, a Tab Control within a Grid. I'm using a Style to generate two Labels within the Columns Header. I am able to pull through the Header field, but I am unable to pull through the controls field.
<Window x:Class="TabHeader.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vw="clr-namespace:TabHeader"
Title="MainWindow" Height="350" Width="525" Name="Tabs">
<Grid>
<TabControl Height="262" HorizontalAlignment="Left" Margin="47,26,0,0" Name="tabControl1" VerticalAlignment="Top" Width="366">
<TabControl.Resources>
<Style TargetType="TabItem" x:Key="tabItemHeaderStyle" >
<Setter Property="HeaderTemplate" >
<Setter.Value>
<DataTemplate DataType="{x:Type TabItem}">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Path=Header, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TabItem}}"/>
<Label Content="{Binding Path=SomeText, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=vw:UserControl1}}"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
<TabItem Style="{StaticResource tabItemHeaderStyle}" Header="TI 1" Name="tabItem1" Width="100">
<vw:UserControl1 x:Name="UserControl11"></vw:UserControl1>
</TabItem>
<TabItem Style="{StaticResource tabItemHeaderStyle}" Header="TI 2" Name="tabItem2">
</TabItem>
</TabControl>
</Grid>
</Window>
Any assistance with this would be greatly appreciated.
Cheers.
Edit 1
For anyone interested added my working code below, where I have used the DependencyProperty.
MainWindow.xaml
<Grid>
<TabControl Height="262" HorizontalAlignment="Left" Margin="47,26,0,0" Name="tabControl1" VerticalAlignment="Top" Width="366">
<TabControl.Resources>
<Style TargetType="TabItem" x:Key="tab1ItemHeaderStyle">
<Setter Property="HeaderTemplate" >
<Setter.Value>
<DataTemplate DataType="{x:Type TabItem}">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Path=Header, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TabItem}}"/>
<Label Content="{Binding Path=UC1Figure, ElementName=uc1}"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
<TabItem Style="{StaticResource tab1ItemHeaderStyle}" Header="[Tab 1]" Name="tabItem1" Width="100">
<vw:UserControl1 x:Name="uc1"></vw:UserControl1>
</TabItem>
<TabControl>
</Grid>
UserControl1.xaml
<Grid>
<Label Height="43" HorizontalAlignment="Left" Margin="69,128,0,0" Name="textBlock1" Content="{Binding Path=UC1Figure, ElementName=uc}" VerticalAlignment="Top" Width="100" />
<Button Name="updateSomeFigure" Content="Press Me" Click="updateSomeFigure_Click" Width="100" Height="100" Margin="69,12,66,71" />
</Grid>
UserControl1.xaml.cs
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public static readonly DependencyProperty SomeFigureProperty =
DependencyProperty.Register("UC1Figure", typeof(int), typeof(UserControl1));
public int UC1Figure
{
get { return (int)this.GetValue(SomeFigureProperty); }
set { this.SetValue(SomeFigureProperty, value); }
}
private void updateSomeFigure_Click(object sender, RoutedEventArgs e)
{
UC1Figure = UC1Figure + 1;
}
}
If you want to data bind a property to the UI of your UserControl, you have two options. The first is to implement the INotifyPropertyChanged Interface in your code behind. The second is to define DependencyPropertys instead of regular CLR properties. You can find out how to do that in the Dependency Properties Overview page on MSDN.
You might also want to read the Data Binding Overviewā€ˇ page on MSDN before you start data Binding.
I have a Usercontrol with a ControlTemplate DependencyProperty (named MyItemTemplate).
public ControlTemplate MyContentControl
{
get { return (ControlTemplate)GetValue(MyContentControlProperty); }
set { SetValue(MyContentControlProperty, value); }
}
public static readonly DependencyProperty MyContentControlProperty =
DependencyProperty.Register("MyContentControl", typeof(ControlTemplate), typeof(MyScroll),
new PropertyMetadata(new ControlTemplate()));
In the xaml of my UserControl I want to use the "MyItemTemplate" as a template for a ContentControl like that :
<ContentControl x:Name="MyContentControl" Template="{Binding MyItemTemplate}" />
I know that the Template="{Binding MyItemTemplate}" is wrong, but I wonder how to do it...
Thanks
You can use a RelativeSource binding to reference a custom DependencyProperty on your UserControl
<ContentControl Template="{Binding
RelativeSource={RelativeSource AncestorType={x:Type local:MyUserControl}},
Path=MyItemTemplate}" />
Edit
If you're working in Silverlight 4.0 or lower, which doesn't support RelativeSource bindings, then give your UserControl tag a Name and use an ElementName binding
<UserControl x:Name="MyUserControl" ...>
<ContentControl Template="{Binding ElementName=MyUserControl, Path=MyItemTemplate}" />
</UserControl>
Have your template as a static resource (defined in your XAML somewhere).
<DataTemplate x:Key="DetailedTemplate">
<Border BorderBrush="Blue" Margin="3" Padding="3" BorderThickness="2" CornerRadius="5" Background="Beige">
<StackPanel Orientation="Horizontal">
<Image Margin="10" Width="250" Height="200" Stretch="Fill" Source="{Binding Path=ImageHref}">
<Image.BitmapEffect>
<DropShadowBitmapEffect />
</Image.BitmapEffect>
</Image>
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
<TextBlock FontSize="25" Foreground="Goldenrod" Text="{Binding Path=ImageName}" />
<Label Content="{Binding Path=ImageRating,Converter={StaticResource RatingConverter}}" />
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
<DataTemplate x:Key="SimpleTemplate">
<Border BorderBrush="Blue" Margin="3" Padding="3" BorderThickness="2" CornerRadius="5" Background="Beige">
<StackPanel HorizontalAlignment="Center">
<Image Margin="10" Width="250" Height="200" Stretch="Fill" Source="{Binding Path=ImageHref}">
<Image.BitmapEffect>
<DropShadowBitmapEffect />
</Image.BitmapEffect>
</Image>
</StackPanel>
</Border>
</DataTemplate>
For example, in XAML:
<ListBox x:Name="lbResults" Grid.Row="1" Grid.Column="0" Height="240"
HorizontalContentAlignment="Stretch" ItemsSource="{StaticResource FavoriteImages}"
ItemTemplate="{StaticResource SimpleTemplate}" />
Then in the code behind something like:
//pull the detailed template from resources, identified by the DetailedTemplate key
DataTemplate detail = this.FindResource("DetailedTemplate") as DataTemplate;
lbResults.ItemTemplate = detail;
and
//pull the summary template from resources, identified by the SimpleTemplate key
DataTemplate summary = this.FindResource("SimpleTemplate") as DataTemplate;
lbResults.ItemTemplate = summary;
Although the best answer is Rachel's, here are some alternatives.
If this logic is not critical, you'd better put the template into resources and get it using StaticResource:
<UserControl>
<UserControl.Resources>
<ControlTemplate x:Key="template">
...
</ControlTemplate>
</UserControl.Resources>
<ContentControl Template="{StaticResource template}"/>
</UserControl>
If you still need to set it from the UserControl's property, you may either define a change callback.
XAML:
<UserControl>
<ContentControl x:Name="contentControl"/>
</UserControl>
Code-behind:
public ControlTemplate MyContentControl
{
get { return (ControlTemplate)GetValue(MyContentControlProperty); }
set { SetValue(MyContentControlProperty, value); }
}
public static readonly DependencyProperty MyContentControlProperty =
DependencyProperty.Register("MyContentControl", typeof(ControlTemplate), typeof(MyScroll), new PropertyMetadata(null, OnMyContentControlChanged));
static void OnMyContentControlChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var userControl = (MyScroll)sender;
userControl.contentControl.Template = e.NewValue as ControlTemplate;
}
And the last option is using a Custom Control.
Code:
public class MyScroll : SomeParentControl
{
public MyScroll()
{
this.DefaultStyleKey = typeof(MyScroll);
}
public ControlTemplate MyContentControl
{
get { return (ControlTemplate)GetValue(MyContentControlProperty); }
set { SetValue(MyContentControlProperty, value); }
}
public static readonly DependencyProperty MyContentControlProperty =
DependencyProperty.Register("MyContentControl", typeof(ControlTemplate), typeof(MyScroll), new PropertyMetadata(null));
}
The template:
<!-- This is a template for what have been your UserControl -->
<ControlTemplate TargetType="{x:Type someNameSpaceAlias:MyScroll}">
<!-- And this is the 'MyContentControl' -->
<ContentControl Template="{TemplateBinding MyContentControl}"/>
</ControlTemplate>
Im having some problems with databinding inside a DataTemplate. In the ControlTemplate below the textbox in the Grid works and prints out the correct value. But the TextBlock inside the HyperlinkButtons DataTemplate does not work. Though the HyperlinkButtons NavigateUri is bound correctly. Could anyone plz help me with this
I have created a simple example that illustrates my problem.
MainPage.xaml
<UserControl x:Class="SilverlightApplication8.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="300" d:DesignWidth="400">
<UserControl.Resources>
<ControlTemplate x:Key="EventControlTemplate" TargetType="Button">
<Grid>
<!--WORKS-->
<!--<Grid >
<TextBlock x:Name="TitleTextBlock" Text="{Binding Title}" Foreground="Red" FontWeight="Bold" />
</Grid>-->
<!--DOES NOT WORK-->
<HyperlinkButton TargetName="_blank" NavigateUri="{Binding Url}" >
<HyperlinkButton.ContentTemplate>
<DataTemplate>
<Grid>
<TextBlock Foreground="Green" Text="{Binding Title}"/>
</Grid>
</DataTemplate>
</HyperlinkButton.ContentTemplate>
</HyperlinkButton>
</Grid>
</ControlTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<ItemsControl x:Name="Links" Foreground="White" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border >
<Button Template="{StaticResource EventControlTemplate}" Click="Button_Click"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>
MainPage.xaml.cs
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace SilverlightApplication8
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
List<Events> events = new List<Events>();
events.Add(new Events(){Title = "This is title 1", Url = "http://www.thesun.co.uk"});
events.Add(new Events(){Title = "This is title 2", Url = "http://www.thesun.co.uk"});
events.Add(new Events() { Title = "This is title 3", Url = "http://www.thesun.co.uk" });
Links.ItemsSource = events;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
}
}
public class Events
{
public string Url { get; set; }
public string Title { get; set; }
}
}
You're setting the ContentTemplate, the DataContext of which will be the Content of the HyperlinkButton. Since you haven't set the Content, you're attempting to bind against null.
This should work:
<HyperlinkButton TargetName="_blank" NavigateUri="{Binding Url}" Content="{Binding Title}">
<HyperlinkButton.ContentTemplate>
<DataTemplate>
<Grid>
<TextBlock Foreground="Green" Text="{Binding .}"/>
</Grid>
</DataTemplate>
</HyperlinkButton.ContentTemplate>
</HyperlinkButton>
But then that begs the question as to why you're even setting the ContentTemplate instead of just doing this:
<HyperlinkButton TargetName="_blank" NavigateUri="{Binding Url}" Content="{Binding Title}"/>
I have a ListBox whose ItemsSource is bound to a list of objects. The Listbox has a ItemTemplate with a DataTemplate containing a TextBlock. The textblock's Text is bound to the object's Name property (i.e. Text="{Binding Name}").
I would like to provide a radio button to show different views of the same list. For example allow a user to toggle between the Name property and an ID property.
I found a SO answer for this at 2381740 but I also have border and a textbox style set in data template (see code below).
Is there anyway to just reset the Textblock binding? I don't want to have to recreate the entire datatemplate. Actually I'm not even sure how to do that, is there an easy way to translating xaml to code?.
Thanks
Cody
<DataTemplate>
<Border Margin="0 0 2 2"
BorderBrush="Black"
BorderThickness="3"
CornerRadius="4"
Padding="3">
<TextBlock Style="{StaticResource listBoxItemStyle}"
Text="{Binding Name}" />
</Border>
</DataTemplate>
Wallstreet Programmer's solution works well for you because you are using radio buttons. However there is a more general solution that I thought I should mention for future readers of this question.
You can change your DataTemplate to use plain "{Binding}"
<DataTemplate x:Key="ItemDisplayTemplate">
<Border ...>
<TextBlock ...
Text="{Binding}" />
</Border>
</DataTemplate>
Then in code you don't have to recreate a full DataTemplate. All you have to do is recreate this:
<DataTemplate>
<ContentPresenter Content="{Binding Name}" ContentTemplate="{StaticResource ItemDisplayTemplate}" />
</DataTemplate>
which is easy:
private DataTemplate GeneratePropertyBoundTemplate(string property, string templateKey)
{
var template = FindResource(templateKey);
FrameworkElementFactory factory = new FrameworkElementFactory(typeof(ContentPresenter));
factory.SetValue(ContentPresenter.ContentTemplateProperty, template);
factory.SetBinding(ContentPresenter.ContentProperty, new Binding(property));
return new DataTemplate { VisualTree = factory };
}
This is particularly convenient if you have many properties, even in your radio button example.
Just make it simple for yourself and use two textblocks and hide one of them.
XAML:
<Window x:Class="Test.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<StackPanel>
<RadioButton Name="nameRadioBtn" Content="Name" IsChecked="True"/>
<RadioButton Name="lengthRadioBtn" Content="Length" />
<ListBox
ItemsSource="{Binding Path=Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Red" BorderThickness="1">
<Grid>
<TextBlock
Text="{Binding .}"
Visibility="{Binding Path=IsChecked, ElementName=nameRadioBtn,
Converter={StaticResource BooleanToVisibilityConverter}}" />
<TextBlock
Text="{Binding Path=Length}"
Visibility="{Binding Path=IsChecked, ElementName=lengthRadioBtn,
Converter={StaticResource BooleanToVisibilityConverter}}" />
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Window>
Code behind:
using System.Collections.Generic;
using System.Windows;
namespace Test
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
DataContext = this;
}
public IEnumerable<string> Items
{
get
{
return new List<string>() {"Bob", "Sally", "Anna"};
}
}
}
}
You can also use a value converter to pick any property of your data object. You will need to bind to the whole object instead of individual properties. If your data object implements INotifyPropertyChanged then this solution will not work for you.
XAML
<Window x:Class="Test.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Test="clr-namespace:Test"
Height="300" Width="300">
<Window.Resources>
<Test:PropertyPickerConverter x:Key="PropertyPickerConverter" />
</Window.Resources>
<StackPanel>
<RadioButton Content="Name" Click="OnRadioButtonClick" IsChecked="True"/>
<RadioButton Content="Length" Click="OnRadioButtonClick" />
<ListBox
ItemsSource="{Binding Path=Items}"
Name="_listBox">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Red" BorderThickness="1">
<StackPanel>
<TextBlock
Text="{Binding ., Converter={StaticResource PropertyPickerConverter}}" />
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Window>
code behind:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace Test
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
_propertyPickerConverter = FindResource("PropertyPickerConverter") as PropertyPickerConverter;
_propertyPickerConverter.PropertyName = "Name";
DataContext = this;
}
public IEnumerable<string> Items
{
get
{
return new List<string>() {"Bob", "Sally", "Anna"};
}
}
private void OnRadioButtonClick(object sender, RoutedEventArgs e)
{
_propertyPickerConverter.PropertyName = (sender as RadioButton).Content as string;
_listBox.Items.Refresh();
}
private PropertyPickerConverter _propertyPickerConverter;
}
public class PropertyPickerConverter : IValueConverter
{
public string PropertyName { get; set; }
#region IValueConverter Members
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string item = value as string;
switch (PropertyName)
{
case "Name": return item;
case "Length": return item.Length;
default: return null;
}
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotImplementedException();
}
#endregion
}
}