WPF Button IsEnabled Check on Multiple Bindings - c#

I have the IsEnabled property of a XAML button configured with the following databinding currently:
<Button Name="ThirdPartyPostoneButton" Content="Postpone"
Click ="postponeThirdPartyUpdatesButton_Click" Margin="5,5,0,0"
Height="25" IsEnabled="{Binding Item3.CanDefer}"/>
I need to also add a check for IsEnabled="{Binding Item3.InstallSourceExists}" (in other words both criteria must be met in order for the button to be enabled). How can I accomplish this?

Two options I can think of:-
Use a MultiBinding plus a custom IMultiValueConverter that checks both values are true.
Expose a new property on your "Item3" model that simply returns true if the other properties are both True. This is a cleaner approach, and means that if the logic changes in the future (e.g. you need to include a third bool property), you don't have to touch your XAML.

Use a multibinding like this:
<Button Name="ThirdPartyPostoneButton" Content="Postpone" Click ="postponeThirdPartyUpdatesButton_Click" Margin="5,5,0,0" Height="25" >
<Button.IsEnabled>
<MultiBinding Converter="{StaticResource MyCustomConvertor}">
<Binding Path="Item3.CanDefer"/>
<Binding Path="Item3.InstallSourceExists"/>
</MultiBinding>
</Button.IsEnabled>
</Button>

Related

Setting AutomationProperties on templated control

I'm needing be able to set an AutomationId on some controls that are generated from a template based on assets that are checked into a system.
I've verified that all of the custom controls that encapsulate the templated controls handle AutomationId properties.
I've tried the following with no luck:
<DataTemplate DataType="assets:IAssetVM">
<Border Background="Transparent" x:Name="ItemContent" MouseLeftButtonUp="ItemContent_OnMouseLeftButtonUp">
<Border.InputBindings>
<MouseBinding Gesture="LeftDoubleClick" Command="{Binding FollowAssetButtonCommand}" />
</Border.InputBindings>
<Grid Height="30">
<AutomationProperties.AutomationId>
<MultiBinding StringFormat="AID_{0}-{1}">
<Binding Path="Name" />
<Binding Path="NumericID" />
</MultiBinding>
</AutomationProperties.AutomationId>
...
</Grid>
</Border>
</DataTemplate>
Update
Looking back through the logical tree of the application while it's running I realized that the last level I was able to get to with the automation properties assignment contains a couple of different GroupItem classes (different command modes for the assets in the system).
So the structure looks like:
-> List View "" "Test_AssetListView"
|-> Group Item "Mode 1" ""
|-> List Item "Vm.Assets.AssetVM2" ""
|-> Group Item "Mode 2" ""
I don't think I should need to override the OnCreateAutomationPeer() method for the Group control as (I'm pretty sure) it's a base(?) type of control.
Any ideas?
Thanks in advance for any help!

Using XAML <Binding> sytax to bind a DataContext?

I have a WPF UserControl which allows the editing of an data object (VariableDataGroup). When I use the following syntax the binding works and my user control displays correctly:
<vdi:VariableDataPageView DataContext="{Binding VariableData}" Grid.Row="4" Grid.Column="1" >
Where VariableData is a property on the parent screen's ViewModel.
However, when I try and use the "<Binding>" syntax then my user control doesn't display the data.
<vdi:VariableDataPageView Grid.Row="4" Grid.Column="1" >
<Binding Path="VariableData" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
<!--<Binding.ValidationRules>
<validation:VDIComittedValidationRule ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>-->
</Binding>
</vdi:VariableDataPageView>
The reason I want to switch to using the syntax is to use a custom validation rule to fit in with the exiting code.
First Question: What would be the equivalent syntax to 'DataContext="{Binding VariableData}"' ?
Second Question: Is there a recommended way of performing validation in a UserControl and integrating that with the validation on the parent view? The way I think it should work is that the UserControl performs all its own validation and just passes a validated yes/no result to the parent page but the whole WPF model of programming is new to me.
Thanks,
Canice.
The equivalent syntax to DataContext="{Binding VariableData}"
<vdi:VariableDataPageView Grid.Row="4" Grid.Column="1" >
<vdi:VariableDataPageView.DataContext>
<Binding Path="VariableData" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
<!--<Binding.ValidationRules>
<validation:VDIComittedValidationRule ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>-->
</Binding>
</vdi:VariableDataPageView.DataContext>
</vdi:VariableDataPageView>

Multiple command parameters wpf button object

How can I send multiple parameters from Button in WPF? I am able to send single parameter which is value of TextBox properly. Here is the code.
XAML
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="133,22,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" />
<Button Content="Button" Grid.Row="1" Height="23" Command="{Binding Path=CommandClick}" CommandParameter="{Binding Text,ElementName=textBox1}" HorizontalAlignment="Left" Margin="133,62,0,0" Name="button1" VerticalAlignment="Top" Width="75" />
Code behind
public ICommand CommandClick { get; set; }
this.CommandClick = new DelegateCommand<object>(AddAccount);
private void AddAccount(object obj)
{
//custom logic
}
Other than using the approach of defining properties in you class (let's call it your ViewModel) to be binded by your view, there are times (not common) where we don't wan't to do so, an important tool to know in these situations is the MultiBinding, so just for completeness sake , even though you are satisfied with the first option, I'll cover another approach.
so to answer your question:
1. MVVM Approach :
Use the MVVM approach and define properties to binded by your view, and use those properties in your ViewModel's command without the need for CommandParameters.
2. MultiBinding : (Can live happily with MVVM approach)
Passing the Command Parameter as a Multi Binded parameter as seen here:
<Button Content="MultiBindingExample" Command="{Binding MyCommand}">
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource MyMultiConverter}">
<Binding Path="..." ElementName="MyTextBox"/>
<Binding Path="..." ElementName="MySomethingElse"/>
</MultiBinding>
</Button.CommandParameter>
</Button>
With your Converter Defined using the IMultiValueConverter Interface:
public class MyMultiConverter: IMultiValueConverter
{
public object Convert(object[] values, ...)
{
return values.Clone();
}
}
and for extracting the values:
Simply refer to the parameter in your command as an Object[] and use the parameters in the same order as in the MultiBinding.
How can i send multiple parameters from button in wpf.
You can only send one parameter as the CommandParameter.
A better solution is typically to just bind the TextBox and other controls to multiple properties in your ViewModel. The command would then have access to all of those properties (since it's in the same class), with no need for a command parameter at all.

How to let View Model know about successfully validated form

I have a registration form with few fields. It´s a PRISM MVVM application.
XAML of one of the field looks like this (RegisterView.xaml):
<TextBlock>Surname</TextBlock>
<TextBox Validation.ErrorTemplate="{StaticResource validationTemplate}" HorizontalAlignment="Left" Margin="0" Name="Surname" VerticalAlignment="Top" >
<TextBox.Text>
<Binding Path="Surname" UpdateSourceTrigger="LostFocus" >
<Binding.ValidationRules>
<val:Required />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
As you can see from the code above, I use class Required to validate the field. Function Validate() of class Required then returns ValidationResult object. I also defined some triggers to styles for inputs, so I´m able to show validation result to the user in view.
What I don't know is how to detect the state of validation of all the inputs in ViewModel. In the ViewModel, I have the SaveUserCanExecute function which should enable/disable registration form submit button on the basic on a validation state of all the inputs.
So is there any simple way how to achieve this?
I could make some workaround for this, but I think is not the proper way.
Now I made a Submit_Click function in a View code behind fired on a Click event of a Submit Button.
In RegisterView.xaml
<Button Content="Register" HorizontalAlignment="Left" Margin="0" Name="Submit" VerticalAlignment="Top" Command="{x:Static inf:Commands.SaveUser}" Click="Submit_Click" />
I also created new public boolean variable "formIsValid" in code behind. When submit button is pressed, then I check whether all inputs has no validation error (with Validation.GetHasError(InputName) function). If so, I set the formIsValid variable to true, otherwise, I set it to false.
In RegisterView.xaml.cs
private void Submit_Click(object sender, RoutedEventArgs e)
{
if (Validation.GetHasError(Firstname) == false && Validation.GetHasError(Surname) == false)
{
registerFormValid = true;
}
else
{
registerFormValid = false;
}
}
Then in ViewModel SaveUserCanExecute function looks like this:
private bool SaveUserCanExecute(string parameter)
{
if (View.registerFormValid == true)
{
return true;
}
return false;
}
But as I mentioned before, I think it´s not the proper way, and I´m looking for some more clear way.
implement IDataErrorInfo in your ViewModel then you have all information you need in your VM. Your XAML just need the ValidatesOnDataErrors=true
<TextBlock>Surname</TextBlock>
<TextBox Validation.ErrorTemplate="{StaticResource validationTemplate}" HorizontalAlignment="Left" Margin="0" Name="Surname" VerticalAlignment="Top" >
<TextBox.Text>
<Binding Path="Surname" UpdateSourceTrigger="LostFocus" ValidatesOnDataErrors="True">
</Binding>
</TextBox.Text>
</TextBox>
EDIT: check the use of DelegeCommand and then your command CanExecute can simply check then for string.IsNullOrEmpty(this.Error).
Bind a command (ICommand) to your Submit Button and implement this logic in Its CanExecute method. Here is a classic ICommand implementation.

How can I set the DataBinding to an arbitrary Property in XAML?

I have the following problem: I am designing an UserControl, a graded-color gauge. I have decieded to use the MVVM design patern, which turns out to be a good choice. However, I have the following problem. In the View XAML file, I try to convert a value to a color, using custtom converter, which needs 2 parameters. For this purpose, I use the MultiBinding:
<ItemsControl ItemsSource="{Binding Path=ViewData}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle Height="2">
<Rectangle.Fill>
<MultiBinding Converter="{StaticResource colorConverter}">
<Binding Path="Value"/>
<Binding Source="{StaticResource Palette_ICOS}"/>
</MultiBinding>
</Rectangle.Fill>
</Rectangle>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The thing is, that I don't want to use
{StaticResource Palette_ISO1}
as a second parameter, but a Property, which is a direct property of the DataContext and is not a property of the ViewData collection member. I have tried several ways to accomplish this scenario, but without signifficant success.
As last, I have tried the following:
<Binding Path="CurrentPallete"/>
and the CurrentPallete looks like:
public Palette CurrentPalette
{
get { return _currentPalette; }
set
{
_currentPalette = value;
}
}
i.e. a Property in the Class, whose instance is set as a DataContext of the main control, which hosts the ItemControl. What I get is a
[0x00000001] = {DependencyProperty.UnsetValue}
value in the Debugger, when the corresponding convertor is invoked,which probably means, that the Property cannot be found. Can anyone point out what is the way to achieve the desired effect? Thanks a lot!
<Binding Path="DataContext.Palette_ICOS"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ItemsControl}" />
Have you tried
<Binding Path="Palette_ICOS"/>
If Palette_ICOS is a property in the current item's DataContext binding it should work.

Categories