How to bind elements in separate xaml files? - c#

I have a MainWindow.xmal which has two TabItems:
<TabItem Header="Config" ... />
<TabItem Header="Results" ... />
I have a separated Config.xaml file for the Config TabItem which has a ListBox:
<ListBox Name="UrlConfig" ... />
I have another separated Results.xaml file for the Results TabItem which has a TaxtBlock:
<TextBlock Name="Url" .../>
The problem is that I'd like to bind the selected value in the ListBox to the TextBlock. How can I do that? Please help :)

I recomend you to work with MVVM, but if not you can implement it with XAML only:
Use sepparate resource like "Bridge" 'Config' and 'Results'
Config.xaml:
<UserControl x:Key="Config">
<ListBox x:Name="ListBox1" SelectedItem="{Binding Source={StaticResource SelectedValue}, Path=Y, Mode=TwoWay}" >
<System:String>Minsk</System:String>
<System:String>London</System:String>
<System:String>NY</System:String>
</ListBox>
</UserControl>
Results.xaml
<UserControl x:Key="Results">
<Label Name="Url" Content="{Binding Source={StaticResource SelectedValue}, Path=Y}" />
</UserControl>
Code of window with TabControl:
<Window.Resources>
<!--"Bridge" resource, here will be your own type-->
<X x:Key="SelectedValue" Y="Minsk"></X>
</Window.Resources>
<Grid>
<TabControl>
<TabItem Header="Config" Content="{StaticResource ResourceKey=Config}"/>
<TabItem Header="Results" Content="{StaticResource ResourceKey=Results}"/>
</TabControl>
</Grid>

If you're working in mvvm way you can bind those to a property on your viewmodel and set the DataContext for to that viewmodel

Related

How to update bindings when TabItem is selected? WPF

I had the following code
<mah:MetroWindow x:Class="NeoTec.SprayMachine.WPF.MainWindow"
namespaces bla bla>
<Window.Resources>
<DataTemplate DataType="{x:Type viewModels:CompanyDatabaseViewViewModel}">
<controls:CompanyDatabaseViewControl/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:UserDatabaseViewViewModel}">
<controls:UserDatabaseViewControl/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:ParametersViewModel}">
<controls:ParamatersControl/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:SettingsViewModel}">
<controls:SettingsControl/>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition/>
</Grid.RowDefinitions>
<controls:UpperPanelControl HorizontalAlignment="Center"/>
<ContentControl Grid.Row="1" Content="{Binding ShownViewModel}"/>
</Grid>
</mah:MetroWindow>
Where UpperPanelControl is a control with buttons that changes ShownViewModel in MainViewModel. For design purposes I decided to change this all to TabControl (there was a requirement from customer to have buttons):
<mah:MetroWindow x:Class="NeoTec.SprayMachine.WPF.MainWindow"
namespaces bla bla>
<TabControl>
<TabItem Header="Company Database">
<controls:CompanyDatabaseViewControl DataContext="{Binding CompanyDatabaseViewModel}"/>
</TabItem>
<TabItem Header="User Database">
<controls:UserDatabaseViewControl DataContext="{Binding UserDatabaseViewModel}"/>
</TabItem>
<TabItem Header="Parameters" IsSelected="{Binding ParametersTabSelected}">
<controls:ParamatersControl DataContext="{Binding ParametersViewModel}"/>
</TabItem>
<TabItem Header="Settings">
<controls:SettingsControl DataContext="{Binding SettingsViewModel}"/>
</TabItem>
<TabItem Header="Info">
<controls:InfoControl/>
</TabItem>
</TabControl>
</mah:MetroWindow>
It looks nicer, but the problem is when I switch tab the data in the tab is not updated. Are there any chance to get this working with TabControl with updating bindings, when tab is changed?
Each TabItem has an IsSelected property. You can bind that in your View Model and take the appropriate action.
<TabItem Header="Company Database" IsSelected="{Binding CompanyDataBaseTabIsSelected}">
<controls:CompanyDatabaseViewControl DataContext="{Binding CompanyDatabaseViewModel}"/>
</TabItem>
private bool _companyDatabaseTabIsSelected;
public bool CompanyDatabaseTabIsSelected
{
get { return _companyDatabaseTabIsSelected; }
set
{
_companyDatabaseTabIsSelected = value;
_companyDatabaseViewModel.Refresh();
}
}

How can one apply an itemtemplate to default TabItems?

I have the following TabControl with 2 default tabitems.
<TabControl>
<TabControl.ItemTemplate>
<DataTemplate>
<ScrollViewer VerticalScrollBarVisibility="Auto" Height="300" Content="{Binding}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabItem Header="Conexión"><local:ConnectionSettings/></TabItem>
<TabItem Header="Cuestionario"><local:QuestionEditor/></TabItem>
</TabControl>
The current xaml doesn't apply the ItemTemplate, for that to happen each tabitem would need to be "naked", like this:
<TabControl>
<TabControl.ItemTemplate>
<DataTemplate>
<ScrollViewer VerticalScrollBarVisibility="Auto" Height="300" Content="{Binding}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<!-- The ItemTemplate is only applied if tabitems are not wrapped in TabItem tags -->
<local:ConnectionSettings/>
<local:QuestionEditor/>
</TabControl>
But if I do that, then I can't specify the header.
I would like for every TabItem to be wrapped in a ScrollViewer (as specified in the ItemTemplate), but at the same be able to specify the header.
Is there a way to apply the ItemTemplate to <TabItem Header="MyHeader"/> tags?
ItemTemplate is the template to format the ItemsSource the headers on top of your tab control. ContentTemplate is the template to format the content of the tabs. To wrap your defined content to the scroll viewer, just make use of a new content control inside your template. Here is a minimal sample:
<TabControl>
<TabControl.ContentTemplate>
<DataTemplate>
<ScrollViewer>
<ContentControl Content="{TemplateBinding Property=ContentControl.Content}"/>
</ScrollViewer>
</DataTemplate>
</TabControl.ContentTemplate>
<TabItem>
<Button Content="Button1"/>
</TabItem>
<TabItem>
<Button Content="Button2"/>
</TabItem>
</TabControl>

Multiple controls with same bindings in single xaml

I have a xaml with a TabControl with two tabs. Each of the TabItems has a treeview which has exactly the same code. The bindings, VM etc are exactly same. They work of different data which is handled in my Model depending upon a property. So my VM and View do not need to worry about it.
Is there any way that I can write my treeview and the HierarchicalDataTemplate once and each tab refers instead of duplicating code in the same xaml?
Something like
<TabControl>
<TabItem Header="Tab1">
<Grid>
<!-- Refer to the tree view here -->
</Grid>
</TabItem>
<TabItem Header="Tab2">
<Grid>
<!-- Refer to the tree view here -->
</Grid>
</TabItem>
</TabControl>
But then How to write the treeview and HierarchicalDataTemplate and then refer them?
Define a DataTemplate that contains your TreeView layout and then use ContentPresenter or ContentControl to present it:
<Window.Resources>
<DataTemplate x:Key="TreeTemplate">
<Your TreeViewLayout ...>
</DataTemplate>
</Window.Resources>
...
<TabControl>
<TabItem Header="Tab1">
<ContentControl Content="{Binding}" ContentTemplate="{StaticResource TreeTemplate}" />
</TabItem>
<TabItem Header="Tab2">
<ContentControl Content="{Binding}" ContentTemplate="{StaticResource TreeTemplate}" />
</TabItem>
</TabControl>

Why would you use DataTemplate in a ListView?

could someone please explain to me what is the difference if I use
DataTemplate inside the ListView in XAML?
I have used ListView to display the content from my ObservableCollection without using DataTemplate and with DataTemplate it seems to look exactly the same?
Why then would I want to use Data Template? I would like to see a simple explanation/example.
DataTemplate is used to show data in ways beyond a simple text block. Sure doing this:
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
Doesn't buy you much. But it allows you to do stuff like this:
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding ImagePath}"/>
<TextBlock Text="{Caption}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
Which is pretty cool! You can put anything inside the template, so it makes ItemsControl (and its derivatives) some of the most powerful classes in WPF.
Please take a look at #HighCore's answer here WPF MVVM Why use ContentControl + DataTemplate Views rather than straight XAML Window Views?.
<Window x:Class="MyViews.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml
xmlns:viewmodel="clr-namespace:Project.ViewModel"
DataContext="{Binding Main, Source={StaticResource Locator}}"
Title="{Binding Title, Mode=TwoWay}" Height="{Binding Height, Mode=TwoWay}" Width="{Binding Width, Mode=TwoWay}" Left="{Binding Left, Mode=TwoWay}" Top="{Binding Top, Mode=TwoWay}" WindowStartupLocation="CenterScreen">
<Window.Resources>
<HierarchicalDataTemplate DataType="{x:Type viewmodel:OtherViewModel1}">
<ContentPresenter Content="{Binding Path=Text}" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type viewmodel:OtherViewModel2}">
<view:ConnectivityLED />
</DataTemplate>
</Window.Resources>
So you can see Mainwindow is talking to more than 1 viewmodel, Main is its own view model which is its datacontext and it also has reference to otherviewmodel1 and otherviewmodel2. Hope this helps, Cheers!

Show Open TabItem Names in a List View

I'm trying to display a list of open tab names in a listview or listbox (recommendations?).
Been going through the different type of binding options and I'm able to bind to a single tab name but it displays vertical instead of horizontal. Here is my XAML:
<ListView DockPanel.Dock="Left"
Height="352"
Name="listView1"
Width="132"
ItemsSource="{Binding ElementName=RulesTab, Path=Name}"
IsSynchronizedWithCurrentItem="True"
FlowDirection="LeftToRight"
HorizontalAlignment="Left"
HorizontalContentAlignment="Left"
DataContext="{Binding}">
Any pointers would be greatly appreciated as I'd like to be able to see a list of all the tabs open and then double click on one to bring the tab into focus. Many thanks!
Here is an example of a TabControl and a ListBox showing the names of the TabItems that are in it:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TabControl Grid.Column="0" Name="tabControl1">
<TabItem Header="Tab1"/>
<TabItem Header="Tab2"/>
<TabItem Header="Tab3"/>
<TabItem Header="Tab4"/>
</TabControl>
<ListBox Grid.Column="1" ItemsSource="{Binding Items, ElementName=tabControl1}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource {x:Type ListBoxItem}}">
<EventSetter Event="MouseDoubleClick" Handler="ListBoxItem_DoubleClick"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
and here's the code behind:
private void ListBoxItem_DoubleClick(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
var tabItem = (TabItem)((ListBoxItem)sender).Content;
tabControl1.SelectedItem = tabItem;
}
Edited to add double-click behavior.
Simplified example how to enumerate the tabs in a tab control with a listview:
<TabControl Name="MyTabControl">
<TabItem Header="Tab1">
</TabItem>
<TabItem Header="Tab2">
</TabItem>
</TabControl>
<ListView DockPanel.Dock="Left"
ItemsSource="{Binding ElementName=MyTabControl, Path=Items}"
DataContext="{Binding}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I'm still unsure as to what exactly you want, anyway, this can be adjusted if needed.
First of all if you bind to a specific item you will always have one item, you need to set ItemsSource to a collection.
Assuming you want to have the names or headers of all the tabs in your list you can set the tab control's Items as the ItemsSource and then apply a ItemTemplate, some example code:
<ListBox ItemsSource="{Binding ElementName=TabControlSrc, Path=Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}" Margin="5"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
If you do not use the ItemTemplate you'll get an error because the same item can only be a visual child of one parent.
Frankly this seems a bit pointless since it just reiterates your tabs, did i misunderstand something? If so please clarify further.
Edit: Oh lol, three almost identical answers...

Categories