Home > Enterprise >  Dynamically changing tabitem via button command not working wfp
Dynamically changing tabitem via button command not working wfp

Time:01-26

Im trying to create a function in a wpf program, where I can select an item in a listview, and press a button and it changes the tabitem and allows me to then edit the item from the listview that was selected. Im having issues with getting the tabitem to change for me.

For the navigation of my app, I have a ViewModelBase, which my AppointmentsViewModel inherits from. Inside the AppointmentsViewVM there is a tabcontrol with 4 items, by clicking each one it loads the requested view/viewmodel for that function.

This is not the only way I've tried to get this to work, Im currently on day 4. I could get the TabIndex to change in the TabControl earlier, but the tab would still not change for me. So I abandoned that and tried the below route (still no luck).

ViewModelBase

    namespace MBR2.ViewModels
{
    public class ViewModelBase : INotifyPropertyChanged
    { 
        public ICommand MainMenuViewDogs_Command { get; set; }
        public ICommand MainMenuViewAppointments_Command { get; set; }

        private object _SelectedViewModel;
        public object SelectedViewModel
        {
            get { return _SelectedViewModel; }
            set
            {
                _SelectedViewModel = value;
                OnPropertyChanged("SelectedViewModel");
            }
        }

        public ViewModelBase()
        {
            MainMenuViewDogs_Command = new BaseCommand(OpenDogs);
            MainMenuViewAppointments_Command = new BaseCommand(OpenAppointments);
        }

        private void OpenDogs(object obj)
        {
            SelectedViewModel = new DogsViewModel();
        }
        private void OpenAppointments(object obj)
        {
            SelectedViewModel = new AppointmentsViewModel();
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private bool _SelectedIndexView;
        public bool SelectedIndexView
        {
            get { return _SelectedIndexView; }
            set
            {
                _SelectedIndexView = value;
                OnPropertyChanged("SelectedIndexView");
            }
        }
        private bool _SelectedIndexAdd;
        public bool SelectedIndexAdd
        {
            get { return _SelectedIndexAdd; }
            set
            {
                _SelectedIndexView = value;
                OnPropertyChanged("SelectedIndexAdd");
            }
        }
        private bool _SelectedIndexEdit;
        public bool SelectedIndexEdit
        {
            get { return _SelectedIndexEdit; }
            set
            {
                _SelectedIndexView = value;
                OnPropertyChanged("SelectedIndexEdit");
            }
        }
        private bool _SelectedIndexDelete;
        public bool SelectedIndexDelete
        {
            get { return _SelectedIndexDelete; }
            set
            {
                _SelectedIndexView = value;
                OnPropertyChanged("SelectedIndexDelete");
            }
        }
    }
}

AppointmentsViewModel

{
    public class AppointmentsViewModel : ViewModelBase
    {

        private AppointmentsAddVM _AppointmentsAddVM;
        public AppointmentsAddVM AppointmentsAddVM { get { return _AppointmentsAddVM; } }
        private AppointmentsEditVM _AppointmentsEditVM;
        public AppointmentsEditVM AppointmentsEditVM { get { return _AppointmentsEditVM; } }
        private AppointmentsDeleteVM _AppointmentsDeleteVM;
        public AppointmentsDeleteVM AppointmentsDeleteVM { get { return _AppointmentsDeleteVM; } }
        private AppointmentsViewVM _AppointmentsViewVM;
        public AppointmentsViewVM AppointmentsViewVM { get { return _AppointmentsViewVM; } }

        public ObservableCollection<object> ViewModelList { get; set; }

        public AppointmentsViewModel()
        {

            this.ViewModelList = new ObservableCollection<object>();
            _AppointmentsAddVM = new AppointmentsAddVM();
            _AppointmentsEditVM = new AppointmentsEditVM();
            _AppointmentsDeleteVM = new AppointmentsDeleteVM();
            _AppointmentsViewVM = new AppointmentsViewVM();
            this.ViewModelList.Add(_AppointmentsAddVM);
            this.ViewModelList.Add(_AppointmentsEditVM);
            this.ViewModelList.Add(_AppointmentsDeleteVM);
            this.ViewModelList.Add(_AppointmentsViewVM);
        }
    }
}

AppointmentsView.xaml

<UserControl
    x:Class="MBR2.Views.AppointmentsView"
        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:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" 
        xmlns:vms="clr-namespace:MBR2.ViewModels.Appointments"
        xmlns:views="clr-namespace:MBR2.Views.Appointments" 
        xmlns:viewmodels="clr-namespace:MBR2.ViewModels" 
        d:DataContext="{d:DesignInstance Type=viewmodels:AppointmentsViewModel}"
        mc:Ignorable="d" 
        d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>
        <DataTemplate DataType="{x:Type vms:AppointmentsViewVM}">
            <views:AppointmentsViewView />
        </DataTemplate>
        <DataTemplate DataType="{x:Type vms:AppointmentsAddVM}">
            <views:AppointmentsAddView />
        </DataTemplate>
        <DataTemplate DataType="{x:Type vms:AppointmentsDeleteVM}">
            <views:AppointmentsDeleteView />
        </DataTemplate>
        <DataTemplate DataType="{x:Type vms:AppointmentsEditVM}">
            <views:AppointmentsEditView />
        </DataTemplate>
    </UserControl.Resources>
    <Grid x:Name="Appointments" Width="Auto" Height="Auto">
        <DockPanel HorizontalAlignment="Center" 
                   Height="Auto" 
                   LastChildFill="False" 
                   VerticalAlignment="Top" 
                   Width="Auto">
            <TabControl x:Name="VMTabControl">
                <TabItem x:Name="ViewTab"
                         TabIndex="0"
                         Header="View" 
                         IsSelected="{Binding SelectedIndexView}"
                         Content="{Binding AppointmentsViewVM}"></TabItem>
                <TabItem x:Name="AddTab"
                         TabIndex="1"
                         Header="Add"
                         IsSelected="{Binding SelectedIndexAdd}"
                         Content="{Binding AppointmentsAddVM}"></TabItem>
                <TabItem x:Name="EditTab"
                         TabIndex="2"
                         Header="Edit" 
                         IsSelected="{Binding SelectedIndexEdit}"
                         Content="{Binding AppointmentsEditVM}"></TabItem>
                <TabItem x:Name="DeleteTab"
                         TabIndex="3"
                         Header="Delete"
                         IsSelected="{Binding SelectedIndexDelete}"
                         Content="{Binding AppointmentsDeleteVM}"></TabItem>
            </TabControl>
        </DockPanel>
    </Grid>
</UserControl>

And the associated AppointmentsViewVM

namespace MBR2.ViewModels.Appointments
{
    public class AppointmentsViewVM : ViewModelBase, INotifyPropertyChanged
    {
        private List<AppointmentsView_Wrapper> _AppointmentsView;
        public List<AppointmentsView_Wrapper> AppointmentsView
        {
            get { return _AppointmentsView; }
            set
            {
                _AppointmentsView = value;
                OnPropertyChanged("AppointmentsView");
            }
        }
        private List<string> _NameColumn = new List<string>();
        public List<string> NameColumn
        {
            get { return _NameColumn; }
            set
            {
                _NameColumn = value;
                OnPropertyChanged("NameColumn");
            }
        }
        private List<string> _ApptDateColumn = new List<string>();
        public List<string> ApptDateColumn
        {
            get { return _ApptDateColumn; }
            set
            {
                _ApptDateColumn = value;
                OnPropertyChanged("ApptDateColumn");
            }
        }
        private List<string> _ApptTimeColumn = new List<string>();
        public List<string> ApptTimeColumn
        {
            get { return _ApptTimeColumn; }
            set 
            {
                    _ApptTimeColumn = value;
                    OnPropertyChanged("ApptTimeColumn");
            }
        }
        private List<string> _ApptVetColumn = new List<string>();
        public List<string> ApptVetColumn
        {
            get { return _ApptVetColumn; }
            set
            {
                _ApptVetColumn = value;
                OnPropertyChanged("ApptVetColumn");
            }
        }
        private List<string> _ApptCreatedColumn = new List<string>();
        public List<string> ApptCreatedColumn
        {
            get { return _ApptCreatedColumn; }
            set
            {
                _ApptCreatedColumn = value;
                OnPropertyChanged("ApptCreatedColumn");
            }
        }
        private List<int> _ApptIDColumn = new List<int>();
        public List<int> ApptIDColumn
        {
            get { return _ApptIDColumn; }
            set
            {
                _ApptIDColumn = value;
                OnPropertyChanged("ApptIDColumn");
            }
        }
        private string _AppointmentEdit_Enabled = "False";
        public string AppointmentEdit_Enabled
        {
            get { return _AppointmentEdit_Enabled; }
            set
            {
                _AppointmentEdit_Enabled = value;
                OnPropertyChanged("AppointmentEdit_Enabled");
            }
        }
        private AppointmentsView_Wrapper _ApptIDSelected;
        public AppointmentsView_Wrapper ApptIDSelected
        {
            get { return _ApptIDSelected; }
            set
            {
                AppointmentEdit_Enabled = "True";
                _ApptIDSelected = value;
                OnPropertyChanged("ApptIDSelected");
            }
        }

        public AppointmentData AppointmentData = new AppointmentData();
        public Messaging Messaging = new Messaging();

        public ICommand AppointmentsListView_Command => new DelegateCommand<object>(AppointmentsListView_Clicked);
        public ICommand EditSelection_Command => new DelegateCommand<object>(EditSelection_Clicked);

        public AppointmentsViewVM()
        {
            BuildPage();
        }

        public async void BuildPage()
        {
            AppointmentsView = await AppointmentData.Appointments_GetAll();
            foreach(var item in AppointmentsView)
            {
                ApptIDColumn.Add(item.ApptID);
                NameColumn.Add(item.DogName);
                ApptDateColumn.Add(item.ApptDate);
                ApptTimeColumn.Add(item.ApptTime);
                ApptVetColumn.Add(item.ApptVet);
                ApptCreatedColumn.Add(item.ApptCreated.ToString("dd/mm/yyyy"));
            }

        }
        public void AppointmentsListView_Clicked(object obj)
        {
            Messaging.ShowAlert(ApptIDSelected.ApptID.ToString());
        }

        public void EditSelection_Clicked(object obj)
        {
            bool result = Messaging.AskQuestion(ApptIDSelected.ApptID.ToString());
            if(result)
            {
                SelectedIndexView = false;
                SelectedIndexAdd = false;
                SelectedIndexEdit = true;
                SelectedIndexDelete = false;
                OnPropertyChanged("SelectedIndexView");
                OnPropertyChanged("SelectedIndexAdd");
                OnPropertyChanged("SelectedIndexEdit");
                OnPropertyChanged("SelectedIndexDelete");
            }
            else
            {
                Messaging.ShowAlert("no");
            }
        }
    }
}

CodePudding user response:

Here's a minimal reproduction of something where you select in a listbox and that then selects a corresponding tab in a tabcontrol.

This is very minimal but we can perhaps imagine a more sophisticated viewmodel per item in the listbox with name and viewmodel or something.

This is mainwindow.

<Window.Resources>
    <DataTemplate DataType="{x:Type local:Avm}">
        <local:Aview/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:Bvm}">
        <local:Bview/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:Cvm}">
        <local:Cview/>
    </DataTemplate>
</Window.Resources>
<Window.DataContext>
    <local:MainWindowViewmodel/>
</Window.DataContext>
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="200"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <ListBox ItemsSource="{Binding ViewModels}"
             x:Name="lb"
             >
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding ViewModelName}"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

    <TabControl Grid.Column="1"
                ItemsSource="{Binding ViewModels}"
                SelectedItem="{Binding ElementName=lb, Path=SelectedItem, Mode=TwoWay}"
                >
        <TabControl.ItemTemplate>
            <DataTemplate>
                <TextBlock
                Text="{Binding ViewModelName}" />
            </DataTemplate>
        </TabControl.ItemTemplate>
        <TabControl.ContentTemplate>
            <DataTemplate>
                <ContentPresenter Content="{Binding}"/>
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>
</Grid>

I have only done 3 views and viewmodels.

Note that the selecteditem of the listbox is bound twoway to the tabcontrol. I have matching views and viewmodels A, B and C

MainWindowViewModel

public class MainWindowViewmodel : ViewModelBase
{
    public ObservableCollection<Object> ViewModels { get; set; } = new ObservableCollection<Object>{
        new Avm{ViewModelName="A viewmodel" }, 
        new Bvm{ViewModelName="B viewmodel" }, 
        new Cvm{ViewModelName="C viewmodel" }
        };
}

Both the itemssource of listbox and tabcontrol are bound to that collection of viewmodels. Which are, as I mentioned, as simple as you get really.

Viewmodelbase

public  class ViewModelBase : INotifyPropertyChanged
{
    public string ViewModelName { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string name = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
}

Avm, Bvm and Cvm just inherit from that.

An example usercontrol view.

    <Grid>
        <TextBlock Text="{Binding ViewModelName}"/>
    </Grid>
</UserControl>

When I spin that up, select and select an item in the listbox the matching tab is selected. And vice versa. Select a tab and it selects the same one in the listbox.

enter image description here

  • Related