在ListView中使用ComboBox时出现问题

时间:2016-05-26 10:39:01

标签: c# wpf user-interface combobox scrollviewer

我有ListView,显示了许多元素。根据元素的类型,选择正确的DataTemplate来显示它们。其中一个模板用于项目列表,这些项目在ComboBox内呈现。

的DataTemplate

  <DataTemplate x:Key="comboBoxTemplate0">
    <ComboBox 
              ItemsSource="{Binding options}" ToolTip="{Binding Title}"
              Margin="2" MinWidth="50" MinHeight="20" HorizontalAlignment="Stretch"
              VerticalAlignment="Center">
      <ComboBox.ItemContainerStyle>
        <Style TargetType="{x:Type ComboBoxItem}">
          <Setter Property="HorizontalContentAlignment" Value="Left" />
          <Setter Property="VerticalContentAlignment" Value="Top" />
        </Style>
      </ComboBox.ItemContainerStyle>
    </ComboBox>
  </DataTemplate>

现在,我发现了一个我无法解释的问题,我相信它可能与某种方式有关,但我不知道。当我打开ComboBox的下拉列表时,我无法拖动内部ScrollViewer。我可以使用滚轮上下移动,或箭头键,但拖动不起作用,而ListView中的ScrollViewer被激活(因此拖动内部ScrollViewer移动外部)。

我似乎无法重现这个错误,也找不到任何让它发生在他们身上的人,所以我不知所措。我正在考虑放弃并简单地隐藏内部ScrollViewer,以便它不会被拖动。

这种行为可能是什么原因?当我尝试拖动内部ComboBox的ScrollViewer时,为什么外部ListView的ScrollViewer会移动?

修改

事情尝试了:

CanContentScroll设置为false - 不起作用

不会从ComboBox中触发

PreviewDragOver

ListView正在侦听4个事件:

的PreviewMouseLeftButtonDown

private void List_PreviewMouseLeftButtonDown (object Sender, MouseEventArgs E)
  {
  startPoint_ = E.GetPosition (null);
  }

的MouseMove

private void List_MouseMove (object Sender, MouseEventArgs E)
  {
  if (allowDrag_)
    {
    Vector Difference = startPoint_ - E.GetPosition (null);

    if (Mouse.LeftButton == MouseButtonState.Pressed &&
        (Math.Abs (Difference.X) > SystemParameters.MinimumHorizontalDragDistance ||
         Math.Abs (Difference.Y) > SystemParameters.MinimumVerticalDragDistance))
      {
      PerformDragAndDrop ((DependencyObject)E.OriginalSource, (ListView)Sender);
      }
    }
  }

dragEnter事件

private void List_DragEnter (object Sender, DragEventArgs E)
  {
  if (!E.Data.GetDataPresent (Strings.DragnDropFormatString) ||
        Sender == E.Source)
    {
    E.Effects = DragDropEffects.None;
    }
  }

并删除

private void List_Drop (object Sender, DragEventArgs E)
  {
  if (E.Data.GetDataPresent (Strings.DragnDropFormatString))
    {
    CSettingBase Data = E.Data.GetData (Strings.DragnDropFormatString) as CSettingBase;

    if (LoadedSettings.FirstOrDefault (s => s.Name == Data.Name) == null)
      {
      LoadedSettings.Add (Data);
      Utility.AutoSizeGridViewColumns (ListViewControl);
      this.HideColumns (8);

      if (((ObservableCollection<CSettingBase>)this.ListViewControl.ItemsSource).FirstOrDefault (x => x.IsGroup == true) == null)
        {
        this.ExpandColumns (1);
        }
      else
        {
        this.ExpandColumns (8);
        }
      }
    }
  }

PerformDragAndDrop

public void PerformDragAndDrop (DependencyObject Origin, ListView List)
  {
  ListViewItem GridRow = Utility.FindAncestor<ListViewItem> (Origin);

  if (GridRow != null)
    {
    CSettingBase Data = (CSettingBase)List.ItemContainerGenerator.ItemFromContainer (GridRow);

    // Initialize the Drag and Drop operation
    DataObject DragData = new DataObject (Strings.DragnDropFormatString, Data);
    DragDrop.DoDragDrop (GridRow, DragData, DragDropEffects.Move);
    }
  }

1 个答案:

答案 0 :(得分:1)

在我看来,问题是您List_*event*正在触发,而不是ComboBox事件。

我认为这是有道理的 - 除非我错过了什么......:)

原因是,它们都是控件,但其中一个包含在另一个控件中。因此,举例来说,如果您的ListView是全屏的,那么每次点击任何内容时,

private void List_PreviewMouseLeftButtonDown (object Sender, MouseEventArgs E)
  {
  startPoint_ = E.GetPosition (null);
  }

仍在被触发。

同样, 每次 你的鼠标光标都会移动,你就会触发:

private void List_MouseMove (object Sender, MouseEventArgs E)
{
  if (allowDrag_)
  {
     Vector Difference = startPoint_ - E.GetPosition (null);

     if (Mouse.LeftButton == MouseButtonState.Pressed &&
     (Math.Abs (Difference.X) > SystemParameters.MinimumHorizontalDragDistance ||
     Math.Abs (Difference.Y) > SystemParameters.MinimumVerticalDragDistance))
     {
       PerformDragAndDrop ((DependencyObject)E.OriginalSource, (ListView)Sender);
     }
  }
}

您可以通过在调试时单步调试代码来检查这一点,或者在这些事件上设置断点,并在尝试操作从属控件时查看它们是否被触发。

最后,如果它们是,你可以简单地在你的代码中放一个子句来检查实际上有什么焦点,并确保它是listview。这样做的问题是,即使激活了子控件,它也可能保持焦点。采取相同行动的另一种方式是确保没有孩子有焦点。这将是更多的代码,因为您要检查包含的每个元素而不是包含的元素。但是,你可能只是使用一种方法来检查这一点。例如:

private void List_PreviewMouseLeftButtonDown (object Sender, MouseEventArgs E)
{
  var fs = GetFocusScope(myComboBox);
  IInputElement fe = FocusManager.GerFocusedElement(fs);

  if (fe == myListView)
  {
      startPoint_ = E.GetPosition (null);
  }
}

private bool focusCheck()
{
    bool childFocused;
    var fs = GetFocusScope(myComboBox);
    IInputElement fe = FocusManager.GetFocusedElement(fs);

    if (fe == myComboBox) { childFocused = true; }
    if (fe == myButton) { childFocused = true; }
    // then repeat the above for every control contained by your list view.
    return childFocused;
}
private void List_PreviewMouseLeftButtonDown (object Sender, MouseEventArgs E)
{
  if (focusCheck() == false) // add this to each event you want to toggle activity of.
  {
      startPoint_ = E.GetPosition (null);
  }
}

无论如何,我根本没有测试过这个,但它可以工作。也许它至少可以帮助你思考一个新的方向!