我正在创建一个简单的自动完成文本框,并且有一个值列表,如果用户开始在其中输入任何字符串,则会显示相应的字符串。
现在我已经为我的ViewModel创建了一个带有Binding属性的Textbox:
<TextBox Text="{Binding ServerURL, UpdateSourceTrigger=PropertyChanged}" />
因此,当用户输入一个新角色时,它将触发我的属性被触发,因此触发一个方法,该方法将检索与之相关的值。
private string _serverURL;
public string ServerURL {
get { return _serverURL; }
set
{
_serverURL = value;
ServerURL_TextChanged();
OnPropertyChanged("ServerURL");
}
}
然后,该方法将使用字符串引用的结果填充ListBox。
当我从ListBox中选择一个值时,我想将Full字符串值设置为TextBox文本属性,但是当我这样做时,它会触发方法ServerURL_TextChanged()。
有没有办法可以设置ServerURL属性,但不能在其中激活方法?
答案 0 :(得分:2)
对于解决方案,需要分离设置ServerURL属性的方式。
public string ServerURL {
get { return _serverURL; }
set
{
setServerURL(value, isSetByUser = true);
}
}
private function void setServerURL(string value, bool isSetByUser){
_serverURL = value;
ServerURL_TextChanged(isSetByUser);
OnPropertyChanged("ServerURL");
}
更改列表后,您可以从代码setServerURL(someValue, isSetByUser = false);
拨打电话
然后在ServerURL_TextChanged
实现决定如何处理它。
答案 1 :(得分:-1)
实现此功能的最简单方法是处理代码隐藏中的TextChanged事件,您可以完全控制此类决策的UI。它不违反MVVM原则来管理代码隐藏的UI操作。
以下是此类代码隐藏实现的示例。您可能会发现它很有用。
public partial class AutoCompleteComboBox : UserControl
{
private Window w;
public AutoCompleteComboBox()
{
InitializeComponent();
}
~AutoCompleteComboBox()
{
if(w == null)
{
return;
}
else
{
w.MouseLeftButtonDown -= Window_MouseLeftDown;
}
}
#region Behaviours
public void FocusTextBox()
{
txt.Focus();
txt.CaretIndex = txt.Text.Length;
}
#endregion
#region DependencyProperties
public static readonly DependencyProperty InputPaddingProperty =
DependencyProperty.Register(
"InputPadding",
typeof(Thickness),
typeof(AutoCompleteComboBox)
);
public Thickness InputPadding
{
get
{
return (Thickness)GetValue(InputPaddingProperty);
}
set
{
SetValue(InputPaddingProperty, value);
}
}
public static readonly DependencyProperty TextBoxHeightProperty =
DependencyProperty.Register(
"TextBoxHeight",
typeof(double),
typeof(AutoCompleteComboBox)
);
public double TextBoxHeight
{
get
{
return (double)GetValue(TextBoxHeightProperty);
}
set
{
SetValue(TextBoxHeightProperty, value);
}
}
public static readonly DependencyProperty ItemPanelMaxHeightProperty =
DependencyProperty.Register(
"ItemPanelMaxHeight",
typeof(double),
typeof(AutoCompleteComboBox)
);
public double ItemPanelMaxHeight
{
get
{
return (double)GetValue(ItemPanelMaxHeightProperty);
}
set
{
SetValue(ItemPanelMaxHeightProperty, value);
}
}
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register(
"ItemsSource",
typeof(IEnumerable),
typeof(AutoCompleteComboBox)
);
public IEnumerable ItemsSource
{
get
{
return (IEnumerable)ItemsSource;
}
set
{
SetValue(ItemsSourceProperty, value);
}
}
public static readonly DependencyProperty DisplayMemberPathProperty =
DependencyProperty.Register(
"DisplayMemberPath",
typeof(string),
typeof(AutoCompleteComboBox)
);
public string DisplayMemberPath
{
get
{
return GetValue(DisplayMemberPathProperty).ToString();
}
set
{
SetValue(DisplayMemberPathProperty, value);
}
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register(
"Text",
typeof(string),
typeof(AutoCompleteComboBox),
new FrameworkPropertyMetadata(
"",
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault
)
);
public string Text
{
get
{
return GetValue(TextProperty).ToString();
}
set
{
SetValue(TextProperty, value);
}
}
public string TargetValue { get; set; } = "";
public static readonly DependencyProperty IsDropDownOpenProperty =
DependencyProperty.Register(
"IsDropDownOpen",
typeof(bool),
typeof(AutoCompleteComboBox),
new FrameworkPropertyMetadata(
false,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault
)
);
public bool IsDropDownOpen
{
get
{
return (bool)GetValue(IsDropDownOpenProperty);
}
set
{
SetValue(IsDropDownOpenProperty, value);
}
}
#endregion
#region Events
private void me_Loaded(object sender, RoutedEventArgs e)
{
w = VisualTreeHelpers.FindAncestor<Window>(this);
w.MouseLeftButtonDown += Window_MouseLeftDown;
FocusTextBox();
}
private void Window_MouseLeftDown(object sender, MouseButtonEventArgs e)
{
IsDropDownOpen = false;
}
private void lst_KeyDown(object sender, KeyEventArgs e)
{
}
private void lst_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (TargetValue != null && TargetValue.Trim().Length > 0)
{
txt.Text = TargetValue;
IsDropDownOpen = false;
}
FocusTextBox();
}
private void lst_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
}
private void lst_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (lst.SelectedItem != null)
{
TargetValue = lst.SelectedItem.ToString();
}
}
private void txt_LostFocus(object sender, RoutedEventArgs e)
{
if (lst.IsFocused == false)
{
IsDropDownOpen = false;
FocusTextBox();
}
}
private void lst_LostFocus(object sender, RoutedEventArgs e)
{
MessageBox.Show("text changed");
if (txt.IsFocused == false)
{
IsDropDownOpen = false;
}
}
private void txt_TextChanged(object sender, TextChangedEventArgs e)
{
IsDropDownOpen = true;
}
private void txt_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (IsDropDownOpen && lst.Items.Count > 0)
{
if (lst.SelectedIndex < 0)
{
lst.SelectedIndex = 0;
}
if (e.Key == Key.Up && lst.SelectedIndex > 0)
{
lst.SelectedIndex--;
}
else if (e.Key == Key.Down && lst.SelectedIndex < lst.Items.Count - 1)
{
lst.SelectedIndex++;
}
else if(e.Key == Key.Enter || e.Key == Key.Tab)
{
if(lst.SelectedIndex > -1)
{
txt.Text = TargetValue;
IsDropDownOpen = false;
FocusTextBox();
}
}
}
}
#endregion
}
这里是XAML
<UserControl x:Class="SHARED_COMPONENTS.AutoCompleteComboBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
x:Name="me"
Loaded="me_Loaded"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<TextBox
x:Name="txt"
Background="CornflowerBlue"
Foreground="White"
Grid.Row="0"
Text="{Binding ElementName=me, Path=Text,UpdateSourceTrigger=PropertyChanged}"
TextChanged="txt_TextChanged" PreviewKeyDown="txt_PreviewKeyDown"
Height="{Binding ElementName=me, Path=ActualHeight}"
Padding="{Binding ElementName=me,Path=InputPadding}"
/>
<Popup IsOpen="{Binding ElementName=me, Path=IsDropDownOpen}" ClipToBounds="False">
<Border Grid.Row="1">
<Border.Effect>
<DropShadowEffect Color="Black" />
</Border.Effect>
<ListBox
x:Name="lst"
Grid.Row="1"
ItemsSource="{Binding ElementName=me, Path=ItemsSource}"
PreviewKeyDown="lst_KeyDown"
SelectionChanged="lst_SelectionChanged"
PreviewMouseLeftButtonDown="lst_MouseLeftButtonDown"
PreviewMouseLeftButtonUp="lst_PreviewMouseLeftButtonUp"
DisplayMemberPath="{Binding ElementName=me, Path=DisplayMemberPath }"
ClipToBounds="False"
>
<ListBox.Style>
<Style TargetType="ListBox">
<Setter Property="Background" Value="#f0f0f0" />
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=lst, Path=HasItems}" Value="True" />
<Condition Binding="{Binding ElementName=me, Path=IsDropDownOpen}" Value="True" />
</MultiDataTrigger.Conditions>
<Setter Property="Visibility" Value="Visible" />
</MultiDataTrigger>
<DataTrigger Binding="{Binding ElementName=me, Path=IsDropDownOpen}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="True">
<Setter Property="IsSelected" Value="True" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="True">
<Setter Property="Foreground" Value="CornflowerBlue" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
</ListBox>
</Border>
</Popup>
</Grid>
</Grid>
</UserControl>