WP8绑定不更新

时间:2012-12-29 16:11:35

标签: c# .net windows-phone-8

我正在尝试创建一个WP8应用程序,它从网站获取数据并显示它们。 我选择了全景模板,Visual Studio创建了一些默认代码。

我想要做的是,如果我更改文本绑定的变量,文本块会自动更新。但是调用changeDate()不会更改UI。文本框仍然显示“dd.mm.yyyy”。

MainPage.xaml:
<phone:LongListSelector.ListHeaderTemplate>
  <DataTemplate>
    <Grid Margin="12,0,0,38">
      <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
      </Grid.RowDefinitions>
      <TextBlock
          Text="{Binding Date}"
          Style="{StaticResource PanoramaItemHeaderTextStyle}"
          Grid.Row="0">
        <TextBlock.DataContext>
          <ViewModels:MainViewModel/>
        </TextBlock.DataContext>
      </TextBlock>
    </Grid>
  </DataTemplate>
</phone:LongListSelector.ListHeaderTemplate>

MainViewModel.cs:
public class MainViewModel : INotifyPropertyChanged
{
    [...]

    private string _date = "dd.mm.yyyy";
    public string Date
    {
        get
        {
            return _date;
        }
        set
        {
            if (value != _date)
            {
                _date = value;
                NotifyPropertyChanged("Date");
            }
        }
    }

    //public void changeDate()
    //{
    //    Date = "fu";
    //    App.ViewModel.Date = "bar";
    //}

**UPDATE 2**
    public bool IsDataLoaded
    {
        get;
        private set;
    }

    public void LoadData()
    {
        System.Net.WebClient wc = new System.Net.WebClient();
        wc.DownloadStringCompleted += wc_DownloadStringCompleted;
        wc.DownloadStringAsync(new Uri("somelink"));
    }

    private void wc_DownloadStringCompleted(object sender, System.Net.DownloadStringCompletedEventArgs e)
    {
        string s = FilterData(e.Result);
    }

    private string FilterData(string s)
    {
        string[] split = System.Text.RegularExpressions.Regex.Split(s, "<tbody>");
        s = split[1];
        split = System.Text.RegularExpressions.Regex.Split(s, "</tbody>");
        s = split[0];
        split = System.Text.RegularExpressions.Regex.Split(s, "\r\n");

        foreach(string str in split)
        {

            if (str.Contains("class=\"xl24\""))
            {
                App.ViewModel.Date = "somedate";
            }
        }

        return s;
    }
**END UPDATE 2**

[...]

    private void NotifyPropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (null != handler)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

更新1

MainPage.xaml.cs:
public MainPage()
{
    InitializeComponent();

    DataContext = App.ViewModel;
}

**UPDATE 2**
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    if (!App.ViewModel.IsDataLoaded)
    {
        App.ViewModel.LoadData();
    }
}
**END UPDATE 2**

[...]

App.xaml.cs:
private static MainViewModel viewModel = null;

public static MainViewModel ViewModel
{
    get
    {
        if (viewModel == null)
            viewModel = new MainViewModel();

        return viewModel;
    }
}
[...]

2 个答案:

答案 0 :(得分:1)

我认为发生的是从某个工作线程调用 NotifyPropertyChanged ,这可能导致从同一个工作线程调用 Date getter。如果UI元素从工作线程调用数据获取器(而不是从主UI线程),则操作以“无效的跨线程访问”结束。如果是这样,您应该从主线程进行处理程序调用。例如:

private void NotifyPropertyChanged(String propertyName)
{
    PropertyChangedEventHandler handler = PropertyChanged;
    if (null != handler)
    {
        Dispatcher dsp = Deployment.Current.Dispatcher;
        dsp.BeginInvoke(() => { 
            handler(this, new PropertyChangedEventArgs(propertyName));
        });
    }
}

希望有所帮助

答案 1 :(得分:0)

<TextBlock.DataContext>
    <ViewModels:MainViewModel/>
</TextBlock.DataContext>

这将创建一个新的MainViewModel对象,您不会更新此对象,而是更新存储在App对象中的对象。

要解决此问题:将View的数据上下文设置为App.ViewModel对象(无需设置TextBlock的数据上下文)

额外:请不要使用此代码:

public void changeDate()
{
    Date = "fu";
    App.ViewModel.Date = "bar";
}

现在,您的ViewModel了解应用程序。只需使用:

public void changeDate()
{
    Date = "fu";
}