I’m porting a WPF app to silverlight 2, and have come across several WPF features which are presently missing from SL. Could anyone help me with equivalents or suggest workarounds.
I want to handle clicks and double clicks on a textbox embedded in a list box. The WPF implementation uses PreviewMouseLeftButtonDown/Up on a listbox control. How can this be done in silverlight, it seems that PreviewMouseLeftButtonDown/Up are missing in silverlight.
I want to handle button presses (F2/Delete) on a textbox embedded in a list box. The WPF implementation uses PreviewKeyDown on a textbox control which embedded as an item in a listbox. It seems that PreviewKeyDown is missing in silverlight. The KeyDown event handler does not seem to get invoked.
I want to change some appearance properties of a textbox depending on the value of some custom attached properties. The WPF implementation uses a DataTrigger to do this. How can this be done in silverlight. It seems that DataTriggers are missing in silverlight.
I want to change the width of a text box depending on the Actual Width of the listbox in which the text box is contained. The WPF implementation uses RelativeSource binding. What is the silverlight equivalent, or workaround for this.
For item 1 and 2, the best way to get access to these input events is to create a custom TextBox deriving from the built in TextBox. Then you can override the OnKeyDown and OnMouseLeftButton down. From there you can either call the necessary code, or fire a new event. e.g.:
public class MyTextBox : TextBox
{
public event MouseButtonEventHandler MySpecialMouseLeftButtonDown;
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
if (MySpecialMouseLeftButtonDown != null)
{
MySpecialMouseLeftButtonDown(this, e);
}
base.OnMouseLeftButtonDown(e);
}
}
Similarly with OnKeyDown.
I'm more familiar with Silverlight than the full WPF. Please considier my responses accordingly.
For number 2. For many keys, I check on KeyUp and KeyDown. I use KeyDown while trying to watch the entire time that the key is held down and KeyUp when it was used just once. You should know this was for a game without an individual text box.
For item 4, you can bind both the listbox width and the textbox width to a static resource's property so that it acts as a router for the binding. You could also use a value converter that you initialize with a reference to the listbox, then use the converter for your textbox width.
For item 3, you could use a similar approach.
Related
I've got a ListBox on a window with some other components.
When I change the Visibility of these other components, the ListBox fires its SelectionChanged event with the new selectedIndex = 0. That's very undesirable. (It doesn't happen if you insert breakpoints, or, presumably, Sleeps).
I want a reliable event that only fires when the user actually changes the ListBox selection, not when WPF merely changes the window layout.
Does such a thing exist, or for something more robust should I just build my own control from scratch using buttons?
for something more robust
If you want a robust application, you need a robust design.
If you're working with WPF, You need to leave behind the traditional event-based approach and understand and embrace The WPF Mentality.
I want to know when a user uses the mouse or keyboard to change the
listbox selection
Instead of handling events, putting a bunch of code behind, and hoping that the complexities of the Visual Tree will allow that to work, simply use proper DataBinding:
<ListBox ItemsSource="{Binding SomeCollection}"
SelectedItem="{Binding SelectedItem}"/>
to a proper ViewModel:
public class MyViewModel
{
public ObservableCollection<MyClass> SomeCollection {get;set;}
public MyClass SelectedItem {get;set;} //Don't forget INotifyPropertyChanged
}
See how I'm not handling any events or putting any code behind. The Visual tree can do whatever it wants and raise as many events, and my code will still work.
Also see how this approach is much cleaner because it allows a true separation between UI and data.
I could go on forever about the advantages of proper MVVM, but I'm too lazy right now. Let me know if you need further help.
When my combobox expands and I select an item, I want the combobox to change visual state(it is highlighted). This will signify something is selected. I tried various VisualStates but none of them would trigger in this scenario. How can I achieve this? Thanks.
The standard ComboBox simply doesn't have states to distinguish between having something selected and having nothing selected.
There are a number of ways to go about solving the underlying problem, and it depends mostly on the answer to the following question:
Do you really need to change the visual appearance of the ComboBox itself or does it suffice to style the selected item more prominently?
If it's the latter, you're best served with the rather easy way of using a custom control template for the ComboBoxItems.
If you really want to style the ComboBox itself that way, there are two options I can think of:
A) Add custom states to a ComboBox with a custom template.
Copy your ComboBox's control template and add another state group to the already present states. Both of this is typically done in Expression Blend.
After that you can update the new states in code with
VisualStateManager.GoToState(this, "Selected", true);
for example. You will have to set those states yourself when the first item is chosen. This could be done on the SelectionChanged event.
B) Derive from ComboBox
If you want to use the control in this way often, it might be worthwhile to derive from ComboBox to make your own custom control.
It would look somthing like this:
[TemplateVisualState(Name = "SelectedStates", GroupName = "Unselected")]
[TemplateVisualState(Name = "SelectedStates", GroupName = "Selected")]
// ... (more attributes copied from the ComboBox ones)
public class MyComboBox : ComboBox
{
public MyComboBox()
{
SelectionChanged += HandleSelectionChanged;
DefaultStyleKey = typeof(MyComboBox);
}
void HandleSelectionChanged(object sender, SelectionChangedEventArgs e)
{
VisualStateManager.GoToState(this, SelectedItem != null ? "Selected" : "Unselected", true);
}
}
And you would then need a default style based on the default ComboBox style (or whatever you usually use).
Note that I didn't test this in any way.
I have an MVVM application with a TextBox control for which I want to validate that it's not empty. As the evaluation should be performed for every key stroke, I changed the binding so it contains
Text={Binding ..., UpdateSourceTrigger=PropertyChanged}
Now I'd also like to perform an action when the TextBox control loses its focus, so the default behaviour of the TextBox control would be suitable. My problem is that I don't know how to combine the two settings (if at all possible).
Any idea? How to react to key strokes and to the LostFocus event?
You can use an attached behavior to map the LostFocus event to a command in your ViewModel.
You would normally implement IDataErrorInfo or INotifyDataErrorInfo interfaces into your ViewModels to handle this in MVVM.
Also, attributes are really powerful and could probably provide you with a good solution, depending on the requirements you have. It would look something like this in your ViewModel.
[Required(ErrorMessage = "Field 'Range' is required.")]
[Range(1, 10, ErrorMessage = "Field 'Range' is out of range.")]
public int Range
{
get
{
return this.range;
}
set
{
if (this.range != value)
{
this.range = value;
this.OnPropertyChanged("Range");
}
}
}
I would recommend that you take a look at these articles.
Attributes-based Validation in a WPF MVVM Application
http://www.codeproject.com/Articles/97564/Attributes-based-Validation-in-a-WPF-MVVM-Applicat
Validating User Input - WPF MVVM
http://www.codeproject.com/Articles/98681/Validating-User-Input-WPF-MVVM
WPF Validation with Attributes and IDataErrorInfo interface in MVVM
http://weblogs.asp.net/marianor/archive/2009/04/17/wpf-validation-with-attributes-and-idataerrorinfo-interface-in-mvvm.aspx
Using IDataErrorInfo for validation in MVVM with Silverlight and WPF
http://www.arrangeactassert.com/using-idataerrorinfo-for-validation-in-mvvm-with-silverlight-and-wpf/
You should consider using the IDataErrorInfo interface and the ValidatesOnErrorInfo property for your binding. A good and simple blog-post on how to use these two can be found here: http://asimsajjad.blogspot.de/2010/08/input-validation-using-mvvm-pattern.html
I've got a simple View with a single textbox that gets databound to a simple ViewModel with a single string property.
I need to catch the TextChanged event of that textbox so that I can do a little validation magic.
The problem that I am running into is that the TextChanged event fires for that textbox when the DataContext is set for the View.
Is there a standard mechanism that I can use to determine if the event is firing because of the DataContext being set versus when the user is making changes?
Thanks!
As far as I know there is no such mechanism. What you should do instead is to do your validation magic using standard means of WPF. Please see the following link: http://msdn.microsoft.com/en-us/library/ms752347.aspx#data_validation.
Anyway, as long as you use MVVM you can always detect that text has changed in the setter of the bound property in your view model.
I'm building a custom control in Silverlight, extending TextBox. The purpose of the control is to provide a watermark logic (default text, typically used in search boxes). I managed that, when accessing the Text property, it will return string.Empty if Text == Watermark. Indeed, you don't want to consider something like "Enter name here" as a relevant value. When it comes to TwoWay databinding, things get more complicated.
I created a ValueConverter, that takes as parameter the watermark and returns string.Empty if Text == Watermark, Text otherwise. I want the control to be very ease to use, so it would be cool if the client code wouldn't have to specify each time that converter when binding to the Text property. Instead, the converter would be plugged inside the custom control, on the binding object related to the Text property.
I tried the following code, but it crashes because the binding object cannot be modified once it has been assigned. I tried that code in the Load() and OnApplyTemplate() events.
var watermarkedTextBox = (WatermarkedTextBox)dependencyObject;
var textBindingExpression = watermarkedTextBox.GetBindingExpression(TextProperty);
if (textBindingExpression != null)
{
var textBinding = textBindingExpression.ParentBinding;
textBinding.Converter = new WatermarkConverter();
textBinding.ConverterParameter = watermarkedTextBox.Watermark;
watermarkedTextBox.SetBinding(TextProperty, textBinding);
}
So I need to intercept the binding object at the right time (where it's still allowed to modify it). Any ideas ?
Thanks in advance,
Thibaut
All right, discussed this with colleagues, found the optimal solution.
The watermark is defined in the ControlTemplate of the custom control. It's a TextBlock added in the TextBox, hidden on focus, shown if text is empty. Code is much better like that :
No need to play with the Text property and change it under certain conditions to change it to watermark, or change it to string.Empty so the watermark text is never returned (was error prone)
Watermark text style can be directly template bound (TemplateBinding), so it's great, without any C# code, client will be able to customize the appearance of the watermark : color, italicize and more
Offers new possibilities (image watermark textbox almost for free)
See you ;)
I haven't tried it yet but the Silverlight 4 Textbox has a Watermark property.