我有一系列可选的TextBoxes。我需要能够单击其中一个并选择鼠标移动的所有文本框,直到释放单击。
我使用了以下代码但是我无法在其他TextBox上点击MouseMove。它总是击中发出Click的TextBox。
class SelectableTextBox: TextBox
{
public Boolean IsSelected { get; protected set; }
public void select(Boolean value)
{
this.IsSelected = value;
if (value)
{
this.Background = System.Windows.Media.Brushes.Aqua;
}
else
{
this.Background = System.Windows.Media.Brushes.White;
}
}
}
private void onPreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
SelectableTextBox textBox = (SelectableTextBox)sender;
this.SelectionStartedRight = !textBox.IsSelected;
textBox.select(!textBox.IsSelected);
}
private void onPreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
SelectableTextBox textBox = (SelectableTextBox)sender;
if (this.SelectionStartedRight)
{
textBox.select(true);
}
}
private void onPreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
SelectableTextBox textBox = (SelectableTextBox)sender;
this.SelectionStartedRight = false;
}
答案 0 :(得分:4)
尝试使用MouseEnter
事件代替MouseMove
。将MouseEnter
附加到您选择的文本框中。这将确保只触发所需的事件处理程序及其代码。
如果您决定继续使用全局处理程序,请在将sender
转换为特定控件类型时小心。当不是“预期”控制时,你需要考虑那些时间:
SelectableTextBox textBox = sender as SelectableTextBox;
if (textBox != null)
{
// The rest of the code here...
}
select
是一个Linq
关键字,因此您可能希望重命名该方法,以避免任何冲突。虽然我认为这不会引起任何问题,但我会改变它。
您不必遵循此约定,但在C#
习惯使用大写字母作为方法的第一个字母。另请注意,类的默认访问修饰符为internal
...只是为了确保您知道这一点,因为您继续开发。
您的上一个方法onPreviewMouseLeftButtonUp(...)
中包含以下代码:
SelectableTextBox textBox = (SelectableTextBox)sender;
正如我上面所描述的那样,它不仅不安全,而且它也绝对没有。
最后......这就是我,我可能会移动代码来处理将可选文本框(选中或未选中)的状态更改为其类,因为它属于那里。为什么其他任何东西应该负责它如何处理它的状态。保留他们所属的东西,您可以更轻松地测试,调试和维护代码。不要陷入“我稍后会重构它”陷阱......它很少会发生。
这是我粗略的例子。我让该类处理其MouseEnter
事件,并检查当时Mouse.LeftButton
是否已关闭。你必须扩展它,但它应该是一个坚实的开始:
在评论中对每个OP的请求进行了一些修改。
预览强>
<强> XAML:强>
<Window x:Class="SelectableTextBoxes.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SelectableTextBoxes"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<local:SelectableTextBox Height="20" Width="100" Margin="10"/>
<local:SelectableTextBox Height="20" Width="100" Margin="10"/>
<local:SelectableTextBox Height="20" Width="100" Margin="10"/>
<local:SelectableTextBox Height="20" Width="100" Margin="10"/>
<local:SelectableTextBox Height="20" Width="100" Margin="10"/>
</StackPanel>
</Window>
C#(请原谅我将SelectableTextBox
放入同一个文件中......):
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace SelectableTextBoxes
{
// Move this class into its own file (it's here for prototyping).
public class SelectableTextBox : TextBox
{
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
if (_isSelected != value)
{
_isSelected = value;
// If the value changes, sets new color.
SetSelectionColor();
}
}
}
public SelectableTextBox()
{
// For handling an initial click if it happens in the textbox.
PreviewMouseDown += SelectableTextBox_PreviewMouseDown;
// For handling selection when mouse enters the textbox
// and left mouse button is down.
MouseEnter += SelectableTextBox_MouseEnter;
// To handle mouse capture (release it).
GotMouseCapture += SelectableTextBox_GotMouseCapture;
}
// Handles the mouse down event within the textbox.
void SelectableTextBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (!IsSelected)
{
IsSelected = true;
}
// If one of the Shift keys is down, return, since
// we don't want to deselect others.
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
{
return;
}
// This part makes a poor assumption that the parent is
// always going to be a Panel... expand on this code to
// cover other types that may contain more than one element.
var parent = VisualTreeHelper.GetParent(this) as Panel;
if (parent != null)
{
foreach (var child in parent.Children)
{
// If a child is not of a correct type, it'll be null.
var tbx = child as SelectableTextBox;
// This is where we check to see if it's null or this instance.
if (tbx != null && tbx != this)
{
tbx.IsSelected = false;
}
}
}
}
// When textbox receives focus, this event fires... we need to release
// the mouse to continue selection.
void SelectableTextBox_GotMouseCapture(object sender, MouseEventArgs e)
{
ReleaseMouseCapture();
}
// Sets selection state to true if the left mouse button is
// down while entering.
void SelectableTextBox_MouseEnter(object sender, MouseEventArgs e)
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
IsSelected = true;
}
}
// Sets the background color based on selection state.
private void SetSelectionColor()
{
if (IsSelected)
{
Background = Brushes.LightCyan;
}
else
{
Background = Brushes.White;
}
}
}
// Window code... should be on its own, but I placed the two
// classes together while prototyping.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}