0

I am Silverlight newbie and I can't make the simple Silverlight binding sample work!

I need to make a view-model, that shows the number of documents in the list, while it is loading.

I made a base-class, that implements INotifyPropertyChanged:

public abstract class BaseViewModel : INotifyPropertyChanged {

    protected BaseViewModel() {}


    #region INotifyPropertyChanged Members

    protected void OnPropertyChanged(string propertyName) {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

I made a child-class, that has "CountDocs" property:

public class DocumentViewModel : BaseViewModel {

    public DocumentViewModel () {
    ...
    }

...

    public int CountDocs {
        get { return countDocs; }
        set {
            if (countDocs != value) {
                countDocs = value;
                OnPropertyChanged("CountDocs");
            }
        }
    }

    public int countDocs;

}

I have DocumentViewModel.xaml with the following contents:

<UserControl 
...
xmlns:vm="clr-namespace: ... .ViewModels" >
...
<UserControl.Resources>
    <vm:DocumentViewModel  x:Key="viewModel"/>
</UserControl.Resources>
...
<TextBlock x:Name="CounterTextBlock" Text="{Binding Source={StaticResource viewModel}, Path=CountDocs}"></TextBlock>

That is I mentioned namespace of my child-class, I made a resource of my child class with key "viewModel", and I entered binding of textblock, to this object's property "CountDocs".

The problem is that the CountDocs property fills the TextBlock only once: on load. But then I set CountDocs, and it does not fill the TextBlock.

I have tried to use the Mode property of binding, to use DataContext, but I still can't make it work.

Is there something wrong with the binding? How to make the ViewModel update when the CountDocs property of my object is changed?

Thanks

4

3 回答 3

0

If I understand the details of your question, you may be updating a UI bound value on a background thread (as documents load).

You need to make that happen on the UI thread or the change will not be visible. In one of our WPF apps random updates were disappearing until we realised this.

We do a lot of multi-threading in our Silverlight (and WPF) apps so to avoid this problem, we implemented our notify helper in a base class like the one below (other stuff trimmed out). It dispatches all notify messages on the main UI thread. Give it a try:

public class ViewModelBase : INotifyPropertyChanged
{
    protected delegate void OnUiThreadDelegate();

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void SendPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            // Ensure property change is on the UI thread
            this.OnUiThread(() => this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)));
        }
    }

    protected void OnUiThread(OnUiThreadDelegate onUiThreadDelegate)
    {
        // Are we on the Dispatcher thread ?
        if (Deployment.Current.Dispatcher.CheckAccess())
        {
            onUiThreadDelegate();
        }
        else
        {
            // We are not on the UI Dispatcher thread so invoke the call on it.
            Deployment.Current.Dispatcher.BeginInvoke(onUiThreadDelegate);
        }
    }
}
于 2012-08-14T09:18:47.723 回答
0

Ok since you created your ViewModel instance in your XAML, you'll need to access and use that ViewModel.

If you have another instance, that instance won't update your binding. Only the instance created in your Resources would be used.

Now you said you set the CountDocs property but I don't see any code for that. Whereever you do that, you have to use the ViewModel instance from your Resources.

This is why I like to instantiate my view model in my constructor of my view and keep a reference to it. Also unless you plan to have many data sources attached to your bindings, you can simply set the LayoutRoot.DataContext to you ViewModel instance and remove the Source attribute in your binding.

ViewModelBase _vm = null;
public MyView()
{
_vm = new DocumentViewModel();
this.LayoutRoot.DataContext = _vm;
}

In XAML, <TextBlock x:Name="CounterTextBlock" Text="{Binding CountDocs}"></TextBlock>

于 2012-08-14T12:11:36.373 回答
0

As we found out in the comments to your question, you had your ViewModel instantiated twice, and changed the property value on the one which was not actually bound to the view.

How can that be? You're either using an MVVM framework that wires up ViewModels to Views automatically, or it happens somewhere in your code where you're not aware of. Put a breakpoint in the constructor, and when it hits, analyze the Call Stack in Visual Studio.

于 2012-08-17T08:40:53.390 回答