如何在2个单独的工具窗口上实现主从模式?

时间:2019-04-18 14:55:45

标签: c# data-binding visual-studio-extensions

我目前正在开发Visual Studio扩展,对C#还是陌生的。我需要具有明显类似于主从模式的东西,但是我需要在2个单独的工具窗口中使用它:

  • 首先,我有一个“结果列表”工具窗口,该窗口是详细信息有限的结果列表。从数据库上传“结果列表”。
  • 第二,我有一个单独的“结果详细信息”工具窗口,该窗口应在“结果列表”中显示当前选定结果的详细信息。

我的问题是:

  • 我发现了很多指南和示例,这些指南和示例在单个XAML文件中的单个视图中显示了主从模式。我永远找不到在2个单独的视图/ XAML文件上能正确显示的内容。

  • 所以我尝试了手动操作:

    • 创建一个单独的“结果列表”工具窗口。单击“结果列表”工具窗口中的按钮时,可以在启动时(通过VS包的Initialize方法)或事件管理中用伪造的硬编码结果填充它。

    • 创建一个单独的“结果详细信息”工具窗口。我可以在启动时或从事件管理中类似地填充伪造数据。但是我无法通过在“结果列表”中选择一行来更新它。

->好像从“外部”调用更新时绑定不起作用。

结果列表XAML:

<UserControl ... Name="ResultsListToolWindow">
    <StackPanel>
        <ToolBar>
            <Button Click="Update_Button">Update List</Button>
        </ToolBar>
        <ScrollViewer ...>
            <DataGrid SelectionMode="Single"
                Name="ResultsListGrid" 
                ItemsSource="{Binding}" 
                SelectedItem="{Binding SelectedItem}"
                SelectionChanged="SelectionChanged"
                IsSynchronizedWithCurrentItem="True" ...>
                ...
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Family" Binding="{Binding Family}"/>
                    <DataGridTextColumn Header="Type" Binding="{Binding Type}"/>
                    <DataGridTextColumn Header="Check" Binding="{Binding Check}"/>
                </DataGrid.Columns>
            </DataGrid>
        </ScrollViewer>
    </StackPanel>
</UserControl>

结果列表后面的代码:

    public partial class ResultsListToolWindowControl : UserControl
    {
        public ResultsListToolWindowControl()
        {
            InitializeComponent();

            DataContext = Data.ResultsList.GetResultsList();
            // Gets an empty Results List
            // ResultsList is an ObservableCollection<Result>
        }

        private void SelectionChanged(
            object sender, SelectionChangedEventArgs e)
        {
            ResultDetailsToolWindow resultDetailsToolWindow = 
                ResultDetailsToolWindow.GetToolWindow();

            resultDetailsToolWindow.UpdateResultDetails(
                ResultsListGrid.SelectedItem as Data.Result); 
            // Some glue is behind to forward to resultDetailsToolWindowControl
        }

        private void Update_Button(object sender, RoutedEventArgs e)
        {
            Data.ResultsList resultsList = 
                (DataContext as Data.ResultsList);
            resultsList.Update(); // Get some hard-coded results list
        }
    }

结果详细信息XAML:

<UserControl ... Name="ResultDetailsToolWindow">
    <Grid Name="ResultDetailsGrid">
        <StackPanel Orientation="Vertical">
            <ToolBar>
                <Button Click="Update_Button">
                    Update Details
                </Button>
            </ToolBar>
            <TextBlock Text="{Binding Finding.Family}"/>
            <TextBlock Text="{Binding Finding.Type}"/>
            <TextBlock Text="{Binding Finding.Check}"/>
        </StackPanel>
    </Grid>
</UserControl>

代码后的结果详细信息:

    public partial class ResultDetailsToolWindowControl : UserControl
    {
        private class SelectedResult: INotifyPropertyChanged
        {
            private Data.Result result;
            public event PropertyChangedEventHandler PropertyChanged;

            private void NotifyPropertyChanged(
                [CallerMemberName] string propertyName = "")
            {
                PropertyChanged?.Invoke(
                    this, new PropertyChangedEventArgs(propertyName));
            }

            public Data.Result Result
            {
                get { return result; }
                set
                {
                    if (result!= value)
                    {
                        result= value;
                        NotifyPropertyChanged();
                    }
                }
            }

            public SelectedResult() { }
        }

        public ResultDetailsToolWindowControl()
        {
            InitializeComponent();

            ResultDetailsGrid.DataContext = new SelectedResult();
        }

        public void UpdateResultDetails(Data.Result selectedResult)
        {
            if (selectedResult != null)
            {
                (ResultDetailsGrid.DataContext as SelectedResult).Finding = selectedResult; 
            }
        }

        private void Update_Button(object sender, RoutedEventArgs e)
        {
            (ResultDetailsGrid.DataContext as SelectedFinding).Finding = new Data.Result()
            {
                Family = "Defect",
                Type = "Defects",
                Check = "Base class assignment operator not called",
            }; 
        }
    }
}

从行选择中调用UpdateResultDetails时,使用调试器步进时会完成DataContext更改,但此后似乎丢失,并且从不更新Result Details UI。好像从“外部”进行更新不起作用。

通过单击按钮调用Update_Button时,DataContext更改已完成,结果详细信息用户界面 已正确更新。好像允许从“内部”进行更新。

任何建议将不胜感激!

1 个答案:

答案 0 :(得分:0)

  

也许您可以添加一个静态中产阶级,其中有一个钥匙(静态   int)。让密钥成为第一个窗口和第二个窗口之间的桥梁,因为很难使第一个窗口直接与第二个窗口交互。

假设您的扩展名类似于带有列表框的窗口和带有文本框的窗口。

在您的FirstWindow.xaml.cs中,在您的单击或选择事件处理程序中添加一个简单的func doGetLocalDataUser() -> logInResponse? { guard let userData = UserDefaults.standard.data(forKey: ConstantStrings.KEY_USER_LOGIN_DATA), let user = try? JSONDecoder().decode(logInResponse.self ,from: userData) else { return nil } return user }

然后在您的key=xxx;中,订阅一个密钥更改的事件(使用dispatcherTimer或其他方法)。每次在SecondWindow.xaml.cs中选择列表框的项目时,都将键变量的值设置为特定值。然后secondToolWindows知道,根据FirstToolWindow的值进行操作。

我认为必须有一种更好的方法来实现您的目标,但是由于时间原因,我想出了一种更好的方法。无论如何,希望它能有所帮助。