2013-02-07 223 views
3

查看下面的代码
Visual Studio 2010
列表框上方有一个文本框。
选中某个项目时,通过绑定TextBox可以变大或变小。
这会导致ListBox移动。
当ListBox移动选定的项目不是被点击的项目。
所选项目是移动列表框上的鼠标下的项目。
有时它甚至不会选择(尝试从9到10或从10到9)。
在此代码中重现问题的奇偶产生不同的长度。
所以,如果你从奇数到奇数甚至到没有问题。
如果你从奇数顶部到底部(没有滚动),那么有时会选择一个甚至不在视图中的项目。
在实际代码中,文本框是对项目的描述,描述的长度也不相同。
有趣的是在调试和get {return boundText; }然后它会选择适当的项目。
我认为它处理选择,然后衡量用户界面,然后在新的用户界面上再次处理选择。
由于它在调试中表现不同,所以很难弄清楚。列表框未选择所选项目

<Window x:Class="ListBoxMissClick.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525" 
     DataContext="{Binding RelativeSource={RelativeSource Self}}"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition Height="*"/> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="*"/> 
     </Grid.ColumnDefinitions> 
     <TextBox Grid.Row="0" Grid.Column="0" Text="{Binding Path=BoundText}" TextWrapping="Wrap" /> 
     <ListBox Grid.Row="1" Grid.Column="0" ItemsSource="{Binding Path=BoundList}" SelectedItem="{Binding Path=BoundListSelected, Mode=TwoWay}"/> 
    </Grid> 
</Window> 

using System.ComponentModel; 

namespace ListBoxMissClick 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window, INotifyPropertyChanged 
    { 
     private string boundListSelected; 
     private string boundText = string.Empty; 
     private List<string> boundList = new List<string>(); 
     private bool shortLong = true; 
     public event PropertyChangedEventHandler PropertyChanged; 

     protected void NotifyPropertyChanged(String info) 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs(info)); 
      } 
     } 

     public MainWindow() 
     { 
      for (int i = 0; i < 1000; i++) 
      { 
       boundList.Add(i.ToString()); 
      } 

      InitializeComponent(); 

     } 
     public string BoundText 
     { 
      get { return boundText; } 
      set 
      { 
       if (boundText != value) 
       { 
        boundText = value; 
        NotifyPropertyChanged("BoundText"); 
       } 
      } 
     } 
     public List<string> BoundList { get { return boundList; } } 
     public string BoundListSelected 
     { 
      get { return boundListSelected; } 
      set 
      { 
       boundListSelected = value; 
       if (Int32.Parse(value) % 2 == 0) 
       { 
        BoundText = value.ToString() + " something very long something very long something very long something very long something very long something very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very long"; 
       } 
       else 
       { 
        BoundText = value.ToString() + " something short "; 
       } 
      } 
     } 

     private void ListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e) 
     { 
      BoundText = " something very long something very long something very long something very long something very long something very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very long"; 
     } 
    } 
} 

除了接受的答案Mouse.Capture和ReleaseMouseCapture的工作。

set 
{ 
    Mouse.Capture(this); 
    { 
     boundListSelected = value; 
     if (Int32.Parse(value) % 2 == 0) 
     { 
      BoundText = value.ToString() + " something very long something very long something very long something very long something very long something very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very long"; 
     } 
     else 
     { 
      BoundText = value.ToString() + " something short "; 
     } 
    } 
    ReleaseMouseCapture(); 
} 
+0

呵呵,是的,如果你只是把鼠标放下,它真的很有趣。所以,布局被更新,鼠标下面的ListBoxItem现在说:“耶!鼠标关闭了,我被选中了!”它有一个突破点时它的唯一原因是它让你有机会在循环继续之前获得鼠标按钮。不幸的是,我不知道如何解决它 - 我试图捕获鼠标事件,并设置一个标志来强制进一步选择,直到鼠标上升,但我无法让它工作。祝你好运! – Jelly

回答

4

我已经重写你的代码位。诀窍是使用MouseCapture来避免进行多个事件处理(使用您的原始代码,由于鼠标按钮被按下时布局发生变化,listBox最多可进行三次选择以获得单击)

以下是代码:

MainWindow.xaml

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     x:Class="TextEditor.MainWindow" 
     Title="MainWindow" Height="350" Width="525"> 

    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition Height="*"/> 
     </Grid.RowDefinitions> 
     <TextBox Grid.Row="0" Text="{Binding Path=BoundText}" TextWrapping="Wrap" /> 
     <ListBox Grid.Row="1" 
       ItemsSource="{Binding Path=BoundList}" 
       SelectedItem="{Binding Path=BoundListSelected, Mode=TwoWay}"/> 
    </Grid> 

</Window> 

MainWindow.xaml.cs

using System; 
using System.Collections.Generic; 
using System.Windows; 
using System.Windows.Input; 

namespace TextEditor 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public string BoundText 
     { 
      get { return (string)GetValue(BoundTextProperty); } 
      set { SetValue(BoundTextProperty, value); } 
     } 

     // Using a DependencyProperty as the backing store for BoundText. This enables animation, styling, binding, etc... 
     public static readonly DependencyProperty BoundTextProperty = 
      DependencyProperty.Register("BoundText", typeof(string), typeof(MainWindow), new PropertyMetadata(string.Empty)); 

     public string BoundListSelected 
     { 
      get { return (string)GetValue(BoundListSelectedProperty); } 
      set { SetValue(BoundListSelectedProperty, value); } 
     } 

     // Using a DependencyProperty as the backing store for BoundListSelected. This enables animation, styling, binding, etc... 
     public static readonly DependencyProperty BoundListSelectedProperty = 
      DependencyProperty.Register("BoundListSelected", typeof(string), typeof(MainWindow), new PropertyMetadata(string.Empty, OnBoundListSelectedChanged)); 

     private static void OnBoundListSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      var mainWindow = d as MainWindow; 
      var value = e.NewValue as string; 

      Mouse.Capture(mainWindow); 

      if (Int32.Parse(value) % 2 == 0) 
      { 
       mainWindow.BoundText = value.ToString() + " something very long something very long something very long something very long something very long something very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very long"; 
      } 
      else 
      { 
       mainWindow.BoundText = value.ToString() + " something short "; 
      } 

      mainWindow.ReleaseMouseCapture(); 
     } 

     public MainWindow() 
     { 
      for (int i = 0; i < 1000; i++) 
      { 
       boundList.Add(i.ToString()); 
      } 

      InitializeComponent(); 
      DataContext = this; 
     } 

     public List<string> BoundList { get { return boundList; } } 
     private List<string> boundList = new List<string>(); 
    } 
} 

编辑:我实际上改变了MainWindow编码的方式(没有必要在DependencyObject上实现INotifyPropertyChanged,所以我只是删除它并设置了两个依赖属性),但是你可以试着用你的ogirinal代码简单地解决你的问题在设置BoundText之前捕获鼠标,然后释放它。

+0

+1工作。如果在接下来的一小时内没有更短的时间出现,将会给你一张支票。我能够捕捉到鼠标,并确定了第一个选择。但我无法弄清楚如何释放鼠标。 – Paparazzi

+0

很高兴我能帮到你。释放鼠标是通过调用以前捕获它的UIElement上的ReleaseMouseCapture()方法完成的。) – Sisyphe

+0

Mouse.Capture和ReleaseMouseCapture的工作原理是我用的解决方案,因为代码更改少,我对DependencyProperty不熟悉。您是否看到该解决方案存在任何风险。再次感谢。 – Paparazzi

1

可以在BoundListSelected二传手添加Thread.Sleep解决你的问题,但我认为更好的解决方案将是在这种情况下,使用格列。当你使用列时,你不需要使用Thread.Sleep

public string BoundListSelected 
{ 
    get { return boundListSelected; } 
    set 
    { 
     Thread.Sleep(TimeSpan.FromSeconds(.2)); 
     boundListSelected = value; 
     if (Int32.Parse(value) % 2 == 0) 
     { 
      BoundText = value.ToString() + " something very long something very long something very long something very long something very long something very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very longsomething very long something very long something very long something very long something very long"; 
     } 
     else 
     { 
      BoundText = value.ToString() + " something short "; 
     } 
    } 
} 

如果你想不使用Thread.Sleep您可以使用网格列:

<Grid> 
    <Grid.ColumnDefinitions>    
     <ColumnDefinition Width="*"/> 
     <ColumnDefinition Width="*"/> 
    </Grid.ColumnDefinitions> 
    <TextBox Grid.Column="0" Text="{Binding Path=BoundText}" TextWrapping="Wrap" /> 
    <ListBox Grid.Column="1" ItemsSource="{Binding Path=BoundList}" SelectedItem="{Binding Path=BoundListSelected, Mode=TwoWay}"/> 
</Grid> 
+0

我尝试过列,但没有为我工作。查看更新问题。 – Paparazzi

+0

睡在.2将仍然失败,只是不经常。几乎所有的时间都在.1睡眠失败。 – Paparazzi

+0

@Blam检查我的答案,我将示例代码添加到网格与列。 – kmatyaszek