using System;
using System.Windows.Data;
using System.Windows;
namespace WaterMarkTextBoxDemo{publicclassTextInputToVisibilityConverter:IMultiValueConverter{publicobjectConvert(object[] values,Type targetType,object parameter,System.Globalization.CultureInfo culture ){// Always test MultiValueConverter inputs for non-null// (to avoid crash bugs for views in the designer)if(values[0]isbool&& values[1]isbool){bool hasText =!(bool)values[0];bool hasFocus =(bool)values[1];if(hasFocus || hasText)returnVisibility.Collapsed;}returnVisibility.Visible;}publicobject[]ConvertBack(objectvalue,Type[] targetTypes,object parameter,System.Globalization.CultureInfo culture ){thrownewNotImplementedException();}}}
Catatan: Ini bukan kode saya. Saya menemukannya di sini , tetapi saya pikir ini adalah pendekatan terbaik.
Bagaimana saya bisa menerapkannya di kotak kata sandi?
Sauron
91
Pendekatan terbaik? tentu tidak! Apakah Anda benar-benar ingin mengetikkan begitu banyak baris kode setiap kali Anda memerlukan tanda air? Solusi dengan properti terlampir jauh lebih mudah untuk digunakan kembali ...
Thomas Levesque
5
Pertimbangkan untuk membuat UserControl.
CSharper
6
Sementara saya sangat menghargai upaya Anda untuk membantu masyarakat, saya benar-benar perlu mengatakan ini masih jauh dari pendekatan yang layak.
r41n
2
Kode ini dibuat oleh Andy L. Anda dapat menemukannya di proyek codep .
aloisdg pindah ke codidact.com
440
Anda dapat membuat tanda air yang dapat ditambahkan ke sembarang TextBoxdengan Properti Terlampir. Berikut adalah sumber untuk Properti Terlampir:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;/// <summary>/// Class that provides the Watermark attached property/// </summary>publicstaticclassWatermarkService{/// <summary>/// Watermark Attached Dependency Property/// </summary>publicstaticreadonlyDependencyPropertyWatermarkProperty=DependencyProperty.RegisterAttached("Watermark",typeof(object),typeof(WatermarkService),newFrameworkPropertyMetadata((object)null,newPropertyChangedCallback(OnWatermarkChanged)));#region Private Fields/// <summary>/// Dictionary of ItemsControls/// </summary>privatestaticreadonlyDictionary<object,ItemsControl> itemsControls =newDictionary<object,ItemsControl>();#endregion/// <summary>/// Gets the Watermark property. This dependency property indicates the watermark for the control./// </summary>/// <param name="d"><see cref="DependencyObject"/> to get the property from</param>/// <returns>The value of the Watermark property</returns>publicstaticobjectGetWatermark(DependencyObject d){return(object)d.GetValue(WatermarkProperty);}/// <summary>/// Sets the Watermark property. This dependency property indicates the watermark for the control./// </summary>/// <param name="d"><see cref="DependencyObject"/> to set the property on</param>/// <param name="value">value of the property</param>publicstaticvoidSetWatermark(DependencyObject d,objectvalue){
d.SetValue(WatermarkProperty,value);}/// <summary>/// Handles changes to the Watermark property./// </summary>/// <param name="d"><see cref="DependencyObject"/> that fired the event</param>/// <param name="e">A <see cref="DependencyPropertyChangedEventArgs"/> that contains the event data.</param>privatestaticvoidOnWatermarkChanged(DependencyObject d,DependencyPropertyChangedEventArgs e){Control control =(Control)d;
control.Loaded+=Control_Loaded;if(d isComboBox){
control.GotKeyboardFocus+=Control_GotKeyboardFocus;
control.LostKeyboardFocus+=Control_Loaded;}elseif(d isTextBox){
control.GotKeyboardFocus+=Control_GotKeyboardFocus;
control.LostKeyboardFocus+=Control_Loaded;((TextBox)control).TextChanged+=Control_GotKeyboardFocus;}if(d isItemsControl&&!(d isComboBox)){ItemsControl i =(ItemsControl)d;// for Items property
i.ItemContainerGenerator.ItemsChanged+=ItemsChanged;
itemsControls.Add(i.ItemContainerGenerator, i);// for ItemsSource property DependencyPropertyDescriptor prop =DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, i.GetType());
prop.AddValueChanged(i,ItemsSourceChanged);}}#region Event Handlers/// <summary>/// Handle the GotFocus event on the control/// </summary>/// <param name="sender">The source of the event.</param>/// <param name="e">A <see cref="RoutedEventArgs"/> that contains the event data.</param>privatestaticvoidControl_GotKeyboardFocus(object sender,RoutedEventArgs e){Control c =(Control)sender;if(ShouldShowWatermark(c)){ShowWatermark(c);}else{RemoveWatermark(c);}}/// <summary>/// Handle the Loaded and LostFocus event on the control/// </summary>/// <param name="sender">The source of the event.</param>/// <param name="e">A <see cref="RoutedEventArgs"/> that contains the event data.</param>privatestaticvoidControl_Loaded(object sender,RoutedEventArgs e){Control control =(Control)sender;if(ShouldShowWatermark(control)){ShowWatermark(control);}}/// <summary>/// Event handler for the items source changed event/// </summary>/// <param name="sender">The source of the event.</param>/// <param name="e">A <see cref="EventArgs"/> that contains the event data.</param>privatestaticvoidItemsSourceChanged(object sender,EventArgs e){ItemsControl c =(ItemsControl)sender;if(c.ItemsSource!=null){if(ShouldShowWatermark(c)){ShowWatermark(c);}else{RemoveWatermark(c);}}else{ShowWatermark(c);}}/// <summary>/// Event handler for the items changed event/// </summary>/// <param name="sender">The source of the event.</param>/// <param name="e">A <see cref="ItemsChangedEventArgs"/> that contains the event data.</param>privatestaticvoidItemsChanged(object sender,ItemsChangedEventArgs e){ItemsControl control;if(itemsControls.TryGetValue(sender,out control)){if(ShouldShowWatermark(control)){ShowWatermark(control);}else{RemoveWatermark(control);}}}#endregion#region Helper Methods/// <summary>/// Remove the watermark from the specified element/// </summary>/// <param name="control">Element to remove the watermark from</param>privatestaticvoidRemoveWatermark(UIElement control){AdornerLayer layer =AdornerLayer.GetAdornerLayer(control);// layer could be null if control is no longer in the visual treeif(layer !=null){Adorner[] adorners = layer.GetAdorners(control);if(adorners ==null){return;}foreach(Adorner adorner in adorners){if(adorner isWatermarkAdorner){
adorner.Visibility=Visibility.Hidden;
layer.Remove(adorner);}}}}/// <summary>/// Show the watermark on the specified control/// </summary>/// <param name="control">Control to show the watermark on</param>privatestaticvoidShowWatermark(Control control){AdornerLayer layer =AdornerLayer.GetAdornerLayer(control);// layer could be null if control is no longer in the visual treeif(layer !=null){
layer.Add(newWatermarkAdorner(control,GetWatermark(control)));}}/// <summary>/// Indicates whether or not the watermark should be shown on the specified control/// </summary>/// <param name="c"><see cref="Control"/> to test</param>/// <returns>true if the watermark should be shown; false otherwise</returns>privatestaticboolShouldShowWatermark(Control c){if(c isComboBox){return(c asComboBox).Text==string.Empty;}elseif(c isTextBoxBase){return(c asTextBox).Text==string.Empty;}elseif(c isItemsControl){return(c asItemsControl).Items.Count==0;}else{returnfalse;}}#endregion}
Properti Terlampir menggunakan kelas yang disebut WatermarkAdorner, di sini adalah sumber itu:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;/// <summary>/// Adorner for the watermark/// </summary>internalclassWatermarkAdorner:Adorner{#region Private Fields/// <summary>/// <see cref="ContentPresenter"/> that holds the watermark/// </summary>privatereadonlyContentPresenter contentPresenter;#endregion#region Constructor/// <summary>/// Initializes a new instance of the <see cref="WatermarkAdorner"/> class/// </summary>/// <param name="adornedElement"><see cref="UIElement"/> to be adorned</param>/// <param name="watermark">The watermark</param>publicWatermarkAdorner(UIElement adornedElement,object watermark):base(adornedElement){this.IsHitTestVisible=false;this.contentPresenter =newContentPresenter();this.contentPresenter.Content= watermark;this.contentPresenter.Opacity=0.5;this.contentPresenter.Margin=newThickness(Control.Margin.Left+Control.Padding.Left,Control.Margin.Top+Control.Padding.Top,0,0);if(this.ControlisItemsControl&&!(this.ControlisComboBox)){this.contentPresenter.VerticalAlignment=VerticalAlignment.Center;this.contentPresenter.HorizontalAlignment=HorizontalAlignment.Center;}// Hide the control adorner when the adorned element is hiddenBinding binding =newBinding("IsVisible");
binding.Source= adornedElement;
binding.Converter=newBooleanToVisibilityConverter();this.SetBinding(VisibilityProperty, binding);}#endregion#region Protected Properties/// <summary>/// Gets the number of children for the <see cref="ContainerVisual"/>./// </summary>protectedoverrideintVisualChildrenCount{get{return1;}}#endregion#region Private Properties/// <summary>/// Gets the control that is being adorned/// </summary>privateControlControl{get{return(Control)this.AdornedElement;}}#endregion#region Protected Overrides/// <summary>/// Returns a specified child <see cref="Visual"/> for the parent <see cref="ContainerVisual"/>./// </summary>/// <param name="index">A 32-bit signed integer that represents the index value of the child <see cref="Visual"/>. The value of index must be between 0 and <see cref="VisualChildrenCount"/> - 1.</param>/// <returns>The child <see cref="Visual"/>.</returns>protectedoverrideVisualGetVisualChild(int index){returnthis.contentPresenter;}/// <summary>/// Implements any custom measuring behavior for the adorner./// </summary>/// <param name="constraint">A size to constrain the adorner to.</param>/// <returns>A <see cref="Size"/> object representing the amount of layout space needed by the adorner.</returns>protectedoverrideSizeMeasureOverride(Size constraint){// Here's the secret to getting the adorner to cover the whole controlthis.contentPresenter.Measure(Control.RenderSize);returnControl.RenderSize;}/// <summary>/// When overridden in a derived class, positions child elements and determines a size for a <see cref="FrameworkElement"/> derived class. /// </summary>/// <param name="finalSize">The final area within the parent that this element should use to arrange itself and its children.</param>/// <returns>The actual size used.</returns>protectedoverrideSizeArrangeOverride(Size finalSize){this.contentPresenter.Arrange(newRect(finalSize));return finalSize;}#endregion}
Sekarang Anda dapat meletakkan tanda air di sembarang TextBox seperti ini:
<AdornerDecorator><TextBox x:Name="SearchTextBox"><controls:WatermarkService.Watermark><TextBlock>Type here to search text</TextBlock></controls:WatermarkService.Watermark></TextBox></AdornerDecorator>
Tanda air dapat berupa apa saja yang Anda inginkan (teks, gambar ...). Selain berfungsi untuk TextBoxes, tanda air ini juga berfungsi untuk ComboBoxes dan ItemControls.
Saya telah menyelesaikannya dengan memodifikasi tugas margin konstruktor WatermarkAdorner sebagai: Margin = Ketebalan baru (Control.Padding.Left, Control.Padding.Top + 1, Control.Padding.Right, Control.Padding.Bottom)
JoanComasFdz
3
@JohnMyczek Untuk melokalisasi watermark: bagaimana saya bisa mengikat TextBox.Text dalam deklarasi Watermark xaml ke properti dari ViewModel?
JoanComasFdz
7
@Matze @JoanComasFdz Inilah cara saya dapat mengikat TextBlock.Textproperti ke model tampilan saya (letakkan ini di WatermarkAdornerkonstruktor): FrameworkElement feWatermark = watermark as FrameworkElement;if(feWatermark != null && feWatermark.DataContext == null) { feWatermark.DataContext = this.Control.DataContext; }
Sean Hall
9
Kemungkinan tautan memori di sini. Anda menambahkan kontrol tanda air ke kamus statis internal tetapi tidak pernah menghapusnya. Ini mungkin akan mencegah pandangan Anda dari pengumpulan sampah setelah Anda selesai melakukannya. Saya akan mempertimbangkan untuk menggunakan referensi yang lemah di sini.
Jared G
3
Selain kamus statis itemcontrols, kode PropertyDescriptor juga bocor memori. Anda perlu memanggil RemoveValueChanged (). Jadi berhati-hatilah saat Anda menggunakan kode ini.
muku
284
Hanya menggunakan XAML, tanpa ekstensi, tanpa konverter:
<Grid><TextBoxWidth="250"VerticalAlignment="Center"HorizontalAlignment="Left" x:Name="SearchTermTextBox"Margin="5"/><TextBlockIsHitTestVisible="False"Text="Enter Search Term Here"VerticalAlignment="Center"HorizontalAlignment="Left"Margin="10,0,0,0"Foreground="DarkGray"><TextBlock.Style><StyleTargetType="{x:Type TextBlock}"><SetterProperty="Visibility"Value="Collapsed"/><Style.Triggers><DataTriggerBinding="{Binding Text, ElementName=SearchTermTextBox}"Value=""><SetterProperty="Visibility"Value="Visible"/></DataTrigger></Style.Triggers></Style></TextBlock.Style></TextBlock></Grid>
Yang sangat sederhana, sebaiknya juga. Saya tidak tahu mengapa Anda akan menggunakan semua yang lain ketika Anda bisa memiliki 10 baris skrip xaml ini dan hanya itu. Terima kasih.
dj.lnxss
4
Anda mungkin ingin menambahkan Padding="6,3,0,0"ke TextBlock.
aloisdg pindah ke codidact.com
1
Sangat bagus, tetapi tidak berfungsi pada Windows Phone Silverlight :-(
Andrea Antonangeli
14
Bagaimana cara membuat Template Kontrol ini dapat digunakan kembali?
Richard
2
@cyrianox Ini karena properti Kata Sandi pada Kotak Kata Sandi tidak dapat diikat karena alasan keamanan. Anda dapat membuatnya bindable menggunakan contoh ini di sini: wpftutorial.net/PasswordBox.html namun mungkin lebih cepat dan lebih mudah hanya menggunakan acara yang diubah sandi dan kode di belakang untuk mengatur visibilitas dalam kasus ini.
apc
54
Saya tidak percaya bahwa tidak ada yang memposting Toolkit WPF yang jelas - WatermarkTextBox dari Xceed. Ini bekerja dengan sangat baik dan merupakan sumber terbuka jika Anda ingin menyesuaikan.
Di mesin win8 saya semua kontrol WPF Toolkit memiliki gaya windows 7 (sudut membulat, dll). Dan setiap kontrol toolkit WPF terlihat benar-benar tidak pada tempatnya ketika dicampur dengan kontrol standar.
Gman
1
Pendekatan "Properti Terlampir" oleh John Myczek memiliki bug di mana jika kotak teks ditutupi oleh elemen lain, tanda air akan berdarah dan masih terlihat. Solusi ini tidak memiliki masalah itu. (Seandainya saya perhatikan ini sebelumnya karena saya sudah menggunakan toolkit). Pantas lebih banyak upvotes.
Dax Fohl
Solusi John Myczek juga memiliki kebocoran memori yang jelas, di mana WatermarkService akan menyimpan referensi dalam kamus statis untuk ItemsControl mana watermark terpasang. Ini pasti bisa diperbaiki, tetapi saya akan mencoba versi Extended WPF Toolkit.
Ok, baik itu tidak mungkin 3 baris XAML diformat, tetapi adalah cukup sederhana.
Satu hal yang perlu diperhatikan adalah bahwa ia menggunakan metode ekstensi non-standar pada properti Text, yang disebut "IsEmpty". Anda perlu menerapkan ini sendiri, namun artikel tersebut sepertinya tidak menyebutkannya.
TextBox seharusnya IsHitTestVisible="False". Juga, itu harus datang setelah TextBox, kalau tidak mungkin tidak terlihat jika TextBox memiliki latar belakang.
Saya melihat solusi John Myczek , dan komentarnya tentang Kompatibilitas ke ComboBoxdan PasswordBox, jadi saya meningkatkan solusi John Myczek, dan ini dia:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;/// <summary>/// Class that provides the Watermark attached property/// </summary>publicstaticclassWatermarkService{/// <summary>/// Watermark Attached Dependency Property/// </summary>publicstaticreadonlyDependencyPropertyWatermarkProperty=DependencyProperty.RegisterAttached("Watermark",typeof(object),typeof(WatermarkService),newFrameworkPropertyMetadata((object)null,newPropertyChangedCallback(OnWatermarkChanged)));#region Private Fields/// <summary>/// Dictionary of ItemsControls/// </summary>privatestaticreadonlyDictionary<object,ItemsControl> itemsControls =newDictionary<object,ItemsControl>();#endregion/// <summary>/// Gets the Watermark property. This dependency property indicates the watermark for the control./// </summary>/// <param name="d"><see cref="DependencyObject"/> to get the property from</param>/// <returns>The value of the Watermark property</returns>publicstaticobjectGetWatermark(DependencyObject d){return(object)d.GetValue(WatermarkProperty);}/// <summary>/// Sets the Watermark property. This dependency property indicates the watermark for the control./// </summary>/// <param name="d"><see cref="DependencyObject"/> to set the property on</param>/// <param name="value">value of the property</param>publicstaticvoidSetWatermark(DependencyObject d,objectvalue){
d.SetValue(WatermarkProperty,value);}/// <summary>/// Handles changes to the Watermark property./// </summary>/// <param name="d"><see cref="DependencyObject"/> that fired the event</param>/// <param name="e">A <see cref="DependencyPropertyChangedEventArgs"/> that contains the event data.</param>privatestaticvoidOnWatermarkChanged(DependencyObject d,DependencyPropertyChangedEventArgs e){Control control =(Control)d;
control.Loaded+=Control_Loaded;if(d isTextBox|| d isPasswordBox){
control.GotKeyboardFocus+=Control_GotKeyboardFocus;
control.LostKeyboardFocus+=Control_Loaded;}elseif(d isComboBox){
control.GotKeyboardFocus+=Control_GotKeyboardFocus;
control.LostKeyboardFocus+=Control_Loaded;(d asComboBox).SelectionChanged+=newSelectionChangedEventHandler(SelectionChanged);}elseif(d isItemsControl){ItemsControl i =(ItemsControl)d;// for Items property
i.ItemContainerGenerator.ItemsChanged+=ItemsChanged;
itemsControls.Add(i.ItemContainerGenerator, i);// for ItemsSource property DependencyPropertyDescriptor prop =DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, i.GetType());
prop.AddValueChanged(i,ItemsSourceChanged);}}/// <summary>/// Event handler for the selection changed event/// </summary>/// <param name="sender">The source of the event.</param>/// <param name="e">A <see cref="ItemsChangedEventArgs"/> that contains the event data.</param>privatestaticvoidSelectionChanged(object sender,SelectionChangedEventArgs e){Control control =(Control)sender;if(ShouldShowWatermark(control)){ShowWatermark(control);}else{RemoveWatermark(control);}}#region Event Handlers/// <summary>/// Handle the GotFocus event on the control/// </summary>/// <param name="sender">The source of the event.</param>/// <param name="e">A <see cref="RoutedEventArgs"/> that contains the event data.</param>privatestaticvoidControl_GotKeyboardFocus(object sender,RoutedEventArgs e){Control c =(Control)sender;if(ShouldShowWatermark(c)){RemoveWatermark(c);}}/// <summary>/// Handle the Loaded and LostFocus event on the control/// </summary>/// <param name="sender">The source of the event.</param>/// <param name="e">A <see cref="RoutedEventArgs"/> that contains the event data.</param>privatestaticvoidControl_Loaded(object sender,RoutedEventArgs e){Control control =(Control)sender;if(ShouldShowWatermark(control)){ShowWatermark(control);}}/// <summary>/// Event handler for the items source changed event/// </summary>/// <param name="sender">The source of the event.</param>/// <param name="e">A <see cref="EventArgs"/> that contains the event data.</param>privatestaticvoidItemsSourceChanged(object sender,EventArgs e){ItemsControl c =(ItemsControl)sender;if(c.ItemsSource!=null){if(ShouldShowWatermark(c)){ShowWatermark(c);}else{RemoveWatermark(c);}}else{ShowWatermark(c);}}/// <summary>/// Event handler for the items changed event/// </summary>/// <param name="sender">The source of the event.</param>/// <param name="e">A <see cref="ItemsChangedEventArgs"/> that contains the event data.</param>privatestaticvoidItemsChanged(object sender,ItemsChangedEventArgs e){ItemsControl control;if(itemsControls.TryGetValue(sender,out control)){if(ShouldShowWatermark(control)){ShowWatermark(control);}else{RemoveWatermark(control);}}}#endregion#region Helper Methods/// <summary>/// Remove the watermark from the specified element/// </summary>/// <param name="control">Element to remove the watermark from</param>privatestaticvoidRemoveWatermark(UIElement control){AdornerLayer layer =AdornerLayer.GetAdornerLayer(control);// layer could be null if control is no longer in the visual treeif(layer !=null){Adorner[] adorners = layer.GetAdorners(control);if(adorners ==null){return;}foreach(Adorner adorner in adorners){if(adorner isWatermarkAdorner){
adorner.Visibility=Visibility.Hidden;
layer.Remove(adorner);}}}}/// <summary>/// Show the watermark on the specified control/// </summary>/// <param name="control">Control to show the watermark on</param>privatestaticvoidShowWatermark(Control control){AdornerLayer layer =AdornerLayer.GetAdornerLayer(control);// layer could be null if control is no longer in the visual treeif(layer !=null){
layer.Add(newWatermarkAdorner(control,GetWatermark(control)));}}/// <summary>/// Indicates whether or not the watermark should be shown on the specified control/// </summary>/// <param name="c"><see cref="Control"/> to test</param>/// <returns>true if the watermark should be shown; false otherwise</returns>privatestaticboolShouldShowWatermark(Control c){if(c isComboBox){return(c asComboBox).SelectedItem==null;//return (c as ComboBox).Text == string.Empty;}elseif(c isTextBoxBase){return(c asTextBox).Text==string.Empty;}elseif(c isPasswordBox){return(c asPasswordBox).Password==string.Empty;}elseif(c isItemsControl){return(c asItemsControl).Items.Count==0;}else{returnfalse;}}#endregion}
Sekarang, ComboBoxdapat juga Editable, dan PasswordBoxdapat menambahkan tanda air juga. Jangan lupa untuk menggunakan komentar JoanComasFdz di atas untuk menyelesaikan masalah margin.
Dan, tentu saja, Semua kredit jatuh ke tangan John Myczek.
Solusi bagus Mengapa membayangi properti Foreground? SetBinding (TextProperty, Binding baru ()) melempar InvalidOperationException: Pengikatan dua arah memerlukan Path atau XPath?
Tim Murphy
Saya menyembunyikan properti Foreground karena TextBoxWatermarked menggunakannya untuk tujuannya sendiri. Saya tidak tahu mengapa InvalidOperationException dilempar, mungkin jika Anda menggunakan WPF (saya menggunakannya dengan Silverlight), Anda harus melewati null alih-alih Binding baru ().
Vitaliy Ulantikov
2
Untuk menggunakan kode ini di WPF, gunakan BindingOperations.ClearBinding(this, TextProperty)alih-alih SetBinding(TextProperty, new Binding())di kedua tempat.
Sebastian Krysmanski
1
Ini sebenarnya berubah Textmenjadi watermark. Tidak akan bekerja untuk saya
lobsterism
mungkin berguna untuk menambahkan baris namespace ke ini, atau sepenuhnya memenuhi syarat beberapa hal ini.
Richard June
6
Saya mengalami sedikit kesulitan ketika menggunakan kode @ john-myczek dengan TextBox yang terikat. Karena TextBox tidak memunculkan acara fokus saat diperbarui, tanda air akan tetap terlihat di bawah teks baru. Untuk memperbaikinya, saya cukup menambahkan pengendali event lain:
Seandainya saya memperhatikan jawaban ini sebelum saya melakukannya sendiri.
lobsterism
5
@ Veton - Saya sangat menyukai kesederhanaan solusi Anda, tetapi reputasi saya belum cukup tinggi untuk menabrak Anda.
@Tim Murphy - Bahwa kesalahan "Pengikatan dua arah memerlukan Path atau XPath" adalah perbaikan yang mudah ... kode yang diperbarui termasuk beberapa penyesuaian kecil lainnya (hanya WPF yang diuji):
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;publicclassTextBoxWatermarked:TextBox{publicstringWatermark{get{return(string)GetValue(WaterMarkProperty);}set{SetValue(WaterMarkProperty,value);}}publicstaticreadonlyDependencyPropertyWaterMarkProperty=DependencyProperty.Register("Watermark",typeof(string),typeof(TextBoxWatermarked),newPropertyMetadata(newPropertyChangedCallback(OnWatermarkChanged)));privatebool _isWatermarked =false;privateBinding _textBinding =null;publicTextBoxWatermarked(){Loaded+=(s, ea)=>ShowWatermark();}protectedoverridevoidOnGotFocus(RoutedEventArgs e){base.OnGotFocus(e);HideWatermark();}protectedoverridevoidOnLostFocus(RoutedEventArgs e){base.OnLostFocus(e);ShowWatermark();}privatestaticvoidOnWatermarkChanged(DependencyObject sender,DependencyPropertyChangedEventArgs ea){var tbw = sender asTextBoxWatermarked;if(tbw ==null||!tbw.IsLoaded)return;//needed to check IsLoaded so that we didn't dive into the ShowWatermark() routine before initial Bindings had been made
tbw.ShowWatermark();}privatevoidShowWatermark(){if(String.IsNullOrEmpty(Text)&&!String.IsNullOrEmpty(Watermark)){
_isWatermarked =true;//save the existing binding so it can be restored
_textBinding =BindingOperations.GetBinding(this,TextProperty);//blank out the existing binding so we can throw in our WatermarkBindingOperations.ClearBinding(this,TextProperty);//set the signature watermark grayForeground=newSolidColorBrush(Colors.Gray);//display our watermark textText=Watermark;}}privatevoidHideWatermark(){if(_isWatermarked){
_isWatermarked =false;ClearValue(ForegroundProperty);Text="";if(_textBinding !=null)SetBinding(TextProperty, _textBinding);}}}
Ini dapat membantu memeriksa dengan kode Anda. Ketika diterapkan ke kotak kata sandi, itu akan menampilkan kata sandi, yang akan hilang ketika mengetik.
Konverter, seperti yang tertulis sekarang tidak perlu MultiConverter, tetapi dalam hal ini dapat diperpanjang dengan mudah
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace WPFControls{classShadowConverter:IMultiValueConverter{#region Implementation of IMultiValueConverterpublicobjectConvert(object[] values,Type targetType,object parameter,CultureInfo culture){var text =(string) values[0];return text ==string.Empty?Visibility.Visible:Visibility.Collapsed;}publicobject[]ConvertBack(objectvalue,Type[] targetTypes,object parameter,CultureInfo culture){returnnewobject[0];}#endregion}}
dan akhirnya kode di belakang:
using System.Windows;
using System.Windows.Controls;
namespace WPFControls{/// <summary>/// Interaction logic for ShadowedTextBox.xaml/// </summary>publicpartialclassShadowedTextBox:UserControl{publiceventTextChangedEventHandlerTextChanged;publicShadowedTextBox(){InitializeComponent();}publicstaticreadonlyDependencyPropertyWatermarkProperty=DependencyProperty.Register("Watermark",typeof(string),typeof(ShadowedTextBox),newUIPropertyMetadata(string.Empty));publicstaticreadonlyDependencyPropertyTextProperty=DependencyProperty.Register("Text",typeof(string),typeof(ShadowedTextBox),newUIPropertyMetadata(string.Empty));publicstaticreadonlyDependencyPropertyTextChangedProperty=DependencyProperty.Register("TextChanged",typeof(TextChangedEventHandler),typeof(ShadowedTextBox),newUIPropertyMetadata(null));publicstringWatermark{get{return(string)GetValue(WatermarkProperty);}set{SetValue(WatermarkProperty,value);}}publicstringText{get{return(string)GetValue(TextProperty);}set{SetValue(TextProperty,value);}}privatevoid textBox_TextChanged(object sender,TextChangedEventArgs e){if(TextChanged!=null)TextChanged(this, e);}publicvoidClear(){
textBox.Clear();}}}
MahApps.Metro untuk WPF memiliki kontrol tanda air bawaan , jika Anda lebih suka tidak menggulungnya sendiri. Cukup mudah digunakan.
<AdornerDecorator><TextBoxName="txtSomeText"Width="200"HorizontalAlignment="Right"><Controls:TextBoxHelper.Watermark>I'm a watermark!</Controls:TextBoxHelper.Watermark></TextBox></AdornerDecorator>
Ini adalah kotak teks dengan backgound transparan yang menutupi label. Teks abu-abu label berubah transparan oleh pemicu data yang menyala setiap kali teks terikat bukan string kosong.
Untuk meningkatkan penggunaan kembali Gaya ini, Anda juga dapat membuat satu set properti terlampir untuk mengontrol teks spanduk isyarat aktual, warna, orientasi dll.
Ini adalah contoh sempurna yang menggambarkan bagaimana tidak melakukannya, terutama dengan WPF.
Alexandru Dicu
0
Teknik ini menggunakan properti Latar Belakang untuk menampilkan / menyembunyikan kotak teks placeholder. Placeholder ditampilkan acara ketika Textbox memiliki fokus
Bagaimana itu bekerja:
Saat kosong, latar belakang TextBox diatur ke Transparan untuk menampilkan teks PlaceHolder.
Ketika latar belakang tidak kosong diatur ke Putih untuk menutupi teks PlaceHolder.
Ini adalah contoh dasar. Untuk tujuan saya sendiri, saya mengubahnya menjadi UserControl.
Anda dapat menyimpan nilai terpisah untuk teks yang dimasukkan dan Anda bisa mengaturnya bersama dengan bidang "Teks" dari kotak teks di acara "GotFocus" dan "LostFocus". Saat Anda mendapatkan fokus, Anda akan ingin menghapus kotak teks jika tidak ada nilai. Dan ketika Anda kehilangan fokus, Anda ingin mengatur untuk mendapatkan nilai "Teks" dari kotak teks dan kemudian mengatur ulang nilai "Teks" dari kotak teks ke tempat penampung jika kosong.
Jika alih-alih memiliki visibilitas tanda air tergantung pada status fokus kontrol, Anda ingin itu bergantung pada apakah pengguna telah memasukkan teks, Anda dapat memperbarui jawaban John Myczek (dari OnWatermarkChangedbawah) ke
Inilah pendekatan saya Sangat bagus untuk MVVM di mana saya juga memeriksa apakah kotak Teks memiliki fokus, Anda juga dapat menggunakan pemicu biasa hanya untuk nilai teks dan intinya adalah saya hanya mengubah gambar latar belakang ketika nilai berubah:
Saya memutuskan untuk menyelesaikan ini melalui Perilaku. Ini menggunakan Hintproperti untuk mendefinisikan teks yang akan ditampilkan (juga bisa menjadi objek, jika Anda suka) dan Valueproperti untuk mengevaluasi apakah petunjuknya harus terlihat atau tidak.
Perilaku dinyatakan sebagai berikut:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Interactivity;
using System.Windows.Media;publicclassHintBehavior:Behavior<ContentControl>{publicstaticreadonlyDependencyPropertyHintProperty=DependencyProperty.Register("Hint",typeof(string),typeof(HintBehavior)//, new FrameworkPropertyMetadata(null, OnHintChanged));publicstringHint{get{return(string)GetValue(HintProperty);}set{SetValue(HintProperty,value);}}publicstaticreadonlyDependencyPropertyValueProperty=DependencyProperty.Register("Value",typeof(object),typeof(HintBehavior),newFrameworkPropertyMetadata(null,OnValueChanged));privatestaticvoidOnValueChanged(DependencyObject d,DependencyPropertyChangedEventArgs e){var visible = e.NewValue==null;
d.SetValue(VisibilityProperty, visible ?Visibility.Visible:Visibility.Collapsed);}publicobjectValue{get{returnGetValue(ValueProperty);}set{SetValue(ValueProperty,value);}}publicstaticreadonlyDependencyPropertyVisibilityProperty=DependencyProperty.Register("Visibility",typeof(Visibility),typeof(HintBehavior),newFrameworkPropertyMetadata(Visibility.Visible//, new PropertyChangedCallback(OnVisibilityChanged)));publicVisibilityVisibility{get{return(Visibility)GetValue(VisibilityProperty);}set{SetValue(VisibilityProperty,value);}}publicstaticreadonlyDependencyPropertyForegroundProperty=DependencyProperty.Register("Foreground",typeof(Brush),typeof(HintBehavior),newFrameworkPropertyMetadata(newSolidColorBrush(Colors.DarkGray)//, new PropertyChangedCallback(OnForegroundChanged)));publicBrushForeground{get{return(Brush)GetValue(ForegroundProperty);}set{SetValue(ForegroundProperty,value);}}publicstaticreadonlyDependencyPropertyMarginProperty=DependencyProperty.Register("Margin",typeof(Thickness),typeof(HintBehavior),newFrameworkPropertyMetadata(newThickness(4,5,0,0)//, new PropertyChangedCallback(OnMarginChanged)));publicThicknessMargin{get{return(Thickness)GetValue(MarginProperty);}set{SetValue(MarginProperty,value);}}privatestaticResourceDictionary _hintBehaviorResources;publicstaticResourceDictionaryHintBehaviorResources{get{if(_hintBehaviorResources ==null){var res =newResourceDictionary{Source=newUri("/Mayflower.Client.Core;component/Behaviors/HintBehaviorResources.xaml",UriKind.RelativeOrAbsolute)};
_hintBehaviorResources = res;}return _hintBehaviorResources;}}protectedoverridevoidOnAttached(){base.OnAttached();var t =(ControlTemplate)HintBehaviorResources["HintBehaviorWrapper"];AssociatedObject.Template= t;AssociatedObject.Loaded+=OnLoaded;}privatevoidOnLoaded(object sender,RoutedEventArgs e){AssociatedObject.Loaded-=OnLoaded;var label =(Label)AssociatedObject.Template.FindName("PART_HintLabel",AssociatedObject);
label.DataContext=this;//label.Content = "Hello...";
label.SetBinding(UIElement.VisibilityProperty,newBinding("Visibility"){Source=this,Mode=BindingMode.OneWay});
label.SetBinding(ContentControl.ContentProperty,newBinding("Hint"){Source=this,Mode=BindingMode.OneWay});
label.SetBinding(Control.ForegroundProperty,newBinding("Foreground"){Source=this,Mode=BindingMode.OneWay});
label.SetBinding(FrameworkElement.MarginProperty,newBinding("Margin"){Source=this,Mode=BindingMode.OneWay});}}
Itu membungkus target dengan templatnya sendiri, menambahkannya label:
Untuk menggunakannya, cukup tambahkan itu sebagai perilaku dan ikat nilai-nilai Anda (dalam kasus saya, saya menambahkannya dalam ControlTemplate, karenanya mengikat):
Jawaban:
Ini adalah contoh yang menunjukkan cara membuat kotak teks watermark di WPF:
TextInputToVisibilityConverter didefinisikan sebagai:
Catatan: Ini bukan kode saya. Saya menemukannya di sini , tetapi saya pikir ini adalah pendekatan terbaik.
sumber
Anda dapat membuat tanda air yang dapat ditambahkan ke sembarang
TextBox
dengan Properti Terlampir. Berikut adalah sumber untuk Properti Terlampir:Properti Terlampir menggunakan kelas yang disebut
WatermarkAdorner
, di sini adalah sumber itu:Sekarang Anda dapat meletakkan tanda air di sembarang TextBox seperti ini:
Tanda air dapat berupa apa saja yang Anda inginkan (teks, gambar ...). Selain berfungsi untuk TextBoxes, tanda air ini juga berfungsi untuk ComboBoxes dan ItemControls.
Kode ini diadaptasi dari posting blog ini .
sumber
TextBlock.Text
properti ke model tampilan saya (letakkan ini diWatermarkAdorner
konstruktor):FrameworkElement feWatermark = watermark as FrameworkElement;
if(feWatermark != null && feWatermark.DataContext == null)
{feWatermark.DataContext = this.Control.DataContext;
}Hanya menggunakan XAML, tanpa ekstensi, tanpa konverter:
sumber
Padding="6,3,0,0"
keTextBlock
.Saya tidak percaya bahwa tidak ada yang memposting Toolkit WPF yang jelas - WatermarkTextBox dari Xceed. Ini bekerja dengan sangat baik dan merupakan sumber terbuka jika Anda ingin menyesuaikan.
sumber
Ada artikel tentang CodeProject tentang bagaimana melakukannya di "3 baris XAML".
Ok, baik itu tidak mungkin 3 baris XAML diformat, tetapi adalah cukup sederhana.
Satu hal yang perlu diperhatikan adalah bahwa ia menggunakan metode ekstensi non-standar pada properti Text, yang disebut "IsEmpty". Anda perlu menerapkan ini sendiri, namun artikel tersebut sepertinya tidak menyebutkannya.
sumber
IsHitTestVisible="False"
. Juga, itu harus datang setelah TextBox, kalau tidak mungkin tidak terlihat jika TextBox memiliki latar belakang.Text.IsEmpty
kerjanya: IsEmpty sedang diselesaikan dari CollectionView.IsEmptySaya melihat solusi John Myczek , dan komentarnya tentang Kompatibilitas ke
ComboBox
danPasswordBox
, jadi saya meningkatkan solusi John Myczek, dan ini dia:Sekarang,
ComboBox
dapat jugaEditable
, danPasswordBox
dapat menambahkan tanda air juga. Jangan lupa untuk menggunakan komentar JoanComasFdz di atas untuk menyelesaikan masalah margin.Dan, tentu saja, Semua kredit jatuh ke tangan John Myczek.
sumber
Solusi sederhana menggunakan gaya:
Solusi hebat:
https://code.msdn.microsoft.com/windowsdesktop/In-place-hit-messages-for-18db3a6c
sumber
Perpustakaan ini memiliki tanda air.
Paket nuget
Penggunaan sampel:
sumber
Saya telah membuat implementasi kode saja yang berfungsi dengan baik untuk WPF dan Silverlight juga:
Pemakaian:
sumber
BindingOperations.ClearBinding(this, TextProperty)
alih-alihSetBinding(TextProperty, new Binding())
di kedua tempat.Text
menjadi watermark. Tidak akan bekerja untuk sayaSaya mengalami sedikit kesulitan ketika menggunakan kode @ john-myczek dengan TextBox yang terikat. Karena TextBox tidak memunculkan acara fokus saat diperbarui, tanda air akan tetap terlihat di bawah teks baru. Untuk memperbaikinya, saya cukup menambahkan pengendali event lain:
sumber
@ Veton - Saya sangat menyukai kesederhanaan solusi Anda, tetapi reputasi saya belum cukup tinggi untuk menabrak Anda.
@Tim Murphy - Bahwa kesalahan "Pengikatan dua arah memerlukan Path atau XPath" adalah perbaikan yang mudah ... kode yang diperbarui termasuk beberapa penyesuaian kecil lainnya (hanya WPF yang diuji):
sumber
Anda dapat menggunakan
GetFocus()
danLostFocus()
acara untuk melakukan iniberikut adalah contohnya:
sumber
Cara termudah untuk WaterMark Of TextBox
dan tambahkan gaya StaticResource textbox
sumber
Ini dapat membantu memeriksa dengan kode Anda. Ketika diterapkan ke kotak kata sandi, itu akan menampilkan kata sandi, yang akan hilang ketika mengetik.
sumber
Nah ini milik saya: belum tentu yang terbaik, tetapi karena sederhana mudah untuk mengedit sesuai selera Anda.
Konverter, seperti yang tertulis sekarang tidak perlu MultiConverter, tetapi dalam hal ini dapat diperpanjang dengan mudah
dan akhirnya kode di belakang:
sumber
sumber
MahApps.Metro untuk WPF memiliki kontrol tanda air bawaan , jika Anda lebih suka tidak menggulungnya sendiri. Cukup mudah digunakan.
sumber
Siapkan kotak teks dengan teks placeholder dalam warna lembut ...
Ketika kotak teks mendapatkan fokus, hapus dan ubah warna teks
sumber
Inilah solusi paling sederhana:
Ini adalah kotak teks dengan backgound transparan yang menutupi label. Teks abu-abu label berubah transparan oleh pemicu data yang menyala setiap kali teks terikat bukan string kosong.
sumber
Juga, lihat jawaban ini . Anda dapat melakukannya dengan lebih mudah dengan VisualBrush dan beberapa pemicu dalam Style:
Untuk meningkatkan penggunaan kembali Gaya ini, Anda juga dapat membuat satu set properti terlampir untuk mengontrol teks spanduk isyarat aktual, warna, orientasi dll.
sumber
hai saya menempatkan tugas ini ke dalam perilaku. jadi Anda hanya perlu menambahkan sesuatu seperti ini ke kotak teks Anda
Anda dapat menemukan posting blog saya di sini
sumber
Solusi saya cukup sederhana.
Di jendela login saya. xaml seperti ini.
kodenya seperti ini.
Hanya memutuskan untuk menyembunyikan atau menunjukkan kotak teks watermark sudah cukup. Meski tidak cantik, tapi bekerja dengan baik.
sumber
Teknik ini menggunakan properti Latar Belakang untuk menampilkan / menyembunyikan kotak teks placeholder.
Placeholder ditampilkan acara ketika Textbox memiliki fokus
Bagaimana itu bekerja:
Ini adalah contoh dasar. Untuk tujuan saya sendiri, saya mengubahnya menjadi UserControl.
Berikut adalah ValueConverter untuk mendeteksi string yang tidak kosong di DataTrigger.
sumber
Anda dapat menyimpan nilai terpisah untuk teks yang dimasukkan dan Anda bisa mengaturnya bersama dengan bidang "Teks" dari kotak teks di acara "GotFocus" dan "LostFocus". Saat Anda mendapatkan fokus, Anda akan ingin menghapus kotak teks jika tidak ada nilai. Dan ketika Anda kehilangan fokus, Anda ingin mengatur untuk mendapatkan nilai "Teks" dari kotak teks dan kemudian mengatur ulang nilai "Teks" dari kotak teks ke tempat penampung jika kosong.
Maka Anda hanya perlu memastikan bahwa nilai "Teks" dari kotak teks diinisialisasi ke teks tempat penampung.
Anda selanjutnya dapat mengekstrak ini ke kelas yang memperluas kelas "TextBox" dan kemudian menggunakannya kembali di seluruh proyek Anda.
Dan kemudian ini bisa ditambahkan secara langsung di xaml.
sumber
Jika alih-alih memiliki visibilitas tanda air tergantung pada status fokus kontrol, Anda ingin itu bergantung pada apakah pengguna telah memasukkan teks, Anda dapat memperbarui jawaban John Myczek (dari
OnWatermarkChanged
bawah) keIni lebih masuk akal jika kotak teks Anda mendapatkan fokus secara otomatis saat menampilkan formulir, atau saat penyatuan data ke properti Teks.
Juga jika tanda air Anda selalu hanya string, dan Anda membutuhkan gaya tanda air agar sesuai dengan gaya kotak teks, maka di Adorner lakukan:
sumber
Inilah pendekatan saya Sangat bagus untuk MVVM di mana saya juga memeriksa apakah kotak Teks memiliki fokus, Anda juga dapat menggunakan pemicu biasa hanya untuk nilai teks dan intinya adalah saya hanya mengubah gambar latar belakang ketika nilai berubah:
sumber
Saya memutuskan untuk menyelesaikan ini melalui Perilaku. Ini menggunakan
Hint
properti untuk mendefinisikan teks yang akan ditampilkan (juga bisa menjadi objek, jika Anda suka) danValue
properti untuk mengevaluasi apakah petunjuknya harus terlihat atau tidak.Perilaku dinyatakan sebagai berikut:
Itu membungkus target dengan templatnya sendiri, menambahkannya label:
Untuk menggunakannya, cukup tambahkan itu sebagai perilaku dan ikat nilai-nilai Anda (dalam kasus saya, saya menambahkannya dalam ControlTemplate, karenanya mengikat):
Saya akan senang umpan balik jika ini dianggap sebagai solusi bersih. Tidak memerlukan kamus statis dan karenanya tidak memiliki kebocoran memori.
sumber
Saya menemukan cara ini untuk melakukannya dengan cara yang sangat cepat dan mudah
Mungkin ini bisa membantu siapa saja yang mencoba melakukan ini
Sumber: http://www.admindiaries.com/displaying-a-please-select-watermark-type-text-in-a-wpf-combobox/
sumber
sumber
Tambahkan mahapps.metro ke proyek Anda. Tambahkan kotak teks dengan kode di atas ke jendela.
sumber