C#TreeView选择和聚焦元素

时间:2017-11-23 13:46:03

标签: c# wpf mvvm

我使用基于this描述中的按需加载演示的MVVM模式在C#中实现了TreeView。之后我尝试添加一个函数,不仅可以选择,还可以在TreeView中聚焦元素。因此我实现了这个类:

namespace TreeViewWithViewModelDemo.LoadOnDemand
{ 
  public static class FocusExtension{
    public static bool GetIsFocused(DependencyObject obj){
      return (bool)obj.GetValue(IsFocusedProperty);
    }

    public static void SetIsFocused(DependencyObject obj, bool value){
      obj.SetValue(IsFocusedProperty, value);
    }

    public static readonly DependencyProperty IsFocusedProperty =
      DependencyProperty.RegisterAttached(
          "IsFocused", typeof(bool), typeof(FocusExtension),
          new UIPropertyMetadata(false, OnIsFocusedPropertyChanged));

    private static void OnIsFocusedPropertyChanged(
         DependencyObject d,
         DependencyPropertyChangedEventArgs e){
      var uie = (UIElement)d;
      if ((bool)e.NewValue) {
         uie.Focus(); // Don't care about false values.
      }
    }
  }
}

在我的TreeViewItemViewModel.cs中,我添加了参数IsTextBoxFocused:

private bool _isFocused = true;
public bool IsTextBoxFocused
{
  get{ return _isFocused; }
  set
  {
    PropertyChangedEventHandler handler = PropertyChanged;
    if (_isFocused == value)
    {
      _isFocused = false;

      if (handler != null)
        handler(this, new PropertyChangedEventArgs("IsTextBoxFocused"));
    }
    _isFocused = value;
    if (handler != null)
      handler(this, new PropertyChangedEventArgs("IsTextBoxFocused"));
  }
}

在我的XAML中,我更改了区域的HierarchicalDataTemplate:

<HierarchicalDataTemplate 
      DataType="{x:Type local:RegionViewModel}" 
      ItemsSource="{Binding Children}"
      >
        <StackPanel Orientation="Horizontal">
          <Grid local:FocusExtension.IsFocused="{Binding IsTextBoxFocused}" Focusable="True">
            <Grid.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Rename"/>
                </ContextMenu>
            </Grid.ContextMenu>
            <!-- Normal state of the header -->
            <TextBlock x:Name="textBlockHeader" Focusable="True" Text="{Binding RegionName}" Margin="3,0" />
            <!-- This state is active in the edit mode -->
          </Grid>
        </StackPanel>
</HierarchicalDataTemplate>

直到这里,我的代码完全正常,但仅适用于我的树中的Region节点。在下一步中,我试图让State节点也成为焦点。因此,我使用与IsTextBoxFocused相同的方式实现了一个新变量IsGridBoxFocused。在我的XAML中,我更改了状态的HierarchicalDataTemplate:

<HierarchicalDataTemplate 
      DataType="{x:Type local:StateViewModel}" 
      ItemsSource="{Binding Children}"
      >
      <StackPanel Orientation="Horizontal">
            <Grid local:FocusExtension.IsFocused="{Binding IsGridBoxFocused}" Focusable="True">
                <Grid.ContextMenu>
                    <ContextMenu>
                        <MenuItem Header="Rename"/>
                    </ContextMenu>
                </Grid.ContextMenu>
                <!-- Normal state of the header -->
                <TextBlock x:Name="textBlockHeader" Focusable="True" Text="{Binding StateName}" Margin="3,0" />
                <!-- This state is active in the edit mode -->
             </Grid>
        </StackPanel>
    </HierarchicalDataTemplate>

最后我更改了IsSelected功能。 在TreeViewItemViewModel中:

public virtual bool IsSelected
{
    get { return _isSelected; }
    set
    {
        if (value != _isSelected)
        {
            _isSelected = value;
            this.OnPropertyChanged("IsSelected");
            if (!_isSelected)
            {
              this.IsExpanded = false;
            }
            else
            {
              this.IsExpanded = true;
            }
        }
    }
}

在RegionViewModel中:

public override bool IsSelected
{
  get
  {
     return base.IsSelected;
  }

  set
  {
    base.IsSelected = value;
    IsTextBoxFocused = value;
    if (value == true)
    {
      foreach (var elem in this.Children)
      {
        elem.IsGridBoxFocused = !value;
      }
    }
  }
}

在StateViewModel中:

public override bool IsSelected
{
  get
  {
    return base.IsSelected;
  }
  set
  {
    IsGridBoxFocused = value;
    Parent.IsTextBoxFocused = !value;
    base.IsSelected = value;
  }
}

我的问题是,当我选择一个Region节点时它可以正常工作,当我第一次选择State(Child)节点时它也可以工作,但是当我选择第二个State节点时,会选择一个父节点。有人可以帮我解决这个问题吗?

0 个答案:

没有答案