I've got a GridviewItem. This GridviewItem has a background which is an ImageBrush. Now I want to change this ImageBrush to a new source when clicking a certain button.
For this I'm using:
blck.Background = new ImageBrush(new BitmapImage(new Uri("ms-appx:///Assets/SensorBG.png")));
It does work however the new image only shows whenever I click on the corresponding GridviewItem. Can anyone tell me how to update it without having to click on the GridviewItem?
I've already tried to put it within this block with no success:
CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
blck.Background = new ImageBrush(new BitmapImage(new Uri("ms-appx:///Assets/SensorBG.png")));
}
);
The best would be, if you have defined your ItemClass with suitable properties and implement INotifyPropertyChanged - with appropriate binding, every change will update the UI. Here is a small sample - XAML:
<StackPanel>
<Button Content="Change background of second item" Click="Button_Click"/>
<GridView Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" ItemsSource="{x:Bind Items}">
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:ItemClass">
<Border>
<Border.Background>
<ImageBrush ImageSource="{x:Bind Image, Mode=OneWay}"/>
</Border.Background>
<TextBlock Text="{x:Bind Name}"/>
</Border>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</StackPanel>
and the code behind:
public sealed partial class MainPage : Page
{
public List<ItemClass> Items = new List<ItemClass>();
public MainPage()
{
Items.Add(new ItemClass { Name = "First item", Image = new BitmapImage(new Uri("ms-appx:///Assets/StoreLogo.png")) });
Items.Add(new ItemClass { Name = "Second item", Image = new BitmapImage(new Uri("ms-appx:///Assets/StoreLogo.png")) });
this.InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e) => Items[1].Image = new BitmapImage(new Uri("ms-appx:///test.jpg"));
}
public class ItemClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseProperty(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
private ImageSource image;
public ImageSource Image
{
get { return image; }
set { image = value; RaiseProperty(nameof(Image)); }
}
public string Name { get; set; }
}
Related
I put image in Content Dialog but I cannot see any image fetched from the source. It seems that the image source cannot binding from the view model. However it works well with Page
This is my XAML of Content Dialog
<ContentDialog
x:Class="SmartEducation.App.Teacher.ContentViewer.Views.SketchDetailPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SmartEducation.App.Teacher.ContentViewer.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:uwpControls="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d"
Title="Student's Sketch"
CloseButtonText="Cancel"
DefaultButton="Primary"
Background="White" Width="750" Height="500">
<RelativePanel>
<ScrollViewer x:Name="scrollView" ZoomMode="Enabled" DoubleTapped="ScrollViewer_DoubleTapped" HorizontalScrollBarVisibility="Visible" HorizontalScrollMode="Enabled" MinZoomFactor="1">
<StackPanel Background="White" Width="750" Height="500">
<Image Name="imgSketch" Source="{Binding ImageUri}"/>
</StackPanel>
</ScrollViewer>
</RelativePanel>
I already add ViewModel to DataContext in my xaml.cs
private SketchDetailPageViewModel ViewModel
{
get { return DataContext as SketchDetailPageViewModel; }
}
public SketchDetailPage()
{
this.InitializeComponent();
}
I put the ImageUri in my ViewModel
private string _imgContent;
public string ImageUri
{
get { return _imgContent; }
set
{
_imgContent = value;
OnPropertyChanged(nameof(ImageUri));
}
}
Firstly, please make sure the ImageUri has an image resource reference. In your xaml.cs code, just providing a ViewModel property by your following code can not set the dialog's data context, so it will not get the image source.
private SketchDetailPageViewModel ViewModel
{
get { return DataContext as SketchDetailPageViewModel; }
}
You can just configure the dialog's data context by the following code in the dialog's xaml.cs,
public SketchDetailPage()
{
this.InitializeComponent();
this.DataContext = new SketchDetailPageViewModel() { ImageUri= "ms-appx:///Assets/Image.png" };
}
If you put the image source in the ViewModel. Such as,
private string _imgContent= "ms-appx:///Assets/Image.png";
public string ImageUri
{
get { return _imgContent; }
set
{
_imgContent = value;
OnPropertyChanged(nameof(ImageUri));
}
}
Then you can set the page data context on the XAML of Content Dialog,
<ContentDialog
...
Background="White" Width="750" Height="500">
<ContentDialog.DataContext>
<local:SketchDetailPageViewModel/>
</ContentDialog.DataContext>
<RelativePanel>
<ScrollViewer x:Name="scrollView" ZoomMode="Enabled"
DoubleTapped="ScrollViewer_DoubleTapped"
HorizontalScrollBarVisibility="Visible"
HorizontalScrollMode="Enabled"
MinZoomFactor="1">
<StackPanel Background="White" Width="750" Height="500">
<Image Name="imgSketch" Source="{Binding ImageUri}"/>
</StackPanel>
</ScrollViewer>
</RelativePanel>
</ContentDialog>
Or you can set the data context in the xaml.cs,
public SketchDetailPage()
{
this.InitializeComponent();
this.DataContext = new SketchDetailPageViewModel();
}
------ Update ------
but the binding image uri doesn't change although image uri of source change
If you want to change the image by changing the image uri, you can expose the dialog's data context as the following code, meanwhile, your SketchDetailPageViewModel should implement the INotifyPropertyChanged interface. It seems you have implement the interface, here is a simple example,
SketchDetailPageViewModel class,
internal class SketchDetailPageViewModel : INotifyPropertyChanged
{
private string _imgContent;
public string ImageUri
{
get { return _imgContent; }
set
{
_imgContent = value;
OnPropertyChanged(nameof(ImageUri));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
class SketchDetailPage : ContentDialog,
public SketchDetailPage()
{
this.InitializeComponent();
this.DataContext = new SketchDetailPageViewModel() { ImageUri= "ms-appx:///Assets/Image.png" };
}
internal SketchDetailPageViewModel ViewModel
{
get { return DataContext as SketchDetailPageViewModel; }
}
you can change the image when you use the SketchDetailPage dialog,
private async void Button_Click(object sender, RoutedEventArgs e)
{
SketchDetailPage dialog = new SketchDetailPage();
//change the dialog image
dialog.ViewModel.ImageUri = "ms-appx:///Assets/StoreLogo.png";
await dialog.ShowAsync();
}
i am having an issue while trying to bind an image to an ImageSource. I have tried some of the other fix on stackoverflow but none of them works.
I seem to get an error on this line saying that collection "Items" must be empty.
ImageList.ItemsSource = List;
The bind works well while using the "url" member of the FlickrData class.
MainWindow.xaml
<ScrollViewer>
<ListView x:Name="ImageList" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<Rectangle Margin="5" Width="100" Height="100">
<Rectangle.Fill>
<ImageBrush ImageSource="{Binding imageBinding}"/>
</Rectangle.Fill>
</Rectangle>
</ListView>
</ScrollViewer>
FlickrData Class:
public class FlickrData
{
public String url { get; set;}
public FlickrData(Photo photo)
{
url = photo.SmallUrl;
}
public ImageBrush imageBinding
{
get
{
ImageBrush brush = new ImageBrush();
brush.ImageSource = new BitmapImage(new Uri(url));
return brush;
}
}
}
MainWindow class:
public partial class MainWindow : Window
{
public ObservableCollection<FlickrData> List = new ObservableCollection<FlickrData>();
public static Flickr flickr = new Flickr("XXXXXXXXXXXXXX");
public MainWindow()
{
InitializeComponent();
}
public void SearchWithInput(object sender, RoutedEventArgs e)
{
var options = new PhotoSearchOptions { Tags = SearchInput.Text, PerPage = 20, Page = 1 };
PhotoCollection photos = flickr.PhotosSearch(options);
List.Clear();
foreach (Photo photo in photos)
{
String flickrUrl = photo.WebUrl;
Console.WriteLine("Photo {0} has title {1} with url {2}", photo.PhotoId, photo.Title, photo.WebUrl);
List.Add(new FlickrData(photo));
}
ImageList.ItemsSource = List;
}
}
Do this to clean up the process
Change your XAML's ListView to ItemsSource="{Binding List}" which only needs to be done once.
Remove the now redundant ImageList.ItemsSource = List;
The list control will update itself accordingly because an ObservableCollection sends notifications of the change which are subscribed to by the list control.
I fill a TreeView (WPF) in the code and want to use some icons in the items.
I can load and add BitmapImage but it is only displayed, when the BitmapImage is also assigned to another ImageControl in the window (and shown there):
TreeViewItem newItem = new TreeViewItem();
Image tempImage = new Image();
BitmapImage bitmapImage = new BitmapImage(new Uri(#"/Resources/ok-01.png", UriKind.Relative));
tempImage.Source = bitmapImage;
imageControlInWindow.Source = bitmapImage; //if I delete this line (it is not needed) the image in the TreeViewItem is not shown
TextBlock tempTextBlock = new TextBlock();
tempTextBlock.Inlines.Add(tempImage);
tempTextBlock.Inlines.Add("SomeText");
newItem.Header = tempTextBlock;
How can I force the image to be shown in the TreeView without the hack of showing it outside the treeview as copy?
You are not loading the image files from a proper Resource File Pack URI.
It should look like this:
var bitmapImage = new BitmapImage(new Uri("pack://application:,,,/Resources/ok-01.png"));
The Build Action of the image file must be set to Resource.
MainWindow:
<Window x:Class="TreeViewTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TreeView ItemsSource="{Binding Items}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate >
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Text}" />
<Image Source="{Binding ImageSource}" Stretch="Uniform" Height="30"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
Code behind:
public partial class MainWindow
{
public List<MyItem> Items { get; private set; }
public MainWindow()
{
InitializeComponent();
DataContext = this;
Items = new List<MyItem>
{
new MyItem {Text = "Item 1", ImageSource = "/image1.png"},
new MyItem {Text = "Item 2", ImageSource = "/image2.png"}
};
}
}
public class MyItem
{
public string Text { get; set; }
public string ImageSource { get; set; }
}
Hey so I was wondering what UIElement does skype use for its Contact List in order to display additional details within each ListItem (such as Status Updates, Avatars, Online Status and so forth)?
(source: iforce.co.nz)
As far as I know the regular System.Windows.Forms.ListBox only lets you display a single line of text to represent that Object.
(source: iforce.co.nz)
I'm looking to recreate something similar but for a different purpose, but I haven't been able to find much on google (So that's why I'm seeing if anyone here has experience modifying the design of a ListBox, to gain a better perspective over each detail).
Thanks
Here is a very basic example of creating a custom Datatemplate for WPF.
First you create your Model with all the properties you want to be displayed, then bind a list of them to your ListBox. Then you can create a DataTemplate this is basically a xaml(visual) representation of your Model, you can make it look however you want and you can use any of the properties from your Model in the DataTemplate.
Example:
Window code:
public partial class MainWindow : Window
{
private ObservableCollection<MyListBoxItemModel> _listBoxItems = new ObservableCollection<MyListBoxItemModel>();
public MainWindow()
{
InitializeComponent();
ListBoxItems.Add(new MyListBoxItemModel { Title = "Item 1", Image = new BitmapImage(new Uri("http://icons.iconarchive.com/icons/custom-icon-design/mini/32/Search-icon.png")) });
ListBoxItems.Add(new MyListBoxItemModel { Title = "Item 2", Image = new BitmapImage(new Uri("http://icons.iconarchive.com/icons/custom-icon-design/mini/32/Search-icon.png")) });
ListBoxItems.Add(new MyListBoxItemModel { Title = "Item 3", Image = new BitmapImage(new Uri("http://icons.iconarchive.com/icons/custom-icon-design/mini/32/Search-icon.png")) });
}
public ObservableCollection<MyListBoxItemModel> ListBoxItems
{
get { return _listBoxItems; }
set { _listBoxItems = value; }
}
}
Model:
public class MyListBoxItemModel : INotifyPropertyChanged
{
private string _title;
private string _line2 = "Line2";
private BitmapImage _image;
public string Title
{
get { return _title; }
set { _title = value; NotifyPropertyChanged("Title"); }
}
public string Line2
{
get { return _line2; }
set { _line2 = value; NotifyPropertyChanged("Line2"); }
}
public BitmapImage Image
{
get { return _image; }
set { _image = value; NotifyPropertyChanged("Image"); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string p)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(p));
}
}
}
Xaml:
<Window x:Class="WpfApplication7.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication7"
Title="MainWindow" Height="351" Width="464" Name="UI" >
<Window.Resources>
<!-- The tempate for MyListBoxItemModel -->
<DataTemplate DataType="{x:Type local:MyListBoxItemModel}">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image}" />
<StackPanel>
<TextBlock Text="{Binding Title}" FontWeight="Medium" />
<TextBlock Text="{Binding Line2}" />
</StackPanel>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding ElementName=UI, Path=ListBoxItems}" />
</Grid>
</Window>
This is just a simple example with an Image and some text, but it should get you started, Just modify the DataTemplate and Model how you want to display the snp code data
Result:
I have a simple app where after clicking a button the value of a label is updated every second.I'm doing this as a POC for a progress bar control that I want to develop.
I would like to know if there is a way to apply some kind of scroller animation to the label which will:
1) When the content of a label is updated it will scroll the new value from the top and the old one will be scrolled down and disappear from view(Hope this makes sence).
I know that this could probably be achieved with some kind of animation but I couldn't find any helpful examples on the web if anyone knows how this can be done please share your expertise:
View:
<Window x:Class="WpfApplication1.ScrollerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Scroller" DataContext="{StaticResource scrollerVM}" Height="150" Width="300">
<Grid>
<ListBox ItemsSource="{Binding Messages}" Width="200" Height="50" BorderThickness="0" VerticalAlignment="Top" HorizontalAlignment="Left">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Text}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
<Button Width="70" Height="24" Content="Add new" Command="{Binding AddNew}" HorizontalAlignment="Left" Margin="0,56,0,30" />
</Grid>
</Window>
View model:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Threading;
namespace WpfApplication1.Scroller
{
public class Message
{
public Message(string _text)
{
text = _text;
}
private string text;
public string Text
{
get { return text; }
set {text = value;}
}
}
public class ScrollerViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public DelegateCommand AddNew { get; protected set; }
ObservableCollection<Message> _messages = new ObservableCollection<Message>();
public ObservableCollection<Message> Messages
{
get { return _messages; }
set
{
_messages = value;
OnPropertyChanged("Messages");
}
}
public ScrollerViewModel()
{
AddNew = new DelegateCommand(Add);
}
private void Add(object parameter)
{
DispatcherTimer timer = new DispatcherTimer();
timer.Tick += new System.EventHandler(timer_Tick);
timer.Interval = new System.TimeSpan(0, 0, 1);
timer.Start();
}
private void timer_Tick(object sender, EventArgs e)
{
Messages.Clear();
Messages.Add(new Message(DateTime.Now.ToString("ss")));
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
More comprehensive/different examples here.
The following will result in a basic vertical marquee (scrolling text block).
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Loaded="Window_Loaded">
<Canvas Name="canvas1" >
<TextBlock Name="textBlock1">Hello</TextBlock>
</Canvas>
</Window>
Code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void BeginAnimation()
{
DoubleAnimation doubleAnimation = new DoubleAnimation();
doubleAnimation.From = -textBlock1.ActualHeight;
doubleAnimation.To = canvas1.ActualHeight;
doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(3));
textBlock1.BeginAnimation(Canvas.TopProperty, doubleAnimation);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
BeginAnimation();
}
}
First, you'll want "smooth scrolling" on the ListBox:
ScrollViewer.CanContentScroll="False"
Then, you could create a custom Attached Property to specify the vertical offset you want to scroll. Then create a custom Behavior that hooks up to the ListBox's ItemsSource's "ItemsSourceChanged" event, which would fire off an animation that you can define inside the behavior. That should at least be a start. I'm not sure what the specific animation would be...some DoubleAnimation using a calculation of your offset plus new item's height.