I am currently developing an application in C# using WPF. What I need to be able to do is on a label make their be an image to the left of the text of the label a small image of an X or a small image of a tick depending on the circumstances. I have got the images included in the project in a folder named images.
How can I assign the images to be placed on the left of the label programatically in the code and not using the XAML code.
You can either group this inside a grid:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{Binding ImageSourceProperty}" />
<Label Grid.Column="1" Content="{Binding LabelTextProperty}" />
</Grid>
Or, since the label is a content control, you can simply put the image control inside a label control:
<Label>
<Image Source="{Binding ImageSourceProperty}" />
My Text
</Label>
Once you know how the xaml should look like, it is very easy to create the same elements via code.
Since you want this in code behind and not within XAML I would suggest ditching the Label and using a StackPanel coupled with an Image and TextBlock as seen below where MyGrid could be any container...
<Grid Name="MyGrid"/>
...then in your code behind...
StackPanel myStackPanel = new StackPanel();
myStackPanel.Orientation = Orientation.Horizontal;
Image myImage = new Image();
BitmapImage myImageSource = new BitmapImage();
myImageSource.BeginInit();
myImageSource.UriSource = new Uri("Images/MyImage.png");
myImageSource.EndInit();
myImage.Source = myImageSource;
TextBlock myTextBlock = new TextBlock();
myTextBlock.Text = "This is my image";
myStackPanel.Children.Add(myImage);
myStackPanel.Children.Add(myTextBlock);
MyGrid.Children.Add(myStackPanel);
I don't agree with the two other answers here. There is no need for a grid to be added to wrap the content. The stackpanel is sufficient.
In the xaml add a stackpanel to where you need the content to be.
<StackPanel Name="myStack" Orientation="Horizontal"></StackPanel>
Then in the code behind, like in a button handler or when the window loads add this
Image coolPic = new Image() {
Name="pic",
Source = new BitmapImage(new Uri("pack://application:,,,/images/cool.png")),
Stretch = Stretch.None // this preserves the original size, fill would fill
};
TextBlock text = new TextBlock() {
Name = "myText",
Text = "This is my cool Pic"
};
myStack.Children.Add(coolPic); // adding the pic first places it on the left
myStack.Children.Add(text); // the text would show up to the right
You can swap the location of the image and the text by adding the text first then the image.
If you don't see the image ensure the image's build action is set to resource in the properties window of the image.
In order for the code to be more useful and or more dynamic you would need a way to change either the text or the image.
So lets say you did want to change those and you go ahead and do a
((TextBlock)FindName("myText")).Text = "my other cool pic";
You would expect the text to be changed but what happens?
Object reference not set to an instance of an object.
Drats but I gave it a name. You would need to add
// register the new control
RegisterName(text.Name, text);
So that you can access the textblock later. This is needed because you added the control to the framework after it was built and displayed. So the final code looks like this after registering the image too
Image coolPic = new Image() {
Name="pic",
Source = new BitmapImage(new Uri("pack://application:,,,/images/cool.png")),
Stretch = Stretch.None // this preserves the original size, fill would fill
};
// register the new control
RegisterName(coolPic.Name, coolPic);
TextBlock text = new TextBlock() {
Name = "myText",
Text = "This is my cool Pic"
};
// register the new control
RegisterName(text.Name, text);
myStack.Children.Add(coolPic);
myStack.Children.Add(text);
Related
How can I enlarge image in C# (exactly in UWP) after clicking on it?
I tried few things:
1) I tried to add button, with image content, what I want to enlarge, and then I added event Click. But I don't know what I should to add into that code.
2) i also tried to add image directly to my XAML page, and I wanted to create Tapped event, but again, I don't know what I should to add into that code.
I just want to create a small photogallery, so after clicking on image thumbnail will be opened larger image.
Or if there is any possibility to add pdf files, you can write it too. That's another solution of my problem.
You could enlarge the Image by settings its RenderTransform property to a ScaleTransform:
private void Image_Tapped(object sender, TappedRoutedEventArgs e)
{
Image image = sender as Image;
image.RenderTransform = new ScaleTransform() { ScaleX = 2, ScaleY = 2 };
}
<Image Source="ms-appx:///Assets/pic.png" Tapped="Image_Tapped" Stretch="None" />
The ScaleX and ScaleY properties gets or sets the scaling factor. Please refer to the MSDN documentation for more information: https://msdn.microsoft.com/library/windows/apps/br242940?f=255&MSPPError=-2147217396
Looks good, but there is a problem. When I add more images, like into GridView, they are overlapping, and highlighted. Images can overlap, but image, which I click should be always on top...
You could put the tapped Image in a Popup then and then for example add it back to its original Panel when it is tapped again. I put together an example that should give you the idea and something to build on:
private void Image_Tapped(object sender, TappedRoutedEventArgs e)
{
Image image = sender as Image;
Panel parent = image.Parent as Panel;
if (parent != null)
{
image.RenderTransform = new ScaleTransform() { ScaleX = 2, ScaleY = 2 };
parent.Children.Remove(image);
parent.Children.Add(new Popup() { Child = image, IsOpen = true, Tag = parent });
}
else
{
Popup popup = image.Parent as Popup;
popup.Child = null;
Panel panel = popup.Tag as Panel;
image.RenderTransform = null;
panel.Children.Add(image);
}
}
<GridView SelectionMode="None" isItemClickEnabled="True">
<GridView.ItemTemplate>
<DataTemplate>
<Grid>
<Image Source="ms-appx:///Assets/pic.png" Tapped="Image_Tapped" Stretch="None" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
I am working on a UWP project with xaml and c#. I have a stackpanel of images on the right where you can click on the image and it will display a related larger image to the left of the stackpanel.
The large image is set initially to the "large" image that relates to the first "small" image in the stackpanel when you load the page but when you click any of the other small images in the stackpanel, the large image does not update.
The whole thing is a datatemplate that is placed inside a flyout. The relevant xaml for the "large" image is here:
<Border Background="White" Grid.Row="2">
<Image Stretch="Uniform">
<Image.Source>
<BitmapImage UriSource="{Binding SelectedImage}" />
</Image.Source>
</Image>
</Border>
When the small image is clicked, it triggers the "tapped" method for that image and that method is:
private void Image_Tapped(object sender, TappedRoutedEventArgs e)
{
var img = ((Windows.UI.Xaml.Controls.Image)sender).DataContext as obj
img.FlyoutContent.SelectedImage = new Uri(img.relatedPath);
}
I am using the above code to set the image initially and it works. It just does not change the large image when the small one is clicked.
In debugging, when I click on the small image in the stackpanel, I break at the "image tapped" method and I can see that the uri is getting updated properly and there are no binding errors. The UI never changes.
What am I missing?
Thank you,
Zach
*Side note: the "obj" is just a made up name of a custom class.
For Binding properties you need to implement INotifyPropertyChangedclass so that the UI gets updated automatically.
class CustomClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _imageLink;
public string ImageLink
{
get
{
return _imageLink;
}
set
{
_imageLink = value;
RaisePropertyChanged();
}
}
private void RaisePropertyChanged([CallerMemberName] string name = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
Or as you are using a Tapped event, why not give your XAML element a x:name and set the source of the image of that name to your URi.
To update the ImageLink property, you need to create an instance of the CustomClass in the page you are changing the property.
CustomClass ab = new CustomClass();
ab.ImageLink = "code here";
I have a pivot like this on the page:
<phone:Pivot Name="pivot">
<phone:PivotItem Name="item1">
</phone:PivotItem>
</phone:Pivot>
I want to add some images to the item programmatically, so the user can scroll up-down.
When I do this, the scroll viewer doesn't work, I mean doesn't scroll down.
Image image1 = new Image();
image1.Source = ...
Image image2 = new Image();
image2.Source = ...
Image image3 = new Image();
image3.Source = ...
Grid grid2 = new Grid();
grid2.Children.Add(image1);
grid2.Children.Add(image2);
grid2.Children.Add(image3);
ScrollViewer scroll = new ScrollViewer();
scroll.Content = grid2;
item1.Content = scroll;
How can I scroll up and down content of the pivot item which is added programmatically? no matter with a ScrollViewer or without it.
Well the first thing I would do is add a listbox to your pivot
<phone:Pivot Name="pivot">
<phone:PivotItem Name="item1">
<ListBox name="ListOfStuff">
</ListBox>
</phone:PivotItem>
</phone:Pivot>
Then in your cod instead of adding the items to the grid you add them to the listbox.
ListOfStuff.Items.Add(ImageWhatever);
That should pretty much be it. Your list box will add the items and scroll as normal. Just make sure that the listbox height and width is set to the screen size or smaller. Otherwise your Listbox wont work properly.
You can even get more complicated with this and make nice designs.
Forexample:
StackPanel sp = new StackPane();
Image im1 = new Image();
TextBlock tb = new TextBlock();
//...Put your sizing and editing of objects here...
sp.orientation = System.Windows.Controls.Orientation.Horizontal;
sp.add(im1);
sp.add(tb);
ListOfStuff.Items.Add(sp);
This will cause you to have an image with a textblock next to it and it will be a single selectable item in your list.
I am developing a silverlight navigation application and got stuck on the following problem...
The guy I am developing the app wants to have a News page where you can see all published news on the left side and the clicked (or latest news if none is clicked) on the right side. He wanted to have a header, text and publishing date for each news in the news list. Also he wanted to have paging so that there won't be to many news in the list at once...
I did this:
foreach (Model.News news in s)
{
StackPanel stackPanel = new StackPanel();
HyperlinkButton hyperlinkButton = new HyperlinkButton();
hyperlinkButton.Tag = news.Header;
hyperlinkButton.Content = news.Header;
hyperlinkButton.FontSize = 15;
hyperlinkButton.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
hyperlinkButton.Click += new RoutedEventHandler(Button_Click);
stackPanel.Children.Add(hyperlinkButton);
TextBlock textBlock = new TextBlock();
textBlock.Foreground = new SolidColorBrush(Colors.Gray);
textBlock.FontSize = 12;
textBlock.FontFamily = new FontFamily("Verdana");
textBlock.TextWrapping = TextWrapping.Wrap;
textBlock.Text = news.Text;
stackPanel.Children.Add(textBlock);
TextBlock dateTextBlock = new TextBlock();
dateTextBlock.Foreground = new SolidColorBrush(Colors.Gray);
dateTextBlock.FontSize = 10;
dateTextBlock.FontFamily = new FontFamily("Verdana");
dateTextBlock.TextWrapping = TextWrapping.Wrap;
dateTextBlock.FontWeight = FontWeights.Bold;
dateTextBlock.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
dateTextBlock.Text = news.Date.ToShortDateString();
stackPanel.Children.Add(dateTextBlock);
stackPanel.Children.Add(new TextBlock());
newsStackPanel.Children.Add(stackPanel);
}
PagedCollectionView itemListView = new PagedCollectionView(newsStackPanel.Children);
newsPager.Source = itemListView;
and all of it goes here
<Grid x:Name="LayoutRoot" Loaded="LayoutRoot_Loaded" MaxWidth="1100">
<Grid.RenderTransform>
<CompositeTransform/>
</Grid.RenderTransform>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="2"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<RichTextBox Name="contentRTB" MaxWidth="1000" Margin="10, 30, 10, 30" Grid.Column="2"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
TextWrapping="Wrap"
Style="{StaticResource RichTextBoxStyle}" IsReadOnly="True"/>
<Rectangle Grid.Column="1" Margin="0,10"
Fill="#FF0067C6"/>
<TextBlock Name="header" Foreground="#FF0067C6" FontSize="18" FontFamily="Verdana" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Column="0"></TextBlock>
<sdk:DataPager x:Name="newsPager"
DisplayMode="FirstLastNumeric"
Background="#FF0067C6"
PageSize="3"
AutoEllipsis="True"
NumericButtonCount="3"/>
<StackPanel Name="newsStackPanel" Grid.Column="0" Orientation="Vertical" Margin="0,50,0,0"/>
</Grid>
The newsPager displayes (correctly) 2 pages because i have currently 5 news and the pageSize is set to 3 but they are all displayed on the same page so I dont get the desired paging... how can i fix it
Your code is adding all the items to a StackPanel, then it is putting that StackPanel inside another StackPanel called "newsStackPanel" below the DataPager. So, right now, the DataPager has nothing to do with the display of your news articles, and you won't be seeing any paging happening.
Instead, take a look at the DataPager sample code here:
http://msdn.microsoft.com/en-us/library/system.windows.controls.datapager(VS.95).aspx#Y9406
You'll need to modify that sample code to contain a list of StackPanels like this:
List<StackPanel> itemList = new List<StackPanel>();
Then, for each of your news items, add them to that list instead of an outer StackPanel:
itemList.Add(stackPanel);
You'll then wrap that up and bind it to both your data pager and a new list control:
// Wrap the itemList in a PagedCollectionView for paging functionality
PagedCollectionView itemListView = new PagedCollectionView(itemList);
// Set the DataPager and ListBox to the same data source.
newsPager.Source = itemListView;
listBox1.ItemsSource = itemListView;
The sample uses a ListBox called "listBox1". You have lots of choices there. Perhaps replace the "newsStackPanel" with a ListBox called "newsList".
OK, that should be enough to get you through this.
Now for a little more homework:
You should really consider switching this to the MVVM pattern where you bind these values and template them instead of making UI controls in C#. This results in much cleaner code, enables much easier reuse, improves testability, and so on. There are a million zillion articles on the web for this. Here is one from MS:
http://msdn.microsoft.com/en-us/library/gg430869(v=PandP.40).aspx
I don't know if the DataPager control you're using handles the paging completely.
You could only add the news items that are on the page you want to view to the stack panel.
One easy way to do that could be to use LINQ in your for each, something like:
foreach (Model.News news in s.Skip(newsPager.PageSize * newsPager.PageIndex).Take(newsPager.PageSize))
you'd have to reinitialize the items in the pager when the page index changes then too.
I am creating Dynamic Rectangle and adding into StackPanel. I need to add text to each rectangle. How can I do that?
A Rectangle doesn't have any child content, so you will need to put both controls inside of another panel, such as a grid:
<Grid>
<Rectangle Stroke="Red" Fill="Blue"/>
<TextBlock>some text</TextBlock>
</Grid>
You can also use a Border control, which will take a single child and draw a rectangle around it:
<Border BorderBrush="Red" BorderThickness="1" Background="Blue">
<TextBlock>some text</TextBlock>
</Border>
You say "dynamic rectangle", so it sounds like you are doing this in code. The equivalent C# would look something like this:
var grid = new Grid();
grid.Children.Add(new Rectangle() { Stroke = Brushes.Red, Fill = Brushes.Blue });
grid.Children.Add(new TextBlock() { Text = "some text" });
panel.Children.Add(grid);
// or
panel.Children.Add(new Border()
{
BorderBrush = Brushes.Red,
BorderThickness = new Thickness(1),
Background = Brushes.Blue,
Child = new TextBlock() { Text = "some text" },
});
But if you want a dynamic list of rectangles, you should probably use an ItemsControl:
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Red" BorderThickness="1" Background="Blue">
<TextBlock Text="{Binding Text}"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
If you set the DataContext to a list of objects, this XAML will create a Border with a TextBlock for each one with the text set to the Text property on the object.
First of all you can do this, but not by adding the control. And there is a very good reason to do this, for high speed hardware rendering. You can create a special brush from a UI element that caches itself in hardware and fill the rectangle with this hardware, and it is extremely fast. I will just show the code behind because it is the example I have offhand
Rectangle r = new Rectangle();
r.Stroke = Brushes.Blue;
r.StrokeThickness = 5;
r.SetValue(Grid.ColumnProperty, 1);
r.VerticalAlignment = VerticalAlignment.Top;
r.HorizontalAlignment = HorizontalAlignment.Left;
r.Margin = new Thickness(0);
r.Width = 200;
r.Height = 200;
r.RenderTransform = new TranslateTransform(100, 100);
TextBlock TB = new TextBlock();
TB.Text = "Some Text to fill";
// The next two magical lines create a special brush that contains a bitmap
// rendering of the UI element that can then be used like any other brush
// and it's in hardware and is almost the text book example for utilizing
// all hardware rending performances in WPF unleashed 4.5
BitmapCacheBrush bcb = new BitmapCacheBrush(TB);
r.Fill = bcb;
MyCanvas.Children.Add(r);
You need to add a textual control to your StackPanel, such as Label or TextBlock.