WPF数据绑定到数据模型作为应用程序资源

时间:2011-12-01 12:00:20

标签: wpf xaml data-binding

我遇到数据绑定问题。我在XAML中定义了一个应用程序资源,如下所示:

<Application.Resources>
   <local:DataModel x:Key="myDataModel"/>
</Application.Resources>

我将该模型绑定到列表中,如下所示:

<ListView Name="ListBox" 
          ItemsSource="{Binding Source={StaticResource myDataModel}, Path=StatusList}" 
          HorizontalAlignment="Left" 
          HorizontalContentAlignment="Left" 
          VerticalContentAlignment="Top" 
          BorderThickness="0" 
          Background="#000000">
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"></StackPanel>
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>

    <ListView.ItemTemplate>
        <DataTemplate>
            <Button MinWidth="20" 
                    MinHeight="100" 
                    Background="{Binding Converter={StaticResource StatusConverter}}" 
                    Content="{Binding}" />
        </DataTemplate>
     </ListView.ItemTemplate>
</ListView>

现在的问题是,如果我在绑定后更改应用程序资源的值,则不会更新列表。似乎绑定是使用副本而不是引用完成的。模型的数据更新正常,引发了PropertyChanged事件,但列表中的数据永远不会更改。

为了您的理解:我有一个网络客户端,每隔10秒就会收到需要在该列表中绘制数据的新数据。现在每当我收到数据时,我都会更新应用程序资源,正如我所说的那样应该绑定到列表中。当我调试代码停在包含列表的XAML文件的InitializeComponent()方法前面并等待几秒钟时,我得到了传输数据的最新结果,但就是这样,它永远不会再次更新

您能告诉我一个更好的方法来定义我的模型的全局可用实例或更好的绑定方式吗?如你所见,我需要在程序的多个部分中使用它。

2 个答案:

答案 0 :(得分:0)

public class DataModel
{
  private IObservableCollection<short> this.statusList;
  public IObservableCollection<short> StatusList
  {
    get {
      return this.statusList;
    }
    set {
      this.statusList = value;
      this.RaisePropertyChanged("StatusList");
    }
  } 
}

现在你可以做到这一点

this.StatusList = new ObservableCollection<short>();

希望这会有所帮助

修改

以下是我正在运行的示例,没有任何问题。

<Window x:Class="WpfStackOverflowSpielWiese.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfStackOverflowSpielWiese"
        Title="Window1"
        Height="300"
        Width="300">

  <Window.Resources>
    <local:DataModel x:Key="myDataModel" />
    <local:StatusConverter x:Key="StatusConverter" />
  </Window.Resources>

  <Grid>

    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition />
    </Grid.RowDefinitions>

    <Button Grid.Row="0"
            Content="Update"
            Click="Button_Click" />

    <ListView Name="ListBox"
              Grid.Row="1"
              ItemsSource="{Binding Source={StaticResource myDataModel}, Path=StatusList}"
              HorizontalAlignment="Left"
              HorizontalContentAlignment="Left"
              VerticalContentAlignment="Top"
              BorderThickness="0"
              Background="#000000">
      <ListView.ItemsPanel>
        <ItemsPanelTemplate>
          <StackPanel Orientation="Horizontal"></StackPanel>
        </ItemsPanelTemplate>
      </ListView.ItemsPanel>

      <ListView.ItemTemplate>
        <DataTemplate>
          <Button MinWidth="20"
                  MinHeight="100"
                  Background="{Binding Converter={StaticResource StatusConverter}}"
                  Content="{Binding}"></Button>
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>

  </Grid>
</Window>


using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;

namespace WpfStackOverflowSpielWiese
{
  /// <summary>
  /// Interaction logic for Window1.xaml
  /// </summary>
  public partial class Window1 : Window
  {
    public Window1() {
      this.InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e) {
      var dataModel = this.TryFindResource("myDataModel") as DataModel;
      if (dataModel != null) {
        dataModel.UpdateStatusList(new[] {(short)1, (short)2, (short)3});
      }
    }
  }

  public class DataModel : INotifyPropertyChanged
  {
    private ObservableCollection<short> statusList;

    public DataModel() {
      this.StatusList = new ObservableCollection<short>();

      this.UpdateStatusList(new[] {(short)1, (short)2, (short)3});
    }

    public void UpdateStatusList(IEnumerable<short> itemsToUpdate) {
      foreach (var s in itemsToUpdate) {
        this.StatusList.Add(s);
      }
    }

    public ObservableCollection<short> StatusList {
      get { return this.statusList; }
      set {
        this.statusList = value;
        this.RaisePropertyChanged("StatusList");
      }
    }

    private void RaisePropertyChanged(string propertyName) {
      var eh = this.PropertyChanged;
      if (eh != null) {
        eh(this, new PropertyChangedEventArgs(propertyName));
      }
    }

    public event PropertyChangedEventHandler PropertyChanged;
  }

  public class StatusConverter : IValueConverter
  {
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
      if (value is short) {
        switch ((short)value) {
          case 1:
            return Brushes.Red;
          case 2:
            return Brushes.Orange;
          case 3:
            return Brushes.Green;
        }
      }
      return Brushes.White;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
      return DependencyProperty.UnsetValue;
    }
  }
}

答案 1 :(得分:0)

我已经解决了这个问题。我更改了列表中的值。但我需要做的是创建一个新值并添加新值。我需要做的就是添加这一行:

this.StatusList = new IObservableCollection<short>()

而不是这样做:

for(int i=0; i<ListSize; i++)
    StatusList[i] = i;

我必须这样做:

for(int i=0; i<ListSize; i++)
    StatusList.add( i );

您还需要从此处获得一些解决方法:ListBoxItem produces "System.Windows.Data Error: 4" binding error

surronding元素需要使用如下样式设置对齐属性:

<Style TargetType="{x:Type ListBoxItem}">
    <Setter Property="HorizontalContentAlignment" Value="Left" />
    <Setter Property="VerticalContentAlignment" Value="Top" />
</Style>

这样可以避免System.Windows.Data错误4异常

再次感谢所有回答的人! :)