I'm designing a form for a complex backing model in WPF. Some of the form controls rely on multiple options being set on the underlying view model, so I've set up for example
<TextBlock.Visibility>
<MultiBinding Converter="{StaticResource AndMultiValueVisibilityConverter}">
<Binding Path="RelevantSystemOption" />
<Binding Path="RelevantLicenseKeyOption"/>
</MultiBinding>
</TextBlock.Visibility>
AndMultiValueVisibilityConverter takes booleans and only makes something visible if they're all true, for reference.
This turns the control's visibility off at design time, which I don't want.
I'm aware of the ability of Expression Blend and design-time attributes to make certain layout determinations that can be ignored at run-time. d:IsHidden isn't being respected, and d:LayoutOverrides doesn't work on Visibility since it's a dynamic property.
I'd rather not dummy up an entire backing model with d:DataContext. I will if I have to, but is there an easier way to just force this particular control and maybe a handful of others to always be visible at design-time?
Just use
DesignerProperties.GetIsInDesignMode(new DependencyObject())
in your multivalue converter to determine if you're in the designer and, if so, return true.
It's okay to use this in a converter in an MVVM application, if you think it might go against the pattern. The converter is a UI concern.
https://msdn.microsoft.com/en-us/library/system.componentmodel.designerproperties(v=vs.110).aspx
Related
I am attempting to validate input on a DataGrid which is populated by a DataView (e.g. myDataGrid.ItemsSource = myDataView). However, all the WPF DataGrid validation examples I have seen assume that the DataGrid source is a C# class. I can't figure out how to hook up a single cell (i.e. a column) to a code-behind validation. Can someone give an example or point me to one?
Ok, I did some quick tests; I think the main impediment to really doing it manually is that the DataGridCell doesn't create any bindings for its content when assigning directly a DataView for display. However, if you're willing to jump through the hoops of assigning custom DataGridTemplateColumns when creating the DataGrid, you can access the bindings on, say, the TextBox instances inside the template, and set custom validation errors on them.
Well actually, either this or override the default style of the textboxes generated by the DataGrid; you see, the default textbox style doesn't have any borders or anything, so setting a validation error on it doesn't have any effect. Making it into a normal textbox with DataTemplate or overriding its style would enable you to actually make something visible as an effect of setting the validation error.
However you'll need to do some research by yourself; I did a quick prototype and it works, but I can't create the binding correctly in the DataTemplate (either I forgot all the WPF I knew since I worked with it last, or I only know how to work with proper bindings :)). If you get somewhere with that it's easier going forward:
Somehow get access to a BindingExpression; what I did was attach a handler to the LostFocus event and checking if what lost focus was a textbox that was inside a DataGridCell; if so, I simply mark that binding as invalid (with t representing a TextBox instance):
var x = t.GetBindingExpression(TextBox.TextProperty);
Validation.MarkInvalid(x, new ValidationError(new ExceptionValidationRule(), x.ParentBinding, "error", new Exception("error")));
I must confess I'm not sure anymore what each argument's role is in the ValidationError constructor is (I think the exception message is displayed by default in the validation tooltip? Or is it the error content?), but I'm sure you can figure it out. Now if you don't mind, I think I'll take a break... like I said, it's not easy going against the flow :)
So I did some more research, and what I was basically missing was that I can specify the column name with the Path attribute of a Binding (or even use the column ordinal in brackets, e.g. Path="[0]"). After that realization, everything is basically the same as using a class property. So a typical DataGrid column definition I use follows:
<DataGridTextColumn Header="Regular" EditingElementStyle="{StaticResource ValidationErrorStyleBoxRA}" ElementStyle="{StaticResource ValidationErrorStyleBlockRA}" Width="60">
<DataGridTextColumn.Binding>
<Binding Path="HourlyRate" StringFormat="F3" ValidatesOnExceptions="True" ValidatesOnDataErrors="True" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:HourlyRatesAmountValidate ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</DataGridTextColumn.Binding>
</DataGridTextColumn>
I have an object that contains an IEnumerable called ValidPhones as a property. When I bind it to a WPF ListView like such:
<ListView DataContext="{Binding ValidPhones}">
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat='{}{0}: {1}'>
<Binding Path='Type' />
<Binding Path='PhoneNumber' />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</ListView>
It still ends up displaying the ": " in the UI even when the Enumerable is empty. Is there a simple way to suppress that from happening?
What backend language are you using with wpf? I'm fairly sure it's either c# or VB.NET. I'm no expert, but I'm pretty sure you can access things like ListViews from code.
EDIT: sorry...I missed the comment at the top. Please mark your threads as closed when you solve the problem so silly people like me don't post useless answers.
Sure! In fact, there are a few options for you to consider.
Option 1: You can always change the visibility of your control to "collapsed" when the list is empty, which will keep your application from rendering it in the xaml. This can be done from your C# code or your xaml. this is a viable solution, but be careful that you don't have other controls that are dependant upon the location of the listview, because setting the visibility to "collapsed" will tell your applicaitonPage not to render the listview at all, which can mess with your layout.
Option 2: You can set up an "IsEmpty" attribute for your iEnumerable, and then bind that attribute to the textblock's text property. If you do it this way then you will need a converter that can return either a blank string or the properly formatted one depending on the value of IEnumerable. This opiton is slightly more complicated, but it has the benefit of leaving your listview alone so that the other controls don't move around.
Please let me know if you need help with either of these options, or if they need clarificaiton :)
I have control thats inherits from textbox
public class MyTextBox : TextBox
This has a style
<Style TargetType="{x:Type Controls:MyTextBox}">
one of the Setters is
<Setter Property="Template">
I want to be able to set the Binding.ValidationRules to something in the template, thus affecting all instances of this type of textbox.
I can therefore make textboxes for say Times, Dates, Numerics, post/zip codes.. or whatever i want,
I don't want to have to set the validation rules every time i create a textbox. I just want to say i want a NumericTextBox and have it validate in whatever way is set in the template.
Is this possible?
All i have seen so far is the ValidationRules being set on each instance of the control e.g.
<TextBox x:Name="txtEMail" Template={StaticResource TextBoxErrorTemplate}>
<TextBox.Text>
<Binding Path="EMail" UpdateSourceTrigger="PropertyChanged" >
<Binding.ValidationRules>
<local:RegexValidationRule Pattern="{StaticResource emailRegex}"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
(from http://www.wpftutorial.net/DataValidation.html)
As you see, validation rules are set along with bindings. I came across the same problem and the working solution for me was to do something like this:
public MyTextBox()
{
this.Loaded += new RoutedEventHandler(MyTextBox_Loaded);
}
void MyTextBox_Loaded(object sender, RoutedEventArgs e)
{
var binding = BindingOperations.GetBinding(this, TextBox.ValueProperty);
binding.ValidationRules.Add(new MyValidationRule());
}
The problem here is to be sure that the binding is set before we add the validation rule, hence the use of Loaded, but i'm not sure if this will work on every scenario.
I am not sure it is possible to do exactly what you want. You might be able to do it with a lot of trickery in property setters (I wouldn't rely on this, since it would involve modifying bindings, which are by definition dynamic), or with code behind/custom controls.
Instead I suggest you push your validation into your ViewModel, probably with IDataErrorInfo. There are many articles out there. Here's one of the first ones I found with a search just now for "MVVM validation":
MVVM - Validation
Doing this will allow you to use standard OO composition techniques, so you can avoid repeating yourself :)
Long version:
I have a simple WPF converter than does date conversions for me. The converter basically checks the date and formats it in dd/M/yyyy format. The converter does some smarts with the handling of the date which means that the user could type "23061971" and the value will be converted to "23/06/1971".
All this is trivial and working. The problem is that when I update the value, it does not update the caret position. Assume "|" is the caret and the user types "23061971|" then a millisecond later it is updated to "230619|71".
What I'd like to do is detect if the caret at the end of the value - if so, shift it to the end of the edit field once the new value has been updated. In order to do this, I'll need access to the edit control to which the converter is attached.
Short version:
From A WPF converter, can I get a reference to the control that is bound to that converter?
Here is an excellent article on how to get direct access to the control from within a converter: http://social.technet.microsoft.com/wiki/contents/articles/12423.wpfhowto-pass-and-use-a-control-in-it-s-own-valueconverter-for-convertconvertback.aspx
Essentially:
<MultiBinding Converter="{StaticResource MyConverter}" >
<Binding RelativeSource="{RelativeSource Self}" Mode="OneTime"/>
<Binding Path="MyValue2" />
</MultiBinding>
in the converter values[0] will be your control, ready for casting and values[1] would be the data that you are binding.
In a ValueConverter you can't get access to the control - however you can get access if you use a multibinding with a multivalueconverter.
In the multibinding the first binding is your binding as now - without the converter. The second binding you bind to the control itself - there you go acces to the control.
I have used this approach to gain other things also - you can make "dummy" bindings to properties you want to trigger updates, i.e. if you bind to the control itself you will only get updated if it changes, not if a property does - so create dummybindings for those.
You can send the control with the MultiBinding like this.
<TextBox Height="100" x:Name="textbox1" DockPanel.Dock="Top">
<TextBox.Text>
<MultiBinding Converter="{StaticResource MultiConverter}">
<Binding ElementName="textbox1" Path="." />
</MultiBinding>
</TextBox.Text>
</TextBox>
I don't thknk a converter has any way to get at the control that is using it. It is only a simple piece of logic that converts one object to another object.
However, in you case, perhaps you can trap the change event and then manually move the caret. If you think about it, caret position is strictly a view concern; it has nothing to do with converters or the data. You should not burden view-controller logic with it. You should definitely not burden converter logic (which is classified under utility classes) with it.
I have a WPF app with many list based controls in a window, which all are bound to different CollectionViews.
At the window level is there a way to get the current selected item for the currently in focus list based control? I know I can do this with some fairly trivial code by looking for the in focus element but does WPF support this as a concept out of the box?
Something like Window.CurrentSelectedDataItem would be great. I am looking into using this as a way to centralize command management for enabling disabling commands based on a current selected data item.
I don't think that there is a property like you specify, but as an alternative you could register a ClassHandler for the ListBox.SelectionChanged event in your Window class:
EventManager.RegisterClassHandler(typeof(ListBox), ListBox.SelectionChanged,
new SelectionChangedEventHandler(this.OnListBoxSelectionChanged));
This will get called whenever the selection changes in any ListBox in your application. You can use the sender argument to determine which ListBox it was that changed its selection, and cache this value for when you need it.
I haven't tried this, but you could try using a MultiBinding with a converter to get to the correct item:
<MultiBinding Converter="{StaticResource coalesce}">
<MultiBinding.Bindings>
<MultiBinding Converter="{StaticResource nullIfFalse}">
<MultiBinding.Bindings>
<Binding ElementName="List1" Path="HasFocus" />
<Binding ElementName="List1" Path="SelectedItem" />
nullIfFalse returns the second parameter, if the first is true, null otherwise. coalesce returns the first non-null element.