问题
See code below
Visual Studio 2010
Above the ListBox have a TextBox.
Via binding the TextBox can get bigger or smaller when an item is selected.
That causes the ListBox to move.
When the ListBox moves the selected item is NOT the item that was clicked.
The selected item is the item under the mouse on the moved ListBox.
Some times it will not even select at all (try and go from 9 to 10 or from 10 to 9).
In this code to reproduce the problem even and odd produce different lengths.
So if you go from odd to odd or even to even then no problem.
If you go from on odd at the top an even at the bottom (without scrolling) then sometimes an item that was not even in view will be selected.
In the real code the TextBox is a description of the item and the descriptions are different lengths.
Interesting is in debug and there is a break point on get { return boundText; } then it does select the proper item.
I think it processes the select, then measures out the UI, and then processes the select a second time on the new UI.
Since it behaves different in debug it is hard to figure out.
<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";
}
}
}
In addition to the accepted answer Mouse.Capture and ReleaseMouseCapture work.
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();
}
回答1:
I've rewritten your code a bit. The trick is to use a MouseCapture to avoid having multiple event handling (with your original code, the listBox was getting up to three selection for a single click due to the layout changeing while mouse button was pressed)
Here is the code :
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>();
}
}
Edit : I actually changed the way MainWindow was coded (it's not necessary to implement INotifyPropertyChanged on a DependencyObject, so i just removed it and set two dependency properties) but you could try solving your issue with your ogirinal code by simply capturing the mouse before setting BoundText, and then releasing it.
回答2:
You can add Thread.Sleep
in BoundListSelected
setter to solve your problem, but I think that better solution will be using grid columns in this situation. When you use columns you need not to use 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 ";
}
}
}
If you want not use Thread.Sleep
you can use grid with columns:
<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>
来源:https://stackoverflow.com/questions/14755878/listbox-not-selecting-the-selected-item