Give WPF design mode default objects - c#

In my application I have
<Rectangle.Margin>
<MultiBinding Converter="{StaticResource XYPosToThicknessConverter}">
<Binding Path="XPos"/>
<Binding Path="YPos"/>
</MultiBinding>
</Rectangle.Margin>
The Data Context is set during runtime. The application works, but the design window in VS does not show a preview but System.InvalidCastException. That’s why I added a default object in the XYPosToThicknessConverter which is ugly.
class XYPosToThicknessConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// stupid check to give the design window its default object.
if (!(values[0] is IConvertible))
return new System.Windows.Thickness(3, 3, 0, 0);
// useful code and exception throwing starts here
// ...
}
}
My Questions:
What does VS/the process that builds the design window pass to XYPosToThicknessConverter and what is way to find it out by myself.
How do I change my XAML code, so that the design window gets its default object and is this the best way to handle this problem?
I’m using VS2010RC with Net4.0

Try put a fallback value to your binding. That's what I do to get stuff to display 'as if' in the design mode.
Something="{Binding Smthing, FallbackValue='hello world'}"
HTH

You'll need to make sure that the designer can get a valid copy of "XPos" and "YPos", and they are the same values as at runtime.
Chances are your DataContext is not being set in the View appropriately, so the converter gets null. If you set the DataContext to a valid object (which can be design time data), you're code should work without the defaults in the converter.

Related

Bind text to converter based on change in two different objects [duplicate]

This question already has answers here:
Binding ConverterParameter
(3 answers)
Closed 4 years ago.
I am trying to bind the text of a textblock based on two things -
Object ShoppingList
Object Items(which is a property of the ShoppingList object. Type is List).
I want to invoke the converter as I want the text to be dependent on change in the value of either of the above.The only way that I could think of was this way as shown below. But this is not possible as I cannot bind the ConverterParameter to the object ShoppingList as it is not a dependency property .
<TextBlock
Margin="5"
TextWrapping="Wrap"
Text="{Binding Items, Converter={StaticResource ABCDConverter}, ConverterParameter="???" />
Below is the converter I had written
Convert(Items obj, object par, xyz culture)
{
if (obj != null && par!=null)
{
var parameter = (ShoppingList)par;
// Different Logic to determine the string to be returned
}
return string.Empty;
}
In simple words, how can I invoke the converter based on changes in either of Items or ShoppingList
Sounds like you're looking for MultiBinding, paired with an IMultiValueConverter.
That being said, I would strongly suggest that you determine the needed value in your ViewModel since you already have all the needed properties there and you know when and how they change. Once you have your derived property, just use regular binding to bind to it in the View. Using MultiBindings will generally tend to break your separation of concerns as you will end up adding specific logic to the converter that really should be in the ViewModel. One case where I did find MultiBindings indispensable was in a group header template (i.e. for a DataGrid). It would be pretty well impossible to get the values from the ViewModel as you don't know how many groups you have or what they will contain at runtime as there are just too many moving parts. In this case, MultiBindings were great.
On the other hand, if you are just targeting a specific element that you know about at design time, you should generally avoid using MultiBinding for the reasons stated above. In addition, MutliBinding are quite verbose compared to regular Bindings, making your XAML harder to read which creates a greater potential for bugs and limits future extensibility and maintainability.
But if you must, here's a simple example:
XAML
<Window x:Class="testapp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:testapp"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:MyMultiConverter x:Key="multiTextConverter"/>
</Window.Resources>
<Grid>
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource multiTextConverter}">
<Binding Path="someProp"/>
<Binding Path="someOtherProp" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Grid>
</Window>
Converter
public class MyMultiConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType,
object parameter, CultureInfo culture)
{
string ret = null;
if(values.Count() > 1)
{
string value1 = values[0] as string;
string value2 = values[1] as string;
ret = value1 + value2;
}
return ret;
}
public object[] ConvertBack(object value, Type[] targetTypes,
object parameter, CultureInfo culture)
{
}
}
Now, if you're binding to a List, and, assuming you care when items are added or removed, you will rather need to use an ObservableCollection as it implements the INotifyCollectionChanged Interface see here.But this is not quite enough, as the binding will not be subscribing to that event. You will need to listen to the change in collection in your DataContext (ViewModel?). Then create some dummy property, and when the collection changes, just increment the dummy property (with INotifyPropertyChanged of course) and use that property in the multibinding as a third binding. This way, the TextBlock text will get updated if either a property changes, or your list changes.
If you don't care about the changes in the collection, only when you assign a whole new collection, then the sample provided will work as is.

How do I validate user input in a Prism 6.3 WPF app?

I am trying to write a WPF application using c# and the with the help of Prism 6.3 library. I watched all available tutorials on pluralsight.com for Prism by #BrianLagunas . But not of them show how to do data validation.
I need to add input validation before I submit the data to the database.
How can I add validation rule, and how can I check if the form is valid before I save the data to the database?
You are look for MvvmValidation.
I think the library satisfy your needs.
Go and have a try, it has some examples.
Simple wpf binding validation might work here.
Given this code from a view's xaml:
<TextBox>
<TextBox.Text>
<Binding Path="Data">
<Binding.ValidationRules>
<myNamespace:IntegerValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
and this rule
public class IntegerValidationRule : ValidationRule
{
public override ValidationResult Validate( object value, CultureInfo cultureInfo )
{
var stringData = value as string;
if( stringData == null )
return new ValidationResult( false, "not a string" );
int dummy;
if( !int.TryParse( stringData, out dummy ) )
return new ValidationResult( false, "not an integer" );
return ValidationResult.ValidResult;
}
}
you'll get a nice red border around the text box if you enter something that's not an integer. And, more importantly, the view model's Data property setter won't be called.
If you need complex validation (i.e. no single property value is valid, but only a combination of values of differnet properties), then your view model needs to implement INotifyDataErrorInfo. You basically do your validation in any of the affected properties' setters and finally raise ErrorsChanged...

How do I invoke RelayCommand with multiple parameters?

I need to change some functionality in a WPF app we've written. We use MVVM Light to implement MVVM. Whenever we've needed to pass some parameters to a method we've used MVVM Light's Messenger class. I've got to pass 3 parameters to a method, but I thought I'd try doing this without using the Messenger class, but instead I hoped I could do it using the RelayCommand() method. I did a search and found this post here on SO, from some years ago. But at least to me, I think this won't work as it's using just 1 type; string in this case. After making some trials and realizing that I'd done it wrong, I decided I could probably create a class with the 3 values I need in it as properties of the class, put it into Models folder and use
new RelayCommand<MyClass>()
So, first question, just to verify that I've got the right idea, I think I would do something like this:
new RelayCommand<MyClass>((mc) => MyMethod(mc.Prop_A, mc.Prop_B, mc.Prop_C)
Is that correct?
Assuming the answer to the above is yes, then how do I actually pass parameters to this when I bind to it in the XAML? This command is going to be associated with a button on the window/page, so I'll be using the Button's Command property. How do I actually pass in the values for the MyClass instances Prop_A, Prop_B and Prop_C?
So, first question, just to verify that I've got the right idea, I
think I would do something like this:
new RelayCommand<MyClass>((mc) => MyMethod(mc.Prop_A, mc.Prop_B, mc.Prop_C)
This is correct.
Assuming the answer to the above is yes, then how do I actually pass
parameters to this when I bind to it in the XAML? This command is
going to be associated with a button on the window/page, so I'll be
using the Button's Command property. How do I actually pass in the
values for the MyClass instances Prop_A, Prop_B and Prop_C?
This will actually depend on where would Prop_A, Prop_B and Prop_C come from. If these properties are already inside your view model, then there is no need for you to pass parameters using XAML.
new RelayCommand<MyClass>((mc) => MyMethod(mc.Prop_A, mc.Prop_B, mc.Prop_C)
will change to
new RelayCommand<object>((param) =>
{
// param is not used.
var mc = this.MC; // assuming your view model holds the mc value
MyMethod(mc.Prop_A, mc.Prop_B, mc.Prop_C);
});
We must make sure that when we load our view model, we have everything we need. Else, use an IoC to fetch whatever it is you need to.
Binding a parameter to your command is often useful for something like a calculator app where you want to pass the button value to your command such as 0 - 9.
<Button Grid.Row="0" Grid.Column="1" Content="7" Command="{Binding PerformAction}" CommandParameter="7"/>
I would want to stay away from defining classes in your view. For the separation of concern, the view should only know of the properties to be bounded to and not the models.
So, first question, just to verify that I've got the right idea, I think I would do something like this:
new RelayCommand<MyClass>((mc) => MyMethod(mc.Prop_A, mc.Prop_B, mc.Prop_C)
Is that correct?
Yes, it is.
How do I actually pass in the values for the MyClass instances Prop_A, Prop_B and Prop_C?
Simply create an instance of the class that holds the parameters inside your xaml as command parameter:
<Button Command="{Binding Command}">
<Button.CommandParameter>
<local:MyClass Prop_A="a value" Prop_B="b value" Prop_C="c value" />
</Button.CommandParameter>
</Button>
There is another approach to do this by using IMultiValueConverter:
class MultiValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
foreach (var item in values)
{
//process the properties passed in and you will need to unbox those parameters
}
return new object();
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
And then in xaml (Button code):
<Button Content="Test" Style="{StaticResource contextMenuAware}" Command="{Binding MultiParameterCommand}">
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource MultiValueConverter}">
<Binding Path="Items"/>
<!-- Pass more Bindings here or static values -->
</MultiBinding>
</Button.CommandParameter>
</Button>
Here is the code for inclusion of the converter:
xmlns:converter="clr-namespace:SO_app.Converters"
And then in you Window Resources tag:
<converter:MultiValueConverter x:Key="MultiValueConverter"/>
This way you can use Binding when passing parameters without implementing DependencyProperties.
Here is how I did it:
Your CommandRelay object takes object as parameter, you convert that object to object[] then each element to its own object.
private RelayCommand<object> _YourCommand;
public RelayCommand<object> YourCommand
{
get
{
return _YourCommand ?? (_YourCommand = new RelayCommand<object>(p =>
{
var values = (object[]) p;
int item1 = int.Parse(values[0].ToString());
string item2 = values[1].ToString();
double item3 = double.Parse(values[2].ToString());
}));
}
}
Then, in xaml (Of course, your Paths in Binding must be valid references to your binded objects)
<Button Command="{Binding YourCommand}">
<Button.CommandParameter>
<MultiBinding>
<Binding Path="Item1"/>
<Binding Path="Item2"/>
<Binding Path="Item3"/>
</MultiBinding>
</Button.CommandParameter>
</Button>

Accessing Binding from Type Converter?

I've spent a fair bit of time trying a number of different ways to solve an issue I'm having, to no avail, so I'm hoping someone here can help.
I have a Text Box element with Two-Way binding, which utilises a Type Converter to convert the value from a string to a custom Data type, say, MyCustomType. This is working fine, however due to a change in my project's requirements, I now need to perform extra processing prior to the conversion taking place.
In order to perform this extra processing, however, I need to be able to access the "source" text box, or the binding context. Neither of which I have been able to access.
Is there any way to access the source text box, from a Type Converter's ConvertFrom() method?
I have tried to use the ITypeDescriptorContext parameter passed (by WPF) to the ConvertFrom() method, however most of the properties therein are null.
i.e.
public class MyCustomTypeConverter : TypeConverter
{
...
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
// Context is
return new MyCustomType(value);
}
...
}
I have also tried using a MultiValueConverter, and avoiding the Type converter entirely, however this led to a LOT of extra code, and didn't really help. I would prefer to avoid going down this route, as a Type Converter is much more elegant.
Any advice/assistance would be greatly appreciated! :)
EDIT: I ended up changing the way that validation is performed (using INotifyDataError instead of validating on exceptions), and ended up re-writing the ConvertFrom() method in my Type Converter, such that I wouldn't need to access the TypeDescriptor's context anymore.
I wouldn't recommend using the context from the ConvertFrom() method, as it (being a private property) isn't guaranteed that the property will exist in the future (though I haven't read anything to support this, it is best to assume that private properties can be removed/renamed without notification from the MS development team), and it isn't set when setting a property's value programmatically, like so:
TypeConverter converter = TypeDescriptor.GetConverter(typeof(MyCustomType));
converter.ConvertFrom(mySourceValue);
If you're reading this and really need to access the context parameter, you can do so using my method below, at your own risk.
I was able to solve this by interrogating the ValueConverterContext class, and accessing the private _targetElement field, like this:
var sourceTextBox = context.GetType().GetField("_targetElement", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(context)
Thanks for your help nonetheless. :)
edit: To access the Bindings for this TextBox, you can simply cast sourceTextBox as TextBox and then:
var BindingExpression = sourceTextBox.GetBindingExpression(TextBox.TextProperty);

Where to place the dependency property?

I am confused about where I put a dependency property when building a WPF application using the MVVM pattern. Does it go in the Model or the ViewModel?
Edit
After looking at early answers (thanks for those), I find that I am still confused, so I am giving more detail to help someone explain this to me.
I have a class called Station. It is used by surveyors and civil engineers to represent the length along a road. For the most part, a Station is just a double, but it has a few decorations. First off, the format is different. When distance along is greater than 100 feet, we add a + symbol as another way to format it. So 1234.56 feet down the road we might have Station 12+34.56. (I will skip the other decorations since this one is good enough for my point.)
Thus the logic for the special formatting lives in Station, a class in the Model. I want a TextBox in the View to take user input of 1234.56 and coerce it to a text value of "12+34.56". So I want a TextBox to give the user access to a value in the Model, so it needs to be a dependency property. (That is correct, isn't it?) But the business logic for coercing/parsing/understanding how to go back and forth between a TextBox and a Station should live in the Station class. (Right?)
Furthermore, I will later want to give the user the ability to set the station value by clicking on a graphical drawing of the road, including dynamically updating the value as the mouse moves and locking the value in upon issuing a data point. (Now you see why I tried to keep this brief.)
So is this not something that I would want to make a dependency property, especially with the dynamic data point possibly getting involved later? If not, how do I hook a text box item to a station using MVVM? (I really have researched this a lot before asking my question, but with no success.)
Paul
Typically, you wouldn't use Dependency Properties in either the ViewModel or the Model.
Dependency properties are really intended for View-related functionality only. You'd bind a View's DP to a ViewModel, which would instead implement INotifyPropertyChanged.
Putting a DP into the ViewModel or the Model itself would actually violate one of the main goals of MVVM, as this would couple the user interface technology (WPF) to your Model or application-specific types.
With MVVM, you prefer INotifyPropertyChanged properties over DependencyProperties.
Your Station class should implement the property with INotifyPropertyChanged. Your TextBox binding should use a converter to present and read the value in the format you wish.
public class Station : INotifyPropertyChanged
{
private decimal _value;
public decimal Value
{
get { return _value; }
set
{
if (_value == value) return;
_value = value;
NotifyPropertyChanged("Value");
}
}
/* INotifyPropertyChanged implementation */
}
public class StationConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string formattedValue = // Add the plus here
return formattedValue;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string numericValue = // Parse the optional '+' out of the value
decimal stationValue = decimal.Parse(numericValue);
}
}
XAML:
<UserControl.Resources>
<StationConverter Key="StationConverter" />
<TheViewModel Key="TheVM" />
<UserControl.Resources>
<TextBox Text="{Binding Path=Station.Value, Source={StaticResource TheVM}, Converter={StaticResource StationConverter}, Mode=TwoWay}"/>

Categories