У меня есть несколько вкладок (tab1, tab2,... и т. д.) в элементе управления вкладками WPF. Когда я нажимаю кнопку, я хочу перезапустить приложение и открыть определенную вкладку, скажем, вкладку 2 (в удобном для MVVM формате).
Чтобы перезапустить приложение, которое я использую
Process.Start(Application.ResourceAssembly.Location);
Application.Current.Shutdown();
Но как указать, какую вкладку отображать после перезапуска?
@ mm8 Есть ли другие способы перезапустить приложение при нажатии кнопки, где я могу передать информацию о том, какую вкладку выбрать после перезапуска?





Очевидно, что ваш новый экземпляр приложения должен «что-то знать» о требовании открыть конкретный элемент вкладки.
Есть и другие возможности, такие как создание файла конфигурации, но, вероятно, здесь хорошо подойдет параметр командной строки. Чтобы запустить новый экземпляр, вы можете использовать что-то вроде Process.Start(Application.ResourceAssembly.Location, "/StartTab=MyTab3");
Затем в вашей ViewModel создайте строковое свойство, например public string SelectedTabName {get; set;}, и инициализируйте его во время создания виртуальной машины:
var tabInfo = Environment.GetCommandLineArgs().FirstOrDefault(a => a.ToLower().StartsWith("/starttab = "));
if (!string.IsNullOrWhiteSpace(tabInfo))
{
SelectedTabName = tabInfo.Substring(tabInfo.IndexOf('=')+1);
}
Наконец, в коде XAML привяжите свойство IsSelected элементов вкладки к строке SelectedTabName с помощью StringToBooleanConverter, используя ConverterParameter как имя вкладки.
public class StringMatchesParameterToBooleanConverter : IValueConverter
{
public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
{
if (value is not string val)
return false;
if (parameter is not string param)
return false;
return val == param;
}
[ExcludeFromCodeCoverage]
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
{
throw new NotImplementedException();
}
}
Ваш код TabControl Xaml может работать так
<TabControl>
<TabControl.Resources>
<converters:StringMatchesParameterToBooleanConverter x:Key = "StringMatchesParameterToBooleanConverter" />
</TabControl.Resources>
<TabItem x:Name = "MyTab1"
IsSelected = "{Binding SelectedTabName, Converter = {StaticResource StringMatchesParameterToBooleanConverter}, ConverterParameter=MyTab1}">
</TabItem>
<TabItem x:Name = "MyTab2"
IsSelected = "{Binding SelectedTabName, Converter = {StaticResource StringMatchesParameterToBooleanConverter}, ConverterParameter=MyTab2}">
</TabItem>
<TabItem x:Name = "MyTab3"
IsSelected = "{Binding SelectedTabName, Converter = {StaticResource StringMatchesParameterToBooleanConverter}, ConverterParameter=MyTab3}">
</TabItem>
</TabControl>
Спасибо за Ваш ответ. Поскольку я использую более старую версию С# (5.0), можете ли вы показать мне коды для if (value is not string val) и if (parameter is not string param) для более старой версии?
Вау, тебе стоит подумать о том, чтобы больше не ездить на лошади, когда она уже мертва :), но это другая тема, которая здесь неуместна. Эти операторы «сопоставления с образцом» — просто сжатые варианты старого доброго кода (извините за отсутствующие разрывы строк) var val = string.Empty; if (typeof(value) != typeof(string)) return false; val = (строка) значение; (Извините за пропущенные разрывы строк)
Я получаю сообщение об ошибке The type or namespace name 'value' could not be found (are you missing a using directive or an assembly reference?) (CS0246)
if (value == null || value.GetType() != typeof(string)) return false; var val = (строка)значение; Извините, что не проверил этот старый диалект. Помните: эта лошадь мертва.
Теперь я получаю System.NotImplementedException: The method or operation is not implemented. в ConvertBack из StringMatchesParameterToBooleanConverter, когда я нажимаю на любой из вкладок :(
Вместо того, чтобы бросать, пусть метод convertBack возвращает Binding.DoNothing
Всякий раз, когда я запускаю приложение, оно всегда открывает MyTab3, хотя я хотел сделать это только при нажатии определенной кнопки...
Не знаю, в чем твоя проблема, может быть, ты покажешь нам свой код?
Не знаю, что было раньше, но теперь все работает нормально! Может быть, я сделал какую-то опечатку раньше, не уверен ...
Тем временем я сделал тестовый проект (в VS 2022 с использованием .net 6.0), и он работает в основном так, как описано ранее. Нет проблем с созданием исключения в части преобразователя ConvertBack. Единственная разница заключалась в перезапуске программы с использованием Environment.ProcessPath вместо Application.ResourceAssembly.Location:
MainWindow.xaml:
<Window x:Class = "TestStartWithButtonClick.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:TestStartWithButtonClick"
mc:Ignorable = "d"
d:DataContext = "{d:DesignInstance Type=local:MainViewModel, IsDesignTimeCreatable=True}"
SizeToContent = "WidthAndHeight"
Title = "MainWindow" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height = "*" />
<RowDefinition Height = "Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width = "Auto"/>
<ColumnDefinition Width = "Auto"/>
<ColumnDefinition Width = "Auto"/>
</Grid.ColumnDefinitions>
<TabControl Grid.Row = "0" Grid.ColumnSpan = "3">
<TabControl.Resources>
<local:StringMatchesParameterToBooleanConverter x:Key = "StringMatchesParameterToBooleanConverter" />
</TabControl.Resources>
<TabItem x:Name = "MyTab1" Header = "MyTab1"
IsSelected = "{Binding SelectedTabName, Converter = {StaticResource StringMatchesParameterToBooleanConverter}, ConverterParameter=MyTab1}">
<StackPanel Width = "300" Height = "100" />
</TabItem>
<TabItem x:Name = "MyTab2" Header = "MyTab2"
IsSelected = "{Binding SelectedTabName, Converter = {StaticResource StringMatchesParameterToBooleanConverter}, ConverterParameter=MyTab2}">
<StackPanel Width = "300" Height = "100" />
</TabItem>
<TabItem x:Name = "MyTab3" Header = "MyTab3"
IsSelected = "{Binding SelectedTabName, Converter = {StaticResource StringMatchesParameterToBooleanConverter}, ConverterParameter=MyTab3}">
<StackPanel Width = "300" Height = "100" />
</TabItem>
</TabControl>
<Button Grid.Row = "1" Grid.Column = "0" Margin = "0,0,6,0" Content = "Start With Tab 1" Command = "{Binding StartNewInstanceCommand}" CommandParameter = "MyTab1"/>
<Button Grid.Row = "1" Grid.Column = "1" Margin = "6,0,6,0" Content = "Start With Tab 2" Command = "{Binding StartNewInstanceCommand}" CommandParameter = "MyTab2"/>
<Button Grid.Row = "1" Grid.Column = "2" Margin = "6,0,0,0" Content = "Start With Tab 3" Command = "{Binding StartNewInstanceCommand}" CommandParameter = "MyTab3"/>
</Grid>
</Window>
MainWindow.xaml.cs с помощью System.Windows;
namespace TestStartWithButtonClick
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}
}
MainViewModel.cs:
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Input;
namespace TestStartWithButtonClick
{
public class MainViewModel : INotifyPropertyChanged
{
private string _selectedTabName = string.Empty;
public event PropertyChangedEventHandler? PropertyChanged;
public MainViewModel()
{
var tabInfo = Environment.GetCommandLineArgs().FirstOrDefault(a => a.ToLower().StartsWith("/starttab = "));
if (!string.IsNullOrWhiteSpace(tabInfo))
{
SelectedTabName = tabInfo.Substring(tabInfo.IndexOf('=') + 1);
}
else
{
SelectedTabName = "MyTab1";
}
}
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public StartNewInstanceCommand StartNewInstanceCommand { get; set; } = new();
public string SelectedTabName
{
get => _selectedTabName;
set
{
if (value == _selectedTabName) return;
_selectedTabName = value;
OnPropertyChanged(nameof(SelectedTabName));
}
}
}
public class StartNewInstanceCommand : ICommand
{
public bool CanExecute(object? parameter)
{
return true;
}
public void Execute(object? parameter)
{
if (parameter is not string tabItem)
throw new ArgumentException("parameter is not string", nameof(parameter));
Process.Start(Environment.ProcessPath, $"/StartTab = {tabItem}");
Application.Current.Shutdown(0);
}
public event EventHandler? CanExecuteChanged;
}
}
StringMatchesParameterToBooleanConverter.cs:
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Windows.Data;
namespace TestStartWithButtonClick
{
public class StringMatchesParameterToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is not string val)
return false;
if (parameter is not string param)
return false;
return val == param;
}
[ExcludeFromCodeCoverage]
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Вам нужно как-то передать информацию о том, какую вкладку выбрать процессу, например, с помощью аргумента командной строки.