Not getting a proper solution on how add a textblock to checkbox content property in XAML.
Issue is that checkbox content is not properly displayed for other languages.
So i need to add a textblock to it and apply texttrimming with "CharacterEllipsis".
Please help with a sample XAML code
I have the other properties defined for our custom checkbox:
<uxCCl:UxCheckBox x:Name="btnShowHide"
Height="24"
MaxWidth="200"
Margin="16,0,0,0"
HorizontalAlignment="Left"
Command="{Binding Path=ShowHideErrorOutCommand}"
Foreground="#638EAC"/>
So simply doing this won't work:
<Checkbox.Content>
<Textblock> <Text></Textblock>
</Checkbox.Content>
Please suggest some solution.
Simply add the TextBlock to the CheckBox content like so:
<CheckBox>
<CheckBox.Content>
<TextBlock Text="text block" TextTrimming="CharacterEllipsis"></TextBlock>
</CheckBox.Content>
</CheckBox>
EDIT:
Edit the custom CheckBox like I suggested above.
Add a Dependency Property to the custom CheckBox:
public string TextContent
{
get { return GetValue(TextContentProperty).ToString(); }
set { SetValue(TextContentProperty, value); }
}
public static readonly DependencyProperty TextContentProperty = DependencyProperty.Register(
"TextContent",
typeof(string),
typeof(YOURCLASSNAME),
new PropertyMetadata(string.Empty)
);
Add a Binding to the Text property of the TextBlock:
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Path=TextContent}"></TextBlock>
<CheckBox.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" TextTrimming="CharacterEllipsis"/>
</DataTemplate>
</CheckBox.ContentTemplate>
Related
I have a ContentControl where I am setting its content to a DataTemplate. I am setting the Tag value of the ContentControl. Is there a way to access this Tag Element in the Data Template and pass it as CommandParameter. In other words I am trying to pass the Tag as a parameter to the DataTemplate. Please help.
<DataTemplate x:Key="SensorStatusControlTemplate" x:DataType="viewModel:SensorBufferState">
<Grid>
<Rectangle x:Name="SensorRectangle"
Fill="{x:Bind Converter={StaticResource SensorStateOverflowConverter},
ConverterParameter={What do I say here to get the Tag}}"
Height="30"
Width="125" />
<TextBlock x:Name="SensorTextBlock"
Text="{x:Bind Converter={StaticResource SensorStateOverflowConverter}}"
FontSize="{StaticResource FontSizeMedium}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="White" />
</Grid>
</DataTemplate>
Here is my ControlTemplate. Is there a way to access the Tag in the DataTemplate?
<ContentControl Content="{Binding VmPRWControlData.OverflowSensorState,UpdateSourceTrigger=PropertyChanged}"
ContentTemplate="{StaticResource SensorStatusControlTemplate}"
Tag="Overflow"
HorizontalAlignment="Center"
Width="{Binding ElementName=LABLidSensorTextBlock,Path=ActualWidth}" />
Edit: I have tried doing like this but the parameter value is null,
ConverterParameter={Binding Tag, RelativeSource={RelativeSource Mode=TemplatedParent}}
You should traverse the tree to find the parent control using RelativeSource.AncestorType:
<DataTemplate DataType="{x:Type viewModel:SensorBufferState}">
<Button CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=Tag}"/>
</DataTemplate>
As you correctly mentioned UWP doesn't support RelativeSource.AncestorType.
The following solutions work with WPF too:
Solution 1
You can use Binding.ElementName instead
App.xaml
<DataTemplate x:Key="DataTemplate">
<Button CommandParameter="{Binding ElementName=ContentControl, Path=Tag}"/>
</DataTemplate>
MainPage.xaml
<ContentControl x:Name="ContentControl"
Tag="123"
ContentTemplate="{StaticResource DataTemplate}" />
Solution 2
Or alternatively use the DataContext set to a view model or a DependencyProperty instead of the Tag property:
App.xaml
<DataTemplate x:Key="DataTemplate">
<Button CommandParameter="{Binding CommandParameterValue}"/>
</DataTemplate>
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public static readonly DependencyProperty CommandParameterValueProperty = DependencyProperty.Register(
"CommandParameterValue",
typeof(string),
typeof(MainPage),
new PropertyMetadata(default(string)));
public string CommandParameterValue
{
get => (string) GetValue(MainPage.CommandParameterValueProperty);
set => SetValue(MainPage.CommandParameterValueProperty, value);
}
public MainPage()
{
this.InitializeComponent();
this.DataContext = this;
this.CommandParameterValue = "ABC";
}
}
MainPage.xaml
<ContentControl ContentTemplate="{StaticResource DataTemplate}" />
I have a WPF combobox which is populated from code-behind.
Code-behind (xaml.cs):
namespace WpfApplication1
{
private ObservableCollection<TransportType> transportTypes = new ObservableCollection<TransportType>();
transportTypes.Add(new TransportType() {Icon = Properties.Resources.Air, ValueMember = "A100", DisplayMember = "By Air" });
transportTypes.Add(new TransportType() {Icon = Properties.Resources.Maritime, ValueMember = "M200", DisplayMember = "Maritime" });
this.ComboBoxTransportTypes.ItemsSource = transportTypes;
}
TransportType class:
namespace WpfApplication1
{
public class TransportType
{
public Image Icon
{
get;
set;
}
public string DisplayMember
{
get;
set;
}
public string ValueMember
{
get;
set;
}
}
}
View:
<ComboBox x:Name="ComboBoxTransportTypes"
Grid.Column="1"
ItemsSource="{Binding}"
DisplayMemberPath="DisplayMember"
SelectedValuePath="ValueMember"
SelectionChanged="ComboBoxTransportTypes_SelectionChanged">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
Now I am trying to apply a ComboBox ItemTemplate and bound to the "transportTypes" collection. I would like each combobox item to be as below:
<ComboBoxItem>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding bind-icon-here}" />
<TextBlock Foreground="AliceBlue"
VerticalAlignment="Center"
Text="{Binding bind-DisplayMember-here}"/>
</StackPanel>
</ComboBoxItem>
So how can I create the above combobox item template bound to my collection in order to each item to be presented with an icon followed by a string?
I have tried below but it does not work. I also do not know how to bind each item in the collection to the image and textblock within stackpanel, I have done as below but only string is displayed and not icon.
<ComboBox x:Name="ComboBoxTransportTypes"
Grid.Column="1"
ItemsSource="{Binding}"
DisplayMemberPath="DisplayMember" <-- removed from here as I cannot define DisplayMemberPath and item template at the same time.
SelectedValuePath="ValueMember"
SelectionChanged="ComboBoxTransportTypes_SelectionChanged">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
<ComboBox.ItemTemplate>
<DataTemplate DataType="l:TransportType">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Icon}" />
<TextBlock Foreground="AliceBlue"
VerticalAlignment="Center"
Text="{Binding DisplayMember}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Also, in MVVM is it better to populate combobox from code-behind as I have done here or from view model constructor?
The problem is that you're setting the ItemSource in both the XAML and in the code behind. If you remove ItemSource="{Binding}" from the XAML then it should work.
If you are using MVVM, the collection should be populated in the view model, not in the code behind. There should be very little code in your code behind - only things related to the view should go there (such as displaying a child window).
The problem is that Image.Source takes an ImageSource not an Image. Change ...
<Image Source="{Binding Icon}" />
to...
<Frame Content="{Binding Icon}"/>
and things will start working.
you must use bottom syntax for custom template ComboBox
<TextBlock Text="{Binding Path=DisplayMember}"/>
or
<Image Source="{Binding Path=Icon}" />
in wpf list tags like combobox,listbox,... for custom tamplate like DataTemplate you must use Path
My main window has following portion of XAML
<StackPanel>
<TextBox x:Name="textbox1" />
<my:UserControl1 />
</StackPanel>
my:UserControl1 goes like this
<TextBox x:Name="userControlTextBox" />
I would like to bind the above textbox's Text property to Text property of the textbox outside.
I have tried
<TextBox x:Name="userControlTextBox" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=textbox1.Text}" />
You can't bind like you shown in the question. There are two ways to achieve that:
First, bind Text of textBox1 to some property in ViewModel. And bind Text of userControlTextBox to same bound property.
<TextBox x:Name="textbox1" Text="{Binding SomeProperty}"/>
and in UserControl
<TextBox x:Name="userControlTextBox" Text="{Binding SomeProperty}"/>
Make sure your property is notifiable (INPC should be implemented by containing class) so that any changes in it gets propagated to GUI.
Second would be to create custom DP on your userControl of type string. Bind that DP with Text value of textbox1. And bind Text of userControlTextBox to that DP.
<StackPanel>
<TextBox x:Name="textbox1" />
<my:UserControl1 TextValue="{Binding Text, ElementName=textBox1}"/>
</StackPanel>
Here, TextValue is custom DP declared in your userControl.
public string CustomValue
{
get { return (string)GetValue(CustomValueProperty); }
set { SetValue(CustomValueProperty, value); }
}
public static readonly DependencyProperty CustomValueProperty =
DependencyProperty.Register("CustomValue", typeof(string),
typeof(UserControl1));
Now, bind textBox in UserControl like this:
<TextBox x:Name="userControlTextBox"
Text="{Binding TextValue, RelativeSource={RelativeSource FindAncestor,
AncestorType=UserControl}}"/>
In my MVVM app I have a treeview representing records in a database. My views and viewmodels are linked in a resource dictionary like this
<DataTemplate DataType="{x:Type vm:TrialSiteViewModel}">
<vw:TrialSiteView />
</DataTemplate>
I want to display a preview of the view when a user hovers over an icon using the tooltip. My HierarchicalDataTemplate in the treeview is this
<HierarchicalDataTemplate DataType="{x:Type vm:TrialSiteViewModel}"
ItemsSource="{Binding Path=Children}">
...
<Button Style="{StaticResource previewButtonStyle}">
<Button.ToolTip>
<ToolTip Style="{x:Null}">
<ToolTip.ContentTemplate>
<DataTemplate>
<localtools:ObjectPreview
PreviewObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeViewItem}}, Path=DataContext}"
/>
</DataTemplate>
</ToolTip.ContentTemplate>
</ToolTip>
</Button.ToolTip>
</Button>
</StackPanel>
</HierarchicalDataTemplate>
This correctly picks up the TrialSiteViewModel that is the DataContext for the Treeviewitem.
ObjectPreview uses a viewbox and contentcontrol to display the view of the record
<Viewbox Grid.Row="1" Name="treeviewViewBox"
Stretch="Uniform"
IsEnabled="False">
<ContentControl Name="treeViewItemViewModel"
Content="{Binding PreviewObject}">
</ContentControl>
</Viewbox>
and the code behind contains the dependency property
public partial class ObjectPreview : UserControl
{
public ObjectPreview()
{
InitializeComponent();
}
public static readonly DependencyProperty _previewObjectProperty =
DependencyProperty.Register("PreviewObject", typeof(TreeViewItemViewModel), typeof(ObjectPreview));
public TreeViewItemViewModel PreviewObject
{
get { return (TreeViewItemViewModel)GetValue(_previewObjectProperty); }
set { SetValue(_previewObjectProperty, value); }
}
}
The problem I'm having is that the Template used to display the object is the same as that used in the treeview. This simply shows an icon and an object summary (ie. Primary Key and one or two key fields) rather than the entire template as defined in the view TrialSiteView. If I amend the code to use a button Command on the TrialSiteViewModel and inject it into ObjectPreview I can set the contentcontrol in the code behind and the TrialSiteView is used.
I'm guessing that somehow the Template is inferred from the TreeViewItem. Can anyone tell me how I can ensure the tooltip uses the TrialSiteView?
UPDATE
Ok, so I've fixed this but had to resort to code behind and removed the usercontrol and put the view directly in the tooltip. The key bit is getting the datatemplate from the resources. I'd tried to do this previously by assigning a key to the datatemplate, but either my code was flawed or it did not work. Anyhow, this works but is not the preferred Xaml solution.
private void PreviewObject_MouseEnter(object sender, MouseEventArgs e)
{
Image image = (Image)sender;
var key = new System.Windows.DataTemplateKey(image.DataContext.GetType());
var datatemplate = (DataTemplate)this.FindResource(key);
ToolTip tooltip = new ToolTip();
tooltip.Style = VisualUtils.GetResource<Style>("ControlTemplates.xaml", "toolTipWithContentStyle");
tooltip.MaxWidth = 460;
ContentControl contentcontrol = new ContentControl();
contentcontrol.ContentTemplate = datatemplate;
contentcontrol.Content = image.DataContext as TreeViewItemViewModel;
Viewbox viewbox = new Viewbox();
viewbox.Stretch = Stretch.Uniform;
viewbox.Child = contentcontrol;
tooltip.Content = viewbox;
image.ToolTip = tooltip;
}
What you need to do is to specify explicitly what data template to use. In order to do that just add a template property along with the PreviewObject property in the preview control:
public static readonly DependencyProperty _previewObjectTemplateProperty =
DependencyProperty.Register("PreviewObjectTemplate", typeof(DataTemplate), typeof(ObjectPreview));
public DataTemplate PreviewObjectTemplate
{
get { return (DataTemplate)GetValue(_previewObjectTemplateProperty); }
set { SetValue(_previewObjectTemplateProperty, value); }
}
Then, in the ObjectPreview.xaml add the ContentTemplate property that is bound to the PreviewObjectTemplate property:
<Viewbox Grid.Row="1" Name="treeviewViewBox"
Stretch="Uniform"
IsEnabled="False">
<ContentControl Name="treeViewItemViewModel"
Content="{Binding PreviewObject}"
ContentTemplate="{Binding PreviewObjectTemplate}" >
</ContentControl>
</Viewbox>
And finally, give a key to your data template and specify a reference to it explicitly when you declare ObjectPreview:
<DataTemplate x:Key="FullViewTemplate" DataType="{x:Type vm:TrialSiteViewModel}">
<vw:TrialSiteView />
</DataTemplate>
...
<ToolTip Style="{x:Null}">
<ToolTip.ContentTemplate>
<DataTemplate>
<localtools:ObjectPreview
PreviewObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeViewItem}}, Path=DataContext}"
PreviewObjectTemplate="{StaticResource FullViewTemplate}"
/>
</DataTemplate>
</ToolTip.ContentTemplate>
My google skills fail me. Anyone heard of a control like that for WPF. I am trying to make it look like this (winforms screenshot).
You can do this yourself by setting the DataTemplate of the combo box. This article shows you how - for a listbox, but the principle is the same.
Another article here is perhaps a better fit for what you are trying to do, simple set the first column of the item template to be a checkbox and bind it to a bool on your business object.
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected}"
Width="20" />
<TextBlock Text="{Binding DayOfWeek}"
Width="100" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
There is my combobox. I use Martin Harris code and code from this link Can a WPF ComboBox display alternative text when its selection is null?
<ComboBox Name="cbObjects" Grid.Column="1" Grid.Row="1" VerticalAlignment="Center" Margin="2,2,6,0" SelectionChanged="OnCbObjectsSelectionChanged" >
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected}" Width="20" VerticalAlignment="Center" Checked="OnCbObjectCheckBoxChecked" Unchecked="OnCbObjectCheckBoxChecked" />
<TextBlock Text="{Binding ObjectData}" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock IsHitTestVisible="False" Name="tbObjects" Text="Выберите объекты..." Grid.Column="1" Grid.Row="1" VerticalAlignment="Center" Margin="6,2,6,0" />
Small class for datasource:
public class SelectableObject <T> {
public bool IsSelected { get; set; }
public T ObjectData { get; set; }
public SelectableObject(T objectData) {
ObjectData = objectData;
}
public SelectableObject(T objectData, bool isSelected) {
IsSelected = isSelected;
ObjectData = objectData;
}
}
And there is two handler - one for handling CheckBox clicked and one for forming Text for ComboBox.
private void OnCbObjectCheckBoxChecked(object sender, RoutedEventArgs e) {
StringBuilder sb = new StringBuilder();
foreach (SelectableObject<tblObject> cbObject in cbObjects.Items)
{
if (cbObject.IsSelected)
sb.AppendFormat("{0}, ", cbObject.ObjectData.Description);
}
tbObjects.Text = sb.ToString().Trim().TrimEnd(',');
}
private void OnCbObjectsSelectionChanged(object sender, SelectionChangedEventArgs e) {
ComboBox comboBox = (ComboBox)sender;
comboBox.SelectedItem = null;
}
For ComboBox.ItemsSource I use
ObservableCollection<SelectableObject<tblObject>>
where tblObject is type of my object, a list of which I want to display in ComboBox.
I hope this code is useful to someone!
Give a try to CheckComboBox from Extended WPF Toolkit.
The main advantage for me is having two lists for binding:
all items available for selection
just selected items
I find this approach more practical. In addition you can specify value and display members of the collections you're binding.
If you don't want to bring a bunch of other controls with CheckComboBox, you can get the source code of it, it's pretty straightforward (need to bring Selector class as well).
ComboBox with Checkboxes
<ComboBox Height="16" Width="15">
<CheckBox Content="First Checkbox" />
<CheckBox Content="Second Checkbox" />
<CheckBox Content="Third Checkbox" />
<TextBlock Text="Some Text" />
</ComboBox>
The provided answers surprisingly didn't work for me, I tried many variations and kept getting error messages about the checkbox not being part of combobox and the data context seemed to be broken.
In the end I didn't have to do anything involving data templates or any code behind and my bindings are working fine (not shown in example)
I must say I'm happy with how easy this turned out to be after reading all the answers.