【问题标题】:Silverlight bind object in list view using converterSilverlight 使用转换器在列表视图中绑定对象
【发布时间】:2012-05-23 11:05:07
【问题描述】:

您好,我在强制更新列表视图时遇到了一点问题。 我有 ObservableCollection,它包含具有属性 Buffer 的 TestClass 对象。

ObservalbeCollection 驻留在 ViewModel BaseViewModel 中

public partial class MainPage : PhoneApplicationPage {
   // Constructor
    public MainPage() {
      InitializeComponent();
      this.DataContext = new BaseViewModel();
    }
  }
}

public class BaseViewModel : INotifyPropertyChanged {
  public ObservableCollection<TestClass> TestList { get; set; }
  public BaseViewModel() {
    TestList = new ObservableCollection<TestClass>();
    TestList.Add(new TestClass() { Buffer = "1", SomeValue = 1 });
    TestList.Add(new TestClass() { Buffer = "2", SomeValue = 2 });
    TestList.Add(new TestClass() { Buffer = "3", SomeValue = 3 });
    TestList.Add(new TestClass() { Buffer = "4", SomeValue = 4 });
  }

  private TestClass selectedItem;
  public TestClass SelectedItem {
    get {
      return selectedItem;
    }
    set {
      if (selectedItem == value) {
        return;
      }

      selectedItem = value;
      selectedItem.Buffer += "a";
      selectedItem.SomeValue += 1;
      selectedItem = null;
      RaisePropertyChanged("SelectedItem");
    }
  }

  #region notifie property changed
  public event PropertyChangedEventHandler PropertyChanged;

  public void RaisePropertyChanged(string propertyName) {
    PropertyChangedEventHandler handler = this.PropertyChanged;
    if (handler != null) {
      handler(this, new PropertyChangedEventArgs(propertyName));
    }
  }
  #endregion
}

public class TestClass : INotifyPropertyChanged  {

  public TestClass() {
  }

  public int SomeValue { get; set; }

  private string buffer;
  public string Buffer {
    get {
      return this.buffer;
    }
    set {
      this.buffer = value;
      RaisePropertyChanged("Buffer");        
    }
  }

  #region notifie property changed
  public event PropertyChangedEventHandler PropertyChanged;

  public void RaisePropertyChanged(string propertyName) {
    PropertyChangedEventHandler handler = this.PropertyChanged;
    if (handler != null) {
      handler(this, new PropertyChangedEventArgs(propertyName));
    }
  }
  #endregion
}

我正在将视图模型绑定到页面。

页面xml:

<phone:PhoneApplicationPage 
     xmlns:converters="clr-namespace:PhoneApp2.Test">

<phone:PhoneApplicationPage.Resources>
    <converters:TestClassConverter x:Key="testConverter"/>
</phone:PhoneApplicationPage.Resources>

<ListBox Grid.Row="1" x:Name="tasksListBox" ItemsSource="{Binding TestList}"
                 SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
                 >
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="SomeText"/>
                    <TextBlock Text="{Binding Path=Buffer}"/>
                    <TextBlock Text="{Binding Converter={StaticResource testConverter}}"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

现在第二个文本块在缓冲区更改时正确更新,但第三个仅更新一次(在列表加载时)。转换器只被调用一次。

我想使用第三个选项,因为:

a) 我使用 TestCalass 作为其他子类的基类

b) 我想根据 TestClass 类型格式化输出并使用在 TestClass 中设置的其他参数

c) 我想使用 Localizable String 资源,但我不想在 TestClass 中使用它们,而是使用 POCO 对象。

编辑: 我已经更新了源代码。第二个文本框改变,而第三个没有。所有类都期望 MainPage 驻留:

namespace PhoneApp2.Test

【问题讨论】:

    标签: c# silverlight windows-phone-7 xaml


    【解决方案1】:

    更新时将TestList改为调用RaisePropertyChanged是否有效?

    (如果你提供了完整的复制品,我会自己检查。)

    【讨论】:

    • 如何更改“TestList”以便调用“RaisPropertyChanged”。我应该创建自己的 ObservableList 实现吗?我不更改列表中的对象数。我只更改了该列表中对象的某些属性。但在此之后我设置 'SelectedIndex=null';
    【解决方案2】:

    一旦更新其组件之一,并且如果此更新由事件(如 PropertyChanged)宣布,则绑定会立即更新。

    绑定

    <TextBlock Text="{Binding Converter={StaticResource testConverter}}"/>
    

    始终不变:它始终绑定到同一个列表条目。因此,无论您在此列表条目中进行什么更改,都不会通知 Binding。

    AFAIK 如果引发 INotifyCollectionChanged 的​​ CollectionChanged 事件,将重新评估绑定。您可以通过在已引发的 PropertyChanged 事件之外引发 CollectionChanged 事件来做到这一点 - 但是这会重新评估整个列表并可能导致性能问题。

    编辑:您需要引发 TestList 的 CollectionChanged 事件,这可能是不可能的。您可能需要从 ObservableCollection 中调用 BaseViewModel 才能执行此操作。

    【讨论】:

    • 也许我应该以不同的方式完全做到这一点。有什么建议?这种情况有什么规律吗?
    • 取决于你的最终目标... - Idea 0(一般无用):如果转换器不需要该值,则将其绑定到 Buffer。这将触发重新评估。 - 想法1(肮脏的黑客,快速):向TestClass添加一个属性,该属性返回类实例本身,将其绑定到转换器并为缓冲区和这个新属性引发PropertyChanged。 - 想法 2(干净、通用、慢):为 TestClass 及其所有派生类创建模板,实现 ItemTemplateSelector / DataTemplateSelector,如 link
    猜你喜欢
    • 1970-01-01
    • 2012-03-10
    • 2011-07-30
    • 2015-01-16
    • 1970-01-01
    • 1970-01-01
    • 2011-03-07
    • 2012-01-14
    • 2012-03-27
    相关资源
    最近更新 更多