【问题标题】:WPF data binding to a data model as an application resourceWPF 数据绑定到数据模型作为应用程序资源
【发布时间】:2011-12-01 12:00:20
【问题描述】:

我遇到了数据绑定问题。我在 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() 方法前面停止并等待几秒钟的代码时,我得到了传输数据的最新结果,但就是这样,它再也不会更新了。

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

【问题讨论】:

  • 如何更改应用资源的值?
  • 在我的客户内部。 DataModel 有一个名为 update(Message) 的方法,我在其中传递收到的消息并相应地更新值。所以客户端知道 DataModel 并且也需要访问它。
  • 你的数据模型是什么?收藏?一个列表?上课?
  • 如果它是一个 ObservableCollection 并且你正在做 list = new List();这不起作用,您需要执行 .Clear() 然后添加元素。
  • DataModel 是一个类,它包含一个名为 StatusList 的列表和一些其他属性,当然还有更新列表的方法,它是一个普通的 List 列表,ListStatusList。

标签: wpf xaml data-binding


【解决方案1】:
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;
    }
  }
}

【讨论】:

  • 您好 punker76,感谢您的回复。它完成了更新值的工作。但现在它抛出了很多这样的异常:System.Windows.Data 错误:4:找不到与引用'RelativeSource FindAncestor,AncestorType ='System.Windows.Controls.ItemsControl',AncestorLevel ='1''的绑定源。绑定表达式:路径=垂直内容对齐;数据项=空;目标元素是'ListViewItem'(名称='');目标属性是“VerticalContentAlignment”(类型“VerticalAlignment”)
  • 我无法想象它与重置列表有关。带有ListView的xaml代码只是整段代码的摘录吗?
  • 是的,它是 XAML 文件中唯一的代码,代码隐藏文件中也没有代码。我认为它与 new 运算符有关,当它应用时,源丢失,抛出异常?
  • 您是否尝试过从 ListView 中删除 Horizo​​ntalContentAlignment="Left" VerticalContentAlignment="Top"
  • 我试过了,但没有帮助。相反,它增加了我得到的异常数量;)
【解决方案2】:

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

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-05
    • 1970-01-01
    • 1970-01-01
    • 2011-02-03
    • 1970-01-01
    • 2011-02-21
    • 2013-11-07
    相关资源
    最近更新 更多