3

以下のコードを参照してください
Visual Studio 2010
ListBox の上に TextBox があります。
バインディングを介して、アイテムが選択されたときに 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 は 1 回のクリックで最大 3 つの選択を取得していました)。

コードは次のとおりです。

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 を実装する必要はないので、それを削除して 2 つの依存関係プロパティを設定するだけです)が、設定する前にマウスをキャプチャするだけで、元のコードで問題を解決することができますBoundText を作成してから解放します。

于 2013-02-07T18:58:05.380 に答える
1

Thread.Sleep問題を解決するためにセッターを追加できBoundListSelectedますが、この状況ではグリッド列を使用する方が良い解決策だと思います。列を使用する場合は、使用する必要はありません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 に答える