Change image source when loaded event of other image - wpf

I'm working with new MS technology UWP. I have 2 images in DataTemplate, CopyImage and MainImage. It's because of image flickering, when source is changed. So I would like to ask, how can I set the source of CopyImage, when event Loaded of MainImage is fired? In WPF I can use DataTriggers, but they are not in UWP. I want to do that in XAML, no in code-behind.
Many thanks guys
EDIT
<Image Grid.Column="0" x:Name="MainImage" Source="{x:Bind ImageStatusUri, Mode=OneWay}" Margin="0,8,12,8">
<Image.Triggers>
<EventTrigger RoutedEvent="Image.Loaded">
</EventTrigger>
</Image.Triggers>

I hope you are using Template10
<Page xmlns:interact="using:Microsoft.Xaml.Interactivity"
xmlns:interactcore="using:Microsoft.Xaml.Interactions.Core">
...
<Image Grid.Column="0" x:Name="MainImage" Source="{x:Bind ImageStatusUri, Mode=OneWay}" Margin="0,8,12,8" >
<interact:Interaction.Behaviors>
<interactcore:EventTriggerBehavior EventName="Loaded">
<interactcore:ChangePropertyAction PropertyName="Source" Value="" TargetObject="{Binding ElementName=CopyImage}"/>
</interactcore:EventTriggerBehavior>
</interact:Interaction.Behaviors>
</Image>
</Page>

Related

WPF (mvvm, caliburn.micro) button click inside a listview item

I have a simple listview and listviewitem structure.
The Heart of the ListView.xaml is like the following
<StackPanel>
<ListBox x:Name="Movies" SelectedItem="{Binding SelectedMovie}">
<ListBox.ItemTemplate>
<DataTemplate>
<v:ListItemView/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
and the heart of the ListTtemView.xaml is the following:
<StackPanel>
<TextBlock Text="{Binding Id}"/>
<TextBlock Text="{Binding Title}"/>
<Button cal:Message.Attach="RunOperation" cal:Action.TargetWithoutContext="{Binding ElementName=UserControl, Path=DataContext}" Content="Run"/>
</StackPanel>
in the ListViewItemViewModel, I have a method called RunOperation and the scenario is when the user clicks the button in a listviewitem, the method RunOperation should be called. However, I get an exception: 'No target found for method RunOperation.'
I have read that the caliburn micro doesn't work in a case like this and if this is the case, I realised that I still don't know how to make it work the simple WPF way.
Apparently, RunOperation method cannot be found so I tried few combinations of cal:Action.TargetWithoutContext="{Binding ...}" but no help.
Thanks
If someone is still looking for a solution, here is what I did, With reference to caliburn.micro and interactivity in the xaml like below,
xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro.Platform"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
<Button Content="Run">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="RunOperation">
<cal:Parameter Value="{Binding}" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
The view model button click method will be
public void RunOperation(object obj)
{
//Do your things
}
Since your xaml involving button is not available in question, am not sure if you have already tried this, but following should help you hit the function on Button's click event.
<Button cal:Message.Attach="[Event Click] = [Action RunOperation]"/>
I don't know anything about caliburn.micro.
But the normal WPF approach would be this
Step 1:
Create a Command in your ViewModel
class ViewModel
{
...
public ICommand RunOperationCommand { get; }
...
}
Step 2: Bind to it
<Button Command="{Binding RunOperationCommand }" />
That's not the caliburn.micro solution. And I don't know if there is a valid caliburn.micro solution for situations like this.
But the following works:
<Button Command="{Binding DataContext.RunOperationCommand, RelativeSource={RelativeSource AncestorType=ListBox}}" />
I was having the same issue, plus I was trying to get around it using a normal WPF approach.
I had Buttons being created dynamically inside a List Control which a source of was Bindable Collection of Sensors (my class).
You need to make sure you add a reference to the "xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" and
"xmlns:cal="http://www.caliburnproject.org" on your UserControl or Window.
Can find all the information and examples on Caliburn Micro Docs:
CaliburnActions Docs
<UserControl x:Class="BeckerGasApp.Views.MapView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BeckerGasApp.Views"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cal="http://www.caliburnproject.org">
<Grid>
<Grid>
<ItemsControl x:Name="Sensors" Background="Transparent" ItemsSource="{Binding Path=Sensors, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
<ItemsControl.ItemTemplate>
<DataTemplate >
<Button Background="Transparent" Content="{Binding SensorName}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="Sensor">
<cal:Parameter Value="{Binding SensorName}" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Viewbox>
</Grid>
</UserControl>
To do it inside a listview I had the following extra tag cal:Action.Target to be able to access ÀctionMessage for an item in listview.
<ListView
x:Name="LV"
Background="Transparent"
BorderBrush="Transparent"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListViewItem>
<Button x:Name="StartPage">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:Action.Target>
<cal:ActionMessage MethodName="StartPage">
<cal:Parameter Value="{Binding}" />
</cal:ActionMessage>
</cal:Action.Target>
</i:EventTrigger>
</i:Interaction.Triggers>
<Button.Template>
<ControlTemplate>
<StackPanel Width="210" Orientation="Horizontal">
<Image Source="../Assets/img_home.png" Stretch="None" />
<TextBlock Style="{StaticResource font_style}" Text="Home" />
</StackPanel>
</ControlTemplate>
</Button.Template>
</Button>
</ListViewItem>

XAML-only clear combobox on button click [duplicate]

I have the following XAML snippet:
<TextBox x:Name="FilterTB" TextChanged="FilterTB_TextChanged"/>
<Button x:Name="CancelFilterSelectionButton" FontWeight="Bold" Content="X"/>
I'd like to erase the content of the TextBox when the user presses the Button.
Of course doing so from Code Behind is a trivial task, but I wanted to accomplish it only through the use of XAML, and so using Triggers.
I tried researching on the net, but I either found uncorrect solutions, or overly-convoluted solutions, so I'd like to hear some clean and compact solutions.
Here I had a spare minute, hope this helps, cheers.
namespaces;
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
and easy peasy.
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBox x:Name="ThatThangToClear" Width="250"/>
<Button x:Name="ClearThatThang" Content="Clear That Thang" Margin="5,0">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:ChangePropertyAction
TargetName="ThatThangToClear"
TargetObject="{Binding ElementName=ThatThangToClear}"
PropertyName="Text" Value="{x:Null}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
Oh, and P.S. - You really only need either TargetName OR TargetObject but I included both for examples sake.

How to set a default source for an Image if binding source is null?

I'm using binding for source of an Image control.
<Image Source="{Binding ImageUri}"/>
But this ImageUri can be null, therefor I want to use a default image, a place holder, for that, which can be in /Assets/PlaceHolder.png for example.
How can I set a default image? thanks.
(It's a WP8 app, but should not be different of WPF)
You can achieve it by setting TargetNullValue
<Image>
<Image.Source>
<Binding Path="ImageUri" >
<Binding.TargetNullValue>
<ImageSource>/Assets/PlaceHolder.png</ImageSource>
</Binding.TargetNullValue>
</Binding>
</Image.Source>
</Image>
You can actually go the other way around which is a better experience in my opinion by simply using two Image controls in a Grid layout, one with the local placeholder source and one with the remote Binding. The local image is already there when you your remote binding is null. However if the binding is not null, it automatically covers the local placeholder image once it gets rendered.
<Grid>
<Image Source="Assets/Placeholder.png"/>
<Image Source="{Binding ImageUri}"/>
</Grid>
You can set the ImageFailed event on your image,
<Image Source="{Binding ImageUri}" ImageFailed="Image_ImageFailed"/>
and use the following C# to load a specific image in its place.
private void Image_ImageFailed(object sender, ExceptionRoutedEventArgs e)
{
((Image)sender).Source = new BitmapImage(new Uri("/Assets/MyDefaultImage.png", UriKind.Relative));
}
You may try this:
<Image>
<Image.Source>
<Binding Path="ImageUri">
<Binding.TargetNullValue>
<BitmapImage UriSource="/ProjName;component/Assets/PlaceHolder.png" />
</Binding.TargetNullValue>
</Binding>
</Image.Source>
</Image>
You can use ImageFailed event and ChangePropertyAction.
This Code Snippet worked for me:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
<Image x:Name="GeologyMapsLegend" Stretch="Fill" Height="150">
<i:Interaction.Triggers>
<i:EventTrigger EventName="ImageFailed">
<ei:ChangePropertyAction PropertyName="Source" TargetName="GeologyMapsLegend">
<ei:ChangePropertyAction.Value>
<ImageSource>
/LanSysWebGIS;component/Pictures/Icon/NoImageAvailable.jpg
</ImageSource>
</ei:ChangePropertyAction.Value>
</ei:ChangePropertyAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
use TargetNullValue attribute. It is very helpful if I don't want to display any image.
You should try to play with FallBackValue here. These two links should provide more help
WPF Binding - Default value for empty string
MSDN

Data change in DataContext with animation

i have no idea to solve the problem with follwing code:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Window.Resources>
<XmlDataProvider x:Key="InternalData" XPath="/Workspace">
<x:XData>
<Workspace Name="Workspace" xmlns="">
<Project Name="Project 1"/>
<Project Name="Project 2"/>
<Project Name="Project 3"/>
</Workspace>
</x:XData>
</XmlDataProvider>
</Window.Resources>
<StackPanel DataContext="{StaticResource InternalData}">
<ListBox ItemsSource="{Binding XPath=//Workspace/Project}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding XPath=#Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBox Text="{Binding XPath=//Workspace/Project[1]/#Name, Mode=TwoWay}"/>
</StackPanel>
</Window>
As you can see, i can change the Name of the first Project in the Workspace with the TextBox.
By changing the data, i want to start an animation to fade out the old value, change the value and start an animation to fade in the new value (e.g. opacity of "Project 1" from 1 to 0, change data and opacity of "" from 0 to 1)
If possible, i wanted to implement the solution only in XAML. But no idea. Maybe something with DataTrigger and EnterAction and ExitAction or stuff like that?
Kind regards
Shounborugh
You might want to try looking in to WPF storyboards. This is a common practice if you want to start an animation using only XAML. This is the best place to start about storyboards in WPF
http://msdn.microsoft.com/en-us/library/ms742868.aspx
This is how you can start the storyboard upon changing the text in the textbox
<TextBox Height="23" HorizontalAlignment="Left" Margin="90,44,0,0" Name="textBox1" VerticalAlignment="Top" Width="120">
<TextBox.Triggers>
<EventTrigger RoutedEvent="TextBox.TextChanged">
<BeginStoryboard>
<Storyboard>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBox.Triggers>
</TextBox>

ZIndex of pushpins in WP7 bing map control

I have a Bing silverlight map control for Windows phone 7. I am trying to display on top currently selected pushpin. Here is the snippet:
<my:Map x:Name="map" Canvas.ZIndex="1" CredentialsProvider="{StaticResource Credentials}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
CopyrightVisibility="Collapsed" LogoVisibility="Collapsed">
<my:MapItemsControl x:Name="Pushpins">
<my:MapItemsControl.ItemTemplate >
<DataTemplate>
<my:Pushpin Location="{Binding Location}" Canvas.ZIndex="{Binding Zindex}" PositionOrigin="0.515625,0.859375" Content="{Binding Id}" Template="{StaticResource PushpinControlTemplate}" Tap="Pushpin_Tap"/>
</DataTemplate>
</my:MapItemsControl.ItemTemplate>
</my:MapItemsControl>
</my:Map>
The control is ignoring the ZIndex. Am I missing something or the ZIndex is not supported. The ZIndex is property of a class which implements INotifyPropertyChanged
private int _zIndex;
public int Zindex
{
get { return _zIndex; }
set
{
_zIndex = value;
OnPropertyChanged(new PropertyChangedEventArgs("Zindex"));
}
}
I had the same problem where I had multiple pushpins close together and the problem was exacerbated when I had additional content to show when the pushpin was clicked.
The way I got around this problem was to remove the pushpin and then re-add it. That way it became the topmost pushpin.
map1.Children.Remove(pushpin);
map1.Children.Add(pushpin);
In a recent project I used two map layers to achieve this. The first map layer was bound to my list of pushpins ("resultsLayer"), the 2nd map layer was bound to a single 'SelectedItem' ("selectedLayer") on my view model.
The 2nd map layer will render on top of the first one. So, when a pushpin on the first layer was selected, it was removed from the collection (consequently removed from the layer) and set to be the selected pin which added it to the 2nd layer. The puspin control template for the 2nd layer contained the 'callout' which in my case was a button with some text in it that the user could click to open another page.
Here is my xaml:
<m:Map CredentialsProvider="xxxx" x:Name="map" Center="{Binding MapCenter, Mode=TwoWay}" ZoomLevel="{Binding MapZoomLevel, Mode=TwoWay}">
<m:MapLayer x:Name="resultsLayer" Visibility="{Binding IsBusy, Converter={StaticResource booleanNotCollapsedConverter}}">
<m:MapItemsControl ItemsSource="{Binding VenuesFound}">
<m:MapItemsControl.ItemTemplate>
<DataTemplate>
<m:Pushpin Location="{Binding VLocation}" PositionOrigin="BottomCenter" >
<m:Pushpin.Template>
<ControlTemplate>
<Image x:Name="mapPin" Grid.Row="1" Source="{Binding MapPin}" Stretch="None" />
</ControlTemplate>
</m:Pushpin.Template>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<gs:EventToCommand Command="{Binding SelectPinCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</m:Pushpin>
</DataTemplate>
</m:MapItemsControl.ItemTemplate>
</m:MapItemsControl>
</m:MapLayer>
<m:MapLayer x:Name="selectedLayer" DataContext="{Binding SelectedV}" Visibility="{Binding IsBusy, Converter={StaticResource booleanNotCollapsedConverter}}">
<m:Pushpin Location="{Binding VLocation}" PositionOrigin="BottomCenter">
<m:Pushpin.Template>
<ControlTemplate>
<StackPanel>
<Button Style="{StaticResource PushPinCallout}" Command="{Binding SelectItemCommand}">
<TextBlock Text="{Binding Name}" Foreground="White" Margin="2" TextWrapping="Wrap" />
</Button>
<Image x:Name="mapPin" Grid.Row="1" Source="{Binding MapPin}" Stretch="None" />
</StackPanel>
</ControlTemplate>
</m:Pushpin.Template>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<gs:EventToCommand Command="{Binding SelectPinCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</m:Pushpin>
</m:MapLayer>
</m:Map>
As the BingMapsControl is not a Silverlight control it does not have any concept of a canvas.
Instead of trying to ensure the selected one is at the front, I'd change the selected pin to be of a larger, more prominent style.
It doesn't make sense (to me) to be able to control the z-index of pins as doing so could create a scenario where a pin appears to be on top of another pin, rather than on the map.

Resources