I have 2 textbox, each in a different listview. First textbox is supposed to show data from a xml file. So when i click on the textbox, the data in the first textbox will show on the second textbox. I did this by doing a very big round about, getting the specific object when i click it and append to another listview. Is there a shorter way to do this through binding by element name in the xaml? My elementName in textbox1 will be the name for textbox2. I try doing it, but I am not sure what my path should be?
Sorry for not including my xaml.
<Window x:Class="GridViewTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
xmlns:local="clr-namespace:GridViewTest"
Title="MainWindow" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DesignHeight="541" d:DesignWidth="858" SizeToContent="WidthAndHeight">
<Window.Resources>
<local:PacketList x:Key="PacketList"/>
<local:BindableSelectionTextBox x:Key="BindableSelectionTextBox"/>
</Window.Resources>
<Grid Height="500" Width="798">
<Grid.RowDefinitions>
<RowDefinition Height="142*" />
<RowDefinition Height="145*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="234*" />
<ColumnDefinition Width="233*" />
</Grid.ColumnDefinitions>
<ListView ItemsSource="{Binding}" x:Name="lvItems" Grid.RowSpan="2" Grid.ColumnSpan="2">
<ListView.View>
<GridView AllowsColumnReorder="True">
<GridViewColumn Header="Header" Width="200">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBox Name ="A" Tag="Header" Text="{Binding SelectedText, Path=headerObj.headervalue}" PreviewMouseLeftButtonUp="Handle_Click"
IsReadOnly="True" BorderThickness="0" >
</TextBox>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<ListView Margin="0,245,0,8" Grid.ColumnSpan="2" Grid.RowSpan="2" >
<TextBox Name="headText" Text="{Binding SelectedText,ElementName=A}"/>
</ListView>
</Grid>
Firstly let us have some education on NameScoping in WPF. In WPF any Bindings within Templates are scoped to that Template only. Also any element named within a template wont be available for Binding.ElementName reference outside the template.
So in your case TextBox A cannot be referred by TextBox headText as textbox A is name-scoped under GridViewColumn.CellTemplate.
Also why is headText textbox under a ListView? ItemsControls like ListBox, ListView, DataGrid should not be used as panels or containers to host single elements. Their intention is to show multiple items. Use Panels or ContentControl instead.
<Grid Margin="0,245,0,8" Grid.ColumnSpan="2" Grid.RowSpan="2" >
<TextBox Name="headText" Text="{Binding SelectedText,ElementName=A}"/>
</Grid>
OR
<ContentControl Margin="0,245,0,8" Grid.ColumnSpan="2" Grid.RowSpan="2" >
<TextBox Name="headText" Text="{Binding SelectedText,ElementName=A}"/>
</ContentControl>
Now to synchronize selection between two textboxes use the following trick...
XAML
<TextBox Name="SelectionSource"
Tag="{Binding ElementName=SelectionTarget}"
SelectionChanged="SelectionSource_SelectionChanged" />
<TextBox Name="SelectionTarget"
Text="{Binding SelectedText, ElementName=SelectionSource,
Mode=TwoWay, UpdateSourceTrigger=Explicit}" />
Code Behind ...
private void SelectionSource_SelectionChanged(object sender, RoutedEventArgs e)
{
var targetTextBox = ((TextBox) sender).Tag as TextBox;
if (targetTextBox != null)
{
var bndExp
= BindingOperations.GetBindingExpression(
targetTextBox, TextBox.TextProperty);
if (bndExp != null)
{
bndExp.UpdateTarget();
}
}
}
If you are using MVVM then handle this SelectionSource_SelectionChanged event in attached behavior.
EDIT 2:
Now in case if one text box is part of ListBox template and other is outside the template then use content control hack...
XAML:
<Window.Resources>
<TextBox x:Key="SelectionTarget"
Text="{Binding Tag.SelectedText,
RelativeSource={RelativeSource Self},
Mode=TwoWay,
UpdateSourceTrigger=Explicit}" />
</Window.Resources>
<StackPanel>
<ListBox>
<ListBox.ItemsSource>
<x:Array Type="{x:Type System:String}">
<System:String>Test String 1</System:String>
<System:String>Test String 2</System:String>
<System:String>Test String 3</System:String>
</x:Array>
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Name="SelectionSource"
Text="{Binding Path=., Mode=TwoWay}"
Tag="{StaticResource SelectionTarget}"
SelectionChanged="SelectionSource_SelectionChanged" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ContentControl Content="{StaticResource SelectionTarget}">
</ContentControl>
</StackPanel>
Code Behind
private void SelectionSource_SelectionChanged(
object sender, RoutedEventArgs e)
{
var targetTextBox
= ((TextBox) sender).Tag as TextBox;
if (targetTextBox != null)
{
targetTextBox.Tag = (TextBox) sender;
var bndExp
= BindingOperations.GetBindingExpression(
targetTextBox, TextBox.TextProperty);
if (bndExp != null)
{
bndExp.UpdateTarget();
}
}
}
Hope this helps.
I'm not really sure what's going on with "SelectedText" you are trying to bind to, but if all you are trying to do is display the "lvItems" SelectedItem text in your "headText" TextBox the following should work
<TextBox Name="headText" Text="{Binding ElementName=lvItems, Path=SelectedItem.headerObj.headervalue}" />
You'll need to change your TextBox "A" binding as well.
<TextBox Name ="A" Tag="Header" Text="{Binding headerObj.headervalue}" IsReadOnly="True" BorderThickness="0" >
</TextBox>
Assuming that headerObj is a property of the Packet class, and headervalue is a property of that, and headervalue is the value you wish to bind to.
The text in "headText" will update when the SelectedItem is changed (not when the TextBox is clicked).
Related
I am having a hard time trying to figure out how to bind in xaml a nested Observable Collection. The PLC class contains Tags. This might be familiar if you work in Automation. I have marked the areas of code I am having trouble with by saying "!Can't Figure this out". I am new to xaml and trying to do the binding in the xaml. If it can't be done in the xaml, a code behind solution would be helpful.
PLC Class
public class PLC
{
public string Name { get; set; }
public ObservableCollection<Tag> Tags { get; set; }
public PLC(string name)
{
Name = name;
Tags = new ObservableCollection<Tag>();
}
public override string ToString()
{
return Name;
}
}
Tag Class The PLC's tags when you click on a PLC the ListView to the right will get the tags associated with that PLC.
public class Tag
{
public Tag(string name, int value)
{
Name = name;
Value = value;
}
public string Name { get; set; }
public int Value { get; set; }
}
xaml - note this is a user control binded to the parent's viewmodel.
<UserControl x:Class="Test.UserControls.RuntimeControl"
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="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<TextBlock Foreground="Red" Margin="10,0,0,0" >Runtime</TextBlock>
</Grid>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<ListView x:Name="PLCLV" Grid.Column="0" Margin="10" FontSize="25" SelectionMode="Single" ScrollViewer.VerticalScrollBarVisibility="Visible"
BorderThickness="0" ItemsSource="{Binding PLCs}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView Grid.Column="1" Margin="10" FontSize="25" AlternationCount="2" ScrollViewer.VerticalScrollBarVisibility="Visible"
BorderThickness="0 " ItemsSource=***!Can't Figure this out!***>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Focusable" Value="false"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text = "Name: "/>
<Run Text =***!Can't Figure this out!***
<Run Text ="Value: "/>
<Run Text =***!Can't Figure this out!***
</TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Grid>
</UserControl>
FIX in the UserControl xaml Answer Marked as accepted
<ListView Grid.Column="1" Margin="10" FontSize="25"
DataContext="{Binding SelectedItem, ElementName=PLCLV}"
ItemsSource="{Binding Tags}">
First: you set the ItemsSource by list of PLC on "PLCLV" named ListView , so the type of object in SelectedItem of this ListView must be PLC type (or null), you can make this SelectedItem be the source of Tag list.
<ListView Grid.Column="1" Margin="10" FontSize="25" AlternationCount="2" ScrollViewer.VerticalScrollBarVisibility="Visible"
BorderThickness="0 " ItemsSource="{Binding SelectedItem.Tags, ElementName=PLCLV}">
<!-- Or SelectedItem.(local:PLC.Tags), the "(local:PLC.Tags)" means "the speicified property of specified type on unspecified type boxed property" -->
<!-- you can use Binding.ElementName to find the sepcified "Name/x:Name" named element in visual tree to be the Binding source -->
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Focusable" Value="false"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<!-- "x:Type" is a speicial markup for return a specific "Type" object -->
<!-- Set DataType of DataTemplate can help XAML editor show IntelliSense to help you -->
<!-- "local:" is a prefix of namespace for the type in xml, defined by "xmlns:", here make the editor know the this DataTemplate is apply on the "Tag" type -->
<DataTemplate DataType="{x:Type local:Tag}">
<TextBlock>
<Run Text="Name: "/>
<Run Text="{Binding Name}" />
<Run Text="Value: "/>
<Run Text="{Binding Value}" />
</TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Or, use DataContext and ItemsSource:
<ListView Grid.Column="1" Margin="10" FontSize="25" AlternationCount="2" ScrollViewer.VerticalScrollBarVisibility="Visible"
BorderThickness="0"
DataContext="{Binding SelectedItem, ElementName=PLCLV}"
ItemsSource="{Binding Tags}">
<!-- Or ItemsSource="{Binding Path=(local:PLC.Tags)}" -->
...
Assuming the DataContext of the UserControl is set correctly (i.e. the binding of PLCs is correct)
Add this property in code behind under PLCs collection property (probably you will need it later in code behind)
private PLC _selectedPlc;
public PLC SelectedPlc
{
get => _selectedPlc;
set
{
_selectedPlc = value;
OnPropertyChanged(nameof(SelectedPlc)); // this will update the second ListView
}
}
public ObservableCollection PLCs {set; get;} // you have this already
The first ListView can see all PLCs.. Let's bind the DataContext of the second ListView with SelectedPlc property, this way, the second ListView will only see one PLC.
<ListView x:Name="PLCLV" Grid.Column="0" Margin="10" FontSize="25" SelectionMode="Single" ScrollViewer.VerticalScrollBarVisibility="Visible"
BorderThickness="0" ItemsSource="{Binding PLCs}"
SelectedItem="{Binding SelectedPlc}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Foreground="{Binding ForegroundColor}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView Grid.Column="1" Margin="10" FontSize="25" AlternationCount="2" ScrollViewer.VerticalScrollBarVisibility="Visible"
BorderThickness="0"
DataContext="{Binding SelectedPlc}"
ItemsSource="{Binding Tags}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Focusable" Value="false"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text= "Name: "/>
<Run Text="{Binding Name}"
<Run Text="Value: "/>
<Run Text="{Binding Value}"
</TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Do not forget to fill PLCs (and Tags inside each PLC) collections with some data!
Note: there is ForegroundColor property missing in your PLC class!
I want to create a simple window that would display different controls (SpinEdit or TextEdit) based on the view-model that is selected.
I have the code and logic behind it done already, what is left is displaying the control (SpinEdit or TextEdit) itself.
XAML:
<dx:DXWindow.Resources>
<DataTemplate x:Key="DataTemplate_Value">
<dxe:SpinEdit Height="23" MinWidth="200" Width="Auto"
Text="{Binding Path=Value, Mode=TwoWay}"
Mask="{Binding Mask, Mode=OneWay}"
MaxLength="{Binding Path=InputLength}" />
</DataTemplate>
<DataTemplate x:Key="DataTemplate_Text">
<dxe:TextEdit Height="23" MinWidth="200" Width="Auto"
Text="{Binding Path=Value, Mode=TwoWay}"
MaskType="RegEx" Mask="{Binding Mask, Mode=OneWay}"
MaxLength="{Binding Path=InputLength}"/>
</DataTemplate>
<local:PropertyDataTemplateSelector x:Key="templateSelector"
DataTemplate_Value="{StaticResource DataTemplate_Value}"
DataTemplate_Text="{StaticResource DataTemplate_Text}" />
</dx:DXWindow.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" >
<Label x:Uid="Label" MinHeight="24" MinWidth="60" Content="Value" />
<ContentControl ContentTemplateSelector="{StaticResource templateSelector}" />
</StackPanel>
<StackPanel Grid.Row="1" x:Uid="OKCancel_Buttons" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Bottom">
<Button Height="23" x:Name="OK_Button" Click="OK_Click" Content="OK" IsDefault="True" HorizontalAlignment="Right" MinWidth="95" />
<Button Height="23" x:Name="Cancel_Button" Click="Cancel_Click" Content="Cancel" HorizontalAlignment="Right" MinWidth="95" />
</StackPanel>
Where in the <ContentControl> I want to select which control will be displayed (SpinEdit for numbers and TextEdit for names/letters)
C#:
public class PropertyDataTemplateSelector : DataTemplateSelector
{
public DataTemplate DataTemplate_Value { get; set; }
public DataTemplate DataTemplate_Text { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var selector = item as TInputBaseVM;
if(selector is TInputValueVM)
return DataTemplate_Value;
return DataTemplate_Text;
}
}
Where I want to return a specific DataTemplate based on the view-model that is created in the c++/cli code.
C++/cli:
TInputValueVM ^oExchange_Value;
TInputTextVM ^oExchange_Text;
int inputFormat = A_Attributes.GetInputFormat();
if(inputFormat)
oExchange_Text = gcnew TInputTextVM(gcnew System::String(A_Attributes.GetTitle()), gcnew System::String(A_Attributes.GetMask()),
A_Attributes.GetInputLength(), gcnew System::String(A_Attributes.GetInitialText()));
else
oExchange_Value = gcnew TInputValueVM(gcnew System::String(A_Attributes.GetTitle()), gcnew System::String(A_Attributes.GetMask()),
A_Attributes.GetInputLength(), A_Attributes.GetInitialValue());
Dialogs::TSignalNumberPositionDialog^ dialog = gcnew Dialogs::TSignalNumberPositionDialog();
if(inputFormat)
dialog->DataContext = oExchange_Text;
else
dialog->DataContext = oExchange_Value;
dialog->ShowDialog();
The point is, the item value in the overriden selector function always has the null value and I have no idea how to bind it in XAML since all the examples I've managed to find so far are ListBoxes etc. There's no example on how to display different controls based on the view-model.
EDIT:
As suggested, I added Content property in the ContentControl and passed it an argument which is now the 'item' argument in the selector. Works just fine!
You do not need a DataTemplateSelector. WPF provides a mechanism that automatically selects a DataTemplate for the ContentTemplate of a ContentControl according to the type of a Content.
As explained in DataTemplate.DataType:
When you set this property to the data type without specifying an x:Key, the DataTemplate gets applied automatically to data objects of that type.
So drop the x:Key value and your DataTemplateSelector, set DataType
<dx:DXWindow.Resources>
<DataTemplate DataType="{x:Type local:TInputValueVM}">
<dxe:SpinEdit Height="23" MinWidth="200" Width="Auto"
Text="{Binding Path=Value, Mode=TwoWay}"
Mask="{Binding Mask, Mode=OneWay}"
MaxLength="{Binding Path=InputLength}" />
</DataTemplate>
<DataTemplate DataType="{x:Type local:TInputTextVM}">
<dxe:TextEdit Height="23" MinWidth="200" Width="Auto"
Text="{Binding Path=Value, Mode=TwoWay}"
MaskType="RegEx" Mask="{Binding Mask, Mode=OneWay}"
MaxLength="{Binding Path=InputLength}"/>
</DataTemplate>
</dx:DXWindow.Resources>
and bind the ContentControl's Content to a property that returns either a TInputValueVM or a TInputTextVM:
<ContentControl Content="{Binding InputVM}" />
The appropriate DataTemplate will now be selected automatically.
You have to add some value in the Content property of the ContentControl. That value will be passed to the SelectTemplate as the object item. You probably should bind to it some property in your ViewModel to be able to change that from there.
I'm trying to change the Visibility of elements inside a ListBoxItem by clicking on a CheckBox outside the ListBox which contains Items, but it doesn't seem to work.
It looks like the the binding doesn't work inside the ListBoxItems.
I'm using a template for my items
XAML
<UserControl.Resources>
<local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<DataTemplate x:Key="ShotTemplate">
<Grid x:Name="GridItem" Width="200">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox x:Name="ShotBox" Grid.Column="1" Text="{Binding Path=Description}" Visibility="{Binding EditMode, ElementName=EditMode, Converter={StaticResource BooleanToVisibilityConverter}}" />
<TextBlock x:Name="ShotBlock" Grid.Column="1" Text="{Binding Path=Description}" Visibility="{Binding EditMode, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=False }" />
</Grid>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ListBox Name="ShotList" ItemsSource="{Binding AllShotsCollection}" ItemTemplate="{StaticResource ShotTemplate}"/>
<CheckBox Name="EditMode" IsChecked="{Binding EditMode}" Content="Edit Mode" HorizontalAlignment="Left" Margin="12,30,0,0" VerticalAlignment="Top"/>
</Grid>
ViewModel
private bool _editMode = true;
public bool EditMode
{
get { return _editMode; }
set { _editMode = value; RaisePropertyChanged("EditMode"); }
}
How do I change ShotBox and ShotBlock Visibility by checking or unchecking the CheckBox. I know the converter works correctly, that's not the problem it must have something to do with the binding.
The ElementName binding scope is within the template only. I would define an attached property on the ListView (not the ListViewItem) and have the Checkbox toggle that property. Within the DataTemplate, you'll be able to use RelativeSource / FindAncestor binding to find the ListView.
This line of xaml code is not working. You are trying to bind to the view element and viewmodel prop. at the same time.
<TextBox x:Name="ShotBox" Grid.Column="1" Text="{Binding Path=Description}" Visibility="{Binding EditMode, ElementName=EditMode, Converter={StaticResource BooleanToVisibilityConverter}}" />
Remove this 'ElementName=EditMode' so that it would bind properly to the viewmodel property 'EditMode'.
OR if you want to bind to the view element only use
Visibility="{Binding Path=IsChecked, ElementName=EditMode, Converter={StaticResource BooleanToVisibilityConverter}}" />
I have a WPF application with a DataGrid (from WPF Toolkit) control. The ItemsSouce property is bound to an ObservableCollection in my ViewModel.
The data grid has a column with a TextBox in it:
<dg:DataGrid.Columns>
<dg:DataGridTemplateColumn Header="Name">
<dg:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding UserName}" Width="300"/>
</DataTemplate>
</dg:DataGridTemplateColumn.CellTemplate>
</dg:DataGridTemplateColumn>
...
I also have an "Add" button to create a new user. When I click this, a new row is created. I would like, however, for the above textbox to get the input focus (on the new row of course). I have looked at:
WPF MVVM Focus Field on Load
WPF-MVVM: Setting UI control focus from ViewModel
How to set focus to textbox using MVVM?
Set focus on textbox in WPF from view model (C#)
But all of them seem to rely on same variation of an "ElementName" binding and none look like they would work in an ItemsControl. What is the correct way to get this behavior?
One way I believe you can do this is to have a trigger on the textbox that handles on Loaded and have it set focus. Something like this
<dg:DataGridTemplateColumn Header="Name">
<dg:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" Text="{Binding UserName}" Width="300">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<local:SetFocusTrigger/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
</DataTemplate>
</dg:DataGridTemplateColumn.CellTemplate>
</dg:DataGridTemplateColumn>
And the SetFocusTrigger class is :-
public class SetFocusTrigger : TargetedTriggerAction<Control>
{
protected override void Invoke(object parameter)
{
if (Target == null) return;
Target.Focus();
}
}
Note I haven't tried this out.
I tried to do in pure XAML
<DataGrid CanUserAddRows="True"
ItemsSource="{Binding List}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Name">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"
Width="300" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding Name}"
FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}"
Width="300" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
I added two templates 1 for normal and other for edit mode. so once cell enter edit mode it will focus the text box.
if you always want the text box to be visible then it would have a different behavior as the new row is binded to placeholder and the value is text box will persist and move over to every new row but the real row.
ListView Solution (MVVM)
sample XAML
<StackPanel>
<Button Command="{Binding AddItem}"
Content="Add Item"/>
<ListView ItemsSource="{Binding List}"
Grid.IsSharedSizeScope="True">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="name" />
<!--other columns-->
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBox Text="{Binding Name}"
FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}" />
<TextBox Text="other column" Grid.Column="1"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
sample VM
public ViewModel()
{
AddItem = new SimpleCommand(i => List.Add(new Person()));
List = new ObservableCollection<object>(new[] { new Person() { Name = "a person"} });
}
public ObservableCollection<object> List { get; set; }
class Person
{
public string Name { get; set; }
}
public ICommand AddItem { get; set; }
so upon adding new item the new row will be created by means of adding a new Person to the List and will be displayed in view with the focus on the text box.
run the sample above and see the behavior, no code behind involved.
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...