I have a TabControl which is bound to a List of UserControls (MyControls)
<TabControl Background="{x:Null}" x:Name="MyView" ItemsSource="{Binding MyControls}" >
I want to bind the header of each tab item to a property(Title) in each UserControl. Which I did as below
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding Title}"/>
</Style>
</TabControl.ItemContainerStyle>
However since I override the ItemContainerStyle I lost all the default style for the application. My tab header looks different from other tab headers in the application
Is there any way to just bind to the Title without changing any style?
Define an ItemTemplate:
<TabControl Background="{x:Null}" x:Name="MyView" ItemsSource="{Binding MyControls}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}" />
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
MyControls shouldn't return an IEnumerable<UserControl> though. It should return an IEnumerable<YourObject> where YourObject is a POCO class with a Title property along with any other properties. You should then use DataTemplates to define the appearance of a YourObject.
Related
I want to create a Listbox from where it's possible to select elements with checkboxes. It gets the elements through data-binding from a database. The items appear in the Listbox, but when I send the form, the code-behind doesn't receive a SelectedItem value.
The XAML section for the listbox looks like this:
<Grid x:Name="grMozik" Visibility="Visible" Margin="0,0,0,0" DataContext="{Binding}" Grid.Row="3" Grid.ColumnSpan="2">
<ListBox Name="lbMozik" Margin="15" Width="300" Height="200" ItemsSource="{Binding}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Focusable" Value="False"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding MoziNeve}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
And for test purposes the code that would show the selected item looks like this:
string text = ((ListBoxItem)lbMozik.SelectedItem).Content.ToString();
MessageBox.Show(text2);
ListBox.SelectedItem comes from a ListBoxItem which has IsSelected property set to true. If you want to select by CheckBoxes, then bind each of them to owner ListBoxItem.IsSelected:
<CheckBox Content="{Binding MoziNeve}"
IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"/>
I am working on WPF application using MVVM. I have two page. I have multiple UserControls in a page 1, on selection of UserControls from page 1, I want to show that selected userControl in 2nd page. Below are my code.
ViewModel Code
public RelayCommand<string> OnClickSelectWidgetCommand => new RelayCommand<string>((setUserControlName) =>
{
using (new CursorWait())
{
var MyContentControl = setUserControlName;
MessageBox.Show(MyContentControl);
//How to render UserControl to View?
}
}, true);
Here in above code I get the UserControl name in setUserControlName variable. Now how to bind that UserControl to XAML page? Below are my code that I have tried.
View Code
<StackPanel Background="Black" VerticalAlignment="Top">
<Border Name="UserControl1BorderLow" BorderBrush="White" BorderThickness="0" >
<ItemsControl ItemsSource="{Binding LowCollection}" Margin="4,0" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel HorizontalAlignment="Left" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<controls:UserControlColumn1XL HorizontalAlignment="Left" Margin="2" />
<!--what can I do here in above line to make it dynamically render the userControl in place of UserControlColumn1XL-->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border></StackPanel>
Above code, In DataTemplate what need to be change to bind UserControls dynamically?
There are two ways to solve this, one involves setting the template based on your data type (DataTemplates) and the second involves setting it based on the data itself (DataTriggers).
In the first case your LowCollection should be an array of objects, or some base class that your view models are all derived from (ViewModel1, ViewModel2 etc). In this case you can get rid of your itemtemplate altogether and just add DataTemplates to specify how each of the items in your ItemsControl should be represented:
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type local:ViewModel1}">
<UserControl1 />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ViewModel2}">
<UserControl2 />
</DataTemplate>
... etc...
In the second case you need to set a template based on the value of some property in your view model. In this case you do need to set the ItemTemplate, and you give it a Style which uses data triggers to set an appropriate DataTemplate:
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding}">
<ContentPresenter.Style>
<Style TargetType="{x:Type ContentPresenter}">
<Style.Triggers>
<DataTrigger Binding="{Binding YourProperty}" Value="YourValue1">
<Setter Property="ContentTemplate" Value="{StaticResource YourDataTemplate1}" />
</DataTrigger>
<DataTrigger Binding="{Binding YourProperty}" Value="YourValue2">
<Setter Property="ContentTemplate" Value="{StaticResource YourDataTemplate2}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentPresenter.Style>
</ContentPresenter>
</DataTemplate>
</ItemsControl.ItemTemplate>
The relevant parts to note here are that there is a property in your view model called YourProperty which can have two values i.e. YourValue1 or YourValue2; the style above then selects either YourDataTemplate1 or YourDataTemplate2, depending on the value of YourProperty.
Basically I'm having two related problems:
1) The same problem as in this question How do I make an ItemsControl stretch to fill all availible space?, basically the ItemsControl doesn't fill in the whole space and the provided solution with DockedPanel doesn't work for me, because I need the items to stack vertically and not horizontally. Is there any other way to achieve this than using complex dynamic Grids?
2) There seems to be something off with the way DataGrid is presented when I'm using the method in this question WPF MVVM Multiple ContentControls in TabControl.
The headers are for some reason crushed to the side, also adding info to the table makes it look very bad. This wouldn't normally happen if I wasn't using this method of ItemsControl to display the table.
Code for TabControl:
<TabControl ItemsSource="{Binding Tabs}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Content}"/>
</ScrollViewer>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
Code for DataGrid that is in the UserControl (view.xaml) which is bound to the above TabControl:
<DataGrid Grid.Row="0" Margin="10 10 10 0" ItemsSource="{Binding List}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="ID">
<DataGridTemplateColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
</DataGridTemplateColumn.HeaderStyle>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label Content="{Binding Path=Id}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
//...
//Same for other columns
//...
</DataGrid>
Removing Header style does not help.
Remove the ScrollViewer element from your ContentTemplate. The DataGrid has its own ScrollViewer element built-in into its default ControlTemplate.
I actually found the answer and the accepted answer is correct (there's a workaround):
WPF ScrollViewer around DataGrid affects column width
As for my first question, I just sticked to UniformGrid and binded its row count to the ViewModel.
I have a TabControl that creates the TabItems from a ObservableCollection.
So in my ViewModel I already have a boolean Property IsMultiple and already gets set in code. So how do I hide the Tab header completely, but still display the content of that tab.
I have this:
<TabControl ItemsSource="{Binding myObservableCollection}"
ItemContainerStyle="{StaticResource myTabItemStyle}"
Style="{StaticResource myTabStyle}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding myTabHeaderTextProperty}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<DataTemplate>
</TabControl.ContentTemplate>
Basically I want to hide the itemtemplate, note that I cant just hide the TextBlock, because the style then still is there only with empty text. I want to remove/Hide the complete Tab header.
Set the Visibility property of the ItemContainerStyle to Collapsed:
<TabControl ItemsSource="{Binding myObservableCollection}">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Visibility" Value="Collapsed" />
</Style>
</TabControl.ItemContainerStyle>
<TabControl.ContentTemplate>
<DataTemplate>
<TextBlock>content...</TextBlock>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
I am binding a ObservableCollection of data objects to my tab control item source. I have correctly figured out how to bind the controls within the tabitem that is generated, however I cannot figure out how to change the header property of the tabitem that is generated using the a property within the Observable Collection. Sorry if I am wording this incorrectly. Here is my XAML for the tabitem data template:
<DataTemplate x:Key="TabItemTemplate">
<TreeView Height="461" VerticalAlignment="Top"
Width="625" ItemTemplateSelector="{StaticResource TreeviewDataSelector}" ItemsSource="{Binding}" />
</DataTemplate>
Create a Style for your TabItems that sets the Header property, and apply the style to TabControl.ItemContainerStyle
<TabControl>
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding PathToYourProperty}"/>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
Set the DisplayMemberPath on the TabControl to the name of the property.
<TabControl ItemsSource="{Binding items}" DisplayMemberPath="headerPropertyName">