I have a collection of Objects with dependencyproperties, and Observer patern as I feed realtime data in "AssetIHM" Object.
public class assetVM: DependencyObject ,IObserver
{
public assetVM(AssetIHM aihm)
{
ObserverCollectionSingleton.ObserverCollectionInstance.Add(this);
_aihm = aihm;
}
private string _assetname;
public string assetname
{
get { return _assetname; }
set
{
_assetname = value;
SetValue(assetnameprop, value);
}
}
public static readonly DependencyProperty assetnameprop =
DependencyProperty.Register("assetnameprop", typeof(string),typeof(assetVM), new UIPropertyMetadata(""));
...
I also have a UserControl, Which should display the information contained in the AssetVM object:
public partial class AssetPanel : UserControl
{
public assetVM Asset
{
get
{
return (assetVM)GetValue(assetProperty);
}
set
{
SetValue(assetProperty, value);
}
}
public static DependencyProperty assetProperty = DependencyProperty.Register(
"Asset", typeof(assetVM), typeof(AssetPanel), new PropertyMetadata(null, new PropertyChangedCallback(OnCurrentItemChanged)));
public AssetPanel(assetVM _Asset)
{
Asset = _Asset;
this.DataContext = this;
InitializeComponent();
...
}
public AssetPanel( )
{
this.DataContext = this;
InitializeComponent();
...
}
...
I my main windows, I have a ListBox,
<Window x:Class="ETRportfolio.MainWindow"
DataContext = "{Binding RelativeSource={RelativeSource Self}}"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:UserControls="clr-namespace:ETRportfolio"
Title="MainWindow" Height="1200" Width="1425">
<StackPanel HorizontalAlignment="Left" Height="1153" VerticalAlignment="Top" Width="1400" Margin="10,10,-18,0">
<ListBox x:Name="Gridview" Height="800" >
<ListBox.ItemTemplate>
<DataTemplate>
<UserControls:AssetPanel Asset="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
MY problem is that I would like to feed my Usercontrol with the data contained is the collection of AssetVM.
public partial class MainWindow : Window
{
public static Dispatcher curDispatcher;
public ObservableCollection<assetVM> Datas
{
get
{
return (ObservableCollection<assetVM>)curDispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.DataBind,
(DispatcherOperationCallback)delegate { return GetValue(DataSProperty); },
DataSProperty);
}
set
{
curDispatcher.BeginInvoke(DispatcherPriority.DataBind,
(SendOrPostCallback)delegate { SetValue(DataSProperty, value); },
value);
}
}
public readonly DependencyProperty DataSProperty = DependencyProperty.Register("DataS", typeof(ObservableCollection<assetVM>), typeof(MainWindow), new PropertyMetadata(null, new PropertyChangedCallback(OnCurrentItemChanged)));
public MainWindow()
{
this.DataContext = this;
curDispatcher = this.Dispatcher;
Datas =new ObservableCollection<assetVM>();
InitializeComponent();
Gridview.ItemsSource = Datas;
addasset.addbtn.Click += onclik;
}
When the AssetPanel constructor is created, it doesn't bind with My AssetVM datas. I always pass through the empty constructor.
How Can I do that in XAML?
I guess the problem is there:
ListBox.ItemTemplate>
<DataTemplate>
<UserControls:AssetPanel Asset="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
Thks!
Edit::
I removed this.DataContext = this;
In the UserControl constructor, but the UserControl Constructor called when a DataObject
assetVM
is added to the ObservableCollection Datas, used as datasource for the Listview, is this the empty constructor. but not:
public AssetPanel(assetVM _Asset)
> {
> Asset = _Asset;
> InitializeComponent();
> ValuationInfo.ItemsSource = new List<string> { "%", "Value" };
> AVbox.ItemsSource = Enum.GetValues(typeof(AV)).Cast<AV>();
> }
So it doesn't bind.
Edit2::
private static void OnCurrentItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
AssetPanel instance = (AssetPanel)d;
instance.Asset = (assetVM)e.NewValue;
return;
}
It binds ! :)
Nevertheless, the Registered Dependency properties in the dataobject are not displayed.
This is my Assetpanel xaml:
<UserControl x:Class="ETRportfolio.AssetPanel"
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="152" d:DesignWidth="1400">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border BorderBrush="#FFDE6A6A" BorderThickness="1" Grid.Row="0" Grid.Column="0" Background="lightblue">
<TextBlock x:Name="assetnamebox" TextWrapping="Wrap" Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl }, Path = assetnameprop, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="15"/>
</Border>
...
TextBlock x:Name="assetnamebox" TextWrapping="Wrap" Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl }, Path = assetnameprop,
is not binding with assetVM.assetname VIA the DependencyProperty assetnameprop.
What is wrong there?
thks
Setting a UserControl's DataContext to itself, as done in your constructors by the statements
this.DataContext = this;
effectivly disables binding to properties of inherited DataContexts, like in
<ListBox.ItemTemplate>
<DataTemplate>
<UserControls:AssetPanel Asset="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
where the binding source is the inherited DataContext of the ListBoxItems, i.e. an assetVM instance.
Remove the DataContext assignment from your UserContr's constructors.
Related
I've got a class that has an ObservableCollection of itself embedded within the class.
I'm trying to create a user control that also has a reference to itself in order to display the contents of the observable collection. However, I'm getting a runtime error whenever I'm trying to run the app.
The error is not overly meaningful:
XAML parsing failed.
E_RUNTIME_SETVALUE [Line: 91 Position: 58] (which is the line that has the recursive call to the user control)
The class looks something like this (it's been made shorter for illustration purposes)
public class BookChapterVm : IBookChapterVm
{
public int Id {get;set;}
public string ChapterText {get;set;}
public ObservableCollection<IBookChapterVm> Chapters { get; set; } = new ObservableCollection<IBookChapterVm>();
}
The user control looks something like this (again, unnecessary parts are removed)
<UserControl
x:Class="Cgs.Ux.UserControls.HelpTextEditor.BookChapterEditorCtrl">
<ListView
ItemsSource="{x:Bind Vm.Chapters, Mode=OneWay}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="help:BookChapterVm">
<StackPanel Orientation="Horizontal">
<local:BookChapterEditorCtrl Vm="{Binding}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</UserControl>
I've also tried to set up a recursive data template, but it basically ended up with the same error.
Here is a working exemple :
In your page :
<local:RecursiveContainer ViewModel="{Binding}" />
The code behind :
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = BuildBookChapterVM();
}
private BookChapterVM BuildBookChapterVM()
{
BookChapterVM vm1 = new BookChapterVM { ChapterText = "1" };
BookChapterVM vm21 = new BookChapterVM { ChapterText = "21" };
BookChapterVM vm22 = new BookChapterVM { ChapterText = "22" };
BookChapterVM vm211 = new BookChapterVM { ChapterText = "211" };
vm1.Chapters.Add(vm21);
vm1.Chapters.Add(vm22);
vm21.Chapters.Add(vm211);
return vm1;
}
}
public class BookChapterVM
{
public int Id { get; set; }
public string ChapterText { get; set; }
public ObservableCollection<BookChapterVM> Chapters { get; set; } = new ObservableCollection<BookChapterVM>();
}
The UserControl XAML :
<UserControl
x:Class="WpfApp2.RecursiveContainer"
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:local="clr-namespace:WpfApp2"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<StackPanel>
<TextBlock Text="{Binding ChapterText}" />
<ItemsControl HorizontalContentAlignment="Stretch" ItemsSource="{Binding Chapters, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:RecursiveContainer
Margin="10,5,0,5"
HorizontalAlignment="Stretch"
ViewModel="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</UserControl>
The UC code behind :
public partial class RecursiveContainer : UserControl
{
public RecursiveContainer()
{
InitializeComponent();
}
public BookChapterVM ViewModel
{
get { return (BookChapterVM)GetValue(ViewModelProperty); }
set { SetValue(ViewModelProperty, value); }
}
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.Register("ViewModel", typeof(RecursiveContainer), typeof(RecursiveContainer));
}
See image as proof of concept.
I hope it will help you ;)
I am trying to create a UWP feet/inches control that takes a value in inches, and splits it into two fields, feet and inches. The control, when updated by the user, should update the backend viewmodel with the new inches value.
Requirements
Change the value in 1, then the values in 2 and 3 update
accordingly.
Change the value in 3, the values in 1 and 2 update accordingly
The way I have this written it gets into an endless loop. I am not even sure the FeetInches control is written properly. How would I change this to meet the above requirements?
Downloadable/runnable code is available in GitHub, but here it is inline per SO guidelines...
App.xaml
<Application x:Class="UWPFeetInches.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:UWPFeetInches">
<Application.Resources>
<ResourceDictionary>
<local:NullDecimalConverter x:Key="NullDecimalConverter" />
</ResourceDictionary>
</Application.Resources>
</Application>
MainPage.xaml
<Page
x:Class="UWPFeetInches.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="using:UWPFeetInches"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0"
Text="Enter Inches Value:"
Margin="0,50,10,0"
VerticalAlignment="Center" />
<TextBox Grid.Row="0" Grid.Column="1"
Margin="0,50,10,0"
Text="{x:Bind ViewModel.Inches, Mode=TwoWay, Converter={StaticResource NullDecimalConverter}}" />
<TextBlock Grid.Row="1" Grid.Column="0"
Margin="0,50,10,0"
Text="Inches Display:"/>
<TextBlock Grid.Row="1" Grid.Column="1"
Margin="0,50,10,0"
Text="{x:Bind ViewModel.InchesDisplay, Mode=TwoWay}"/>
<TextBlock Grid.Row="2" Grid.Column="0"
Text="Feet / Inches Control:"
Margin="0,50,10,0"
VerticalAlignment="Center" />
<local:FeetInches Grid.Row="2" Grid.Column="1"
Margin="0,50,10,0"
Value="{x:Bind ViewModel.Inches, Mode=TwoWay}" />
</Grid>
</Page>
MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace UWPFeetInches
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.ViewModel = new InchesViewModel();
}
public InchesViewModel ViewModel { get; set; }
}
public class InchesViewModel : INotifyPropertyChanged
{
private decimal? _Inches;
public decimal? Inches
{
get { return _Inches; }
set
{
if (value != _Inches)
{
_Inches = value;
InchesDisplay = _Inches == null ? "{null}" : _Inches.ToString();
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(nameof(Inches)));
}
}
}
private string _InchesDisplay;
public string InchesDisplay
{
get { return _InchesDisplay; }
set
{
if (value != _InchesDisplay)
{
_InchesDisplay = value;
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(nameof(InchesDisplay)));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
NullDecimalConverter.cs
using System;
using Windows.UI.Xaml.Data;
namespace UWPFeetInches
{
public sealed class NullDecimalConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is decimal m)
{
return m == 0 ? "" : m.ToString();
}
return "";
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
if (!string.IsNullOrWhiteSpace(value?.ToString()))
{
if (Decimal.TryParse(value.ToString(), out decimal m))
{
return m;
}
}
return null;
}
}
}
FeetInches.xaml
<UserControl
x:Class="UWPFeetInches.FeetInches"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:UWPFeetInches"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<StackPanel Orientation="Horizontal">
<TextBox Header="Feet"
Margin="0,0,10,0"
Text="{x:Bind Feet, Mode=TwoWay}" />
<TextBox Header="Inches"
Text="{x:Bind Inches, Mode=TwoWay, Converter={StaticResource NullDecimalConverter}}" />
</StackPanel>
</UserControl>
FeetInches.xaml.cs
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace UWPFeetInches
{
public sealed partial class FeetInches : UserControl
{
public FeetInches()
{
this.InitializeComponent();
}
#region Feet
public int Feet
{
get { return (int)GetValue(FeetProperty); }
set
{
SetValue(FeetProperty, value);
}
}
public static readonly DependencyProperty FeetProperty = DependencyProperty.Register(nameof(Feet), typeof(int), typeof(FeetInches), new PropertyMetadata(0, OnPropertyChanged));
#endregion
#region Inches
public decimal Inches
{
get { return (decimal)GetValue(InchesProperty); }
set
{
SetValue(InchesProperty, value);
}
}
public static readonly DependencyProperty InchesProperty = DependencyProperty.Register(nameof(Inches), typeof(decimal), typeof(FeetInches), new PropertyMetadata(0M, OnPropertyChanged));
#endregion
#region Value
public decimal? Value
{
get { return (decimal)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(nameof(Value), typeof(decimal?), typeof(FeetInches), new PropertyMetadata(null, ValueOnPropertyChanged));
#endregion
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as FeetInches;
control.Value = control.Feet * 12 + control.Inches;
}
private static void ValueOnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as FeetInches;
var inches = control.Value;
control.Feet = inches.HasValue ? (int)(inches.Value / 12M) : 0;
control.Inches = inches.HasValue ? inches.Value - (control.Feet * 12M) : 0M;
}
}
}
When you subscribe the PropertyChanged event for the three dependency properties, it will get into an endless loop. You could try to subscribe the LostFocus event of TextBox in FeetInches.xaml to replace your OnPropertyChanged event for your Feet and Inches properties, in that case, it won't get into an endless loop. For example:
.xaml:
<TextBox Header="Feet"
Margin="0,0,10,0"
x:Name="MyFeet"
Text="{x:Bind Feet, Mode=TwoWay}" LostFocus="TextBox_LostFocus"/>
<TextBox Header="Inches"
x:Name="MyInches"
Text="{x:Bind Inches, Mode=TwoWay, Converter={StaticResource NullDecimalConverter}}" LostFocus="TextBox_LostFocus"/>
.cs:
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
var textbox = sender as TextBox;
Decimal.TryParse(textbox.Text, out decimal m);
if (textbox.Name.Equals("MyFeet"))
{
this.Value = m * 12 + this.Inches;
}
else
{
this.Value = this.Feet * 12 + m;
}
}
When triggered the LostFocus event, the property bound with the Text of TextBox has not changed, so you need to use the value of Text directly instead of the Feet/Inches property and you need to judge which TextBox triggers this event.
Or if you still want to use OnPropertyChanged event for Feet and Inches properties instead of LostFocus event, you can declare a property(e.g. bool valueChanged) to limit the calling of ValueOnPropertyChanged and OnPropertyChanged event.
.cs:
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (valueChanged == false) {
var control = d as FeetInches;
control.Value = control.Feet * 12 + control.Inches;
}
}
private static bool valueChanged = false;
private static void ValueOnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
valueChanged = true;
var control = d as FeetInches;
var inches = control.Value;
control.Feet = inches.HasValue ? (int)(inches.Value / 12M) : 0;
control.Inches = inches.HasValue ? inches.Value - (control.Feet * 12M) : 0M;
valueChanged = false;
}
Update:
You can use the Property property from DependencyPropertyChangedEventArgs data to check which dependency property changes.
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.Property == FeetProperty) {
//do something
}
else{
//do something
}
}
I believe this is possible, but I don't seem to be able to get it to work; here's my view model:
namespace MyApp.ViewModel
{
public class MainViewModel : INotifyPropertyChanged
{
private static MainViewModel _mvm;
public static MainViewModel MVM()
{
if (_mvm == null)
_mvm = new MainViewModel();
return _mvm;
}
private string _imagePath = #"c:\location\image.png";
public string ImagePath
{
get { return _imagePath; }
set
{
SetProperty<string>(ref _imagePath, value);
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
{
if (Equals(storage, value)) return false;
storage = value;
OnPropertyChanged<T>(propertyName);
return true;
}
private void OnPropertyChanged<T>([CallerMemberName]string caller = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(caller));
}
}
...
Here's my App.xaml:
xmlns:vm="using:MyApp.ViewModel">
<Application.Resources>
<ResourceDictionary>
<vm:MainViewModel x:Key="MainViewModel" />
</ResourceDictionary>
</Application.Resources>
Here's the binding:
<Page
...
DataContext="{Binding MVM, Source={StaticResource MainViewModel}}">
<StackPanel Orientation="Horizontal" Margin="20" Grid.Row="0">
<TextBlock FontSize="30" Margin="10">Image</TextBlock>
<TextBox Text="{Binding ImagePath}" Margin="10"/>
</StackPanel>
...
I don't seem to be able to get the binding to work; what have I missed here? I would expect the field to be populated with the default value, but it isn't; I've put breakpoints in the ViewModel, but it is not breaking.
To me your binding syntax is incorrect. DataContext="{Binding MVM, Source={StaticResource MainViewModel} means you should have a "MVM" PROPERTY in your MainViewModel class. In your case MVM is a method.
Try replacing your MVM method by a property. That might work.
Another way to do it, is to set
DataContext="{StaticResource MainViewModel}"
In that case, the MVM method will be obsolete (I did not try it on WinRT)
I have a simple Behavior like that
public class KeyBoardChangeBehavior : Behavior<UserControl>
{
public Dictionary<string, int> DataToCheckAgainst;
protected override void OnAttached()
{
AssociatedObject.KeyDown += _KeyBoardBehaviorKeyDown;
}
protected override void OnDetaching()
{
AssociatedObject.KeyDown -= _KeyBoardBehaviorKeyDown;
}
void _KeyBoardBehaviorKeyDown(object sender, KeyEventArgs e)
{
// My business will go there
}
}
I want to asign value to this dictionary from the view , I call it as following
<UserControl x:Class="newhope2.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Interactivity="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:Behaviors="clr-namespace:newhope2"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Interactivity:Interaction.Behaviors>
<Behaviors:KeyBoardChangeBehavior />
</Interactivity:Interaction.Behaviors>
<Grid x:Name="LayoutRoot" Background="White">
</Grid>
</UserControl>
but how can I pass this dictionary to the behavior from XAML or its code behind
To take a Binding, a property needs to be a DependencyProperty.
You need to define the property, in the Behaviour, like so:
public Dictionary<string, int> DataToCheckAgainst
{
get { return (Dictionary<string, int>)GetValue(DataToCheckAgainstProperty); }
set { SetValue(DataToCheckAgainstProperty, value); }
}
public static readonly DependencyProperty DataToCheckAgainstProperty =
DependencyProperty.Register(
"DataToCheckAgainst",
typeof(Dictionary<string, int>),
typeof(KeyBoardChangeBehavior),
new PropertyMetadata(null));
Use the Visual Studio "propdp" snippet.
Usage is as Adi said, like so:
<Interactivity:Interaction.Behaviors>
<Behaviors:KeyBoardChangeBehavior DataToCheckAgainst="{Binding MyDictionary}" />
</Interactivity:Interaction.Behaviors>
All you need to do is declare the dictionary as a property and then pass it a value via binding.
In the behavior:
public Dictionary<string, int> DataToCheckAgainst { get; set; }
In XAML:
<Interactivity:Interaction.Behaviors>
<Behaviors:KeyBoardChangeBehavior DataToCheckAgainst="{Binding MyDictionary}" />
</Interactivity:Interaction.Behaviors>
I'm using Microsoft Activity Library Designer; For some reasons I need to use ListBox to show some information in it.But I have a problem with it's ItemsSource binding.My Activity side property is like this:
private ObservableCollection<string> _selectedItems;
public ObservableCollection<string> SelectedItems
{
get
{
if (_selectedItems == null)
{
ObservableCollection<string> items = new ObservableCollection<string>();
return items;
}
return _selectedItems;
}
set
{
_selectedItems = value;
}
}
And my XAML side code is like this:
....
<Button Content="Add Item" HorizontalAlignment="Stretch" Grid.Column="0"
Click="Button_Click" Margin="5, 0, 5, 5"/>
<Button Content="Remove Item" HorizontalAlignment="Stretch" Grid.Column="1"
Click="DelButton_Click" Margin="5, 0, 5, 5"/>
....
<ListBox x:Name="LstSelectedPosts" MinHeight="20" ItemsSource="{Binding Path=ModelItem.Selecteditems, Mode=TwoWay}"/>
....
Now when I try to Add/Remove an item to/from this ListBox in Add Item and Remove Item buttons click event, debugger shows me an error that tells I can't modify the ListBox binding source.
So how can I change this Listbox's Items?
Ok there are some errors in your code that could cause the problem.
In the getter, I think you should have this.
if (_selectedItems == null)
{
_selectedItems = new ObservableCollection<string>();
}
return _selectedItems;
In your version, _selectedItems never get initialized.
In the Xaml code, when you set the ItemSource, you wrote Seleceteditems instead of SelectedItems this error doesn't cause an error when you compile but your listBox doesn't have its itemSource setted to the correct element.
And then, you didn't specify the source in
ItemsSource="{Binding Path=ModelItem.Selecteditems, Mode=TwoWay}
that means the source is by default, the DataContext of your object and that DataContext should be initialized with an object that has a public property named ModelItem which has in turn a public property named Selecteditems.
Hope it works.
Here is a small example.
in my xaml file
<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" Height="350" Width="525">
<Grid>
<ListBox Height="287" HorizontalAlignment="Left" Margin="12,12,0,0" x:Name="LstSelectedPosts" VerticalAlignment="Top" Width="294"
ItemsSource="{Binding Path=SelectedItems, Mode=TwoWay}"/>
<Button Content="Add Item" HorizontalAlignment="Stretch" Click="Button_Click" Margin="321,110,68,170"/>
<Button Content="Remove Item" HorizontalAlignment="Stretch" Click="DelButton_Click" Margin="321,147,68,129"/>
</Grid>
in my xaml.cs file
public partial class MainWindow : Window
{
private CDataContext _myCDataContext;
public MainWindow()
{
InitializeComponent();
_myCDataContext = new CDataContext();
DataContext = _myCDataContext;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
_myCDataContext.Add();
}
private void DelButton_Click(object sender, RoutedEventArgs e)
{
_myCDataContext.Remove(LstSelectedPosts.SelectedItem.ToString());
}
}
and my CDataContext class
class CDataContext
{
private int _count = 0;
private ObservableCollection<string> _selectedItems;
public ObservableCollection<string> SelectedItems
{
get
{
if (_selectedItems == null)
{
_selectedItems = new ObservableCollection<string>();
}
return _selectedItems;
}
set
{
_selectedItems = value;
}
}
public void Remove(string s)
{
SelectedItems.Remove(s);
}
public void Add()
{
SelectedItems.Add(_count.ToString());
_count++;
}
}