Archivio per la categoria WPF
Selezionare il contenuto di una TextBox WPF al focus
Riporto qui la soluzione presentata da Donelle su stackoverflow con una piccola modifica.
Innanzitutto il link originale: http://stackoverflow.com/questions/660554/how-to-automatically-select-all-text-on-focus-in-wpf-textbox
La modifica consiste nell’includere il comportamento come un behavior. Ecco il codice:
public static class TextBoxBehaviors { public static void SetSelectOnFocus(UIElement element, Boolean value) { element.SetValue(SelectOnFocusProperty, value); } public static bool GetSelectOnFocus(UIElement element) { return (bool)element.GetValue(SelectOnFocusProperty); } public static readonly DependencyProperty SelectOnFocusProperty = DependencyProperty.RegisterAttached("SelectOnFocus", typeof(bool), typeof(TextBoxBehaviors), new FrameworkPropertyMetadata(false, SelectOnFocusPropertyChangedCallback)); private static void SelectOnFocusPropertyChangedCallback(DependencyObject depObj, DependencyPropertyChangedEventArgs eventArgs) { TextBox tb = depObj as TextBox; if (tb != null) { if ((bool)eventArgs.OldValue == false && (bool)eventArgs.NewValue == true) { //attach events tb.PreviewMouseLeftButtonDown += SelectivelyIgnoreMouseButton; tb.GotKeyboardFocus += SelectAllText; tb.MouseDoubleClick += SelectAllText; } else if ((bool)eventArgs.OldValue == true && (bool)eventArgs.NewValue == false) { //detach events tb.PreviewMouseLeftButtonDown -= SelectivelyIgnoreMouseButton; tb.GotKeyboardFocus -= SelectAllText; tb.MouseDoubleClick -= SelectAllText; } } } private static void SelectivelyIgnoreMouseButton(object sender, MouseButtonEventArgs e) { DependencyObject parent = e.OriginalSource as UIElement; while (parent != null && !(parent is TextBox)) parent = VisualTreeHelper.GetParent(parent); if (parent != null) { var textBox = (TextBox)parent; if (!textBox.IsKeyboardFocusWithin) { textBox.Focus(); e.Handled = true; } } } private static void SelectAllText(object sender, RoutedEventArgs e) { var textBox = e.OriginalSource as TextBox; if (textBox != null) textBox.SelectAll(); } }
E’ possibile ora aggiungere nello xaml il comportamento aggiungendo il behavior:
<TextBox Text="Selezionami per provare" behaviors:TextBoxBehaviors.SelectOnFocus="True" />
INotifyPropertyChanged serve davvero? Sì! Ma le cose si fanno complicate…
Pubblicato da sierrodc in Silverlight, WPF il settembre 17, 2011
Leggendo per caso il blog di Gianni Giaccaglini (http://blogs.wpfitalia.it/GianniGiaccaglini/archive/2011/09/08/Binding-ADO-tramite-classe-ad-hoc.aspx) riguardo il binding verso dataset, ho notato un capitolo, “INotifyPropertyChanged server davvero?” e mi sono ricordato di un problema simile (forse lo stesso) che mi è capitato tempo fa.
Iniziamo dal codice xaml e il datacontext:
<StackPanel>
<TextBox Text="{Binding Path=PrimaProp}" />
<TextBox Text="{Binding Path=PrimaProp}" />
<TextBox Text="{Binding Path=SecondaProp}" />
<TextBox Text="{Binding Path=SecondaProp}" />
<Button Content="Cambia" Click="Button_Click" />
</StackPanel>
public class MyDataContext
{
public string PrimaProp { get; set; }
public string SecondaProp { get; set; }
}
Qualcuno noterà che MyDataContext (nel codebehind viene impostata un istanza come DataContext) non implementa INotifyPropertyChanged.
Modificando una textbox ci si aspetterebbe che le altre non cambino perchè non si notifica alla vista che la proprietà è stata cambiata… E invece tutto funziona!
Ai tempi pensai che l’engine di wpf fosse abbastanza intelligente da usare un oggetto binding uguale se viene scritto uguale in più parti… invece no .
Se proviamo infatti a impostare via codice il binding (es: textbox1.SetBinding(TextBox.TextProperty, new Binding(“PrimaProp”))), con nuove istanze di Binding su diversi oggetti, continua ancora a funzionare.
Proviamo a cambiare la proprietà del datacontext da codice tramite il bottone con:
(this.DataContext as MyDataContext).SecondaProp=”modifica da codice”… NON FUNZIONA!
Non sapendo dove andare a parare, ho cercato con google, e infine ho trovato la soluzione indicata qui: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/9365bb6a-b411-4967-9a03-ae2a810fb215/
Sunto della soluzione:
– Se un oggetto CLR implementa INotifyPropertyChanged, è cura del developer lanciare l’evento NotifyPropertyChanged
– Se un oggetto CLR NON implementa INotifyPropertyChanged, il binding lavora sul TypeDescriptor dell’oggetto. Esso va a registrare alla modifica delle proprietà tramite PropertyDescriptor.AddValueChanged().
Quindi:
1) come far andare il codice precedente riguardo il bottone:
”semplice” (?!?) basta recuperare la PropertyDescriptor dell’oggetto e impostare così la proprietà:
var propertyDescriptor = TypeDescriptor.GetProperties(this.DataContext).Find(“SecondaProp”, false);
propertyDescriptor.SetValue(this.DataContext, “ModificaDaCodice”);
2) come far smettere di andare il precedente esempio:
Implementiamo l’interfaccia INotifyPropertyChanged e propaghiamo l’evento solo per PrimaProp. Questa funziona, ma SecondaProp no .
Performance (mentre l’ho fatto ho sentito l’esigenza di un altro post)
Se eseguo il codice nel thread UI, le performance sono molto simili.
Se eseguo il codice in un altro thread, l’utilizzo di INotifyPropertyChanged risulta più rapido rispetto a PropertyDescriptor.
Conclusioni:
Data la flessibilità e la maggior facilità implementativa, la mia preferenza ricade indubbiamente a INotifyPropertyChanged. Le performance inoltre sembrerebbero avvalorare tale scelta. Quindi Me.NofifyPropertyChanged(“you”);
Multi-touch in WPF 4
Pubblicato un articolo dove vengono mostrare le caratteristiche multitouch di WPF4.
Sicuramente il dispositivi Touch saranno il futuro per quanto riguarda l’interfacciamento uomo-macchina, quindi cominciare fin da subito a capire come funziona e conoscere gli strumenti a disposizione è indubbiamente un vantaggio.
Buona lettura: http://www.wpfitalia.it/Contenuti/VediArticoli/tabid/83/ArticleId/46/Il-supporto-al-multi-touch-in-WPF-4.aspx
Unselect DataGridRow in DataGrid
Oggi si è presentato il seguente problema:
Ho usato una griglia per applicare una sorta di filtro su un altro controllo in base alle DataGridRow selezionate; il cliente ha voluto che, cliccando fuori dalle colonne di una DataGrid, tutte le righe selezionate si deselezionassero (eliminando in questo modo il filtro).
L’unico modo navito per farlo è cliccare sulla DataGridRow selezionata tenendo premuto il tasto CTRL.
Ho quindi creato il codice qui sotto.
In pratica cliccando al di fuori delle colonne (parte destra della Griglia) si clicca su un elemento figlio di una DataGridRow ma non su un elemento figlio di una DataGridCell (si può vedere facilmente con WPF Inspector oppure con Snoop).
Testo quindi questa condizione e deseleziono tutto se verificata:
public static class DataGridBehaviors { public static bool GetUnselectOnClickOutside(DependencyObject obj) { return (bool)obj.GetValue(UnselectOnClickOutsideProperty); } public static void SetUnselectOnClickOutside(DependencyObject obj, bool value) { obj.SetValue(UnselectOnClickOutsideProperty, value); } public static readonly DependencyProperty UnselectOnClickOutsideProperty = DependencyProperty.RegisterAttached("UnselectOnClickOutside", typeof(bool), typeof(DataGridBehaviors), new UIPropertyMetadata(false, UnselectOnClickOutsidePropertyChangedCallback)); private static void UnselectOnClickOutsidePropertyChangedCallback(DependencyObject depObj, DependencyPropertyChangedEventArgs eventArgs) { DataGrid grid = depObj as DataGrid; if (depObj != null) { if ((bool)eventArgs.OldValue == false && (bool)eventArgs.NewValue == true) grid.MouseLeftButtonUp += AssociatedObjectUnselectOnClickOutside; else if ((bool)eventArgs.OldValue == true && (bool)eventArgs.NewValue == false) grid.MouseLeftButtonUp -= AssociatedObjectUnselectOnClickOutside; } } private static void AssociatedObjectUnselectOnClickOutside(object sender, MouseButtonEventArgs e) { DataGrid datagrid = e.Source as DataGrid; DependencyObject originalControl = e.OriginalSource as DependencyObject; DataGridCell cell; DataGridRow row; if (TryFindParent<DataGridRow>(originalControl, out row) && !TryFindParent<DataGridCell>(originalControl, out cell)) { datagrid.UnselectAll(); } } private static bool TryFindParent<T>(DependencyObject child, out T result) where T : class { Contract.Requires(child != null, "child could not be null"); Contract.Ensures(Contract.Result<bool>() == true && Contract.ValueAtReturn<T>(out result) != null && result is T, "Result found rule violated"); Contract.Ensures(Contract.Result<bool>() == false && Contract.ValueAtReturn<T>(out result) == null, "Result not found rule violated"); var parent = VisualTreeHelper.GetParent(child); result = parent as T; if (result != null) return true; else if (parent != null) return TryFindParent<T>(parent, out result); else return false; } }
Questo è un behavior applicabile ad ogni griglia tramite AttachedProperty:
<DataGrid ItemsSource=”{Binding}” local:DataGridBehaviors.UnselectOnClickOutside=”True” />
Et voilà! Les jeux sont faits
Visual State Manager in WPF 4
VisualStateManager, VisualStateGroup, VisualState e VisualTransition sono un nuovo insieme di classi introdotte con la versione 4 del .NET Framework che permettono allo sviluppatore di definire gli stati visuali dei controlli grafici e gestire da codice le regole di passaggio da uno stato a un altro. Uno stato visuale è una rappresentazione consistente del controllo, ovvero un insieme di regole che ne definiscono l’aspetto….
Continua a leggere qui: http://www.wpfitalia.it/Contenuti/VediArticoli/tabid/83/ArticleId/45/Il-Visual-State-Manager-in-WPF-4.aspx