2

New to WPF.

I am trying to bind my Model to my UI. So, when the Property is changed during my User actions I want the field to update whereever it occurs on my UI.

This is my Model:

namespace WpfApplication1
{
    public class model2
    {
        private static string myField2;

        public static string MyField2
        {

            get { return myField2; }
            set { myField2 = value; }
        }
    }
}

My Markup:

<Window x:Class="WpfApplication1.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:WpfApplication1"       
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:model2 x:Key="mymodel"/>
    </Window.Resources>
    <Grid>
        <StackPanel Orientation="Vertical">
            <TextBlock Text="{Binding Source={StaticResource ResourceKey=mymodel}, Path=MyField2}"></TextBlock>     
            <Button Content="static test!" Click="Button_Click_1" />
        </StackPanel>
    </Grid>
</Window>

My code behind:

using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            model2.MyField2 = "static!";
        }
    }
}

The field on the UI does not change?

Andrew Simpson
  • 6,883
  • 11
  • 79
  • 179
  • Your property setter doesn't raise any event, so the binding cannot detect the change. It would have to raise a static PropertyChanged event for this to work. Anyway, are you sure this property really needs to be static? in my experience it's rarely useful to bind t a static property – Thomas Levesque Jan 07 '16 at 14:19
  • @ThomasLevesque hi, thanks for the comment. It all makes sense what you said and yes I am leaning towards using instances now. it was just that when i originally did this app I did not know anything about iNotify and before I did i thought it would be cleaner to implement it. then I found out it was already built in and just needed to be plugged in. Trouble was i had declared everything statically. I tend to declare statically because when I port over to Android devices they all use static properties – Andrew Simpson Jan 07 '16 at 14:24

3 Answers3

6

You need to notify changes to the UI so it can update with new values.

In your case you want to notify static properties of changes so you would need a static event. The problem is the INotifyPropertyChanged interface needs a member event so you won't be able to go that way.

You best shot is to implement the Singleton pattern:

namespace WpfApplication1
{
    public class model2 : INotifyPropertyChanged
    {
        //private ctor so you need to use the Instance prop
        private model2() {}

        private string myField2;

        public string MyField2
        {

            get { return myField2; }
            set { 
                myField2 = value; 
                OnPropertyChanged("MyField2");
            }
        }

        private static model2 _instance;

        public static model2 Instance {
            get {return _instance ?? (_instance = new model2();)}
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName) {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

And then make your property a member property and bind like this:

<Window x:Class="WpfApplication1.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:WpfApplication1"       
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:model2 x:Key="mymodel"/>
    </Window.Resources>
    <Grid>
        <StackPanel Orientation="Vertical">
            <TextBlock Text="{Binding Source={x:Static local:model2.Instance}, Path=MyField2}"/>  
            <Button Content="static test!" Click="Button_Click_1" />
        </StackPanel>
    </Grid>
</Window>

Code behind:

using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            model2.Instance.MyField2 = "static!";
        }
    }
}
nkoniishvt
  • 2,442
  • 1
  • 14
  • 29
2

Use the Static extension to bind the TextBlocks Text Property:

<TextBlock Text="{Binding Source={Static MyModel.MyField2}, Mode=TwoWay">

But still the Property must raise the PropertyChanged event. My understanding why you use the static field is to be able to set the value from somewhere else. Have you thougt about using messages instead? Checkout the MVVM Light toolkit and the messenger. This would decouple the two components

unkreativ
  • 482
  • 2
  • 8
1

I think that static properties are not what you want to use, from comments I can deduce that you are using only to make your program work. Below is the full working code.

App.xaml

Remove the code StartupUri="MainWindow.xaml instead we will instantiate MainWindow in code-behind to provide DataContext.

App.xaml.cs

Here we are assigning object of Model2 as Window.DataContext and then showing the window.

public partial class App : Application
    {
        public App()
        {
            Model2 model = new Model2();
            MainWindow window = new MainWindow();
            window.DataContext = model;
            window.Show();
        }
    }

MainWindow.xaml.cs

   public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            //We get hold of `DataContext` object
            var model = this.DataContext as Model2; 
            model.MyField2 = "Hello World";
        }
    }

Model:

public class Model2 : INotifyPropertyChanged
    {

        private string _myField2;

        public string MyField2
        {
            get { return _myField2; }
            set
            {
                _myField2 = value;
                OnPropertyChanged("MyField2");
            }
        }

        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

MainWindow.xaml

<Window x:Class="WpfApplication2.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>
        <StackPanel Orientation="Vertical">
            <TextBlock Text="{Binding MyField2}"></TextBlock>
            <Button Content="static test!" Click="ButtonBase_OnClick" />
        </StackPanel>
    </Grid>
</Window>

And I checked, it works !

Community
  • 1
  • 1
Marshal
  • 6,551
  • 13
  • 55
  • 91