WPF UserControl property change not updating - c#

I have a UserControl that I add to my main application.
That UserControl contains a button for a UIElement
The UserControl contains a DispatchTimer and every 2 seconds based on some int values determines what the button image will be.
One of the methods called in the UserControl should set it's image but the control never displays the image that it was changed to.
public void SetNormal()
{
btnFlashAlert.Content = new BitmapImage(new Uri("Images/FlashButton.png", UriKind.RelativeOrAbsolute));
}
Is there something i'm missing to get the look of the control update on the main application?
When I look at what .Content contains, it is correct. The UI doesn't reflect the change.
XAML
<UserControl x:Class="SC.FlashSystem.MainButton"
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" Height="53" Width="164">
<Button x:Name="btnFlashAlert" Background="{x:Null}" BorderBrush="{x:Null}" Cursor="Hand" Click="btnFlashAlert_Click">
<Button.Template>
<ControlTemplate>
<Image Source="Images/FlashButton.png"/>
</ControlTemplate>
</Button.Template>
</Button>
Codebehind Updated
public partial class MainButton : UserControl
{
private SupportConsoleWeb.MessageData messageCounts { get; set; }
private readonly DispatcherTimer flashButtonChangeTimer = new DispatcherTimer();
private BitmapImage NormalImage { get; set; }
private BitmapImage CriticalImage { get; set; }
private BitmapImage AlertImage { get; set; }
private BitmapImage InfoImage { get; set; }
public MainButton()
{
InitializeComponent();
messageCounts = new SupportConsoleWeb.MessageData();
messageCounts.CriticalCount = 0;
messageCounts.AlertCount = 0;
messageCounts.InfoCount = 0;
NormalImage = new BitmapImage(new Uri("Images/FlashButton.png", UriKind.RelativeOrAbsolute));
CriticalImage = new BitmapImage(new Uri("Images/FlashButtonRed.png", UriKind.RelativeOrAbsolute));
AlertImage = new BitmapImage(new Uri("Images/FlashButtonOrange.png", UriKind.RelativeOrAbsolute));
InfoImage = new BitmapImage(new Uri("Images/FlashButtonGreen.png", UriKind.RelativeOrAbsolute));
flashButtonChangeTimer.Interval = TimeSpan.FromSeconds(2);
flashButtonChangeTimer.Tick += flashButtonChangeTimer_Tick;
flashButtonChangeTimer.Start();
}
void flashButtonChangeTimer_Tick(object sender, EventArgs e)
{
btnFlashAlert.Dispatcher.BeginInvoke(new Action(() =>
{
if (btnFlashAlert.Content == null)
{
SetNormal();
}
else if (messageCounts.CriticalCount > 0 && btnFlashAlert.Content.Equals(CriticalImage))
{
SetNormal();
}
else if (messageCounts.AlertCount > 0 && btnFlashAlert.Content.Equals(AlertImage))
{
SetNormal();
}
else if (messageCounts.InfoCount > 0 && btnFlashAlert.Content.Equals(InfoImage))
{
SetNormal();
}
else if (messageCounts.CriticalCount > 0)
{
SetCritical();
}
else if (messageCounts.AlertCount > 0)
{
SetAlert();
}
else if (messageCounts.InfoCount > 0)
{
SetInfo();
}
}));
}
public void UpdateMessageCounts(SupportConsoleWeb.MessageData messageCounts)
{
this.messageCounts = messageCounts;
}
private void btnFlashAlert_Click(object sender, RoutedEventArgs e)
{
MainWindow window = new MainWindow();
window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
window.ShowDialog();
}
public void SetMessageCount(int criticalCount, int alertCount, int infoCount)
{
messageCounts.CriticalCount = criticalCount;
messageCounts.AlertCount = alertCount;
messageCounts.InfoCount = infoCount;
}
private void SetNormal()
{
btnFlashAlert.Content = NormalImage;
}
private void SetCritical()
{
btnFlashAlert.Content = CriticalImage;
}
private void SetAlert()
{
btnFlashAlert.Content = AlertImage;
}
private void SetInfo()
{
btnFlashAlert.Content = InfoImage;
}
}

Change your XAML To this
<Image Source="{Binding TheImage}"/>
Add notify property changed
public partial class MainButton : UserControl, INotifyPropertyChanged
Create the OnPropertyChanged Event
void OnPropertyChanged(String prop)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
public event PropertyChangedEventHandler PropertyChanged;
Create a Bitmap prop and notify the prop changed event
private BitmapImage _TheImage;
public BitmapImage TheImage
{
get { return _TheImage; }
set { _TheImage = value; OnPropertyChanged("TheImage"); }
}
In your initializer
public MainButton()
{
this.DataContext = this;
InitializeComponent();
TheImage = new BitmapImage();
Now in your setting methods call
TheImage = //Your Bitmap Goes here
I know this seems excessive but you will see it is a much cleaner implementation in the long run.

I believe its an issue with picture selection logic not having a default image when none of the conditions are met...
With that said, IMHO the picture logic would be better expressed by having all images pre-loaded and their visibility initially set to hidden. Then bind the visibility of each image to a specific flag boolean on the VM. Which the timer event can simply turn on or off the boolean(s) which will ultimately show or hide images as needed.
That removes any latency due to loading and showing of images for they will be pre-loaded; also it will solve any possible future memory issues due to loading/unloading of images.
Example
The following example has a button with two images. Both image's visibility is bound to Booleans on the VM. The VM has one Boolean which the imageas work off of and a timer which changes its status every two seconds switching the images.
Xaml:
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>
<Button x:Name="bStatus" Width="48" Height="48">
<StackPanel Orientation="Vertical">
<Image Source="Images\Copy-icon.png" Visibility="{Binding IsCopyOn,
Converter={StaticResource BooleanToVisibilityConverter}}" />
<Image Source="Images\Recycle-icon.png"
Visibility="{Binding IsRecycleOn,
Converter={StaticResource BooleanToVisibilityConverter}}" />
</StackPanel>
</Button>
VM
public class MainVM : INotifyPropertyChanged
{
private bool _bSwitch;
private readonly DispatcherTimer flashButtonChangeTimer = new DispatcherTimer();
public bool IsRecycleOn
{
get { return _bSwitch; }
}
public bool IsCopyOn
{
get { return !_bSwitch; }
}
public MainVM()
{
flashButtonChangeTimer.Interval = TimeSpan.FromSeconds(2);
flashButtonChangeTimer.Tick += (sender, args) =>
{
_bSwitch = ! _bSwitch;
OnPropertyChanged("IsCopyOn");
OnPropertyChanged("IsRecycleOn");
};
flashButtonChangeTimer.Start();
}
/// <summary>Event raised when a property changes.</summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>Raises the PropertyChanged event.</summary>
/// <param name="propertyName">The name of the property that has changed.</param>
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Related

How to update visibility at runtime in WPF

I am currently developing a hamburger style menu in WPF. In this menu, there are some categories that each have an icon. When the menu is collapsed you can still see those icons. When you expand the menu, there should appear text next to it. My idea was to just set their visibility to Visible as soon as the menu opens but I've had a lot of trouble realizing this. Right now I'm trying to change their visibility by binding them to a property.
XAML:
<ListView x:Name="menuItemsListView" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListViewItem>
<StackPanel Orientation="Horizontal">
<Image x:Uid="Test" Name="InhoudImage" Source="Images/noimage.png" Height="30" Width="auto" VerticalAlignment="Center" Margin="3,0,0,0"></Image>
<TextBlock x:Uid="Test" Text="{Binding Path=TextboxVisibility}" Visibility="{Binding Path=TextboxVisibility}" VerticalAlignment="Center"></TextBlock>
</StackPanel>
</ListViewItem>
</ListView>
C# CS Class:
using System.Windows;
using System.Windows.Controls;
namespace APP
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private bool menuOpen = false;
private int closedMenuWidth = 50;
private int openMenuWidth = 210;
private string textboxVisibility;
public string TextboxVisibility
{
get { return textboxVisibility; }
set { textboxVisibility = value; }
}
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
this.TextboxVisibility = "Hidden";
}
private void MenuButton_Click(object sender, RoutedEventArgs e)
{
if (menuOpen)
{
menuGrid.Width = closedMenuWidth;
menuOpen = false;
this.TextboxVisibility = "Hidden";
}
else
{
menuGrid.Width = openMenuWidth;
menuOpen = true;
this.TextboxVisibility = "Visible";
//foreach (ListViewItem item in menuItemsListView.Items)
//{
// item.
// if (item.Uid == "Test")
// {
// item.Visibility = Visibility.Visible;
// }
//}
}
}
}
}
When I change the value within the MainWindow function, it does have an effect on it when it first starts. But the other times I try to change it, which is at runtime, nothing happens. I have tried all sorts of things with booleans and binding the actual Visibility type but nothing worked.
You should implemente INotifyPropertyChanged on your MainWindow class like this:
public partial class MainWindow: Window,INotifyPropertyChanged {
private string textboxVisibility;
public string TextboxVisibility {
get {
return textboxVisibility;
}
set {
textboxVisibility = value;
OnPropertyChanged();
}
}
//The rest of your code goes here
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
PropertyChanged ? .Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
What OnPropertyChanged method does is, whenever the value is setted, it notifies the view and refreshes it.
This will solve the problem but isn't the right way to use MVVM.
The way you should do this is to change the visibility property of the TextBox instead of binding the visibility property to a value:
First you have to add a name to the TextBlock you want to hide:
<ListView x:Name="menuItemsListView" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListViewItem>
<StackPanel Orientation="Horizontal">
<Image x:Uid="Test" Name="InhoudImage" Source="Images/noimage.png" Height="30" Width="auto" VerticalAlignment="Center" Margin="3,0,0,0"></Image>
<TextBlock Name="textblock" x:Uid="Test" Text="{Binding Path=TextboxVisibility}" Visibility="{Binding Path=TextboxVisibility}" VerticalAlignment="Center"></TextBlock>
</StackPanel>
</ListViewItem>
</ListView>
And then you change the visibility in the code
private void MenuButton_Click(object sender, RoutedEventArgs e) {
if (menuOpen) {
menuGrid.Width = closedMenuWidth;
menuOpen = false;
textblock.Visibility = System.Windows.Visibility.Hidden;
}
else {
menuGrid.Width = openMenuWidth;
menuOpen = true;
textblock.Visibility = System.Windows.Visibility.Visible;
//foreach (ListViewItem item in menuItemsListView.Items)
//{
// item.
// if (item.Uid == "Test")
// {
// item.Visibility = Visibility.Visible;
// }
//}
}
}
If you want to implement MVVM the right way you have to create a ViewModel class and add it as Data Context to your view:
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
And then on you MainWindowViewModel is where you change the property:
public class MainWindowViewModel: INotifyPropertyChanged {
private string textboxVisibility;
public string TextboxVisibility {
get {
return textboxVisibility;
}
set {
textboxVisibility = value;
OnPropertyChanged();
}
}
//The rest of your code goes here
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
PropertyChanged ? .Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

Navigation in C# and XAML

I want to navigate to another page in my Windows Phone 8.1 app.I can easily do this if there is a button by clicking on it and using Frame.Navigate(typeof(MainPage)); in the event handler.But in my case I want to navigate to a second page automatically depending upon an integer value.If it becomes zero,the page automatically goes to second page.In my case I dont have a button and so event handler so to do this.How can I do this?
Implement the INotifyPropertyChanged interface for your view model. Here is a crude implementation, ideally, you would use an mvvm framework and send messages to your views as required.
View Model
public class GameStateViewModel : INotifyPropertyChanged
{
private int currentScore = 10;
/// <summary>
/// The timer here added to simulate whatever is supposed to be changing your value.
/// </summary>
public GameStateViewModel()
{
var timer = new DispatcherTimer
{
Interval = TimeSpan.FromSeconds(2)
};
timer.Tick += (sender, args) =>
{
if (this.CurrentScore > 0)
{
this.CurrentScore--;
}
else
{
timer.Stop();
}
};
timer.Start();
}
public event PropertyChangedEventHandler PropertyChanged;
public int CurrentScore
{
get { return currentScore; }
set
{
currentScore = value;
NotifyPropertyChanged("CurrentScore");
}
}
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Code behind
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
var viewModel = new GameStateViewModel();
viewModel.PropertyChanged += (sender, args) =>
{
if (viewModel.CurrentScore <= 0)
{
this.NavigationService.Navigate(new Uri("/Page2.xaml", UriKind.Relative));
}
};
this.DataContext = viewModel;
}
}
Xaml
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBlock Text="{Binding CurrentScore}" FontSize="{StaticResource PhoneFontSizeExtraLarge}" />
</Grid>

WPF, Property does not return value to the binding

So, I have a project with a scrolling text (marqee) that rotates over a string array. And I want it to change the string value after 20 seconds of each animation iteration.
There is a problem though, the property(ScrollingText) that uses the INotifyPropertyChanged interface to bind to a textblock(using XAML) does not return after the first iteration. Even though it refreshes normally(in the set part), it does not return on the Getter part.... except for the first set in the default ctor.
MAIN CLASS:
class GetScrollingText : CommonBase
{
private string _scrollingtext = String.Empty;
DoubleAnimation Animation;
public GetScrollingText()
{
ScrollingText = GetScrollString();
}
public string ScrollingText
{
get
{
return _scrollingtext;
}
set
{
if (value != _scrollingtext)
{
_scrollingtext = value;
RaisePropertyChanged("ScrollingText");
}
}
} // INJECTS the string in the animated textblock {binding}.
public TextBlock scrollBlock { get; set; }
string GetScrollString()
{
.........
return scrolltext;
}
public void LeftToRightMarqee(double from, double to)
{
Animation = new DoubleAnimation();
Animation.From = from;
Animation.To = to;
Animation.Duration = new Duration(TimeSpan.FromSeconds(20));
Animation.Completed += animation_Completed;
scrollBlock.BeginAnimation(Canvas.LeftProperty, Animation);
}
void animation_Completed(object sender, EventArgs e)
{
ScrollingText = GetScrollString();
scrollBlock.BeginAnimation(Canvas.LeftProperty, Animation);
}
}
For some reason the animation_Completed Event only changes the value ScrollingText, but it does not invoke the Getter part therefore there is not a return to the {binding}.
XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:AnnouncingSys"
x:Class="AnnouncingSys.MainWindow"
x:Name="Window"
Width="1280" Height="720" MinHeight="566" MinWidth="710">
<Window.Resources>
<vm:GetScrollingText x:Key="ScrollingText"/>
</Window.Resources>
<Canvas x:Name="MainCanvas" ClipToBounds="True" Margin="0,0,0,0" Grid.Row="5" Background="Black" Grid.ColumnSpan="5" >
<TextBlock x:Name="ScrollBlock" TextWrapping="Wrap" VerticalAlignment="Top" Height="113" Width="5147" Canvas.Left="-1922" Text="{Binding ScrollingText, Source={StaticResource ScrollingText}}"/>
</Canvas>
</Window>
CODE BEHIND:
public partial class MainWindow : Window
{
GetScrollingText scrolling = new GetScrollingText();
public MainWindow()
{
InitializeComponent();
scrolling.scrollBlock = this.ScrollBlock;
scrolling.LeftToRightMarqee(2000, -3000);
}
}
And finally the helper class CommonBase:
public class CommonBase : INotifyPropertyChanged
{
protected CommonBase()
{
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string PropertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
PropertyChangedEventArgs e = new PropertyChangedEventArgs(PropertyName);
handler(this, e);
}
}
}
I have even put a breakpoint on the return block of the Getter but it only activates on the first: "ScrollingText = GetScrollString()". I mean, shouldn't it return each time the value is changed???
You are using two different instances of your GetScrollingText class, one in XAML as StaticResource, the other in code behind as the scrolling field in class MainWindow.
Instead of creating a StaticResource in XAML, you could just set the DataContext property of your MainWindow:
public partial class MainWindow : Window
{
GetScrollingText scrolling = new GetScrollingText();
public MainWindow()
{
InitializeComponent();
scrolling.scrollBlock = this.ScrollBlock;
scrolling.LeftToRightMarqee(2000, -3000);
DataContext = scrolling; // here
}
}
Now you would not explicitly set the binding's Source property, because the DataContext is used as default binding source:
<TextBlock ... Text="{Binding ScrollingText}"/>

Metro UI not update

I'm just start working on metro app and i'm facing a problem that is dispatcher not updating the UI. My code is below please let me know what was the issue ?
public class Test : DependencyObject
{
public static readonly DependencyProperty CurrentItemProperty =
DependencyProperty.Register("NameOfPerson", typeof(string), typeof(Test), null);
public String NameOfPerson
{
get
{
return (string)GetValue(CurrentItemProperty);
}
set
{
runmethod(value);
}
}
public async void runmethod(String text)
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
SetValue(CurrentItemProperty, text);
}
);
}
}
In main page i have an event button click which when fire update textbox.
private void Button_Click_2(object sender, RoutedEventArgs e)
{
Test t = new Test();
t.NameOfPerson = "Hello Umar";
}
MainPage.xaml look like this
<Page
x:Class="TestApplication.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestApplication"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Button Content="Button" HorizontalAlignment="Left" Margin="207,187,0,0" VerticalAlignment="Top" Height="80" Width="255" Click="Button_Click_2"/>
<TextBox x:Name="textB" Text="{Binding NameOfPerson}" HorizontalAlignment="Left" Height="80" Margin="730,187,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="307"/>
</Grid>
</Page>
If you are what you are trying to do is having a button refresh your Text, you should look into the MVVM pattern and have the Binding update your UI.
To do this you'll have to create your Object, in this case, let's say a person.
public class Person
{
public string Name { get; set; }
}
Secondly you would want to have a person inside a viewmodel that you'll update using your button. The viewmodel will derive from BindableBase which is a part of Windows Store applications if you would use such thing as Basic Page. The Viewmodel looks like this:
public class MainPageViewModel : BindableBase
{
public MainPageViewModel()
{
}
private Person person;
public Person Person
{
get { return person; }
set { SetProperty(ref person, value); }
}
public void LoadData()
{
Person = new Person() { Name = "Simple name" };
}
public void UpdatePerson()
{
Person.Name = "Updated Name";
OnPropertyChanged("Person");
}
}
and in case you dont have the bindableBase, it looks like this:
[Windows.Foundation.Metadata.WebHostHidden]
public abstract class BindableBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
{
if (object.Equals(storage, value)) return false;
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var eventHandler = this.PropertyChanged;
if (eventHandler != null)
{
eventHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
On your MainPage you create the ViewModel and set the DataContext on your Page. Also you would want to handle your object inside your Viewmodel, so you'll create a update method when clicking the button that will modify your Person object:
public sealed partial class MainPage : Page
{
private readonly MainPageViewModel viewModel;
public MainPage()
{
this.InitializeComponent();
viewModel = new MainPageViewModel();
viewModel.LoadData();
this.DataContext = viewModel;
}
private void Button_Tapped(object sender, TappedRoutedEventArgs e)
{
viewModel.UpdatePerson();
}
}
And finally your TextBox in the UI to point at the Person's name property inside the Viewmodel:
<TextBox
x:Name="textB"
Text="{Binding Person.Name}"
HorizontalAlignment="Left"
Height="80"
Margin="730,187,0,0"
TextWrapping="Wrap"
VerticalAlignment="Top"
Width="307" />
I hope this fulfills your question on how you can have a button updating your UI.

WPF Binding to a property in second ViewModel

How do I get the text bound to txtMessage from the second view model? When I had only one view model, the text was working fine. It does not work anymore when I moved the actual download code to second view model. Am I missing something? Any help appreciated.
Xaml:
<DockPanel DockPanel.Dock="Top">
<TextBlock x:Name="txtMessage" DockPanel.Dock="Top" Margin="5" Text="{Binding viewModel1.Message}" />
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="5,5">
<ProgressBar Width="300" Visibility="{Binding IsDownloading, Converter={converter:VisibilityConverter}}" IsIndeterminate="True" />
<Button Content="Cancel" />
</StackPanel>
</DockPanel>
<Button Content="Download" Width="120" Margin="0,0,5,0" Name="btnSubmit" Click="btnSubmit_Click" />
CodeBehind:
public partial class DownloadWindow: Window
{
DownloadWindowViewModel viewModel = new DownloadWindowViewModel();
public DownloadWindow()
{
InitializeComponent();
this.DataContext = viewModel;
}
private void btnSubmit_Click(object sender, RoutedEventArgs e)
{
viewModel.IsDownloading = true;
viewModel.Download();
}
}
viewModel:
public class DownloadWindowViewModel: INotifyPropertyChanged
{
Thread downloadThread;
public DownloadViewModel viewModel1;
public DownloadWindowViewModel()
{
viewModel1 = new DownloadViewModel();
}
private bool _isDownloading; = false;
public bool IsDownloading
{
get
{
return _isDownloading;
}
set
{
_isDownloading; = value;
OnPropertyChanged("IsDownloading");
}
}
public void Download()
{
viewModel1.Download();
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
viewModel1:
public class DownloadViewModel: INotifyPropertyChanged
{
Thread _thread;
public void Download()
{
ThreadStart threadStart = delegate()
{
StartDownload();
};
_thread = new Thread(threadStart);
_thread.IsBackground = true;
_thread.Start();
}
private void StartDownload()
{
for (int i = 10; i < 1500; i++)
{
Thread.Sleep(5000);
Message = "Downloading " + i.ToString();
}
}
private string _message = "";
public string Message
{
get
{
return _message;
}
set
{
if (_message != value)
{
_message = value;
OnPropertyChanged("Message");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Your viewModel1 has to be a property, and it's a field at the moment. Change it to:
public DownloadViewModel viewModel1 { get; set; }
Explanation why such restriction exists, can be found here (primarily due to notification/verifications mechanisms simply not working for fields):
Why does WPF support binding to properties of an object, but not fields?

Categories