3

请参阅下面的代码
Visual Studio 2010
ListBox 上方有一个 TextBox。
通过绑定文本框可以在选择项目时变大或变小。
这会导致 ListBox 移动。
当 ListBox 移动所选项目时,不是被单击的项目。
所选项目是移动的 ListBox 上鼠标下的项目。
有时它甚至根本不会选择(尝试从 9 到 10 或从 10 到 9)。
在此代码中重现问题的偶数和奇数产生不同的长度。
因此,如果您从奇数到奇数或偶数到偶数,则没有问题。
如果您从顶部的奇数到底部的偶数(不滚动),那么有时会选择一个不在视图中的项目。
在实际代码中,TextBox 是对项目的描述,并且描述的长度不同。
有趣的是在调试中,在 get { return boundText; 上有一个断点;} 然后它确实选择了正确的项目。
我认为它会处理选择,然后测量 UI,然后在新 UI 上再次处理选择。
由于它在调试中的行为不同,因此很难弄清楚。

<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();
}
4

2 回答 2

4

我已经稍微改写了你的代码。诀窍是使用 MouseCapture 来避免处理多个事件(使用您的原始代码,由于在按下鼠标按钮时布局发生了变化,因此 listBox 一次单击最多可以选择三个)

这是代码:

主窗口.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>

主窗口.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,所以我只是删除了它并设置了两个依赖属性)但是您可以尝试通过在设置之前简单地捕获鼠标来解决您的原始代码问题BoundText,然后释放它。

于 2013-02-07T18:58:05.380 回答
1

您可以添加setterThread.SleepBoundListSelected解决您的问题,但我认为更好的解决方案是在这种情况下使用网格列。当您使用列时,您不需要使用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>
于 2013-02-07T17:31:28.227 回答