I have some image in my project. I want to change its property Visibility to true when the button pressed. I've created an image
<Image Name="UserimgRock" Source="Rock.png" HorizontalAlignment="Left" Height="100" Margin="277" VerticalAlignment="Top" Width="100" Visibility="Hidden"/>
and button
private void btnRock_Click(object sender, RoutedEventArgs e)
{
UserimgRock.Visibility = Visibility.Visible;
}
but there is an error Error *The name 'UserimgRock' does not exist in the current context. I'm a little confused.
Thanks for a any help!
if these both xaml and code behind belongs to same class then just prefix Name with x: where x: is referring to xaml name space, usually in Window tag like xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
eg
<Image x:Name="UserimgRock" Source="Rock.png" HorizontalAlignment="Left" Height="100" Margin="277" VerticalAlignment="Top" Width="100" Visibility="Hidden"/>
if these both are not in the same class then you may not be able to use the event handler for accessing objects in other class as objects are private to the respective class.
Edit
after looking at your code I discovered a few things including the reason why you cannot access the image
first things first, why you cannot access the image object?
reason is, you've defined the image inside a control template which limits the scope of the objects within to the template itself, so they are not accessible outside
how to fix?
you can define the property you need to access in the code behind and bind them to the respective properties in xaml
eg
define a dependency property UserImgRockVisibility in the usercontrol
public Visibility UserImgRockVisibility
{
get { return (Visibility)GetValue(UserImgRockVisibilityProperty); }
set { SetValue(UserImgRockVisibilityProperty, value); }
}
// Using a DependencyProperty as the backing store for UserImgRockVisibility. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UserImgRockVisibilityProperty =
DependencyProperty.Register("UserImgRockVisibility", typeof(Visibility), typeof(UserControl1), new PropertyMetadata(Visibility.Hidden));
set the data context to itself in constructor
DataContext = this;
or in xaml via binding to self
<UserControl x:Class="RockPaper.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"...
DataContext="{Binding RelativeSource={RelativeSource Self}}">
then use this property to manipulate the visibility
UserImgRockVisibility = Visibility.Visible;
finally bind this property to visibility of the image in xaml
<Image x:Name="userimgRock" Visibility="{Binding UserImgRockVisibility}" ... />
name is not necessary if you do not really need it
this is all you need in order to control the property of a object inside a control template or data template
another approach
Since I do not find a significance of using a style and control template within the user control
you can do it by simply removing the style and control template elements and bring the elements to usercontrol
by doing this you may not require the extra properties you may simply access the objects as they will be in the class scope
All I can see that you've used them for mouse over detection, you can use event triggers in elements directly using MouseEnter, MouseLeave kind of events
eg,
<UserControl x:Class="RockPaper.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Button x:Name="btnRock" Opacity=".3" HorizontalAlignment="Left" Margin="44,82.418,0,0" VerticalAlignment="Top" Width="100" Height="100" Click="btnRock_Click">
<StackPanel>
<Image />
</StackPanel>
</Button>
<Image x:Name="userimgRock" Visibility="Hidden" HorizontalAlignment="Left" Height="100" Margin="277.164,228.418,0,0" VerticalAlignment="Top" Width="100" Opacity="1" />
</Grid>
<UserControl.Triggers>
<EventTrigger SourceName="btnRock" RoutedEvent="MouseEnter" >
<BeginStoryboard>
<Storyboard>
<DoubleAnimation x:Name="enter" To="1" Storyboard.TargetName="btnRock" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger SourceName="btnRock" RoutedEvent="MouseLeave" >
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To=".3" Storyboard.TargetName="btnRock" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</UserControl.Triggers>
</UserControl>
Note I stripped some of the extra code not necessary for example
then use image object normally as
userimgRock.Visibility = Visibility.Visible;
now the choice is yours to choose what you prefer. do try both and see what is convenient to you.
Related
I tried to find answers to my question on the internet, but no answer satisfied me enough. I am writing WPF application and i'm trying to implement dialog mechanism. I have a simple ViewModel, and when some event happens, i would like to show a dialog, collect some output data from it and store it in "parent" View Model.
My method in a view model looks like this:
private void Expand()
{
...
catch(ArgumentNullException)
{
Shrink();
var errorDialogVM = new DialogVM(new Dialog() { Type = DialogType.Error, Message = $"Unauthorized access to \"{FileManager.GetDirectoryName(Path)}\" directory!" });
DialogService.ShowDialog(errorDialogVM);
//Here i need output from dialog
}
}
Implementation of ShowDialog method:
public void ShowDialog(DialogVM dialogVM)
{
var dialog = new DialogBox();
var mainWindow = Application.Current.MainWindow as MainWindow;
dialog.DataContext = dialogVM;
dialog.Owner = mainWindow;
dialog.Show();
}
Now, let's imagine that i need some data from the dialog. How can i pass it to my ViewModel in a proper way?
View model shouldn't handle view elements. A dialog is a view element.
The view model can trigger user input by raising and event e.g., an error event with an data model as event args. The view that has registered to the event shows a dialog to collect user input and stores them in the previously received data model. The view then executes a command on the view model to pass back the data model.
Instead of an event you can also bind the view to a property of the view model e.g. of type bool. On property change show the dialog and return the result using a ICommand.
Alternatively let the view model expose a flag e.g. HasException and a property ExceptionDialogModel which can be used to bind a custom dialog or form. Then create a simple modal dialog yourself:
ExampleDialog
<Grid x:Name="ExampleDialog"
Visibility="Visible"
Panel.ZIndex="100"
VerticalAlignment="Top">
<Rectangle Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=ActualWidth}"
Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=ActualHeight}"
Fill="Gray"
Opacity="0.7" />
<Grid Width="400"
Height="200">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Border Grid.RowSpan="2"
Background="LightGray"
BorderBrush="Black"
BorderThickness="1">
<Border.Effect>
<DropShadowEffect BlurRadius="5"
Color="Black"
Opacity="0.6" />
</Border.Effect>
</Border>
<TextBlock Grid.Row="0"
TextWrapping="Wrap"
Margin="30"
Text="I am a modal dialog and my Visibility or Opacity property can be easily modified by a trigger or a nice animation" />
<StackPanel Orientation="Horizontal"
Grid.Row="1"
HorizontalAlignment="Right"
Height="50">
<Button x:Name="OkButton"
Content="Ok"
Width="80" />
<Button x:Name="CancelButton"
Margin="30,0,30,0"
Content="Cancel"
Width="80" />
</StackPanel>
</Grid>
<Grid.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExampleDialog"
Storyboard.TargetProperty="Visibility"
Duration="0">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Hidden}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
</Grid>
You can put the Grid anywhere in your Window and toggle the Visibility. It will overlay the parent Window and has modal behavior.
Bind the DataContext to the ExceptionDialogModel so that the data is send back via TwoWay binding. Use a command to trigger a retry procedure (e.g., an OK or Retry button).
The Visibility can bind to the HasException property. You can animate this dialog and give it any look and feel you like.
I believe you are doing this backwards. You should pass reference to your view model to the dialog, not the other way around because view model should be separate and not aware of the view's mechanics. Dialog, on the other hand, knows which properties of view model it needs to set. So it will be something like the following:
public class MyDialog : Dialog
{
public MyDialog(DialogVM ViewModel) {
this.InitializeComponent();
this.DataContex = ViewModel;
// TODO: Bind to view model's properties in XAML or set them on OnClose()
}
}
I'm developing universal app. On one page i decided to use FlipView. I can easily animate SelectionChanged event from code-behind, but i'm just curious if there is a way to animate this event using XAML only. (BTW, UseTouchAnimationsForAllNavigation="True" doesnt work).
So, here's simplified example of what i'm doing :
<FlipView x:Name="MultipleItems">
<FlipView.Triggers>
<EventTrigger RoutedEvent="Selector.SelectionChanged">
<BeginStoryboard>
<Storyboard x:Name="ColorStoryboard">
//do stuff
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<FlipView.Triggers>
</FlipView>
I think this way of usage EventTrigger is fine (as far as SelectionChanged event takes arguments inherited from RoutedEventArgs), but it still gives me runtime error on navigation to page that contains FlipView.
Error is next :
WinRT information: Failed to assign to property 'Windows.UI.Xaml.EventTrigger.RoutedEvent'. [Line: 69 Position: 35]
Additional information: The text associated with this error code could not be found.
I believe there's way to assign that RoutedEvent property correctly, but i didnt find it yet. Also I don't wont to use behaviours for such simple thing.
Can anyone help?
You need to install the Microsoft.Xaml.Behaviors.Uwp.Managed in your project. Then the EventTrigger will be supported in an UWP project.
Then in your XAML use this package like this:
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
xmlns:Media="using:Microsoft.Xaml.Interactions.Media"
Now you can for example change the background color of FlipView like this:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.Resources>
<Storyboard x:Key="std" x:Name="std" >
<ColorAnimation From="Red" To="Transparent" Duration="0:0:3"
Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)"
Storyboard.TargetName="flipView"/>
</Storyboard>
</Grid.Resources>
<FlipView x:Name="flipView" ItemsSource="{x:Bind flipviewCollection}">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="SelectionChanged">
<Media:ControlStoryboardAction Storyboard="{StaticResource std}" />
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
<FlipView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding ImageSource}" Stretch="None"/>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
</Grid>
As you can see, I used EventTriggerBehavior and the event's name is SelectionChanged.
I am trying to create a user control similar to a stock ticker. It will slowly scroll the items to the left. So far I am unable to get something going because:
I am new to WPF/XAML and everywhere I search seems to apply to
silvelight
I am using an ItemTemplate within a ItemsControl, and cant find any
examples showing how to add a storyboard for a item within an item template.
here is my XAML:
<UserControl x:Class="WpfApplication.Ctrls.MessageTicker"
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"
mc:Ignorable="d"
xmlns:ctrls="clr-namespace:WpfApplication.Ctrls"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Background="Honeydew">
<ItemsControl ItemsSource="{Binding}" Name="_items">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid x:Name="_panel">
<Grid.Triggers>
<EventTrigger RoutedEvent="Grid.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(Grid.RenderTransform).(TranslateTransform.X)"
Storyboard.TargetName="_panel"
From="0"
To="360"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=Word}" Grid.Column="0" Margin="0" FontWeight="Normal" FontFamily="Segoe UI Semibold"/>
<TextBlock Text="{Binding Path=Percent}" Grid.Column="1" Margin="5,0,3,0" FontFamily="Segoe UI Mono" Foreground="Blue"/>
<Polygon Points="0,10 5,0 10,10" Stroke="Black" Fill="Green" Grid.Column="2" Margin="0,3,10,0"/>
<Polygon Points="5,10 10,0 0,0" Stroke="Black" Fill="Red" Grid.Column="2" Visibility="Collapsed"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>
From what I have read, I should be putting the storyboard within the template. When I add a new item to the ItemsControl, nothing happens. I need to have it start at the end of the ItemsControl and scroll to the right all the way to the beginning of the ItemsControl.
Ok so you're close, but you're missing some key things that might explain why it's not firing as you'd expect.
So your first issue lies with how you're using _panel. We'll want to actually move that to an RenderTransform on this Grid that's acting as your parent.
So instead of;
<Grid x:Name="_panel">
We'll say;
<Grid>
<Grid.RenderTransform>
<TranslateTransform x:Name="_panel">
</Grid.RenderTransform>
...
Because your TargetProperty setting in your storyboard isn't going to magically append that Transform on demand like it looks you're thinking it might (at least I've never seen it done that way I don't think).
So we have that, now let's go talk to that Transform via your Storyboard and have it talk to an actual property of your Transform thusly;
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="X"
Storyboard.TargetName="_panel">
<SplineDoubleKeyFrame KeyTime="0:0:0" Value="360" />
</DoubleAnimation>
</Storyboard>
So what we're doing is basically saying "HEY _panel, guess what? You get to animate, and before you start I want you to know you're moving 360 across your X axis"
We could add a keytime here to make this happen over more keyframes to allow it to fill in the blanks of an actual animation sequence (your ticker anime, hint hint) but for now, we're just telling that bugger to move.
Other than that, you should work. Hope this helps, cheers.
Oh and PS, you'd be surprised how much XAML can work between WPF/SL/WP, etc. etc. if you just know the fundamentals. Best of luck!
First of I should apologize if the question seems to look simple however I'm new to WPF and MVVM and I really don't know how to do the job.
What I need is to show popups from ViewModel. I know I can have a boolean property in the viewModel and bind it to the IsOpen property of the Popup but I don't know where to create this popup window.
I have some views and each view has to display certain popup messages depending on different situations. Now I need to know whether I should create several popups in each view and bind their IsOpen property to that of in the ViewModel or there are better solutions, and if I should create them in the view, where to put them? In a grid, in a StackPanel or anywhere else.
please let me know if I haven't explained clearly. Any help is appreciated.
I usually have a Third object to control my popup's and dialog , like Caliburn's WindowManager
WindowManager
Witch takes a ViewModel as Content and Displays it's Corresponding View in the Popup.
You can do something similar and Bind a Content from your ViewModel to your popup or Dialog.
For Instance , here's an a Custom Action i created for such a purpose :
OpenPopupWindowAction
this is sample popup. reference
basic popup msdn overview
<StackPanel>
<CheckBox Name="PCheckBox" Margin="10,10,0,0"
Content="Popup Window"/>
<Button HorizontalAlignment="Left" Width="129" Margin="10,10,0,0">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="theTransform"
Storyboard.TargetProperty="(RotateTransform.Angle)"
From="0" To="360" Duration="0:0:5" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
Start Animation
</Button>
<Popup IsOpen="{Binding ElementName=PCheckBox,Path=IsChecked}"
PlacementTarget="{Binding ElementName=PCheckBox}"
AllowsTransparency="True"
PopupAnimation="Slide"
HorizontalOffset="150"
VerticalOffset="100"
>
<Canvas Width="100" Height="100" Background="Green" Margin="150">
<Canvas.RenderTransform>
<RotateTransform x:Name="theTransform" />
</Canvas.RenderTransform>
<TextBlock TextWrapping="Wrap" Foreground="LightGray">
Rotating Popup
</TextBlock>
</Canvas>
</Popup>
private void OnPopupLoaded(object sender, RoutedEventArgs e)
{
this.ParentPopup.HorizontalOffset = (Window.Current.Bounds.Width - gdChild.ActualWidth) / 2;
this.ParentPopup.VerticalOffset = (Window.Current.Bounds.Height - gdChild.ActualHeight) / 2;
}
I'm trying to set an event trigger to one of my controls inside a ContentTemplate, i'm using a storyboard and a DoubleAnimation nested with a DoubleAnimationUsingKeyFrames when i set the storyboard TargetName to "ContentPopup" wich is a Grid i hold below, but i get an error telling me that:
The name 'ContentPopup' is not in the namespace 'System.Windows.Controls.Grid'.
The animation code on the control template is:
<Grid Margin="0" Width="55" Height="40">
<Grid.Triggers>
<EventTrigger RoutedEvent="m:Pushpin.MouseDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="00:00:00.5000000" Storyboard.TargetName="ContentPopup" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" To="1">
...
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
...
</Grid>
The code on the grid i need to animate is:
<Grid Name="ContentPopup"
Background="White"
Opacity="0.85"
RenderTransformOrigin="0,0">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0" ScaleY="0"/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Grid.RenderTransform>
...
</Grid>
MSDN says that the following needs to be done to make an object targetable
and a grid is a FrameworkElement i want the animation to run on every single one of the controls i summon on my main window using this control template, they are a lot of them so i need to use the template.
The question is:
Is there a way to assign the element as a target in the template?
So i found the right way to do it, even though grid is a FrameworkElement you can't access it from the control template, so you need to provide some binding or XAML reference to it in order to work, so with the same exact code just instead of using the Storyboard.TargetName property using the Storyboard.Target with value:
Storyboard.Target="{Binding ElementName=ContentPopup}"
or also:
Storyboard.Target="{x:Reference Name=ContentPopup}"
it worked for me