I have an unexpected behaviour with a Wpf-Tabcontrol and Dataemplate with Interaction.Trgiggers.
First I define a "ViewModel". It's quite simple:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
namespace WpfApplication3 {
public class Vm: INotifyPropertyChanged {
public Vm() {
this.CmdClick = new RelayCommand( p => this.ExecuteClick(), p => this.CanExecuteClick() );
}
private string myName;
public string MyName {
get { return myName; }
set {
if( myName != value ) {
myName = value;
if( this.PropertyChanged != null ) {
this.PropertyChanged( this, new PropertyChangedEventArgs( "MyName" ) );
}
}
}
}
private RelayCommand cmdClick;
public RelayCommand CmdClick {
get { return cmdClick; }
set { cmdClick = value; }
}
#region Command
private bool CanExecuteClick() {
return true;
}
public void ExecuteClick() {
MessageBox.Show( "MyName is " + MyName );
}
#endregion
public event PropertyChangedEventHandler PropertyChanged;
}
}
Next, I define a Datatemplate:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:l="clr-namespace:WpfApplication3"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DataTemplate DataType="{x:Type l:Vm}" x:Key="Vm">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Text="{Binding Path=MyName}" Grid.Row="0"/>
<i:Interaction.Triggers>
<ei:KeyTrigger Key="F5" ActiveOnFocus="True" FiredOn="KeyUp" >
<i:InvokeCommandAction Command="{Binding CmdClick}" />
</ei:KeyTrigger>
</i:Interaction.Triggers>
</Grid>
</DataTemplate>
</ResourceDictionary>
I use the datatemplate on the mainform inside a TabControl:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:WpfApplication3"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<TabControl>
<TabItem Header="Tab1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ContentControl ContentTemplate="{StaticResource Vm}" x:Name="vm11" Content="{Binding}" Grid.Row="0"/>
</Grid>
</TabItem>
<TabItem Header="Tab2">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ContentControl ContentTemplate="{StaticResource Vm}" x:Name="vm21" Content="{Binding}" Grid.Row="0"/>
<ContentControl ContentTemplate="{StaticResource Vm}" x:Name="vm22" Content="{Binding}" Grid.Row="1"/>
</Grid>
</TabItem>
</TabControl>
</Window>
The code behind is simple:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication3 {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
this.vm11.Content = vm1;
this.vm21.Content = vm2;
this.vm22.Content = vm3;
this.vm1.MyName = "Name1";
this.vm2.MyName = "Name2";
this.vm3.MyName = "Name3";
}
Vm vm1 = new Vm();
Vm vm2 = new Vm();
Vm vm3 = new Vm();
}
}
When i run the program, I chlick in the first TextBox, press F5 and the MessageBox posup. Ok.
I switch the tabpage, click inside the second TextBox, press F5 and the MessageBox appears again. OK.
I switch back to the firsz tabpage, press F5 and the MessageBox appears twice. Uuuh. Whatss wrong.
I switch back to the second tabpage,the messagebox appears twice again.
After switching to the first tabpage, the messagebox is displayed treetimes now. And so on.
It is like, the KeyUp-Event is assigned internaly, when the datatemplate is displayed again, without dereferencing it. But ehat can I do ?
I think you need to change this property from
private RelayCommand cmdClick;
public RelayCommand CmdClick {
get { return cmdClick; }
set { cmdClick = value; }
To
private RelayCommand cmdClick;
public RelayCommand CmdClick {
get { return cmdClick; }
set { if(cmdClick == null)cmdClick = value; }
Related
I am working on MVVM , I have used interactions.
Purpose is what ever will be typed in text box, same will be displayed in TextBlock.
Interaction trigger will be done event PreviewTextInput of text box.
But it is giving error but not working as expected.
Binding error at runtime image has been attached.
Below is the code.
XAML
<Window x:Class="MVVMApp.TextBindings"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MVVMApp"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d"
Title="Text Bindings" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="Enter Text Value" Grid.Row="0" Grid.Column="0"/>
<TextBox Name="txtBox1" Text="{Binding BxVal,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Row="0" Grid.Column="1" Width="150" Height="30">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewTextInput">
<i:InvokeCommandAction Command="{Binding cmdType}" CommandParameter="{Binding BxVal,ElementName=txtBox1}"></i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
<TextBlock Text="Result --> " Grid.Row="1" Grid.Column="0"/>
<TextBlock Text="{Binding Result,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Background="Lavender" Grid.Row="1" Grid.Column="1"/>
</Grid>
MVVM
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MVVMApp.Helper;
namespace MVVMApp.ViewModel
{
class TextBindingsVM :ViewModelBase
{
DelegateCommand <object> cmdType { get; set; }
private string _Result { get; set; }
public string Result
{
get { return _Result; }
set
{
_Result = value;
OnPropertyChanged(this, "Result");
}
}
private string _BxVal { get; set; }
public string BxVal
{
get { return _BxVal; }
set
{
_BxVal = value;
OnPropertyChanged(this, "BxVal");
Result = BxVal;
}
}
public TextBindingsVM()
{
cmdType = new DelegateCommand<object>(cmdType_Execute);
}
private void cmdType_Execute(object obj)
{
throw new NotImplementedException();
}
}
}
I found the issue. Actually INotifyPropertyChanged was not implemented in ViewModelBase class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MVVMApp.Helper
{
class ViewModelBase:INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(object sender, string PropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
}
}
This question is related to removing an attribute in xaml.
In the below code, I have a Span. During an event, I add a back ground to this Span. During another event, I need to remove it. Please let me know, if there is a way to remove the background attribute I set to Span.
My Xaml looks like this.
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication4"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition Height="40"></RowDefinition>
</Grid.RowDefinitions>
<RichTextBox x:Name="rtb">
<FlowDocument>
<Paragraph>
<Span x:Name="def" Tag="default">
<Run x:Name="deg">Some Text</Run>
</Span>
</Paragraph>
</FlowDocument>
</RichTextBox>
<TextBox x:Name="tx" Grid.Row="1" TextWrapping="Wrap"/>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Content="s" Click="Button_Click"/>
<Button Content="bg-Add" Grid.Column="1" Click="Button_Click"/>
<Button Content="bg-Remove" Grid.Column="2" Click="Button_Click"/>
</Grid>
</Grid>
</Window>
My code looks like this.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows. Shapes;
namespace WpfApplication4
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if ((sender as Button).Content.ToString() == "s")
{
tx.Text = XamlWriter.Save(def);
}
else if ((sender as Button).Content.ToString() == "bg-Add")
{
def.Background = new SolidColorBrush(Colors.Blue);
}
else if ((sender as Button).Content.ToString() == "bg-Remove")
{
//Need to remove the set back color so that I get the default back
}
}
}
}
I am able to find an answer myself.
def.ClearValue(Span.BackgroundProperty);
is going to remove that attribute for me.
You can override ShouldSerializeProperty
public class CustomizedSpan : Span
{
public bool IsRemoveBackGround;
protected override bool ShouldSerializeProperty(DependencyProperty dp)
{
if (dp == Span.BackgroundProperty && IsRemoveBackGround)
{
return false;
}
else
{
return base.ShouldSerializeProperty(dp);
}
}
}
I am a newbie to WPF and while I have read lots of theory and articles, I am unable to put it all together in a working solution.
Presently, I wish to implement dynamic multiple views in a window which could be selected by the user using buttons. The target is very much like one given in the question,
WPF : dynamic view/content
Can somebody please share with me a working code, of simplest implementation of the above. Just a window which contains two grids - one grid has two buttons - second grid changes background color depending on which button is clicked. From there on , I can take things further.
Thank you very much.
Use MVVM
It's a design approach. Basically you treat your Window as shell, and it's responsible for swapping views.
To simplify this snippet, I've referenced MvvmLight .
The Window contains ContentControl which dynamically displays the relevant view
Each dynamic view can communicate with the shell Window (using MvvmLight's Messenger) and tell it to change the view to something else.
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainWindowViewModel></local:MainWindowViewModel>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Grid.Column="0" Command="{Binding ChangeFirstViewCommand}">Change View #1</Button>
<Button Grid.Row="0" Grid.Column="1" Command="{Binding ChangeSecondViewCommand}">Change View #2</Button>
<ContentControl Grid.Row="1" Grid.ColumnSpan="2" Content="{Binding ContentControlView}"></ContentControl>
</Grid>
</Window>
MainWindowViewModel.cs
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace WpfApplication1
{
public class MainWindowViewModel : ViewModelBase
{
private FrameworkElement _contentControlView;
public FrameworkElement ContentControlView
{
get { return _contentControlView; }
set
{
_contentControlView = value;
RaisePropertyChanged("ContentControlView");
}
}
public MainWindowViewModel()
{
Messenger.Default.Register<SwitchViewMessage>(this, (switchViewMessage) =>
{
SwitchView(switchViewMessage.ViewName);
});
}
public ICommand ChangeFirstViewCommand
{
get
{
return new RelayCommand(() =>
{
SwitchView("FirstView");
});
}
}
public ICommand ChangeSecondViewCommand
{
get
{
return new RelayCommand(() =>
{
SwitchView("SecondView");
});
}
}
public void SwitchView(string viewName)
{
switch (viewName)
{
case "FirstView":
ContentControlView = new FirstView();
ContentControlView.DataContext = new FirstViewModel() { Text = "This is the first View" };
break;
default:
ContentControlView = new SecondView();
ContentControlView.DataContext = new SecondViewModel() { Text = "This is the second View" };
break;
}
}
}
}
FirstView.xaml
<UserControl x:Class="WpfApplication1.FirstView"
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"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel>
<Label>This is the second view</Label>
<Label Content="{Binding Text}" />
<Button Command="{Binding ChangeToSecondViewCommand}">Change to Second View</Button>
</StackPanel>
</UserControl>
FirstViewModel.cs
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace WpfApplication1
{
public class FirstViewModel : ViewModelBase
{
private string _text;
public string Text
{
get { return _text; }
set
{
_text = value;
RaisePropertyChanged("Text");
}
}
public ICommand ChangeToSecondViewCommand
{
get
{
return new RelayCommand(() =>
{
Messenger.Default.Send<SwitchViewMessage>(new SwitchViewMessage { ViewName = "SecondView" });
});
}
}
}
}
SecondView.xaml
<UserControl x:Class="WpfApplication1.SecondView"
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"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel>
<Label>This is the second view</Label>
<Label Content="{Binding Text}" />
<Button Command="{Binding ChangeToFirstViewCommand}">Change to First View</Button>
</StackPanel>
</UserControl>
SecondViewModel.cs
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace WpfApplication1
{
public class SecondViewModel : ViewModelBase
{
private string _text;
public string Text
{
get { return _text; }
set
{
_text = value;
RaisePropertyChanged("Text");
}
}
public ICommand ChangeToFirstViewCommand
{
get
{
return new RelayCommand(() =>
{
Messenger.Default.Send<SwitchViewMessage>(new SwitchViewMessage { ViewName = "FirstView" });
});
}
}
}
}
SwitchViewMessage.cs
namespace WpfApplication1
{
public class SwitchViewMessage
{
public string ViewName { get; set; }
}
}
I have a ListView that is supposed to display objects of class Sensor, for which I created a simple (for now) DataTemplate.
In order to further design this DataTemplate in Expression Blend, I created Sample Data from Class as shown in the docs (although I am using Blend for Visual Studio 2013, but it seems to be the same).
I can successfully get the Sample Data I created being displayed in a ListView, but it is not using the DataTemplate I created, since the elements displayed seem to belong to a different, "design" namespace:
The qualified name of my class is Miotec.BioSinais.ModeloDomínio.Sensor;
(But) the qualified name of the displayed class is _.di0.Miotec.BioSinais.ModeloDomínio.Sensor.
What am I doing wrong? (code and screenshot below)
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:dominio="clr-namespace:Miotec.BioSinais.ModeloDomínio;assembly=Miotec.BioSinais"
mc:Ignorable="d"
x:Class="Miotec.ProtótipoColeta.ColetaConfigView"
x:Name="Window"
Title="ColetaConfigView"
Width="640" Height="480">
<Window.Resources>
<DataTemplate DataType="{x:Type dominio:Sensor}">
<Border>
<TextBlock Text="{Binding Nome}"/>
</Border>
</DataTemplate>
</Window.Resources>
<DockPanel x:Name="LayoutRoot">
<Grid x:Name="PainelCentral">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<DockPanel x:Name="PainelSetupsSensores" Background="#FFB8E6E8"/>
<DockPanel x:Name="PainelSensoresDisponiveis" Background="#FFC5E2A8"
Grid.RowSpan="2" Grid.Column="1"
DataContext="{Binding ReceiverAtivo}"
d:DataContext="{d:DesignData /SampleData/ReceiverSimuladoSampleData.xaml}">
<ListView ItemsSource="{Binding Sensores}" Margin="10"/>
</DockPanel>
</Grid>
</DockPanel>
</Window>
====
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Miotec.BioSinais.ModeloDomínio
{
public abstract class Sensor : INotifyPropertyChanged
{
public abstract string Nome { get; set; }
public virtual int NívelBateria { get; set; }
public virtual int NívelSinalWireless { get; set; }
public virtual EstadoSensor Estado { get; protected set; }
public ObservableCollection<Canal> Canais { get; protected set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged (string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
==============
I need to solve following issue: In a Silverlight app, the user needs to be able to upload images to the client (not the server). The images should be displayed in a wrappanel.
I am a complete rookie to silverlight, so you might find several mistakes in the code. Below I posted the code, I hope it is sufficient to answer the question!
App.xaml:
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Dojo_3_wi10b012.ViewModel"
x:Class="Dojo_3_wi10b012.App"
>
<Application.Resources>
<local:ViewModel x:Key="viewModel"/>
</Application.Resources>
</Application>
MainPage.xaml:
<UserControl x:Class="Dojo_3_wi10b012.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:local="clr-namespace:Dojo_3_wi10b012.ViewModel"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource viewModel}">
<sdk:Frame Height="350" Width="450"
Name="frameContainer" Margin="0,0,0,0">
</sdk:Frame>
<Button Content="Add Image" Command="{Binding Path=AddImageCommand}" Height="23" HorizontalAlignment="Left" Margin="468,454,0,0" Name="buttonAddImage" VerticalAlignment="Top" Width="75" />
</Grid>
</UserControl>
Gallery.xaml:
<navigation:Page x:Class="Dojo_3_wi10b012.View.Gallery"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:Dojo_3_wi10b012.ViewModel"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignWidth="640" d:DesignHeight="480"
Title="Gallery Page"
NavigationCacheMode="Required" xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit">
<!-- trying to implement Mr. Eckkrammer's hint (wiki)-->
<UserControl.Resources>
<DataTemplate x:Key="galleryTemplate">
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding Image}"/>
</Image.Source>
</Image>
</DataTemplate>
</UserControl.Resources>
<!-- END OF trying to implement Mr. Eckkrammer's hint (wiki)-->
<Grid x:Name="LayoutRoot" Height="350" Width="450" Background="Beige" DataContext="{StaticResource viewModel}">
<!-- "First attempt
<ItemsControl ItemsSource="{Binding ElementName=ImageDescrList, Path=Image ,Mode=TwoWay}" >
<ScrollViewer Width="449" Height="349" Margin="1,1,0,0">
<toolkit:WrapPanel Orientation="Horizontal" ItemWidth="90" ItemHeight="90" Width="Auto" />
</ScrollViewer>
</ItemsControl>
-->
<!-- 2nd attempt (Mr. Eckkrammer's hint (wiki): -->
<ItemsControl ItemsSource="{Binding ElementName=ImageDescrList}" ItemTemplate="{StaticResource galleryTemplate}">
<ScrollViewer Width="449" Height="349" Margin="1,1,0,0">
<toolkit:WrapPanel Orientation="Horizontal" ItemWidth="90" ItemHeight="90" Width="Auto" />
</ScrollViewer>
</ItemsControl>
</Grid>
</navigation:Page>
ImageDescription.cs:
namespace Dojo_3_wi10b012.Model
{
public class ImageDescription : INotifyPropertyChanged
{
private string _description;
private BitmapImage _image;
public string Description
{
get { return _description; }
set
{
_description = value;
NotifyPropertyChanged("Description");
}
}
public BitmapImage Image
{
get { return _image; }
set
{
_image = value;
NotifyPropertyChanged("Image");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
ViewModel.cs:
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;
using System.IO.IsolatedStorage;
using System.Windows.Media.Imaging;
using System.Collections;
using System.Collections.ObjectModel;
using Dojo_3_wi10b012.Model;
using System.ComponentModel;
namespace Dojo_3_wi10b012.ViewModel
{
public class ViewModel : INotifyPropertyChanged
{
public RelayCommand AddImageCommand { get; private set; }
private ObservableCollection<ImageDescription> _imageDescrList = new ObservableCollection<ImageDescription>();
#region properties
public ObservableCollection<ImageDescription> ImageDescrList
{
get { return _imageDescrList; }
set
{
_imageDescrList = value;
NotifyPropertyChanged("ImageDescrList");
}
}
#endregion
#region Constructor
public ViewModel()
{
AddImageCommand = new RelayCommand(AddImage);
AddImageCommand.IsEnabled = true;
}
#endregion
#region private methods
private void AddImage()
{
//initial ideas: (copy paste + modified from source: http://msdn.microsoft.com/en-us/library/cc221415(v=vs.95).aspx )
// Create an instance of the open file dialog box.
OpenFileDialog openFileDialog1 = new OpenFileDialog();
// Set filter options and filter index.
openFileDialog1.Filter = "JPEG Files (.jpg)|*.jpg|PNG Files (.png)|*.png|GIF Files (.gif)|*.gif|BMP Files (.bmp)|*.bmp|TIFF Files (.tiff)|*.tiff";
openFileDialog1.FilterIndex = 1;
openFileDialog1.Multiselect = false;
// Call the ShowDialog method to show the dialog box.
bool? userClickedOK = openFileDialog1.ShowDialog();
// Process input if the user clicked OK.
if (userClickedOK == true)
{
// Open the selected file to read.
using (var filestream = openFileDialog1.File.OpenRead())
{
var buffer = new byte[filestream.Length];
filestream.Read(buffer, 0, buffer.Length);
//add the image to our list of images
MemoryStream ms = new MemoryStream(buffer, 0, buffer.Length);
BitmapImage temp = new BitmapImage();
temp.SetSource(ms);
ImageDescrList.Add(
new ImageDescription()
{
// Description = filestream.Name,
Description="Default Description",
Image = temp
}
);
ms.Close();
filestream.Close();
}
}
}
#endregion
#region event Handler (property changed)
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}
Try this in your galleryTemplate template to bind the Image Source to your bitmap:
<DataTemplate x:Key="galleryTemplate">
<Image Source="{Binding Image}"/>
</DataTemplate>
You appear to be trying to bind a bitmap UriSource to a Bitmap instead (that would expect a Uri):
<DataTemplate x:Key="galleryTemplate">
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding Image}"/>
</Image.Source>
</Image>
</DataTemplate>