【问题标题】:How to open a specific tabitem on restart of WPF c# app on button click?如何在单击按钮时重新启动 WPF c# 应用程序时打开特定的 tabitem?
【发布时间】:2022-11-27 20:26:24
【问题描述】:

我在 WPF tabcontrol 中有多个 tabitem(tab1、tab2 等)。当我单击一个按钮时,我想重新启动应用程序并打开一个特定的 tabitem,比如 tab2(以 MVVM 友好的方式)。

重新启动我使用的应用程序

            Process.Start(Application.ResourceAssembly.Location);
            Application.Current.Shutdown();

但是如何指定重启后显示哪个tabitem呢?

【问题讨论】:

  • 您需要以某种方式将有关要选择哪个选项卡的信息传递给进程,例如使用命令行参数。
  • @mm8 是否有任何其他方法可以在单击按钮时重新启动应用程序,我可以在其中传递有关重新启动后要选择哪个选项卡的信息?

标签: c# wpf mvvm tabcontrol tabitem


【解决方案1】:

显然,您的新应用程序实例需要“了解”有关打开特定选项卡项的要求。

还有其他可能性,例如创建配置文件,但命令行参数可能会在这里很好地发挥作用。要启动新实例,您可以使用类似 Process.Start(Application.ResourceAssembly.Location, "/StartTab=MyTab3"); 的内容

然后,在你的 ViewModel 中,有一个像 public string SelectedTabName {get; set;} 这样的字符串属性,并在 VM 的构建过程中初始化它:

var tabInfo = Environment.GetCommandLineArgs().FirstOrDefault(a => a.ToLower().StartsWith("/starttab="));
if (!string.IsNullOrWhiteSpace(tabInfo))
{
    SelectedTabName = tabInfo.Substring(tabInfo.IndexOf('=')+1);
}

最后,在 XAML 代码中,在 StringToBooleanConverter 的帮助下,将选项卡项的 IsSelected 属性绑定到 SelectedTabName 字符串,使用 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>

【讨论】:

  • 感谢您的回答。由于我使用的是较旧的 c# 版本 (5.0),您能告诉我旧版本的 if (value is not string val) 和 if (parameter is not string param) 的代码吗?
  • 哇,你应该考虑在马死后不再骑马 :),但这是一个不同的话题,不属于这里。这些“模式匹配”语句只是好的旧代码的压缩变体(抱歉缺少换行符) var val = string.Empty;如果(typeof(值)!= typeof(字符串))返回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)) 返回 false; var val = (字符串)值;很抱歉没有检查那个旧方言。记住:那匹马已经死了。
  • 现在,当我点击任何 tabitems 时,我在 StringMatchesParameterToBooleanConverter 的 ConvertBack 中得到 System.NotImplementedException: The method or operation is not implemented. :(
【解决方案2】:

同时,我完成了一个测试项目(在 VS 2022 中使用 .net 6.0),它的工作原理与前面描述的差不多。在转换器的 ConvertBack 部分抛出异常没有问题。唯一需要的区别是使用 Environment.ProcessPath 而不是 Application.ResourceAssembly.Location 重新启动程序:

主窗口.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>

主窗口.xaml.cs 使用 System.Windows;

namespace TestStartWithButtonClick
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new 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();
        }
    }
}

【讨论】:

    猜你喜欢
    • 2016-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多