In my current project I've got a WPF TreeView and added items like this:
<TreeViewItem Name="treeViewItem6" IsEnabled="False">
<TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image Height="16" Source="Images/16x16_green_lamp.png" Width="16" />
<TextBlock Margin="5,0" Text="Status: Connected" />
</StackPanel>
</TreeViewItem.Header>
</TreeViewItem>
I would like to replace an icon as well as the text of a TextBlock in my C# code to make it look like this:
Is there an easy way to programmatically replace the icon as well as the text of a TreeViewItem or do I have to iterate through the entire tree of sub items? (Unfortunately I'm a WPF novice and I'm more used to the good old WinForms)
To change the source of the image and the text of a textblock you can give the controls a name like this:
<Image Name="imgIcon" Height="16" Source="Images/16x16_green_lamp.png" Width="16" />
<TextBlock Name="tbStatus" Margin="5,0" Text="Status: Connected" />
That way you can change the properties you want to change easily programmatically, like this:
Image img = FindResource("red") as Image;
if (img != null) imgIcon.Source = img.Source;
tbStatus.Text = "Status: Disconnected";
To find the "green" and "red" resources you can add them to the XAML like this:
<Window.Resources>
<Image x:Key="green" Source="Images/16x16_green_lamp.png" />
<Image x:Key="red" Source="Images/16x16_red_lamp.png" />
</Window.Resources>
Of course you will need additional logic to determine the status, but this will get you started.
Instead of hardcoding the path to your image you can actually bind the image source to a string property in your ViewModel. The string property needs to represent the uri to the image you want to display. Once you change the string property (and fire the OnPropertyChanged event) your UI will automatically change the image.
WPF has a build in converter for images so you should not worry too much about that. Here is how your binding should look like:
<Image Source="{Binding ImageSource}" />
Where ItemSource is a string property in your view model.
Hope that helps.
How do you generate the tree? Is there any Data Binding there?
If the tree is constructed manually, why don't you simply give names to the elements that you want to change, and then in code reference those elements:
<TreeViewItem Name="treeViewItem6" IsEnabled="False">
<TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image x:Name="StatusImage" Height="16" Source="Images/16x16_green_lamp.png" Width="16" />
<TextBlock x:Name="StatusText" Margin="5,0" Text="Status: Connected" />
</StackPanel>
</TreeViewItem.Header>
</TreeViewItem>
Then, in C# code:
...
this.StatusImage.Source="..."; // a new ima
this.StatusText.Text = "....;
For the image source, you'll need to generate it (text is not enough):
new BitmapSource( new Uri( "image uri" ) )
You should construct it once and cache it.
Related
What I am trying to do is use the Imagebox as source for my bitmap effect and i dont know how to do that.My imagebox is called image1 .
<Button Content="Blur" Height="23" HorizontalAlignment="Left" Margin="148,12,0,0" Name="button3" VerticalAlignment="Top" Width="42" Click="button3_Click" >
<Image Source ="image1">
<Image.BitmapEffect>
<BlurBitmapEffect Radius="5" />
</Image.BitmapEffect>
</Image>
</Button>
Are you using MVVM? If not, I highly recommend using this pattern because WPF is built to use it and if you don't, you will fight it all the way.
Create a ViewModel class. Create a public property of type Image in this ViewModel class.
Create an instace of the ViewModel and put it into your Window's datacontext. Then add a binding to this property.
Alternatively for a quick fix (please note that this leads to darkness, you will regret having started to program this way):
<Image Source="{Binding Source, ElementName=image1}">
Edit:
Your edit is a completely different story: You have set the Content property twice: once by directly setting it and once by having a child object. Your button has both a text and an image as content. But a button (and most other controls) can only have one content. If you want both, your content needs to be a container control like a StackPanel that can have multiple contents and you need to put both your Image and your TextBlock in there.
Example (you need to put in Orientation and Alignment as you see fit):
<Button Height="23" HorizontalAlignment="Left" Margin="148,12,0,0" Name="button3" VerticalAlignment="Top" Width="42" Click="button3_Click">
<StackPanel>
<TextBlock Text="Test"/>
<Image Source="{Binding Source, ElementName=image1}">
<Image.BitmapEffect>
<BlurBitmapEffect Radius="5" />
</Image.BitmapEffect>
</Image>
</Button>
I want to load multiple images inside a wrappanel, for each image I show a thumbnail and some image details with this code
<Border BorderThickness="1" BorderBrush="#FFD0D1D7" Padding="5" Margin="10,10,0,0">
<StackPanel Orientation="Horizontal">
<!--image and dimensions-->
<Grid Width="88" Height="55">
<Image Source="C:\img1.jpg" Width="88" Height="55"/>
<TextBlock Background="#B2000000" Foreground="White" Height="16" TextAlignment="Center" VerticalAlignment="Bottom">1280x1024</TextBlock>
</Grid>
<!--name, type and size-->
<StackPanel Orientation="Vertical" Margin="5,0,0,0" VerticalAlignment="Center">
<TextBlock Margin="1" Foreground="#FF787878">img13.jpg</TextBlock>
<TextBlock Margin="1" Foreground="#FF787878">Type: JPEG</TextBlock>
<TextBlock Margin="1" Foreground="#FF787878">Size: 321 KB</TextBlock>
</StackPanel>
</StackPanel>
</Border>
But the images are loaded at runtime, and I need some way to create instances of the above code to show the image, dimensions, name, type and size
I tried this solution https://stackoverflow.com/a/4991028/962284
StringBuilder sb = new StringBuilder();
// use xaml to declare a button as string containing xaml
sb.Append(#"<Border BorderThickness='1' BorderBrush='#FFD0D1D7' Padding='5' Margin='10,10,0,0'>
<StackPanel Orientation='Horizontal'>
<!--image and dimensions-->
<Grid Width='88' Height='55'>
<Image Source='C:\img1.jpg' Width='88' Height='55'/>
<TextBlock Background='#B2000000' Foreground='White' Height='16' TextAlignment='Center' VerticalAlignment='Bottom'>1280x1024</TextBlock>
</Grid>
<!--name, type and size-->
<StackPanel Orientation='Vertical' Margin='5,0,0,0' VerticalAlignment='Center'>
<TextBlock Margin='1' Foreground='#FF787878'>img13.jpg</TextBlock>
<TextBlock Margin='1' Foreground='#FF787878'>Type: JPEG</TextBlock>
<TextBlock Margin='1' Foreground='#FF787878'>Size: 321 KB</TextBlock>
</StackPanel>
</StackPanel>
</Border>");
FrameworkElement thumb = (FrameworkElement)System.Windows.Markup.XamlReader.Parse(sb.ToString());
ThumbnailContainer.Children.Add(thumb);
but I get the following error
I also tried with styles, but styles doesnt support multiple parameters (to specify the textblocks: dimensions, size, name, type and size) just "TemplateBinding Tag" for 1 value
What can I do to create instances of the first code to show multiple images at runtime?
Wow. That so looks like the hard way to do things. Time to embrace WPF and XAML.
I had a post about this exact same thing that wasn't quite finished. I took time to finish it for you. I even used your XAML snippet (well, a modified version of it) in the example, just for you.
http://www.wpfsharp.com/2012/10/23/displaying-images-from-a-folder-with-details-in-wpf/
Clemens is correct in his comment to use an ItemsControl.
Yes your approach is wrong and you should be doing this some other way but to get your code snippet to work try adding xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" to your Border element in the string you are building. I suspect that is the error.
I'm trying to use binding with C# and a XAML SemanticZoom control in my Metro app, but honestly I'm at a loss as to how to do it. Here's the XAML code I've gotten so far by piecing together from questions, articles, etc:
<SemanticZoom x:Name="boardZoom" Height="626" Margin="10,132,10,0" VerticalAlignment="Top">
<SemanticZoom.ZoomedInView>
<GridView IsSwipeEnabled="True" x:Name="ItemsGridView">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="10,10,0,0"
HorizontalAlignment="Left" Background="White">
<TextBlock Text="{Binding Title}" TextWrapping="Wrap" Width="200" Height="300"
FontFamily="Global User Interface" FontSize="40" Foreground="Black"
VerticalAlignment="Center" HorizontalAlignment="Left"/>
<Image Source="{Binding Image}" Height="60" Width="60"
VerticalAlignment="Center" Margin="0,0,10,0" Visibility="{Binding isImage}" />
<TextBlock Text="{Binding Category}" TextWrapping="Wrap" Width="200"
FontFamily="Global User Interface" Foreground="Black"
VerticalAlignment="Center" HorizontalAlignment="Left"/>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</SemanticZoom.ZoomedInView>
<!--Didn't include SemanticZoom.ZoomedOutView since I'm still trying to get the ZoomedIn one working first-->
</SemanticZoom>
And my C# code:
List<PinStore.pin> pins = PinStore.CopyFromStream(response.GetResponseStream()); //returns a list of PinStore.pin objects, which have name, type, Image, isImage, and Category objects
System.Collections.ObjectModel.ObservableCollection<SemanticZoomed.zoomedIn> toSource = new System.Collections.ObjectModel.ObservableCollection<SemanticZoomed.zoomedIn>(); //should I be using ObservableCollection or something like List<> here?
foreach (PinStore.pin pin in pins)
{
SemanticZoomed.ZoomedIn toAdd = new SemanticZoomed.ZoomedIn(); //class with Title, Image, isImage, and Category objects
if (pin.type == "text")
{
toAdd.Title = pin.name;
toAdd.Image = null;
toAdd.isImage = Visibility.Collapsed;
toAdd.Category = pin.category;
}
toSource.Add(toAdd);
}
ItemsGridView.DataContext = toSource;
I've not had much experience in XAML/C#, and zero experience with binding. I'm not getting any errors, but I've noticed that if I replace ItemsGridView.DataContext = toSource; with ItemsGridView.ItemsSource = toSource; a blank stackpanel shows up in the GridView, and I can't seem to find a way to fill that with the Title and Category values I specify. Thanks!
Well you should first consider creating a ResourceDictionary so you can save your item style. Then you can set the ItemStyle to the Resource Dictionary.
But regardless you need to do: ItemsGridView.ItemsSource = toSource; If you do not choose to Bind the toSource in the GridView xaml.
Also make sure the SemanticZoomed.zoomedIn object implements the INotifyPropertyChanged interface, And calls the event properly. And make sure the Title, Image, Category, etc are public properties that call the event when edited. and Also you need make sure pin.Text is an actual value. {Making sure}.
If you want to learn more about data binding check out how they do it in C# & XAML with Windows 8 {Should be the same thing}:
http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh464965.aspx
I have a Panorama Control and inside it is a DataTemplate and inside the DataTemplate is an Image control. I want to get the Image control of the selected item to change it to something else. The xaml code is like this:
<controls:Panorama x:Name="FeedsPanorama" FontSize="20">
<controls:Panorama.ItemTemplate>
<DataTemplate x:Name="ItemDataTemplate">
<Grid d:DesignWidth="460" d:DesignHeight="700" Width="Auto" Height="Auto">
<Image HorizontalAlignment="Left" Height="118" Margin="2,8,0,0" VerticalAlignment="Top" Width="167" x:Name="ImageThumbnail" Source="{Binding SummaryImageLink}" />
</Grid>
</DataTemplate>
</controls:Panorama.ItemTemplate>
</controls:Panorama>
For example, every items will have their own images, but when it is selected, I will change the image to something else and then change back to it own image.
You need to get the actual container using the ItemContainerGenerator of your control:
FeedsPanorama.ItemContainerGenerator.ContainerFromItem(currentDataObject);
I'm creating an error list control similar to the in Visual Studio. Each error is represented by a class with three values: type (enum: Error/Warning/Message), text (string) and time (DateTime). The class has also two more read only getters: TimeString (returns time as HH:MM) and Icon (returns icon path based on type).
I have an ItemsControl bound to an ObservableCollection of objects via ItemsSource property.
I now want to implement a context menu for each of the items with two actions: Copy to clipboard and Delete from list.
How can I access the original item from the collection from the context menu item click handler?
Here is my XAML code:
<ItemsControl Name="itemsControl" ItemsSource="{Binding Items, ElementName=ConsoleWindow}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="Console.Items">
<Border Name="itemBorder" BorderBrush="LightGray" BorderThickness="0,0,0,1" SnapsToDevicePixels="True" Padding="4">
<Border.ContextMenu>
<ContextMenu>
<MenuItem Header="Copy to clipboard" />
<MenuItem Header="Delete" />
</ContextMenu>
</Border.ContextMenu>
<DockPanel>
<Image Width="16" Height="16" Source="{Binding Icon}" Margin="0,3,4,0" VerticalAlignment="Top" DockPanel.Dock="Left" />
<TextBlock VerticalAlignment="Center" TextWrapping="Wrap" DockPanel.Dock="Left">
<Run Text="{Binding Text}" />
<TextBlock Foreground="Gray" FontSize="9">
<Run Text=" (" /><Run Text="{Binding TimeString, Mode=OneWay}" /><Run Text=") " />
</TextBlock>
</TextBlock>
</DockPanel>
Thanks for any help
The DataContext property of any of the FrameworkElement derived elements (i.e. the TextBlock or Image or MenuItem) in the DataTemplate should have the original data item (the child automatically inherits the datasource of its parent unless otherwise set).
As part of the click event handler you get the element that is the source of the event, so cast it to MenuItem and check its DataContext property.
#slugster's answer would work. A more WPF-esque way of doing this would be to use a command for each menu item and set the parameter to {Binding}. WPF comes with commands for copy and possibly delete, so you might reuse those.