2013-02-07 224 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