XAML controls binding with another controls which are in datatemplate ! - wpf

i have the following datatemplate in xaml and here i have textbox in datatemplate and button in normal XAML, what i really want is that i want to keep button be disabled until person enters something in textbox ? but its not working i have tried the follwing code
Please look into it and help me as well ! or is there any other way to do this let me know !
<UserControl.Resources>
<DataTemplate x:Key="dataTemplateParameter">
<StackPanel Width="170" Height="Auto" Margin="5">
<TextBlock Width="160" TextAlignment="Left" HorizontalAlignment="Left" Height="22" Text="{Binding Path=ParameterName, Mode=TwoWay}"/>
<TextBox x:Name="txtboxParameter" Width="160" Height="22" HorizontalAlignment="Left" Text="{Binding Path=ParameterValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</DataTemplate>
<Button Grid.Row="6" Name="SearchSourceParamBtn" Content="Search" VerticalAlignment="Bottom" Margin="12,5,92,0" Height="20" Visibility="{Binding SearchSourceBtnVisibility}" Command="{Binding SearchCommand}">
<Button.Style>
<Style TargetType="Button">
<Setter Property="IsEnabled" Value="True"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text,x:ElementName=txtboxParameter}" Value="">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Thanks
nallskarthi

You can achieve this by
1) binding button to RelayCommand. Then,
2) Validate the "ParameterValue" in command's CanExecute delegate.
Edit:
The better way is to have the ParameterValue in ViewModel, but for some reason you won't do that. Then, create a static ChangeNotifyable property in VM, using this property do the validation in CanExecute delegate.

Pls Validate the "ParameterValue" in the CanExecute delegate of Command object.

Related

Displaying an alternative text when no image has been assigned yet

I have an image control on which the user can drag and drop pictures. When no image has been dropped in there and the control is empty, I'd like to show an alternative text such as "Drop a picture here" to better indicate what is expected from him/her.
I can't figure out how to use triggers with this, this shows nothing at all and I can no longer drop pictures on my image control:
<StackPanel Grid.Column="1" Grid.Row="2" FlowDirection="LeftToRight" Orientation="Horizontal" Margin="0px 4px">
<StackPanel.Resources>
<DataTemplate x:Key="tmpTemplate">
<Border BorderThickness="2" BorderBrush="#FF969DFF" CornerRadius="2" VerticalAlignment="Top">
<DockPanel>
<Image Name="imgSelectedViewImage" Source="{Binding Image}" MinWidth="32" MinHeight="32" MaxWidth="48" MaxHeight="48"
HorizontalAlignment="Left" Stretch="None"
IsEnabled="{Binding EditMode}" Margin="2px"/>
<Label Content="Drag here" Name="AltText" Visibility="Collapsed"></Label>
</DockPanel>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=Image}" Value="{x:Null}">
<Setter TargetName="AltText" Property="Visibility" Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</StackPanel.Resources>
I can't tell you what you've done to break your previously working drag and drop functionality and all I can do is to suggest you undo your changes to remedy that. However, if you want to display something when a collection is empty, then there's an easy way to do that. Using the collection's Count property is no good because it won't update when items are added or removed.
You can simply add an int property next to your item collection for this, but you have to make sure that you notify the INotifyPropertyChanged interface for it also when the collection property changes:
public ObservableCollection<YourItem> YourItems
{
get { return yourItems; }
set
{
yourItems = value;
NotifyPropertyChanged("YourItems");
NotifyPropertyChanged("YourItemsCount");
}
}
public int YourItemsCount
{
get { return YourItems.Count; }
}
Then you can use it in a simple DataTrigger like this:
<Grid>
<!-- Put your normal content here -->
<TextBlock FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"
Text="Drop images here">
<TextBlock.Style>
<Style>
<Setter Property="TextBlock.Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding YourItemsCount}" Value="0">
<Setter Property="TextBlock.Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
I did it by setting the TargetNullValue and the FallbackValue to a static resource. See the code snippet below. You can of course set it to everything else you want.
<Image Stretch="Uniform"
Grid.Row="0"
Grid.Column="1"
MaxHeight="250"
MaxWidth="250"
Margin="10"
Source="{Binding Path=Character.Portrait, TargetNullValue={StaticResource FallbackImage}, FallbackValue={StaticResource FallbackImage}}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<cal:ActionMessage MethodName="ChangePicture">
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</image>
Another approach, which could be more to your liking, as it uses triggers could be this solution: Handling null when binding to an Image in XAML (look at the accepted answer). However in my opinion setting TargetNullValue and the FallbackValue is the best way to go.

ListBox item template depends on item values

In WPF, MVVC applicaiton I have quite normal listbox:
<ListBox ItemsSource="{Binding Friends}">
</ListBox>
Then each item of list uses following datatemplate:
<DataTemplate DataType="{x:Type model:Friend}">
<Border BorderThickness="1" BorderBrush="Gray" Padding="3" Name="border" Margin="3">
<StackPanel Grid.Row="1" Grid.Column="2" Orientation="Horizontal">
<TextBlock Name="DescriptionDTDataType" Text="{Binding Path=ConnectedUserID}" />
<TextBlock Name="StatusTitle" Margin="8,0,4,0">Status:</TextBlock>
<TextBlock Name="Status" Text="{Binding Path=Approved}" />
<Button Content="Approve" Command="{x:Static inf:Commands.ApproveUserConnection}" CommandParameter="{Binding}"></Button>
<Button Content="Disapprove" Command="{x:Static inf:Commands.DisapproveUserConnection}" CommandParameter="{Binding}"></Button>
</StackPanel>
</Border>
</DataTemplate>
The question is... I want to hide one of the buttons on the basic of Friend.Approved property. For example if Friend.Approved has value "approved" I want to hide button Approved and show only button Dissaprove. On the other hand if Friend.Approved has value "disapproved" then I want opposite. How to achieve this?
Thank you.
Beside creating a IValueConverter there is a pure XAML solution using DataTriggers
Just add this to your DataTemplate:
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Approved}" Value="approved" >
<Setter TargetName="Approve" Property="Visibility" Value="Collapsed"/>
</DataTrigger>
<DataTrigger Binding="{Binding Approved}" Value="disapproved" >
<Setter TargetName="Disapprove" Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</DataTemplate.Triggers>
And name your buttons:
<Button Name="Approve" Content="Approve" ...></Button>
<Button Name="Disapprove" Content="Disapprove" ...></Button>
However if you want to reuse this hiding logic in multiple places in multiple DataTemplates its better to write the Approved text to Visibility converter.
Bind the Buttons Visibility property to Approved and use a value converter to convert Approved to a Visibility value.

WPF - MVVM - Conditionally include user controls to view

In WPF my MVVM application I need to create an account search view with 2 options simple search by account # or Advanced search (by name, email, etc.)
In my AccountSearchViewModel I have a bool property IsAdvancedMode.
Also I have created 2 UserControls for each mode: SimpleSearchView and AdvancedSearchView
Now I need to show either one based on IsAdvancedMode property.
What is the best way to do it?
Also as a general solution what if I have SearchMode property that is enum. How whould you switch between multiple controls in that case?
I think you need to use Data Templating, to do that you need to create three classes:
public class Search
{
//Your Code
}
public class AdvanceSearch : Search
{
//Your Code
}
public class SimpleSearch : Search
{
//Your Code
}
and then create Data Template base on Classes:
<DataTemplate DataType="{x:Type local:AdvanceSearch }">
<StackPanel>
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text="{Binding Path=Email}"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type local:SimpleSearch }">
<StackPanel>
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
I would use a DataTrigger to swap out the ContentTemplate of a ContentControl as needed. I wrote an article about switching Views in MVVM here if you're interested (examples included)
Here's some quick test code demonstrating it:
<Window.Resources>
<DataTemplate x:Key="TemplateA" >
<TextBlock Text="I'm Template A" />
</DataTemplate>
<DataTemplate x:Key="TemplateB" >
<TextBlock Text="I'm Template B" />
</DataTemplate>
</Window.Resources>
<StackPanel>
<ToggleButton x:Name="Test" Content="Test" />
<ContentControl>
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource TemplateA}" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Test, Path=IsChecked}" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource TemplateB}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</StackPanel>
I usually drop them both and then use the BooleanToVisibilityConverter. Simplest approach with what you've got set up.
<Grid>
<SimpleSearch />
<AdvancedSearch
Visibility="{Binding IsAdvancedMode, Converter={StaticResource btvc}"/>
</Grid>
When IsAdvancedMode is true, the AdvancedSearch control will overlay the SimpleSearch. Again, this is the simplest approach, not necessarily the absolute best.

wpf binding to element

Well i guess it's easy my scenario is having 2 elements:
ListBox and Button:
<ListBox Name="BannedItemsListBox"
Margin="5"
MinWidth="100"
MaxWidth="100" " Height="
204" ItemsSource="{Binding Path=BannedItems, Mode=TwoWay}"></ListBox>
<Button Name="RemoveBannedItemsButton"
Margin="5"
MinWidth="65"
Height="22"
Click="RemoveBannedItemButton_Click">Remove</Button>
I want to bind the IsEnabled property button to be true only if Item from ListBox is selected (focused) in XAML
I tried
IsEnabled="{Binding ElementName=BannedSourcesListBox, Path=TouchesDirectlyOver.Count}"
but no go.
What does the selection have to do with the Touches? (Also the ElementName is off)
I would try this:
IsEnabled="{Binding SelectedItems.Count, ElementName=BannedItemsListBox}"
Explanation: Basically the binding system tries to convert the input to the property at hand, a boolean, so when it gets an integer, 0 will be converter to false, anything higher to true. So the Button will be enabled if one or more items are selected.
<Button Content="Button"
Height="23"
HorizontalAlignment="Left"
Margin="138,12,0,0"
Name="button1"
VerticalAlignment="Top"
Width="75"
Click="button1_Click">
<Button.Style>
<Style>
<Setter Property="Button.IsEnabled"
Value="True" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=lstTest , Path=SelectedItem}"
Value="{x:Null}">
<Setter Property="Button.IsEnabled"
Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>

wpf button trigger doesnt work as it should

I have a simple button. I want to switch it's template(or style ...)when it is being preesed.
I want to change from this
<DataTemplate>
<Button Click="Button_Click"
DataContext="{Binding}"
Height="65" Width="79"
Background="Black"
Content="{Binding Path=CardWasFounded}"/>
</DataTemplate>
to this :
<DataTemplate>
<Button Click="Button_Click"
DataContext="{Binding}"
Height="65" Width="79"
Background="{Binding Path=ButtonColor}"
Content="{Binding Path=CardWasFounded}"/>
</DataTemplate>
EDIT
After i have done
<DataTemplate>
<Button Name="btn"
Click="Button_Click"
DataContext="{Binding}"
Height="65" Width="79"
Background="Black"/>
<DataTemplate.Triggers>
<Trigger SourceName="btn" Property="IsMouseCaptured" Value="True" >
<Setter TargetName="btn" Property="Background" Value="Green"/>
<!--"{Binding Path=ButtonColor}"-->
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
It's still doesn't work I think it's because the .net default or something when the mouse is over the button its get's the blue defult color insted of my green or my binding ...
My goal its when its clicked to hook up a binding to color and a storyboard
can someone help me achive it ?
You can achieve this effect with a trigger. You could set a trigger that changes the Background property to your desired value when the button's IsPressed property (or some similar property) equals true.
For more information, take a look at:
http://en.csharp-online.net/WPF_Styles_and_Control_Templates%E2%80%94Property_Triggers

Resources