在MVVM之后的WPF应用程序中集成上下文相关帮助

时间:2013-06-10 10:44:35

标签: c# wpf mvvm context-sensitive-help

我正在尝试为遵循MVVM模式的wpf应用程序实现帮助功能。我有我的帮助文件,根据应用程序包含许多页面。现在我需要将它集成到我的应用程序中。

以下是我的要求:

  1. 按F1键会根据视图模型在帮助文件中打开某个页面。为此,我想,我需要将F1命令绑定到我的视图模型。我们如何在视图中绑定键?
  2. 在文本字段上按F1可打开该文本字段的帮助。我认为它与要求1相同。但问题是我如何知道某个文本字段,按钮或单选按钮被选中?

1 个答案:

答案 0 :(得分:2)

  1. 侦听视图中的键(或视图的基类),并在DataContext上的HelpCommand上调用execute。

  2. the control that has focus(或其ID或标记,...)作为参数传递给HelpCommand。

  3. Alternative way to find the focussed control使用FocusManager

    以下是一个例子:

    ContextHelp C#:

    public static class ContextHelp
    {
        public static readonly DependencyProperty KeywordProperty =
            DependencyProperty.RegisterAttached(
                "Keyword",
                typeof(string),
                typeof(ContextHelp));
    
        public static void SetKeyword(UIElement target, string value)
        {
            target.SetValue(KeywordProperty, value);
        }
    
        public static string GetKeyword(UIElement target)
        {
            return (string)target.GetValue(KeywordProperty);
        }
    }
    

    ViewBase:

    public abstract class ViewBase : UserControl
    {
        public ViewBase()
        {
            this.KeyUp += ViewBase_KeyUp;
            this.GotFocus += ViewBase_GotFocus;
        }
    
        void ViewBase_GotFocus(object sender, RoutedEventArgs e)
        {
            FocusManager.SetIsFocusScope(this, true);
        }
    
        void ViewBase_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == Key.F1)
            {
                var viewModel = this.DataContext as ViewModelBase;
                if (viewModel != null)
                {
                    var helpTopic = "Index";
                    var focusedElement = 
                        FocusManager.GetFocusedElement(this) as FrameworkElement;
                    if (focusedElement != null)
                    {
                        var keyword = ContextHelp.GetKeyword(focusedElement);
                        if (!String.IsNullOrWhiteSpace(keyword))
                        {
                            helpTopic = keyword;
                        }
                    }
                    viewModel.HelpCommand.Execute(helpTopic);
                }
            }
        }
    }
    

    ViewModelBase:

    public abstract class ViewModelBase: INotifyPropertyChanged
    {
        public ICommand HelpCommand { get; set; }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected void OnPropertyChanged([CallerMemberName] string propertyName="")
        {
            var p = PropertyChanged;
            if (p != null)
            {
                p(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
    

    AViewModel:

    class AViewModel : ViewModelBase
    {
        public AViewModel()
        {
            HelpCommand = new RelayCommand(HelpCommandExecuted, (p)=>true);
        }
    
        private void HelpCommandExecuted(object parameter)
        {
            var topic = parameter as string;
            if (!String.IsNullOrWhiteSpace(topic))
            {
                HelpText = String.Format("Information on the interesting topic: {0}.", topic);
            }
        }
    
        private string _helpText;
    
        public string HelpText
        {
            get { return _helpText; }
            private set
            {
                if (_helpText != value)
                {
                    _helpText = value;
                    OnPropertyChanged();
                }
            }
        }
    }
    

    AView C#:

    public partial class AView : ViewBase
    {
        public AView()
        {
            InitializeComponent();
        }
    }
    

    AView XAML:

    <local:ViewBase x:Class="WpfApplication2.AView"
                 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:WpfApplication2"
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300">
        <Grid>
            <Label Content="{Binding HelpText}" Margin="10,254,10,0" VerticalAlignment="Top" Height="36"/>
            <Button local:ContextHelp.Keyword="Button Info" Content="Button" HorizontalAlignment="Left" Margin="192,32,0,0" VerticalAlignment="Top" Width="75"/>
            <TextBox local:ContextHelp.Keyword="TextBox Info" HorizontalAlignment="Left" Height="23" Margin="29,32,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
            <CheckBox local:ContextHelp.Keyword="CheckBox Info" Content="CheckBox" HorizontalAlignment="Left" Margin="29,80,0,0" VerticalAlignment="Top"/>
            <ComboBox local:ContextHelp.Keyword="ComboBox Info" HorizontalAlignment="Left" Margin="138,80,0,0" VerticalAlignment="Top" Width="120"/>
        </Grid>
    </local:ViewBase>
    

    MainWindow XAML:

    <Window
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication2" x:Class="WpfApplication2.MainWindow"
            Title="MainWindow" Height="700" Width="500">
        <Grid x:Name="ViewPlaceholder">
        </Grid>
    </Window>
    

    MainWindow C#:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
    
            var view = new AView();
            var viewModel = new AViewModel();
            view.DataContext = viewModel;
            ViewPlaceholder.Children.Clear();
            ViewPlaceholder.Children.Add(view);
        }
    }