How to get a child of an "object sender" in a method? - c#

I have a 15 borders with an image inside of it in my application that calls a method on MouseUp.. all images have different names.. hence why i want them all to call this one method
<GroupBox Width="75" Height="75">
<Border MouseLeftButtonUp="Image_MouseUp1" Background="Transparent">
<Image x:Name="RedPick5_Image" Height="Auto" Width="Auto"/>
</Border>
</GroupBox>
I want all of them to be able to set the image source of the child (the image is the child of the border if i understand correctly.. how can i do this?
private void Image_MouseUp1(object sender, MouseButtonEventArgs e)
{
//want to set any image that calls this
//something like Sender.Child.Source = ...
}

you need to cast the sender and check
private void Image_MouseUp1(object sender, MouseButtonEventArgs e)
{
var border = sender as Border; // Cast to Border
if (border != null) // Check if the cast was right
{
var img = border.Child as Image; // Cast to Image
if (img != null) // Check if the cast was right
{
// your code
}
// else your Child isn't an Image her you could hast it to an other type
}
// else your Sender isn't an Border
}
you could also do this
private void Image_MouseUp1(object sender, MouseButtonEventArgs e)
{
var border = sender as Border;
if (border == null) // if the cast to Border failed
return;
var img = border.Child as Image;
if (img == null) // if the cast to Image failed
return;
// your code
}

You can do this way in case image is only and immediate child of border:
Image image = (Image)((Border)sender).Child;
image.Source = // Set image source here.

Alternatively you can use FindName
(Image)(sender as Border).FindName("RedPick5_Image");
It will search Border's children recursively for an element named "RedPick5_Image". This may return null if no elements with the specified name is found.

Related

How to read image source or image name in xamarin.forms?

I am working on Xamarin forms, where I have used TapGestureRecognizer inside image now on tap of that image I need to get the source of the image in c#. How do I get that?. Why I am doing this is, radio buttons are not available in Xamarin forms, On tap of the image I will check the source of the image if the source is checked image then I need to change the source to unchecked and vice versa.
Here is my XAML code
<Image Scale="0.7" HorizontalOptions="Start" x:Name="radioButton" Source="unchecked.png">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="radioButton_Clicked">
</TapGestureRecognizer>
</Image.GestureRecognizers>
</Image>
Here is my C# code
private void radioButton_Clicked(object sender, EventArgs e)
{
var imageSource = "";//get image source here
if (imageSource == "Checked.png")
{
radioButton.Source = "Unchecked.png";
}
else
{
radioButton.Source = "Checked.png";
}
}
you can achieve like this on radioButton_Clicked action
private void radioButton_Clicked(object sender, EventArgs e)
{
var imageSource = (Image)sender;//get image source here
var selectedImage = imageSource.Source as FileImageSource;
if (selectedImage.File == "Checked.png")
{
radioButton.Source = "Unchecked.png";
}
else
{
radioButton.Source = "Checked.png";
}
}
or you can use the custom plugin for support checked box refer this
https://github.com/XLabs/Xamarin-Forms-Labs
you can cast sender to image control
var imageSender = (Image)sender;
gestures

How can I use a C# function to access the WPF control that called it?

I'm working on a game level editor in WPF using C#.
I have a series of image controls for choosing textures, and I want each image to be clickable, with some visible feedback to show which one is selected.
Here's one of the image controls, along with a green highlight border that shows up when it's clicked:
<Image x:Name="tile_image1" Source="as asphalt_test.png" Stretch="Fill" HorizontalAlignment="Right" VerticalAlignment="Top" Width="50" Height="50" MouseDown="texture_click" Margin="0,93,69,0" RenderTransformOrigin="0.16,2.04"/>
<Border x:Name="tile_border" BorderBrush="Lime" BorderThickness="3" HorizontalAlignment="Right" Height="54" Margin="0,91,65,0" VerticalAlignment="Top" Width="54" Visibility="Hidden" />
My question involves the "texture_click" function.
I want to re-use the same function for each image control, which I can easily assign using the MouseDown attribute in XAML. However, what I don't know is how to tell from within the function which control called it, or how to access that control's property's, such as ".Source". I want to be able to grab the file name of the image, as well as move the coordinates of the green border behind the new selection.
Right now, I just have it hard-coded to the first image control. Clicks on the other images will call the function, but the function will only select the first image (not the one that was actually clicked).
// click on tile 1
private void texture_click (object sender, MouseButtonEventArgs e)
{
tile_border.Visibility = Visibility.Visible;
current_tilefile = tile_image1.Source;
string source_string = Convert.ToString (tile_image1.Source);
int last_slash = source_string.LastIndexOf ('/');
current_tile = source_string.Substring (last_slash + 1, 3);
}
I tried using "sender", since I thought that might be the object that called the function, but that returned an error. I also tried calling the function with "texture_click (this)", but that was also no good. These were, admittedly, complete shots in the dark, so I wasn't surprised.
I'm still pretty new to this software, so any insight you guys can give would be great.
You just have to cast the sender parameter to the control type (Image in this case):
private void texture_click (object sender, MouseButtonEventArgs e)
{
//tile_border.Visibility = Visibility.Visible;
var image = sender as Image;
if (image != null)
{
current_tilefile = image.Source;
string source_string = image.Source.ToString();
int last_slash = source_string.LastIndexOf ('/');
current_tile = source_string.Substring (last_slash + 1, 3);
}
}
Of course, this doesn't give you access to the associated border. One thing you can do is to just dump the border into the Image's Tag property:
<Image x:Name="tile_image1" ... Tag="{Binding ElementName=tile_border}" />
<Border x:Name="tile_border" ... />
Then you can retrieve it, again by casting:
private void texture_click (object sender, MouseButtonEventArgs e)
{
var image = sender as Image;
if (image != null)
{
var border = image.Tag as Border;
if (border != null)
{
border.Visibility = Visibility.Visible;
}
// ...
}
}
Note that this (manipulating UI elements from code-behind) is not the ideal way to write a WPF application. Typically you would do something like this by using an existing control (like a ToggleButton), and re-writing its ControlTemplate so that its IsChecked visual state shows a border. But I realize that is a mouthful ...

FlipView SelectionChange C#

I am making a simple metro app to display an image and some content relevant to the image.
Ex :
image : data
img1 : "Image of a butterfly"
img2 : "Hello sky"
img3 : "Picture of a Golden Retriever"
I have loaded images into a flipview.And relevent data into an array.
<FlipView HorizontalAlignment="Left" Margin="102,147,0,0" VerticalAlignment="Top" Width="627" Height="429" Name="fiImage" SelectionChanged="fiImage_SelectionChanged">
<Image Source="Assets/image1.png" Name="Img1" />
<Image Source="Assets/image2.png" Name="Img2" />
</FlipView>
I have a TextBlock in the xaml named as "tbN". What I want to do is when I change the image using pointer, relevant data should display in the textblock.
I tried following code at selection change event
private void fiImage_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
int i = ((FlipView)sender).SelectedIndex;
tbN.Text = a[i]; //error line
}
But when I execute the program, I get an error saying "NullReferenceException was unhandled by the user code: Object reference not set to an instance of an object."
What am I missing?
It seems a[i] has not being initialized and doesn't have values. Is it a global variable?.
Debug your code and check it's content. It must be null.
If it is not null, maybe that array doesn't have the i value. Or maybe it's exceding the array length.
tbN.Text = a[i]; //a[i] must be null, where is it initialized?
SelectionChanged event fires at initialization as well (first child "selected").
Your control (tbN) does not exist at the time.
Check if tbN is null to avoid NRef. Exception!
private void fiImage_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (tbN != null)
{
int i = ((FlipView)sender).SelectedIndex;
tbN.Text = a[i];
}
}
I've found the solution HERE
private void FlipView_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
{
FlipView fv = sender as FlipView;
if (fv.SelectedItem == null) return;
var item = fv.ItemContainerGenerator.ContainerFromItem(fv.SelectedItem);
if (item == null)
{
Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
var itemSecondTime = fv.ItemContainerGenerator.ContainerFromItem(fv.SelectedItem);
if (itemSecondTime == null)
{
throw new InvalidOperationException("no item. Why????");
}
});
}
}

Silverlight Canvas Sizing within a ScrollViewer

I am making a Silverlight 4 website with C#. In one of the pages, I want to have two panels beside each other. On the left is a map control and on the right is an image. That is easy enough, but I also want to be able to click on the image and leave PushPin like objects (like the map) so I put the image in a canvas and just draw circles. The problem is that image can be fairly large and I need to be able to scroll the image. I tried several different ways of achieving this, but so far no luck.
The answers to the following post seemed to be like the way to go, but there must be updates to Silverlight that broke it: WPF: How to make canvas auto-resize?
A similar solution suggested making the Canvas from scratch, but I ran into the same problem.
Most of my attempts end in displaying as much of the image as possible on the screen, but no scroll bars (still greyed out) or the page just goes white when the image is loaded.
The following is how I am currently selecting the image to load:
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = "Image Files (*.png, *.jpg)|*.jpg;*.png";
if(dialog.ShowDialog() == true) {
BitmapImage bitmap = new BitmapImage();
FileStream stream = dialog.File.OpenRead();
bitmap.SetSource(stream);
TheImage.Source = bitmap;
}
There is probably be a nicer solution but this should do the trick.
I have created a small fixed size ScrollViewer that contains a Canvas and an image. I then used a behaviour to modify the size of the canvas to match the size of the image. The behaviour also handles the ImageOpened event to set the correct size of the image once the image is opened.
Here is the xaml:
<ScrollViewer Width="200" Height="200" HorizontalScrollBarVisibility="Auto">
<Canvas x:Name="TheCanvas">
<Image x:Name="TheImage">
<i:Interaction.Behaviors>
<Views:ResizeCanvasBehaviour Canvas="{Binding ElementName=TheCanvas}"/>
</i:Interaction.Behaviors>
</Image>
</Canvas>
</ScrollViewer>
Be sure to declare i as xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
and b matches the namespace where you place the behaviour.
Here is the code for the behaviour:
public class ResizeCanvasBehaviour : Behavior<Image>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.SizeChanged += AssociatedObject_SizeChanged;
AssociatedObject.ImageOpened += AssociatedObject_ImageOpened;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.SizeChanged -= AssociatedObject_SizeChanged;
AssociatedObject.ImageOpened -= AssociatedObject_ImageOpened;
}
private void AssociatedObject_ImageOpened(object sender, RoutedEventArgs e)
{
BitmapSource bitmapSource = AssociatedObject.Source as BitmapSource;
if (bitmapSource == null)
{
return;
}
AssociatedObject.Width = bitmapSource.PixelWidth;
AssociatedObject.Height = bitmapSource.PixelHeight;
Resize();
}
private void AssociatedObject_SizeChanged(object sender, SizeChangedEventArgs e)
{
Resize();
}
public Canvas Canvas
{
get { return GetValue(CanvasProperty) as Canvas; }
set { SetValue(CanvasProperty, value); }
}
public static readonly DependencyProperty CanvasProperty = DependencyProperty.Register(
"Canvas",
typeof(Canvas),
typeof(ResizeCanvasBehaviour),
new PropertyMetadata(null, CanvasPropertyChanged));
private static void CanvasPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((ResizeCanvasBehaviour)d).OnCanvasPropertyChanged();
}
private void OnCanvasPropertyChanged()
{
if (Canvas != null)
{
Resize();
}
}
private void Resize()
{
if ((AssociatedObject != null) && (Canvas != null))
{
Canvas.Width = AssociatedObject.ActualWidth;
Canvas.Height = AssociatedObject.ActualHeight;
}
}
}
To load the image do something like this. I did this in code behind for speed but ideally you should put this in a view model and then data bind the image Source property in xaml:
BitmapImage bi = new BitmapImage();
bi.UriSource = new Uri("http://farm7.static.flickr.com/6149/5942401995_a5a3fd3919_z.jpg");
TheImage.Source = bi;
Turns out the very minimum that I needed to do was set the Width and Height of the canvas to the PixelWidth and PixelHeight of the BitmapImage instance.
This is what Paul was doing with his solution (in a little more complicated way), but for some reason the resize event handlers would not get called when a image was loaded locally.
I had tried several different suggested solutions, but I never got the results I was wanting. This was the only solution that seemed to work.

How can I programmatically scroll a WPF listview?

Is it possible to programmatically scroll a WPF listview? I know winforms doesn't do it, right?
I am talking about say scrolling 50 units up or down, etc. Not scrolling an entire item height at once.
Yes, you'll have to grab the ScrollViwer from the ListView, or but once you have access to that, you can use the methods exposed by it or override the scrolling. You can also scroll by getting the main content area and using it's implementation of the IScrollInfo interface.
Here's a little helper to get the ScrollViwer component of something like a ListBox, ListView, etc.
public static DependencyObject GetScrollViewer(DependencyObject o)
{
// Return the DependencyObject if it is a ScrollViewer
if (o is ScrollViewer)
{ return o; }
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++)
{
var child = VisualTreeHelper.GetChild(o, i);
var result = GetScrollViewer(child);
if (result == null)
{
continue;
}
else
{
return result;
}
}
return null;
}
And then you can just use .LineUp() and .LineDown() like this:
private void OnScrollUp(object sender, RoutedEventArgs e)
{
var scrollViwer = GetScrollViewer(uiListView) as ScrollViewer;
if (scrollViwer != null)
{
// Logical Scrolling by Item
// scrollViwer.LineUp();
// Physical Scrolling by Offset
scrollViwer.ScrollToVerticalOffset(scrollViwer.VerticalOffset + 3);
}
}
private void OnScrollDown(object sender, RoutedEventArgs e)
{
var scrollViwer = GetScrollViewer(uiListView) as ScrollViewer;
if (scrollViwer != null)
{
// Logical Scrolling by Item
// scrollViwer.LineDown();
// Physical Scrolling by Offset
scrollViwer.ScrollToVerticalOffset(scrollViwer.VerticalOffset + 3);
}
}
<DockPanel>
<Button DockPanel.Dock="Top"
Content="Scroll Up"
Click="OnScrollUp" />
<Button DockPanel.Dock="Bottom"
Content="Scroll Down"
Click="OnScrollDown" />
<ListView x:Name="uiListView">
<!-- Content -->
</ListView>
</DockPanel>
The Logical scrolling exposed by LineUp and LineDown do still scroll by item, if you want to scroll by a set amount you should use the ScrollToHorizontal/VerticalOffset that I've used above. If you want some more complex scrolling too, then take a look at the answer I've provided in this other question.
Have you tried ScrollIntoView?
Alternatively, if it's not a specific item you brought into view, but an offset from the current position, you can use BringIntoView.

Categories

Resources