Check which object invoked the ValueChanged Event of a Slider - c#

I am trying to determine which of my Sliders Invoked the Event, so I can call the OutputAnalogChannel Method with the Index of the Slider and the Slider value.
My Sliders that could potentially invoke the Event are called:
{ K8055AnalogOutputSlider1, K8055AnalogOutputSlider2, [...], K8055AnalogOutputSlidern }
So nothing is wrong with the following code, it works, but I feel like this is a very 'bad' way of solving this problem.
What i was thinking is that some kind of 'additional' integer value is added to the Slider which corresponds to the correct Slider at the Index.
Honestly this answer is probably hiding somewhere on stackoverflow, but I am not sure what I'd be searching for, so i posted here. Thanks in advance!
private void K8055AnalogOutputSliderValueChanged(object sender, RoutedEventArgs e)
{
Slider slider = sender as Slider;
K8055.OutputAnalogChannel(int.Parse(slider.Name[slider.Name.Length - 1].ToString()), (int)slider.Value);
}

You could use the controls' Tag property. Just set the property to the index of the control and then check it in your event handler:
K8055.OutputAnalogChannel((int)slider.Tag, (int)slider.Value);

This is a little more work, but it makes things incredibly easy to modify and maintain and read. It also gets you started taking advantage of some very powerful features of WPF. But if you're under severe deadline pressure, Vincent's quick fix has the virtue of simplicity.
C#
public class ChannelViewModel : INotifyPropertyChanged
{
private string _name = "";
public string Name
{
get { return _name; }
set
{
_name = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(Name)));
}
}
private int _channel = 0;
public int Channel
{
get { return _channel; }
set
{
_channel = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(Channel)));
}
}
private int _value = 0;
public int Value
{
get { return _value; }
set
{
_value = value;
K8055.OutputAnalogChannel(Channel, Value);
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(Value)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
Channels.Add(new ChannelViewModel { Name="Fred", Channel = 1, Value = 3 });
Channels.Add(new ChannelViewModel { Name="Bob", Channel = 2, Value = 35 });
}
public ObservableCollection<ChannelViewModel> Channels { get; private set; }
= new ObservableCollection<ChannelViewModel>();
public event PropertyChangedEventHandler PropertyChanged;
}
XAML
<ItemsControl
ItemsSource="{Binding Channels}"
BorderBrush="Black"
BorderThickness="1"
>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="2">
<TextBlock>Channel
<Run Text="{Binding Channel, Mode=OneWay}" />:
<Run Text="{Binding Name, Mode=OneWay}" /></TextBlock>
<Slider Value="{Binding Value}" Minimum="1" Maximum="100" Width="300" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Related

Issue Saving Model from ViewMode/Viewl MVVM

So what I want is when SelectedModel.TechName is updated that it physically saves to the model so that as long as the application is running it will remain whatever the user enters.
I have 2 views SelectedModel.TechName is called in both views. It pulls the data from the model however when I change views the data resets.
Any Suggestion?
edit: I am trying to make the data entered persistent, I thought setting the value would do this however every time i change between views it resets the data. In fact it blinks the data then resets it.
Field from DefaultView.Xaml
<StackPanel Grid.Row="0" Grid.Column="6" Grid.ColumnSpan="1" Margin="5 5 5 0">
<TextBox Name="techName" Text="{Binding SelectedModel.TechName,Mode=TwoWay}" BorderBrush="#FF4A5780" Grid.RowSpan="2"/>
</StackPanel>
<TextBlock x:Name="TextUpdate" Grid.Column="5" HorizontalAlignment="Left" Margin="41,0,0,0"
Grid.Row="1" Text="{Binding SelectedModel.TechName}" TextWrapping="Wrap" VerticalAlignment="Center"/>
DataModel.cs Model File
namespace callFlow.Models
{
public class DataModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string techName;
public DataModel()
{
}
public string TechName
{
get { return techName; }
set { techName = value;
OnPropertyChanged();
}
}
private void OnPropertyChanged([CallerMemberName] string techName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(techName));
}
}
}
DefaultViewModel.cs
namespace callFlow.ViewModels
{
public class DefaultViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public DefaultViewModel() { }
private ObservableCollection<DataModel> model = new ObservableCollection<DataModel>();
private DataModel selectedModel;
private DataModel _SelectedModel;
public DataModel SelectedModel
{
get { return _SelectedModel ?? (_SelectedModel = new SelectedModel()); }
set { _SelectedModel = value;
OnPropertyChanged(); }
}
public void changeSelectedModel(DataModel newSelectedModel)
{
SelectedModel.TechName = newSelectedModel.TechName;
}
private void OnPropertyChanged([CallerMemberName] string techNameVM = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(techNameVM));
}
}
}
On your binding you have
UpdateSourceTrigger=Explicit
in
Text="{Binding SelectedModel.TechName,Mode=TwoWay,
UpdateSourceTrigger=Explicit}"
When you do that, you have to write code to update the source property. Which is the viewmodel property.
Since you don't do that, the viewmodel will not get updated when you type text in there.
You should either remove that off the binding or write some more code.
There are multiple potential issues in your code. First, you use Explicit as UpdateSourceTrigger, but you never call UpdateSource, at least you do not show that in your code. Consequently, the property will never be updated. Use PropertyChanged or LostFocus instead.
If you set the UpdateSourceTrigger value to Explicit, you must call the UpdateSource method or the changes will not propagate back to the source.
Furthermore, you implement INotifyPropertyChanged in your view models, but you never call OnPropertyChanged. Hence, bindings will never be updated when a property changes its value. Your properties should look like below. This applies to all properties that you expose.
public string TechName
{
get { return techName; }
set
{
if (techName != value)
{
techName = value;
OnPropertyChanged();
}
}
}
It is not clear how you create your views and set their DataContext. If you create the data context view model in the XAML of your view, it will be created each time you instantiate a new view.
Simple solution
Remove the UpdateSourceTriger=Explicit from your DefaultView.xaml
<TextBox Name="techName" Text="{Binding SelectedModel.TechName,Mode=TwoWay}" BorderBrush="#FF4A5780" Grid.RowSpan="2"/>
Call the OnPropertyChanged method in the DataModel.TechName's setter. Like this:
public string TechName
{
get {
return techName;
}
set {
techName = value;
OnPropertyChanged();
}
}
Better solution
There are a few problems with your code. Here's how to fix them:
DefaultView.xaml
Remove the UpdateSourceTrigger=Explicit. It requires you to update the binding manually (from code) and you're not doing that.
<StackPanel Grid.Row="0" Grid.Column="6" Grid.ColumnSpan="1" Margin="5 5 5 0">
<TextBox Name="techName" Text="{Binding SelectedModel.TechName,Mode=TwoWay}" BorderBrush="#FF4A5780" Grid.RowSpan="2"/>
<TextBlock x:Name="TextUpdate" Grid.Column="5" HorizontalAlignment="Left" Margin="41,0,0,0"
Grid.Row="1" Text="{Binding SelectedModel.TechName}" TextWrapping="Wrap" VerticalAlignment="Center"/>
DataModel.cs
You were not calling the OnPropertyChanged method in TechName's setter, that's why it wasn't updating. I've done that and refactored the code a bit
public class DataModel : ObservableObject
{
private string _techName;
public string TechName
{
get => _techName;
set {
_techName = value;
OnPropertyChanged();
}
}
}
DefaultViewModel.cs
Here I've just removed the empty default constructor, the extra private DataModel field and refactored the code.
public class DefaultViewModel : ObservableObject
{
private ObservableCollection<DataModel> Models = new ObservableCollection<DataModel>();
private DataModel _selectedModel;
public DataModel SelectedModel
{
get => _selectedModel ?? (_selectedModel = new SelectedModel());
set {
_selectedModel = value;
OnPropertyChanged();
}
}
}
INotifyPropertyChanged implementation - ObservableObject.cs
I've added this class to simplify the rest of the code, since you were using the same code in both DataModel.cs and DefaultViewModel.cs
public class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

WPF nested properties from selected item in databound listBox

I've tried solving this myself, looking at several possible solutions here on Stack Overflow, but alas I've been unable to solve this issue.
TL;DR version:
The problem:
A listBox using databinding to show a list of RPG characters, which have a nested property for their attributes. I can't get the attributes to show due to the limitations with nested properties and databindings.
The code below is related to the issue.
I have a listBox that has a databinding that controls what is shown in the list. The databinding uses ObservableCollection for the list of objects that the list contains. All this works fine, but is related to the issue at hand.
The listBox databinding has several nested properties in each element, that I want to display and change in the form, yet I cannot get nested databinding to work correctly.
This is the listBox XAML:
<ListBox x:Name="listCharacters" Margin="2,0" ItemsSource="{Binding}" Grid.Row="1" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Hidden" SelectionChanged="listCharacters_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type local:Character}" x:Name="Symchar">
<Grid Width="125" HorizontalAlignment="Left" Background="{x:Null}">
<Grid.RowDefinitions>
<RowDefinition Height="18"/>
<RowDefinition Height="12"/>
<RowDefinition Height="16"/>
</Grid.RowDefinitions>
<Image Panel.ZIndex="5" HorizontalAlignment="Right" VerticalAlignment="Top" Height="16" Width="16" Margin="0,2,0,0" Source="Resources/1454889983_cross.png" MouseUp="DeleteCharacter" />
<TextBlock Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" FontWeight="Bold" FontSize="13.333" Grid.Row="0" TextTrimming="CharacterEllipsis" Padding="0,0,16,0" />
<TextBlock Text="{Binding RealRace.Label, UpdateSourceTrigger=PropertyChanged}" FontSize="9.333" Grid.Row="1" FontStyle="Italic" />
<TextBlock FontSize="9.333" Grid.Row="2" HorizontalAlignment="Left" VerticalAlignment="Top">
<Run Text="{Binding RealClass.Archetype.Label, UpdateSourceTrigger=PropertyChanged}"/>
<Run Text=" - "/>
<Run Text="{Binding RealClass.Label, UpdateSourceTrigger=PropertyChanged}"/>
</TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And setting the listBox ItemSource:
this.listCharacters.ItemsSource = CharacterList;
This is the character class, I removed unrelated code (XML serialization attributes etc.)
public class Character : INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
this.NotifyPropertyChanged("Name");
}
}
private string _player;
public string Player
{
get { return _player; }
set
{
_player = value;
this.NotifyPropertyChanged("Player");
}
}
private string _race;
public string Race
{
get { return _race; }
set
{
_race = value;
this.NotifyPropertyChanged("Race");
}
}
private Race _realRace;
public Race RealRace
{
get { return _realRace; }
set
{
_realRace = value;
Race = value.Id;
this.NotifyPropertyChanged("RealRace");
}
}
private string _gender;
public string Gender
{
get { return _gender; }
set
{
_gender = value;
this.NotifyPropertyChanged("Gender");
}
}
private Attributes _attributes;
public Attributes Attributes
{
get { return _attributes; }
set
{
_attributes = value;
this.NotifyPropertyChanged("Attributes");
}
}
private string _class;
public string Class
{
get { return _class; }
set
{
_class = value;
this.NotifyPropertyChanged("Class");
}
}
private Class _realClass;
public Class RealClass
{
get { return _realClass; }
set
{
_realClass = value;
Class = value.Id;
this.NotifyPropertyChanged("RealClass");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
To keep it simple, the property that I've been testing with, is the 'Attributes' property, this is the code for it:
public class Attributes : INotifyPropertyChanged
{
private int _accurate;
public int Accurate
{
get { return _accurate; }
set
{
_accurate = value;
this.NotifyPropertyChanged("Accurate");
}
}
private int _cunning;
public int Cunning
{
get { return _cunning; }
set
{
_cunning = value;
this.NotifyPropertyChanged("Cunning");
}
}
private int _discreet;
public int Discreet
{
get { return _discreet; }
set
{
_discreet = value;
this.NotifyPropertyChanged("Discreet");
}
}
private int _persuasive;
public int Persuasive
{
get { return _persuasive; }
set
{
_persuasive = value;
this.NotifyPropertyChanged("Persuasive");
}
}
private int _quick;
public int Quick
{
get { return _quick; }
set
{
_quick = value;
this.NotifyPropertyChanged("Quick");
}
}
private int _resolute;
public int Resolute
{
get { return _resolute; }
set
{
_resolute = value;
this.NotifyPropertyChanged("Resolute");
}
}
private int _strong;
public int Strong
{
get { return _strong; }
set
{
_strong = value;
this.NotifyPropertyChanged("Strong");
}
}
private int _vigilant;
public int Vigilant
{
get { return _vigilant; }
set
{
_vigilant = value;
this.NotifyPropertyChanged("Vigilant");
}
}
private int _toughness;
public int Toughness
{
get { return _toughness; }
set
{
_toughness = value;
this.NotifyPropertyChanged("Toughness");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
I want to display each individual attribute in a field when a character in the listBox is selected, this works fine with properties directly in the character class, but due to the limitations on nested properties and databindings, I haven't been able to get it to work with the 'Attributes' properties values.
XAML for one of the attribute input fields:
<TextBox x:Name="attr_Accurate" DataContext="{Binding Path=(local:Character.Attributes), XPath=SelectedItem, ElementName=listCharacters, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Text="{Binding Path=(local:Accurate)}" PreviewTextInput="NumericInput"/>
The UpdateSourceTrigger is simply a method to only allow integers to be input in the field:
private void NumericInput(object sender, TextCompositionEventArgs e)
{
if (!char.IsDigit(e.Text, e.Text.Length - 1))
{
e.Handled = true;
}
}
If anyone could help me get the values within the selected character's attributes to show up via databindings, I would greatly appreciate it.
Use binding as following:
To Show Accurate Property value:
<TextBox x:Name="attr_Accurate" Text="{Binding Path=SelectedItem.Attributes.Accurate), ElementName=listCharacters, Mode=OneWay}" PreviewTextInput="NumericInput"/>
To Show Cunning property value:
<TextBox x:Name="attr_Accurate" Text="{Binding Path=SelectedItem.Attributes.Cunning), ElementName=listCharacters, Mode=OneWay}" PreviewTextInput="NumericInput"/>
and so one.
(I'm not sure if you want binding to be two way or one so please
change as your need)

ItemsControl TextBox Name is not Working in .cs File

My WPF Application code generates panels on function call defined in .cs file. There is ItemControl used in code to generates these Panels . I want to Name Textbox defined in this ItemControl and to use this in code. I named it as textEdit1 and used it in code but code generated error that textEdit1 doesn't exist. Can anyone solve my problem? Here Code is:
XAML File:
<dxlc:ScrollBox>
<ItemsControl Name="lstPanels">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="vertical">
<Grid>
<dxe:TextEdit Height="165" Text="{Binding Text,
Mode=TwoWay}" x:Name="textEdit1"/>
</Grid>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</dxlc:ScrollBox>
.CS FILE
public partial class Window1 : Window
{
string valuu;
public Window1()
{
InitializeComponent();
addPanel("Header1");
addPanel("Header2");
addPanel("Header3");
lstPanels.ItemsSource = panels;
}
public ObservableCollection<MyPanel> panels = new ObservableCollection<MyPanel>();
public void addPanel(string buttonId)
{
MyPanel p = new MyPanel { Id = buttonId};
panels.Add(p);
functionb(p);
}
public void functionb(MyPanel obj)
{
valuu = obj.Text;
}
private void button2_Click(object sender, RoutedEventArgs e)
{
foreach (var f in panels.ToList())
{
MessageBox.Show( f.Id + " *** " + f.Text);
}
}
}
public class MyPanel : INotifyPropertyChanged
{
private string _id;
private string _text;
public string Id
{
get { return _id; }
set
{
if (value != _id)
{
_id = value;
NotifyPropertyChanged();
}
}
}
public string Text
{
get { return _text; }
set
{
if (value != _text)
{
_text = value;
NotifyPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged( String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
I see that you are using some 3rd party libraries for your TextBox and ScrollBox. If you provide me with the names of the libraries, I could have a look at them as the functionality might be different from what WPF has out-of-the-box.
As for now you have 3 options (I am giving examples for standard TextBox and ItemsControl):
I) You do not have to access the textbox at all.
An easy way around it is described here: StackOverflow post
II) Handling events and references to TextBoxes in the code behind
Add a Loaded event to your TextBox:
<TextBox x:Name="txtText" Width="300" Height="100" Loaded="txtText_Loaded" />
Add a field to your MyPanel class to hold a reference to a TextBox:
public class MyPanel
{
public string Text { get; set; }
public TextBox TextBox { get; set; }
/* the rest ... */
}
Add a counter to your window, next to a list with panels:
protected ObservableCollection<MyPanel> panels = new ObservableCollection<MyPanel>();
private int counter = 0;
Handle the Load event of the TextBox:
private void txtText_Loaded(object sender, RoutedEventArgs e)
{
panels[counter].TextBox = (TextBox)sender;
counter++;
}
If you want to access a particular TextBox, do it this way:
MessageBox.Show(panels[i].TextBox.Text);
III) Add additional bindings for FontSize:
Add a FontSize property to your MyPanel class:
private double _fontSize = 10;
public double FontSize
{
get { return _fontSize; }
set
{
if (value != _fontSize)
{
_fontSize = value;
NotifyPropertyChanged();
}
}
}
Bind just added property to the TextBox in your ItemsControl:
<TextBox x:Name="txtText" Width="300" Height="100" Text="{Binding Text;, Mode=TwoWay}"
FontSize="{Binding FontSize, Mode=OneWay}" />
Add a slider to the template and bind it to the same property:
<Slider Minimum="10" Maximum="30" Value="{Binding FontSize, Mode=TwoWay}" />
This way if you change the value on a slider, it will change the value in your MyPanel object bound to the panel. This in turn will change the font size of the textbox.
My whole code I tested it on looks like that:
<ItemsControl x:Name="lstItems" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBox x:Name="txtText" Width="300" Height="100" Text="{Binding Text;, Mode=TwoWay}" FontSize="{Binding FontSize, Mode=OneWay}" />
<Slider Minimum="10" Maximum="30" Value="{Binding FontSize, Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And code behind:
public partial class MainWindow : Window
{
protected ObservableCollection<MyPanel> texts = new ObservableCollection<MyPanel>();
public MainWindow()
{
InitializeComponent();
texts.Add(new MyPanel() { Text = "Test 1" });
texts.Add(new MyPanel() { Text = "Test 2" });
lstItems.ItemsSource = texts;
}
}
public class MyPanel : INotifyPropertyChanged
{
private string _id;
private string _text;
private double _fontSize = 10;
public string Id
{
get { return _id; }
set
{
if (value != _id)
{
_id = value;
NotifyPropertyChanged();
}
}
}
public string Text
{
get { return _text; }
set
{
if (value != _text)
{
_text = value;
NotifyPropertyChanged();
}
}
}
public double FontSize
{
get { return _fontSize; }
set
{
if (value != _fontSize)
{
_fontSize = value;
NotifyPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
I personally would go with the last solution.
But again, let me know what libraries you are using, and I will have look at them when I have some time. Good luck.
textEdit1 is part of a template that will be instantiated multiple times, so there will be multiple instances of textEdit1. It wouldn't make sense to generate a field for textEdit1 in the class, because it could only refer to one instance the TextEdit control...

Databinding not working with ViewModel

Cant get any data to work with databinding, I have the INotify event, I have the binding on the xaml objects, but nothing shows up, if I change the content on the lables to "something" it works, but nothing shows on load or on click on my button
My Xaml view
<Grid>
<StackPanel Name="stackpanel">
<Label Content="{Binding Name}" />
<Label Content="{Binding Length}" />
<Label Content="{Binding Rating}" />
<Button Content="Change text" Click="ButtonClick" />
</StackPanel>
</Grid>
Its codebehind
public partial class Movie
{
readonly MovieViewModel _movieViewModel;
public Movie()
{
InitializeComponent();
_movieViewModel = new MovieViewModel { Movie = { Name = "The Dark Knight", Length = 180, Rating = 88 } };
stackpanel.DataContext = _movieViewModel;
}
private void ButtonClick(object sender, RoutedEventArgs e)
{
_movieViewModel.Movie.Name = "bad movie";
}
}
The View Model
class MovieViewModel
{
public MovieViewModel() : this(new Movie())
{
}
public MovieViewModel(Movie movie)
{
Movie = movie;
}
public Movie Movie { get; set; }
}
The Model
class Movie : INotifyPropertyChanged
{
public Movie()
{}
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
NotifyPropertyChanged("Name");
}
}
private int _length;
public int Length
{
get { return _length; }
set
{
_length = value;
NotifyPropertyChanged("Length");
}
}
private int _rating;
public int Rating
{
get { return _rating; }
set
{
if (_rating == value) return;
_rating = value;
NotifyPropertyChanged("_Rating");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
You have your bindings set incorrectly, that's the reason nothing is being shown.
Just take a closer look at your ViewModel and than on the bindings. You try to bind to property named Name but your MovieViewModel does not expose any property with that name. I'm pretty sure binding errors were reported to you (look through messages in Output window).
To make it work, you need either expose properties in your ViewModel to match the ones you try to bind to (bad), or change bindings in your xaml to have correct path:
<Label Content="{Binding Movie.Name}" />
<Label Content="{Binding Movie.Length}" />
<Label Content="{Binding Movie.Rating}" />
This should get you going.
Additionally - you may want to implement INotifyPropertyChanged also on your MovieViewModel class if you plan to change Movie object that is assigned to Movie property. As long as you will only change properties of Movie object already assigned to MovieViewModel everything will be ok, but if you would try to change actual object assigned to this property, no changes notifications will be generated and your UI will stop working correctly.
Moreover - I noticed that you made your NotifyPorpertyChanged method public - I wouldn't advise this as anyone can now trigger this event. Normal approach is to make such methods private or protected, depending if you want to provide way to trigger event from inheriting classes (which is very likely in case of PropertyChanged event).
I think you have one typing mistake
NotifyPropertyChanged("_Rating");
Should be
NotifyPropertyChanged("Rating");
Rather than using Label, I would suggest you to use Texblock. Try the following code
_movieViewModel = new MovieViewModel
{ Movie = { Name = "The Dark Knight", Length = 180, Rating = 88 } };
this.DataContext = _movieViewModel;
and
Textblock like following
<StackPanel Name="stackpanel">
<TextBlock Name="textBlock1" Text="{Binding Path=Name}"/>
<TextBlock Name="textBlock2" Text="{Binding Path=Length}"/>
<Button Content="Change text" Click="ButtonClick" />
</StackPanel>

Binding a Collection<bool> to togglebuttons/checkboxed

I have a collection of bools associated to days of the week - Collection() { true, false, false, false, false, false,false}; So whatever the bool represents means that this collection applies for sunday (sunday being the first day of week here).
Now I have set the itemssource of my listbox, say, to be this collection.
<ListBox ItemsSource={Binding Path=Collection, Mode=TwoWay}>
<ListBox.ItemTemplate>
<ToggleButton IsChecked={Binding Path=BoolValue, Mode=TwoWay}/>
</ListBox.ItemTemplate>
</ListBox>
However my Collection never gets updated (my collection is a dependencyproperty on the window). Plus "MyBool" class is simply just a wrapper around a bool object, with NotifyPropertyChanged implemented.
Any ideas.....my actual code is majorly complex so the above situation is a brutally simplified version, so make assumptions etc if necessary Ill work around this given that I have provided my actual code.
Thanks greatly in advance,
U.
Try to set UpdateSourceTrigger=PropertyChanged in your binding
<ToggleButton IsChecked={Binding Path=BoolValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}/>
edit:
created a small example, seems fine.
The wrapper class
public class MyBool : INotifyPropertyChanged
{
private bool _value;
public bool Value
{
get { return _value; }
set
{
_value = value;
NotifyPropertyChanged("Value");
}
}
public event PropertyChangedEventHandler PropertyChanged;
void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
The XAML
<ListBox ItemsSource="{Binding Path=Users}" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<ToggleButton IsChecked="{Binding Path=Value, Mode=TwoWay}" Content="MyButton"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code behind
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public ObservableCollection<MyBool> Users { get; set; }
public MainWindow()
{
InitializeComponent();
Users = new ObservableCollection<MyBool>();
DataContext = this;
Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
FillUsers();
}
private void FillUsers()
{
for (int i = 0; i < 20; i++)
{
if(i%2 == 0)
Users.Add(new MyBool { Value = true });
else
Users.Add(new MyBool { Value = false});
}
}
}

Categories

Resources