WPF TabStop / TabIndex in ItemsControl - wpf

I'm dynamically adding WPF ComboBox-es and I want to be able to select the added ComboBoxes with the 'TAB' key. (Dynamically generate TabIndex or something)
As it actually is:
What I want:
How would you do that?
This is the code:
<ItemsControl ItemsSource="{Binding}" Name="myItemsControl">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ComboBox Grid.Column="0" ItemsSource="{Binding Source={StaticResource SomeItems}}" IsSynchronizedWithCurrentItem="False" SelectedItem="{Binding Path=SomeValue, Mode=TwoWay}" DisplayMemberPath="Name" TabIndex="20"/>
<ComboBox Grid.Column="1" ItemsSource="{Binding Source={StaticResource SomeOtherItems}}" IsSynchronizedWithCurrentItem="False" SelectedItem="{Binding Path=SomeOtherValue, Mode=TwoWay}" DisplayMemberPath="Value" TabIndex="21"/>
<TextBox HorizontalContentAlignment="Stretch" Grid.Column="2" TabIndex="22" LostKeyboardFocus="TextBox_FormatAfterLostFocus">
<TextBox.Text>
<Binding Path="Wert" Mode="TwoWay" />
</TextBox.Text>
</TextBox>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Thanks in advance !

Here is a small example. I did this in Silverlight, so I guess you will have to modify it to work in WPF. It is not complete, but it is a starting point. You might want to use the Tag property on your controls to identify which of them need tab index fixing.
XAML:
<UserControl x:Class="SilverlightApplication6.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:DesignWidth="640"
d:DesignHeight="480">
<Grid x:Name="LayoutRoot">
<StackPanel>
<ItemsControl ItemsSource="{Binding}"
Name="myItemsControl">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ComboBox Grid.Column="0"
ItemsSource="{Binding Source={StaticResource SomeItems}}"
IsSynchronizedWithCurrentItem="False"
SelectedItem="{Binding Path=SomeValue, Mode=TwoWay}"
DisplayMemberPath="Name"
TabIndex="20" />
<ComboBox Grid.Column="1"
ItemsSource="{Binding Source={StaticResource SomeOtherItems}}"
IsSynchronizedWithCurrentItem="False"
SelectedItem="{Binding Path=SomeOtherValue, Mode=TwoWay}"
DisplayMemberPath="Value"
TabIndex="21" />
<TextBox HorizontalContentAlignment="Stretch"
Grid.Column="2"
TabIndex="22">
<TextBox.Text>
<Binding Path="Wert"
Mode="TwoWay" />
</TextBox.Text>
</TextBox>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="Fix Tab indexes" Click="Button_Click"
TabIndex="999"
></Button>
</StackPanel>
</Grid>
</UserControl>
And C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;
namespace SilverlightApplication6
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.DataContext = new List<int>() { 1, 2, 3, 4, 5 };
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var controls = new List<Control>();
GetChildrenOfSpecificType<Control>(this, ref controls, false);
var index = 1;
controls.ForEach(control =>
{
if (control is ComboBox || control is TextBox)
{
control.TabIndex = index;
index++;
}
});
}
private static void GetChildrenOfSpecificType<T>(DependencyObject parent, ref List<T> resultList, bool getSingle) where T : class
{
if (parent == null)
return;
else
{
int cnt = VisualTreeHelper.GetChildrenCount(parent);
if (cnt > 0)
{
for (int i = 0; i < cnt; i++)
{
var d = VisualTreeHelper.GetChild(parent, i);
if (d is T)
{
resultList.Add(d as T);
if (getSingle)
return;
}
GetChildrenOfSpecificType<T>(d, ref resultList, getSingle);
}
}
}
}
}
}

Related

commands in the child ViewModel not working after navigation in mvvm app

iam working on desktop wpf MVVM app contain one MainWindow containing content control that make navigation for diffrent UserControls .
commands of the MainViewModel in the MainWindow working well.
but commands of the navigated ViewModels not working.
the code of the app.cs:
navigationStore is the store for the navigated viewModels
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
NavigationStore navigationStore = new NavigationStore();
navigationStore.CurrentViewModel = new MainBackGroundVM();
MainWindow = new MainWindow()
{
///inistiation of the main with passing the CurrentViewModel to the mainVM
DataContext = new MainVM(navigationStore)
};
MainWindow.Show();
base.OnStartup(e);
}
}
the code of MainVM
NavigateUsersCommand working well and navigate for usersVM
class MainVM :Utilities.ViewModelBase
{
private readonly NavigationStore _navigationStore;
public ViewModelBase CurrentViewModel => _navigationStore.CurrentViewModel;
public ICommand NavigateUsersCommand { get; }
public MainVM(NavigationStore navigationStore)
{
_navigationStore = navigationStore;
_navigationStore.CurrentViewModelChanged += _navigationStore_CurrentViewModelChanged;
NavigateUsersCommand = new NavigateUsersCommand(navigationStore);
}
private void _navigationStore_CurrentViewModelChanged()
{
OnPropertyChanged(nameof(CurrentViewModel));
}
}
the code for MainWindow.xml
<Window x:Class="Yakout.MainWindow"
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:fa="http://schemas.fontawesome.io/icons/"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:Yakout.ViewModels"
xmlns:v="clr-namespace:Yakout.Views"
xmlns:local="clr-namespace:Yakout"
mc:Ignorable="d"
Title="MainWindow" Height="700" Width="1100" Background="Transparent" AllowsTransparency="True" WindowStartupLocation="CenterScreen" WindowStyle="None" ResizeMode="NoResize" >
<Window.DataContext>
<vm:NavigationVM></vm:NavigationVM>
</Window.DataContext>
<Border BorderThickness="2" BorderBrush="BlueViolet" Background="White">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="5*"/>
</Grid.RowDefinitions>
<Button Style="{StaticResource btnCircle}" Grid.Column="1" Click="Button_Click">
<StackPanel>
<fa:ImageAwesome Icon="Close" Grid.Column="1" Style="{StaticResource close}"/>
</StackPanel >
</Button>
<Border Grid.Row="1" Background="BlueViolet" >
<StackPanel >
<Button Style="{StaticResource btnMainMenu}" Name="btnPOS"
Command="{Binding NavigatePosCommand}">
<StackPanel Style="{StaticResource stack}" Orientation="Horizontal">
<fa:ImageAwesome Icon="ShoppingCart" Style="{StaticResource faMainMenu}" Margin="40 0 0 0"/>
<TextBlock Text="Point Of Sale" Style="{StaticResource tbMainMenu}" Margin="30 10 0 0"/>
</StackPanel>
</Button>
<Button Style="{StaticResource btnMainMenu}" Name="btnSetUp" Command="{Binding NavigateUsersCommand}">
<StackPanel Style="{StaticResource stack}" Orientation="Horizontal" >
<fa:ImageAwesome Icon="Key" Style="{StaticResource faMainMenu}"/>
<TextBlock Text="Set Up" Style="{StaticResource tbMainMenu}"/>
</StackPanel>
</Button>
<Button Style="{StaticResource btnMainMenu}" Name="btnReports"
Command="{Binding NavigateUsersSelectCommand}">
<StackPanel Style="{StaticResource stack}" Orientation="Horizontal">
<fa:ImageAwesome Icon="PencilSquare" Style="{StaticResource faMainMenu}"/>
<TextBlock Text="Reports" Style="{StaticResource tbMainMenu}"/>
</StackPanel>
</Button>
<Button Style="{StaticResource btnMainMenu}" Name="btnOptions"
Command="{Binding NavigateMainBackGroundCommand}" >
<StackPanel Style="{StaticResource stack}" Orientation="Horizontal">
<fa:ImageAwesome Icon="HandPaperOutline" Style="{StaticResource faMainMenu}"/>
<TextBlock Text="Options" Style="{StaticResource tbMainMenu}"/>
</StackPanel>
</Button>
<Button Name="btnLogOut" Style="{StaticResource btnMainMenu}" Margin="5 212 5 0" Click="btnLogOut_Click">
<StackPanel Style="{StaticResource stack}" Orientation="Horizontal">
<fa:ImageAwesome Icon="CircleOutlineNotch" Style="{StaticResource faMainMenu}"/>
<TextBlock Text="Log Out" Style="{StaticResource tbMainMenu}"/>
</StackPanel>
</Button>
</StackPanel>
</Border>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Source="/image/R.png"/>
<StackPanel Orientation="Vertical" Grid.Column="1">
<TextBlock Text="Yakout POS" Margin="5 10 5 5" FontSize="25" FontWeight="Bold" HorizontalAlignment="Center"/>
<TextBlock Text="1.0.0.1" FontSize="15" FontWeight="Bold" HorizontalAlignment="Center"/>
<TextBlock Text="Yakout Company" FontSize="15" Foreground="DodgerBlue" FontWeight="Bold" HorizontalAlignment="Center" TextDecorations="Underline"/>
</StackPanel>
</Grid>
<Border Grid.Column="1" Background="BlueViolet">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Canvas>
<Label x:Name="lbl" FontSize="15" Foreground="White" Canvas.Top="10" Canvas.Right="20" Content="{Binding MyTimer}"/>
<TextBlock Text="Point Of Sale" Canvas.Left="250" FontSize="30" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0 25 0 0"/>
<Ellipse Width="40" Height="40" Fill="DarkViolet" Canvas.Left="150" Canvas.Top="20" StrokeThickness="10"/>
<Ellipse Width="40" Height="40" Fill="DarkViolet" Canvas.Right="230" Canvas.Top="20" StrokeThickness="10"/>
</Canvas>
</Grid>
</Border>
<Rectangle Stroke="BlueViolet" StrokeThickness="3" Grid.Column="0" Grid.Row="0"/>
<ContentControl Content="{Binding CurrentViewModel}" Grid.Row="1" Grid.Column="1" >
</ContentControl>
<!--CurrentView-->
</Grid>
</Border>
the code of the navigated ViewModel , its name UsersVM
the NavigateUsersSelectCommand navigate to new View
and NavigateMainBackGroundCommand navigate back to MainBackGroundView
both commands not working
class UsersVM : Utilities.ViewModelBase
{
public ICommand NavigateUsersSelectCommand { get; }
public ICommand NavigateMainBackGroundCommand { get; }
public UsersVM(NavigationStore navigationStore,SelectedUserStore selectedUserStore)
{
_navigationStore = navigationStore;
NavigateMainBackGroundCommand = new NavigateCommand<MainBackGroundVM>(new NavigationService<MainBackGroundVM>(navigationStore, () => new MainBackGroundVM()));
NavigateUsersSelectCommand = new NavigateCommand<UserSelectVM>(new NavigationService<UserSelectVM>(navigationStore, () => new UserSelectVM(_navigationStore)));
}
}
the xaml code for the usersView
<UserControl x:Class="Yakout.Views.Users"
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"
xmlns:fa="http://schemas.fontawesome.io/icons/"
xmlns:local="clr-namespace:Yakout.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" Style="{StaticResource user}"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.NavigateUsersSelectCommand}">-->
<StackPanel Orientation="Horizontal">
<Button x:Name="select" Style="{StaticResource btnUsers}"
Command="{Binding NavigateUsersSelectCommand}">
<StackPanel>
<fa:ImageAwesome Icon="HandPointerOutline" Style="{StaticResource fa}"/>
<TextBlock Text="Select" Style="{StaticResource btnText}"/>
</StackPanel>
</Button>
<Button x:Name="new" Style="{StaticResource btnUsers}" Click="new_Click">
<StackPanel>
<fa:ImageAwesome Icon="NewspaperOutline" Style="{StaticResource fa}"/>
<TextBlock Text="New" Style="{StaticResource btnText}"/>
</StackPanel>
</Button>
<Button x:Name="save" Style="{StaticResource btnUsers}" Click="save_Click">
<StackPanel>
<fa:ImageAwesome Icon="Save" Style="{StaticResource fa}"/>
<TextBlock Text="Save" Style="{StaticResource btnText}"/>
</StackPanel>
</Button>
<Button x:Name="first" Style="{StaticResource btnUsers}" Click="first_Click">
<StackPanel>
<fa:ImageAwesome Icon="FastBackward" Style="{StaticResource fa}"/>
<TextBlock Text="First" Style="{StaticResource btnText}"/>
</StackPanel>
</Button>
<Button x:Name="back" Style="{StaticResource btnUsers}" Click="back_Click">
<StackPanel>
<fa:ImageAwesome Icon="Backward" Style="{StaticResource fa}"/>
<TextBlock Text="Back" Style="{StaticResource btnText}"/>
</StackPanel>
</Button>
<Button x:Name="next" Style="{StaticResource btnUsers}" Click="next_Click">
<StackPanel>
<fa:ImageAwesome Icon="Forward" Style="{StaticResource fa}"/>
<TextBlock Text="Next" Style="{StaticResource btnText}"/>
</StackPanel>
</Button>
<Button x:Name="last" Style="{StaticResource btnUsers}" Click="last_Click">
<StackPanel>
<fa:ImageAwesome Icon="FastForward" Style="{StaticResource fa}"/>
<TextBlock Text="Last" Style="{StaticResource btnText}"/>
</StackPanel>
</Button>
</StackPanel>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<StackPanel>
<Label Content="User Name" Style="{StaticResource labelUsers}"/>
<Label Content="Password" Style="{StaticResource labelUsers}"/>
<Label Content="Full Name" Style="{StaticResource labelUsers}"/>
<Label Content="Job Des" Style="{StaticResource labelUsers}"/>
<Label Content="Email" Style="{StaticResource labelUsers}"/>
<Label Content="Phone" Style="{StaticResource labelUsers}"/>
</StackPanel>
<StackPanel Grid.Column="1">
<TextBox Name="tx1" Style="{StaticResource box}" Text="{Binding Path=UserName,Mode=OneWay}"/>
<TextBox Name="tx2" Style="{StaticResource box}" Text="{Binding Path=Password,Mode=OneWay}"/>
<TextBox Name="tx3" Style="{StaticResource box}" Text="{Binding Path=FullName,Mode=OneWay }"/>
<TextBox Name="tx4" Style="{StaticResource box}" Text="{Binding Path=JobDes,Mode=OneWay}"/>
<TextBox Name="tx5" Style="{StaticResource box}" Text="{Binding Path=Email,Mode=OneWay }"/>
<TextBox Name="tx6" Style="{StaticResource box}" Text="{Binding Path=Phone,Mode=OneWay }"/>
</StackPanel>
<Canvas Grid.Column="2">
<Button x:Name="btnBack" Style="{StaticResource btnPages}"
Canvas.Right="5" Canvas.Bottom="5"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.NavigateMainBackGroundCommand}">
<StackPanel>
<fa:ImageAwesome Icon="Backward" Style="{StaticResource faPagesBack}"/>
<TextBlock Text="Back" Style="{StaticResource tbPagesBack}"/>
</StackPanel>
</Button>
</Canvas>
</Grid>
</Grid>
the xaml code for the mainBackGroundView
<UserControl x:Class="Yakout.Views.MainBackGround"
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"
xmlns:local="clr-namespace:Yakout.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Image Source="/image/kkk.jpg" Stretch="Fill"/>
</Grid>
data template for the app
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:Yakout.ViewModels"
xmlns:view="clr-namespace:Yakout.Views">
<DataTemplate DataType="{x:Type vm:OptionsVM}">
<view:Options/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:MainBackGroundVM}">
<view:MainBackGround/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:SetUpVM}">
<view:SetUP/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:PosVM}">
<view:Pos/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ReportsVM}">
<view:Reports/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:UsersVM}">
<view:Users/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:UserSelectVM}">
<view:UserSelect/>
</DataTemplate>
code for the app.xml
<Application x:Class="Yakout.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Yakout"
>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/StylesMainWindow.xaml" />
<ResourceDictionary Source="Styles/StylesMain.xaml" />
<ResourceDictionary Source="Styles/StylesUcOptions.xaml" />
<ResourceDictionary Source="/Utilities/DataTemplate.xaml"/>
<ResourceDictionary Source="/Styles/StylesUsers.xaml"/>
<ResourceDictionary Source="/Styles/StylesUserSelect.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
NavigationService
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yakout.Stores;
namespace Yakout.Utilities
{
class NavigationService<TViewModel>
where TViewModel:ViewModelBase
{
private readonly NavigationStore _navigationStore;
private readonly Func<TViewModel> _CreateViewModel;
public NavigationService(NavigationStore navigationStore,Func<TViewModel>CreateViewModel)
{
_navigationStore = navigationStore;
_CreateViewModel = CreateViewModel;
}
public void Navigate()
{
_navigationStore.CurrentViewModel = _CreateViewModel();
}
}
}
ParameterNavigationService
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yakout.Stores;
namespace Yakout.Utilities
{
class ParameterNavigationService<TParameter, TViewModel>
where TViewModel:ViewModelBase
{
private readonly NavigationStore _navigationStore;
private readonly Func<TParameter,TViewModel> _createVM;
public ParameterNavigationService(NavigationStore navigationStore, Func<TParameter, TViewModel> createVM)
{
_navigationStore = navigationStore;
_createVM= createVM;
}
public void Navigate(TParameter parameter)
{
_navigationStore.CurrentViewModel = _createVM(parameter);
}
}
}
NavigateMainBackGroundCommand
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Navigation;
using Yakout.Stores;
using Yakout.Utilities;
using Yakout.ViewModels;
namespace Yakout.Commands
{
class NavigateMainBackGroundCommand : Utilities.CommandBase
{
/// <summary>
/// حاليا مفيش احتياج لاوامر دي
/// </summary>
private readonly NavigationService<MainBackGroundVM> _navigationService;
private readonly MainBackGroundVM _mainBackGroundVM;
public NavigateMainBackGroundCommand(MainBackGroundVM mainBackGroundVM, NavigationService<MainBackGroundVM> navigationService)
{
_navigationService = navigationService;
_mainBackGroundVM = mainBackGroundVM;
}
public override void Execute(object parameter)
{
_navigationService.Navigate();
}
}
}
NavigateUsersCommand
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using Yakout.Stores;
using Yakout.ViewModels;
namespace Yakout.Commands
{
class NavigateUsersCommand : Utilities.CommandBase
{
private readonly NavigationStore _navigationStore;
private readonly SelectedUserStore _selectedUserStore;
public NavigateUsersCommand(NavigationStore navigationStore, SelectedUserStore selectedUserStore)
{
_navigationStore = navigationStore;
_selectedUserStore = selectedUserStore;
}
public override void Execute(object parameter)
{
_navigationStore.CurrentViewModel = new UsersVM(_navigationStore,_selectedUserStore);
}
}
}
this is my code on GitHub
github.com/amryakout1990/Yakout.git
i want solution for my problem
Looking at one of these commands you have in your view:
<Button x:Name="select" Style="{StaticResource btnUsers}"
Command="{Binding NavigateUsersSelectCommand}">
In the viewmodel:
NavigateUsersSelectCommand = new NavigateCommand<UserSelectVM>(new NavigationService<UserSelectVM>(navigationStore, () => new UserSelectVM(_navigationStore)));
That expects a command parameter of UserSelectVM type.
You are not passing that because you define no commandparameter in xaml.
Does it even bind? I would have thought there'd be an error in your xaml errors window in vs2022 or the output window.
I guess this is the selected user you want so you could make the commandparameter selecteditem or you could bind selecteditem and reference it in the aonymous method you have there.
But that is why that command does not work.
I didn't look at other commands because there's quite a lot of code to look through. I suggest you fix that one first and see if you have a similar issue repeated.

how to update listitem(observableObject) in Listview(observerableCollection) in WPF

I have a collection of instruments, and I'd like to configure each of them after I add them to a list
Currently this instrument is defined as a class inherited from ObservableObject, and stored in an ObservableCollection, shown as a Listview with a datatemplate of instrument details.
Now I can add/delete an instrument. but when I try to update instrument details(e.g. names, type). it is not update to instrument class property.
I'm using CommunityToolkit.Mvvm, I tested that it will work if I just put an instrument details in textbox as the direct element in the mainwindow, but not work as listviewitem.
So does it mean that I can't put observableObject under another observableObject/ObserverbaleCollection?
<ListView x:Name="ListView_Instr"
ItemsSource="{Binding InstrumentConfigs, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectInstrumentConfig, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Padding="5,5,5,5" Grid.Row="0">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Width="{Binding Width, ElementName=ListView_Instr}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<CheckBox x:Name="CheckBox_InstrChecked" Grid.Column="0"/>
<StackPanel Orientation="Horizontal" Grid.Column="1">
<Label Content="Type"/>
<ComboBox x:Name="ComboBox_InstrType" ItemsSource="{Binding InstrTypes, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Column="2">
<Label Content="Name"/>
<TextBox x:Name="TextBox_InstrName" Text="{Binding InstrName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Column="3">
<Label Content="Addr"/>
<TextBox x:Name="TextBox_InstrAddr" Text="{Binding InstrAddr, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Column="4">
<Label Content="Interface"/>
<ComboBox x:Name="ComboBox_InstrInterface" ItemsSource="{Binding InstrInterfaceTypes, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Any detail I missed when using Observable?
Thanks
The following way should work.
Instrument.cs
using CommunityToolkit.Mvvm.ComponentModel;
namespace wpf_binding
{
[INotifyPropertyChanged]
public partial class Instrument
{
[ObservableProperty]
private string name;
[ObservableProperty]
private string description;
partial void OnNameChanged(string value)
{
System.Console.WriteLine($"Name changed: {Name}");
}
partial void OnDescriptionChanged(string value)
{
System.Console.WriteLine($"Description changed: {Description}");
}
}
}
ViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel;
using System.Collections.ObjectModel;
namespace wpf_binding
{
[INotifyPropertyChanged]
public partial class ViewModel
{
[ObservableProperty]
private ObservableCollection<Instrument> instruments;
[ObservableProperty]
private Instrument selectedItem;
public ViewModel()
{
Instruments = new ObservableCollection<Instrument>()
{
new Instrument() { Name = "Item 1", Description = "Desc 1" },
new Instrument() { Name = "Item 2", Description = "Desc 2" }
};
}
}
}
MainWindow.xaml
<Window x:Class="wpf_binding.MainWindow"
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"
xmlns:local="clr-namespace:wpf_binding"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<StackPanel Orientation="Vertical">
<ListView ItemsSource="{Binding Instruments}" SelectedItem="{Binding SelectedItem}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Name, Mode=TwoWay}"/>
<TextBox Text="{Binding Description, Mode=TwoWay}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name:"/>
<TextBlock Text="{Binding SelectedItem.Name}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Description:"/>
<TextBlock Text="{Binding SelectedItem.Description}"/>
</StackPanel>
</StackPanel>
</StackPanel>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace wpf_binding
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
}

How can I change the TextBox's width with the text Length?

I want to remake one kind of game from those typing games, where the words are coming from somewhere and you have to write down that word correctly.
Here is one: https://www.youtube.com/watch?v=FqNTKJRBPdc
My first problem is that I don't find nothing, how could I change dynamically the TextBox's width.
So if the whole word won't fit in the TextBox, I want to increase the TextBox's width. How could I do it?
Here is my View:
<UserControl x:Class="Prog_korny.View.GameView"
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"
xmlns:local="clr-namespace:Prog_korny"
xmlns:vm="clr-namespace:Prog_korny.ViewModel"
mc:Ignorable="d"
d:DesignHeight="720" d:DesignWidth="1280" Name="alUO">
<UserControl.Resources>
<vm:GameViewModel x:Key="GameViewModel"/>
</UserControl.Resources>
<Grid DataContext="{Binding Source={StaticResource GameViewModel}}">
<Grid.Background>
<ImageBrush ImageSource="/Prog korny;component/Pictures/background.png"/>
</Grid.Background>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="5*" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="7*" />
<RowDefinition Height="1*" />
<RowDefinition Height="6*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Canvas Grid.ColumnSpan="5" Grid.RowSpan="4"></Canvas>
<TextBox x:Name="txtText" Grid.Column="2" Grid.Row="1" Grid.ColumnSpan="1" Background="Transparent" Foreground="White" BorderBrush="Blue" FontFamily="Bebas Neue" FontSize="35" TextAlignment="Center" VerticalAlignment="Center" Cursor="Hand">
<TextBox.Text>
<Binding Path="textContent" UpdateSourceTrigger="PropertyChanged"/>
</TextBox.Text>
</TextBox>
<Label x:Name="lblLevel" Grid.Column="0" Grid.Row="4" Grid.ColumnSpan="1" Foreground="White" BorderBrush="{x:Null}" FontFamily="Bebas Neue" FontSize="30" Cursor="Hand">
<Label.Content>
<Binding Path="LevelLabel" UpdateSourceTrigger="PropertyChanged"/>
</Label.Content>
</Label>
<Label x:Name="lblScore" Grid.Column="4" Grid.Row="4" Grid.ColumnSpan="1" Foreground="White" BorderBrush="{x:Null}" FontFamily="Bebas Neue" FontSize="30" Cursor="Hand">
<Label.Content>
<Binding Path="ScoreLabel" UpdateSourceTrigger="PropertyChanged"/>
</Label.Content>
</Label>
</Grid>
</UserControl>
ViewModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Prog_korny.ViewModel
{
class GameViewModel : ViewModelBase
{
private string _textContent;
public string TextContent
{
get { return _textContent; }
set { _textContent = value; }
}
private string _levelLabel = "Level: 0";
public string LevelLabel
{
get { return _levelLabel; }
set { _levelLabel = value; }
}
private string _scoreLabel = "Score: 0";
public string ScoreLabel
{
get { return _scoreLabel; }
set { _scoreLabel = value; }
}
}
}
you can define a property which you will bind with the width property in xaml page.
You can control the property from viewmodel based on your given condition.
You can control almost everything which is available to you in your window xaml page.Plus you can define conditional logic based on pairing of two properties.
like if your TextContent property reaches certain limit then set text width property to something.
With low level of control you can achieve controlling width via data triggers.
<Style>
<Setter Property="Width" Value="200"/>
<Style.Triggers>
<<Put your conditions which will set the value>>
</Style.Triggers>
</Style>

Why does the ExtentWidth stay at 10.003?

So I have a ListBox that has a DataTemplate which has a Grid which has a RichTextBox.
For some reason when you type into the RichTextBox it puts each character on a separate line. Digging into this, I find out that the ExtentWidth is equal to 10.003. Why? I have no idea. I was hoping someone could explain to me why and give a nice solution to make it stop doing this.
I did notice that if you set a width on the grid's column, it fixes it, but I don't want a static width on my grid's column.
Below is an example of the problem. I am using .Net 4 and VS 2010.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<ListBox
DockPanel.Dock="Top"
x:Name="TestListBox">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type local:Test}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBox Grid.Column="0" Grid.Row="0" Text="{Binding Name}" />
<TextBlock Grid.Column="1" Grid.Row="0" Text="Test" />
<RichTextBox
Grid.Column="1" Grid.Row="1"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<local:Test Name="Test1" />
<local:Test Name="Test2" />
</ListBox>
using System.Windows;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class Test
{
public string Name { get; set; }
public Test()
{
}
}
}
So I figured out a workaround. If you trade out the ListBox for a DataGrid and use DataGridTemplateColumns with the Width of the TemplateColumn set to "*" then it seems to work.
<DataGrid
x:Name="TestDataGrid"
CanUserReorderColumns="False"
CanUserResizeColumns="False"
>
<DataGrid.Columns >
<DataGridTemplateColumn Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<RichTextBox />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<local:Test Name="Test1" />
<local:Test Name="Test2" />
</DataGrid>
Note I also set the CanUserResizeColumns to False because if you don't and they resize them, the ExtentWidth will snap back to 10.

Stretching the items in a WPF ListView within a ViewBox

I have a frustrating problem that I would much appreciate some help with. I have a ListView within a ViewBox and I can't get the items within the ListView to stretch horizontally.
Here is the XAML:
<Window x:Class="WpfApplication3.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication3"
Title="Window1">
<Window.Resources>
<local:Inning x:Key="inning">
<local:Inning.Skins>
<local:Skin SkinNumber="1"></local:Skin>
<local:Skin SkinNumber="2"></local:Skin>
<local:Skin SkinNumber="3"></local:Skin>
</local:Inning.Skins>
</local:Inning>
</Window.Resources>
<Grid DataContext="{StaticResource inning}">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Background="Black"
Text="SKINS"
Foreground="White"
FontSize="80"
FontWeight="Bold"
HorizontalAlignment="Center"></TextBlock>
<Grid Margin="2"
Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Viewbox>
<ListView Name="lvSkinNumbers"
ItemsSource="{Binding Skins}"
HorizontalAlignment="Stretch"
Background="Black"
VerticalAlignment="Stretch"
VerticalContentAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock FontSize="250"
VerticalAlignment="Stretch"
LineStackingStrategy="BlockLineHeight"
Margin="2"
TextAlignment="Center"
HorizontalAlignment="Stretch"
Background="Black"
Foreground="White"
Text="{Binding SkinNumber}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Viewbox>
<Viewbox Grid.Column="1">
<ListView Name="lvFirstInningSkins"
ItemsSource="{Binding Skins}"
Grid.Column="1"
HorizontalContentAlignment="Stretch"
Background="Black">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock FontSize="250"
VerticalAlignment="Stretch"
LineStackingStrategy="BlockLineHeight"
Margin="2"
TextAlignment="Center"
HorizontalAlignment="Stretch"
Background="Green"
Foreground="White"
Text="{Binding SkinNumber}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Viewbox>
<Viewbox Grid.Column="2"
HorizontalAlignment="Stretch">
<ListView Name="lvSecondInningSkins"
ItemsSource="{Binding Skins}"
Grid.Column="2"
HorizontalAlignment="Stretch"
Background="Black">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock FontSize="250"
VerticalAlignment="Stretch"
LineStackingStrategy="BlockLineHeight"
Margin="2"
TextAlignment="Center"
HorizontalAlignment="Stretch"
Background="Green"
Foreground="White"
Text="{Binding SkinNumber}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Viewbox>
</Grid>
</Grid>
</Window>
Here is the code behind with the definitions of the Skin and Inning objects:
using System;
using System.Windows;
using System.ComponentModel;
using System.Collections.ObjectModel;
namespace WpfApplication3
{
public class Inning
{
private ObservableCollection<Skin> _skins = new ObservableCollection<Skin>();
public ObservableCollection<Skin> Skins
{
get { return _skins; }
set { _skins = value; }
}
}
public class Skin : INotifyPropertyChanged
{
public Skin()
{
}
public Skin( int skinNumber, Inning inning )
{
this.SkinNumber = skinNumber;
this.Inning = inning;
}
public Inning Inning { get; set; }
public int SkinNumber { get; set; }
public int SkinCount
{
get { return this.Inning.Skins.Count; }
}
public void Notify( string propertyName )
{
if ( PropertyChanged != null )
PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
}
public event PropertyChangedEventHandler PropertyChanged;
}
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
}
The number of skins that can occur in an inning can change, and can be changed by the user, so I've put the ListViews into ViewBoxes so they automatically resize accordingly when the number of skins change. The resulting window can be seen here: http://i52.tinypic.com/244wqpl.jpg
I've tried all sorts of combinations of HorzontalAlignment="Stretch" and HorizontalContentAlignment="Stretch" and tried modifying the ItemsPanel template but I can't for the life of me seem to figure out how to get the ListView to stretch horizontally. Is what I'm trying to do impossible without some code behind to alter the width of the ListView dynamically? Or am I missing something really simple?
Any help that anyone can offer would be most appreciated.
Thanks,
Matthew
Try setting the ItemContainerStyle for your ListView to something like:
<ListView>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
You also might need to set <Viewbox Stretch="Fill"/>.
After this, I think you can remove all those other "HorizontalAlignment = Stretch" and "HorizontalContentAlignment = Stretch" setters in your code since it probably won't be necessary anymore.
Unexpectedly setting ScrollViewer.HorizontalScrollBarVisibility="Disabled" also worked for me:
<ListView ItemsSource="{Binding SourceList}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">

Resources